Class Expr represents a mathematical expression. An Expr can be an atomic entity such as a constant, a function, or a differential operator; or an expr can be a compound object such as a sum, project, or list of exprs.
The simplest type of Expr to create is a constant real-valued Expr, for example:
Expr solarMass = 2.0e33; // mass of the Sun in grams
More generally, you can create an Expr by giving its constructor a pointer to an ExprBase subclass object. For example, to construct an Expr that represents the coordinate on the zeroth (x) axis, create a new CoordExpr object and pass it to an Expr ctor as follows:
Expr x = new CoordExpr(0, "x");
The expression types that can be created at the user level are
You might want to do several types of output with Exprs:
Expr f = 1.0 + 2.0*x; cout << f << endl; // writes 1 + 2*x; // or cout << f.toString() << endl;
It is important to understand the meaning of the assignment (=) operator for Sundance Exprs. Assignment and copy are by reference, so that if you create an expression
f = a + b + c;
c
\c, c = sin(x);
cout << f << endl; // will print a + b + sin(x)
This feature lets you automatically update expressions in timestepping or nonlinear solve loops, making the code for such problems more efficient and much easier to understand.
The case when the lhs of an assignment operator appears on the rhs is handled as follows: the sequence of operations
x = 5; x = y + x;
Exprs can be listed heterogeneously. Listing can be used to create vector-valued or tensor-valued exprs.
You can create a listed expr using the List global method. For example, List(a, List(b, c)) produces a list that is structured like {a, {b, c}}. Lists can be manipulated with append(), join(), and flatten() methods, and elements (either scalar entries or sublists) can be accessed with the bracket ([]) operator.
The List() methods can take at most four entries. If you want to build a list with greater than four elements, create a list and then append to it.
Operator overloading is used to represent operations on Exprs:
Expr f = x + y + x;
cout << f << endl; // prints 2*x + y
Expr f = x + y - x;
cout << f << endl; // prints y
Warning It is quite possible to create a meaningless expr, for example dividing by a vector-valued expr, x/{y,z}. It is not possible to detect such nonsensical exprs at compile-time, so all operations are checked at runtime and if nonsense is detected an exception is thrown.
Differentiation operators are represented by the Derivative class. Application of a Derivative is done with the overloaded multiplication operator:
// create a differentiation operator Expr dx = new Derivative(0,1); // create some function f Expr f = x*x; // differentiate f Expr df = dx*f; cout << df << endl; // prints 2*x
Sundance symbolic objects are programmed to obey the sum, product, quotient, and chain rules.
Elementary functions have been overloaded to act on Sundance Exprs. The argument to an elementary function must be a scalar-valued Expr. Example:
Expr f = sin(x);
Expr df = dx*f;
cout << df << endl; // prints cos(x)
Currently, Sundance defines: sin, cos, exp, log, cosh, sinh, sqrt, and pow.