/** @page libsbml-csharp-math Mathematical Expressions and their Manipulation This section describes libSBML's facilities for working with SBML representations of mathematical expressions. @section math-overview Basic concepts LibSBML uses Abstract Syntax Trees (ASTs) to provide a canonical, in-memory representation for all mathematical formulas regardless of their original format (i.e., C-like infix strings or MathML). In libSBML, an AST is a collection of one or more objects of type @link libsbmlcs.ASTNode ASTNode@endlink. An AST @em node in libSBML is a recursive structure containing a pointer to the node's value (which might be, for example, a number or a symbol) and a list of children nodes. Each @link libsbmlcs.ASTNode ASTNode@endlink node may have none, one, two, or more child depending on its type. The following diagram illustrates an example of how the mathematical expression "1 + 2" is represented as an AST with one @em plus node having two @em integer children nodes for the numbers @c 1 and @c 2. The figure also shows the corresponding MathML 2.0 representation: @htmlinclude astnode-illustration.html The following are noteworthy about the AST representation in libSBML: @li A numerical value represented in MathML 2.0 as a real number with an exponent is preserved as such in the AST node representation, even if the number could be stored in a @c double data type. This is done so that when an SBML model is read in and then written out again, the amount of change introduced by libSBML to the SBML during the round-trip activity is minimized. @li Rational numbers are represented in an AST node using separate numerator and denominator values. These can be retrieved using the methods libsbmlcs.ASTNode.getNumerator() and libsbmlcs.ASTNode.getDenominator(). @li The children of an @link libsbmlcs.ASTNode ASTNode@endlink are other @link libsbmlcs.ASTNode ASTNode@endlink objects. The list of children is empty for nodes that are leaf elements, such as numbers. For nodes that are actually roots of expression subtrees, the list of children points to the parsed objects that make up the rest of the expression. For many applications, the details of ASTs are irrelevant because the applications can use the text-string based translation functions such as libsbmlcs.formulaToString(), libsbmlcs.parseL3Formula(), and libsbmlcs.parseFormula(). If you find the complexity of using the AST representation of expressions too high for your purposes, perhaps the string-based functions will be more suitable. Finally, it is worth noting that the AST and MathML handling code in libSBML remains written in C, not C++, as all of libSBML was originally written in C. Readers may occasionally wonder why some aspects are more C-like than following a C++ style, and that's the reason. @section math-convert Converting between ASTs and Text Strings SBML Levels 2 and 3 represents mathematical expressions using MathML 2.0 (more specifically, a subset of the content portion of MathML 2.0), but most software applications using libSBML do not use MathML directly. Instead, applications generally either interact with mathematics in text-string form, or else they use the API for working with Abstract Syntax Trees (described below). LibSBML provides support for both approaches. The libSBML formula parser has been carefully engineered so that transformations from MathML to infix string notation and back is possible with a minimum of disruption to the structure of the mathematical expression. The example below shows a simple program that, when run, takes a MathML string compiled into the program, converts it to an AST, converts that to an infix representation of the formula, compares it to the expected form of that formula, and finally translates that formula back to MathML and displays it. The output displayed on the terminal should have the same structure as the MathML it started with. The program is a simple example of using the various MathML and AST reading and writing methods, and shows that libSBML preserves the ordering and structure of the mathematical expressions. @code{.cs} using System; using libsbml; public class Example { public static void Main(String[] args) { String expected = "1 + f(x)"; String input_mathml = "" + "" + " 1 " + " f x " + " " + ""; ASTNode ast_result = libsbmlcs.libsbml.readMathMLFromString(input_mathml); String ast_as_string = libsbmlcs.libsbml.formulaToString(ast_result); if (ast_as_string == expected) { Console.WriteLine("Got expected result."); } else { Console.WriteLine("Mismatch after readMathMLFromString()."); Environment.Exit(1); } ASTNode new_mathml = libsbmlcs.libsbml.parseFormula(ast_as_string); String new_string = libsbmlcs.libsbml.writeMathMLToString(new_mathml); Console.WriteLine("Result of writing AST to string:"); Console.WriteLine(new_string); } } @endcode The text-string form of mathematical formulas produced by libsbmlcs.libsbml.formulaToString() and read by libsbmlcs.libsbml.parseL3Formula() and libsbmlcs.libsbml.parseFormula() are in a simple C-inspired infix notation. It is summarized in the next section below. A formula in this text-string form therefore can be handed to a program that understands SBML mathematical expressions, or used as part of a translation system. In summary, the functions available are the following: @li libsbmlcs.libsbml.formulaToString(ASTNode) \f$\rightarrow\f$ @c string reads an AST, converts it to a text string in SBML Level 1 formula syntax, and returns it. The caller owns the character string returned and should free it after it is no longer needed. @li libsbmlcs.libsbml.parseFormula(string) \f$\rightarrow\f$ @link libsbmlcs.ASTNode ASTNode@endlink reads a text-string containing a mathematical expression in SBML Level 1 syntax, and returns an AST corresponding to the expression. @li libsbmlcs.libsbml.parseL3Formula(string) \f$\rightarrow\f$ @link libsbmlcs.ASTNode ASTNode@endlink reads a text-string containing a mathematical expression in an expanded syntax more compatible with SBML Levels 2 and 3, and returns an AST corresponding to the expression. @section math-diffs The String Formula Syntax and Differences with MathML The text-string formula syntax is an infix notation essentially derived from the syntax of the C programming language and was originally used in SBML Level 1. The formula strings may contain operators, function calls, symbols, and white space characters. The allowable white space characters are tab and space. The following are illustrative examples of formulas expressed in the syntax: @code 0.10 * k4^2 @endcode @code (vm * s1)/(km + s1) @endcode The following table shows the precedence rules in this syntax. In the Class column, @em operand implies the construct is an operand, @em prefix implies the operation is applied to the following arguments, @em unary implies there is one argument, and @em binary implies there are two arguments. The values in the Precedence column show how the order of different types of operation are determined. For example, the expression a * b + c is evaluated as (a * b) + c because the @c * operator has higher precedence. The Associates column shows how the order of similar precedence operations is determined; for example, a - b + c is evaluated as (a - b) + c because the @c + and @c - operators are left-associative. The precedence and associativity rules are taken from the C programming language, except for the symbol @c ^, which is used in C for a different purpose. (Exponentiation can be invoked using either @c ^ or the function @c power.) @htmlinclude math-precedence-table.html A program parsing a formula in an SBML model should assume that names appearing in the formula are the identifiers of @link libsbmlcs.Species Species@endlink, @link libsbmlcs.Parameter Parameter@endlink, @link libsbmlcs.Compartment Compartment@endlink, @link libsbmlcs.FunctionDefinition FunctionDefinition@endlink, or @link libsbmlcs.Reaction Reaction@endlink objects defined in a model. When a function call is involved, the syntax consists of a function identifier, followed by optional white space, followed by an opening parenthesis, followed by a sequence of zero or more arguments separated by commas (with each comma optionally preceded and/or followed by zero or more white space characters), followed by a closing parenthesis. There is an almost one-to-one mapping between the list of predefined functions available, and those defined in MathML. All of the MathML funcctions are recognized; this set is larger than the functions defined in SBML Level 1. In the subset of functions that overlap between MathML and SBML Level 1, there exist a few differences. The following table summarizes the differences between the predefined functions in SBML Level 1 and the MathML equivalents in SBML Level 2: @htmlinclude math-functions.html @section math-ast Methods for working with libSBML's Abstract Syntax Trees Every @link libsbmlcs.ASTNode ASTNode@endlink in a libSBML AST has an associated type, a value taken from a set of constants with names beginning with AST_ and defined in the interface class @link libsbmlcs.libsbml libsbml@endlink. The list of possible types is quite long, because it covers all the mathematical functions that are permitted in SBML's subset of MathML. The values are shown in the following table; their names hopefully evoke the construct that they represent:
AST_UNKNOWNAST_FUNCTION_ARCCOTHAST_FUNCTION_POWER
AST_PLUSAST_FUNCTION_ARCCSCAST_FUNCTION_ROOT
AST_MINUSAST_FUNCTION_ARCCSCHAST_FUNCTION_SEC
AST_TIMESAST_FUNCTION_ARCSECAST_FUNCTION_SECH
AST_DIVIDEAST_FUNCTION_ARCSECHAST_FUNCTION_SIN
AST_POWERAST_FUNCTION_ARCSINAST_FUNCTION_SINH
AST_INTEGERAST_FUNCTION_ARCSINHAST_FUNCTION_TAN
AST_REALAST_FUNCTION_ARCTANAST_FUNCTION_TANH
AST_REAL_EAST_FUNCTION_ARCTANHAST_LOGICAL_AND
AST_RATIONALAST_FUNCTION_CEILINGAST_LOGICAL_NOT
AST_NAMEAST_FUNCTION_COSAST_LOGICAL_OR
AST_NAME_TIMEAST_FUNCTION_COSHAST_LOGICAL_XOR
AST_CONSTANT_EAST_FUNCTION_COTAST_RELATIONAL_EQ
AST_CONSTANT_FALSEAST_FUNCTION_COTHAST_RELATIONAL_GEQ
AST_CONSTANT_PIAST_FUNCTION_CSCAST_RELATIONAL_GT
AST_CONSTANT_TRUEAST_FUNCTION_CSCHAST_RELATIONAL_LEQ
AST_LAMBDAAST_FUNCTION_EXPAST_RELATIONAL_LT
AST_FUNCTIONAST_FUNCTION_FACTORIALAST_RELATIONAL_NEQ
AST_FUNCTION_ABSAST_FUNCTION_FLOOR
AST_FUNCTION_ARCCOSAST_FUNCTION_LN
AST_FUNCTION_ARCCOSHAST_FUNCTION_LOG
AST_FUNCTION_ARCCOTAST_FUNCTION_PIECEWISE
There are a number of methods for interrogating the type of an ASTNode and for testing whether a node belongs to a general category of constructs. The methods are the following: @li @c int @link libsbmlcs.ASTNode.getType() ASTNode.getType()@endlink returns the type of this AST node. @li @c bool @link libsbmlcs.ASTNode.isConstant() ASTNode.isConstant()@endlink returns @c true if this AST node is a MathML constant (@c true, @c false, @c pi, @c exponentiale), @c false otherwise. @li @c bool @link libsbmlcs.ASTNode.isBoolean() ASTNode.isBoolean()@endlink returns @c true if this AST node returns a boolean value (by being either a logical operator, a relational operator, or the constant @c true or @c false). @li @c bool @link libsbmlcs.ASTNode.isFunction() ASTNode.isFunction()@endlink returns @c true if this AST node is a function (i.e., a MathML defined function such as @c exp or else a function defined by a FunctionDefinition in the Model). @li @c bool @link libsbmlcs.ASTNode.isInfinity() ASTNode.isInfinity()@endlink returns @c true if this AST node is the special IEEE 754 value infinity. @li @c bool @link libsbmlcs.ASTNode.isInteger() ASTNode.isInteger()@endlink returns @c true if this AST node is holding an integer value. @li @c bool @link libsbmlcs.ASTNode.isNumber() ASTNode.isNumber()@endlink returns @c true if this AST node is holding any number. @li @c bool @link libsbmlcs.ASTNode.isLambda() ASTNode.isLambda()@endlink returns @c true if this AST node is a MathML @c lambda construct. @li @c bool @link libsbmlcs.ASTNode.isLog10() ASTNode.isLog10()@endlink returns @c true if this AST node represents the @c log10 function, specifically, that its type is @c AST_FUNCTION_LOG and it has two children, the first of which is an integer equal to 10. @li @c bool @link libsbmlcs.ASTNode.isLogical() ASTNode.isLogical()@endlink returns @c true if this AST node is a logical operator (@c and, @c or, @c not, @c xor). @li @c bool @link libsbmlcs.ASTNode.isName() ASTNode.isName()@endlink returns @c true if this AST node is a user-defined name or (in SBML Level 2) one of the two special @c csymbol constructs "delay" or "time". @li @c bool @link libsbmlcs.ASTNode.isNaN() ASTNode.isNaN()@endlink returns @c true if this AST node has the special IEEE 754 value "not a number" (NaN). @li @c bool @link libsbmlcs.ASTNode.isNegInfinity() ASTNode.isNegInfinity()@endlink returns @c true if this AST node has the special IEEE 754 value of negative infinity. @li @c bool @link libsbmlcs.ASTNode.isOperator() ASTNode.isOperator()@endlink returns @c true if this AST node is an operator (e.g., @c +, @c -, etc.) @li @c bool @link libsbmlcs.ASTNode.isPiecewise() ASTNode.isPiecewise()@endlink returns @c true if this AST node is the MathML @c piecewise function. @li @c bool @link libsbmlcs.ASTNode.isRational() ASTNode.isRational()@endlink returns @c true if this AST node is a rational number having a numerator and a denominator. @li @c bool @link libsbmlcs.ASTNode.isReal() ASTNode.isReal()@endlink returns @c true if this AST node is a real number (specifically, @c AST_REAL_E or @c AST_RATIONAL). @li @c bool @link libsbmlcs.ASTNode.isRelational() ASTNode.isRelational()@endlink returns @c true if this AST node is a relational operator. @li @c bool @link libsbmlcs.ASTNode.isSqrt() ASTNode.isSqrt()@endlink returns @c true if this AST node is the square-root operator @li @c bool @link libsbmlcs.ASTNode.isUMinus() ASTNode.isUMinus()@endlink returns @c true if this AST node is a unary minus. @li @c bool @link libsbmlcs.ASTNode.isUnknown() ASTNode.isUnknown()@endlink returns @c true if this AST node's type is unknown. Programs manipulating AST node structures should check the type of a given node before calling methods that return a value from the node. The following meethods are available for returning values from nodes: @li @c int @link libsbmlcs.ASTNode.getInteger() ASTNode.getInteger()@endlink @li @c char @link libsbmlcs.ASTNode.getCharacter() ASTNode.getCharacter()@endlink @li @c string @link libsbmlcs.ASTNode.getName() ASTNode.getName()@endlink @li @c int @link libsbmlcs.ASTNode.getNumerator() ASTNode.getNumerator()@endlink @li @c int @link libsbmlcs.ASTNode.getDenominator() ASTNode.getDenominator()@endlink @li @c double @link libsbmlcs.ASTNode.getReal() ASTNode.getReal()@endlink @li @c double @link libsbmlcs.ASTNode.getMantissa() ASTNode.getMantissa()@endlink @li @c int @link libsbmlcs.ASTNode.getExponent() ASTNode.getExponent()@endlink Finally (and rather predictably), libSBML provides methods for setting the values of AST nodes. @li @link libsbmlcs.ASTNode.setCharacter(char) ASTNode.setCharacter(char)@endlink sets the value of this @link libsbmlcs.ASTNode ASTNode@endlink to the given character. If character is one of @c +, @c -, @c *, @c / or @c ^, the node type will be to the appropriate operator type. For all other characters, the node type will be set to @c AST_UNKNOWN. @li @link libsbmlcs.ASTNode.setName(string) ASTNode.setName(string)@endlink sets the value of this AST node to the given name. The node type will be set (to @c AST_NAME) only if the AST node was previously an operator (@link libsbmlcs.ASTNode.isOperator() isOperator()@endlink != 0) or number (@link libsbmlcs.ASTNode.isNumber() isNumber()@endlink != 0). This allows names to be set for @c AST_FUNCTIONs and the like. @li @link libsbmlcs.ASTNode.setValue(int) ASTNode.setValue(int)@endlink sets the value of the node to the given integer. @li @link libsbmlcs.ASTNode.setValue(int, int) ASTNode.setValue(int, int)@endlink sets the value of this @link libsbmlcs.ASTNode ASTNode@endlink to the given rational in two parts: the numerator and denominator. The node type is set to @c AST_RATIONAL. @li @link libsbmlcs.ASTNode.setValue(double) ASTNode.setValue(double)@endlink sets the value of this @link libsbmlcs.ASTNode ASTNode@endlink to the given floating-point number and sets the node type to @c AST_REAL. @li @link libsbmlcs.ASTNode.setValue(double, int) ASTNode.setValue(double, int)@endlink sets the value of this @link libsbmlcs.ASTNode ASTNode@endlink to the given floating-point number in two parts: the mantissa and the exponent. The node type is set to @c AST_REAL_E. The following are some miscellaneous methods for manipulating ASTs: @li @link libsbmlcs.ASTNode ASTNode@endlink @link libsbmlcs.ASTNode.ASTNode(int) ASTNode.ASTNode(int)@endlink creates a new @link libsbmlcs.ASTNode ASTNode@endlink object and returns a pointer to it. The returned node will have the type identified by the code passed as the argument, or a type of @c AST_UNKNOWN if no type is explicitly given or the type code is unrecognized. @li unsigned int @link libsbmlcs.ASTNode.getNumChildren() ASTNode.getNumChildren()@endlink returns the number of children of this AST node or 0 is this node has no children. @li @link libsbmlcs.ASTNode.addChild(ASTNode) ASTNode.addChild(ASTNode)@endlink adds the given node as a child of this AST node. Child nodes are added in left-to-right order. @li @link libsbmlcs.ASTNode.prependChild(ASTNode) ASTNode.prependChild(ASTNode)@endlink adds the given node as a child of this AST node. This method adds child nodes in right-to-left order. @li @link libsbmlcs.ASTNode ASTNode@endlink @link libsbmlcs.ASTNode.getChild (long) ASTNode.getChild (long)@endlink returns the nth child of this AST node or @c NULL if this node has no nth child (n > (@link libsbmlcs.ASTNode.getNumChildren() ASTNode.getNumChildren()@endlink - 1)). @li @link libsbmlcs.ASTNode ASTNode@endlink @link libsbmlcs.ASTNode.getLeftChild() ASTNode.getLeftChild()@endlink returns the left child of this AST node. This is equivalent to @link libsbmlcs.ASTNode.getChild() ASTNode.getChild(0)@endlink; @li @link libsbmlcs.ASTNode ASTNode@endlink @link libsbmlcs.ASTNode.getRightChild() ASTNode.getRightChild()@endlink returns the right child of this AST node or @c NULL if this node has no right child. @li @link libsbmlcs.ASTNode.swapChildren(ASTNode) ASTNode.swapChildren(ASTNode)@endlink swaps the children of this @link libsbmlcs.ASTNode ASTNode@endlink with the children of @c that @link libsbmlcs.ASTNode ASTNode@endlink. @li @link libsbmlcs.ASTNode.setType(int) ASTNode.setType(int)@endlink sets the type of this @link libsbmlcs.ASTNode ASTNode@endlink to the type identified by the type code passed as argument, or to @c AST_UNKNOWN if the type is unrecognized. @section math-reading Reading and Writing MathML from/to ASTs As mentioned above, applications often can avoid working with raw MathML by using either libSBML's text-string interface or the AST API. However, when needed, reading MathML content directly and creating ASTs, as well as the converse task of writing MathML, is easily done using two methods designed for this purpose: @li @link libsbmlcs.ASTNode ASTNode@endlink @link libsbmlcs.libsbml.readMathMLFromString(string) readMathMLFromString(string)@endlink reads raw MathML from a text string, constructs an AST from it, then returns the root @link libsbmlcs.ASTNode ASTNode@endlink of the resulting expression tree. @li @c string @link libsbmlcs.libsbml.writeMathMLToString(ASTNode) writeMathMLToString(ASTNode)@endlink writes an AST to a string. The caller owns the character string returned and should free it after it is no longer needed. */