expression

This module defines the function parse(), which parses a tensor expression.

nutils.expression.parse(expression, variables, functions, indices, arg_shapes={}, default_geometry_name='x')

Parse expression and return AST.

This function parses a tensor expression with Einstein Summation Convection stored in a str and returns an Abstract Syntax Tree (AST). The syntax of expression is as follows:

  • Integers or decimal numbers are denoted in the usual way. Examples: 1, 1.2, .2. A number may not start with a zero, except when followed by a dot: 0.1 is valid, but 01 is not.

  • Variables are denoted with a string of alphanumeric characters. The first character may not be a numeral. Unlike Python variables, underscores are not allowed, as they have a special meaning. If the variable is an array with one or more axes, all those axes should be labeled with a latin character, the index, and appended to the variable with an underscore. For example an array a with two axes can be denoted with a_ij. Optionally, a single numeral may be used to select an item at the concerning axis. Example: in a_i0 the first axis of a is labeled i and the first element of the second axis is selected. If the same index occurs twice, the trace is taken along the concerning axes. Example: the trace of the first and third axes of b is denoted by b_iji. It is invalid to specify an index more than twice. The following names cannot be used as variables: n, δ, $. The variable named x, or the value of argument default_geometry_name, has a special meaning, detailed below.

  • A term, the product of two or more arrays or scalars, is denoted by space-separated variables, constants or compound expressions. Example: a b c denotes the product of the scalars a, b and c. A term may start with a number, but a number is not allowed in other parts of the term. Example: 2 a denotes two times a; 2 2 a and 2 a 2` are invalid. When two arrays in a term have the same index, this index is summed. Example: a_i b_i denotes the inner product of a and b and A_ij b_j` a matrix vector product. It is not allowed to use an index more than twice in a term.

  • The operator / denotes a fraction. Example: in a b / c d a b is the numerator and c d the denominator. Both the numerator and the denominator may start with a number. Example: 2 a / 3 b. The denominator must be a scalar. Example: 2 / a_i b_i is valid, but 2 a_i / b_i is not.

    Warning

    This syntax is different from the Python syntax. In Python a*b / c*d is mathematically equivalent to a*b*d/c.

  • The operators + and - denote add and subtract. Both operators should be surrounded by whitespace, e.g. a + b. Both operands should have the same shape. Example: a_ij + b_i c_j is a valid, provided that the lengths of the axes with the same indices match, but a_ij + b_i is invalid. At the beginning of an expression or a compound - may be used to negate the following term. Example: in -a b + c the term a b is negated before adding c. It is not allowed to negate other terms: a + -b is invalid, so is a -b.

  • An expression surrounded by parentheses is a compound expression and can be used as single entity in a term. Example: (a_i + b_i) c_i denotes the inner product of a_i + b_i with c_i.

  • Exponentiation is denoted by a ^, where the left and right operands should be a number, variable or compound expression and the right operand should be a scalar. Example: a^2 denotes the square of a, a^-2 denotes a to the power -2 and a^(1 / 2) the square root of a.

  • An argument is denoted by a name — following the same rules as a variable name — prefixed with a question mark. An argument is a scalar or array with a yet unknown value. Example: basis_i ?coeffs_i denotes the inner product of a basis with unknown coefficient vector ?coeffs. If possible the shape of the argument is deduced from the expression. In the previous example the shape of ?coeffs is equal to the shape of basis. If the shape cannot be deduced from the expression the shape should be defined manually (see parse()). Arguments and variables live in separate namespaces: ?x and x are different entities.

  • An argument may be substituted by appending without whitespace (arg = value) to a variable of compound expression, where arg is an argument and value the substitution. The substitution applies to the variable of compound expression only. The value may be an expression. Example: 2 ?x(x = 3 + y) is equivalent to 2 (3 + y) and 2 ?x(x=y) + 3 is equivalent to 2 (y) + 3. It is possible to apply multiple substitutions. Example: (?x + ?y)(x = 1, y = )2 is equivalent to 1 + 2.

  • The gradient of a variable to the default geometry — the default geometry is variable x unless overriden by the argument default_geometry_name — is denoted by an underscore, a comma and an index. If the variable is an array with more than one axis, the underscore is omitted. Example: a_,i denotes the gradient of the scalar a to the geometry and b_i,j the gradient of vector b. The gradient of a compound expression is denoted by an underscore, a comma and an index. Example: (a_i + b_j)_,k denotes the gradient of a_i + b_j. The usual summation rules apply and it is allowed to use a numeral as index. The surface gradient is denoted with a semicolon instead of a comma, but follows the same rules as the gradient otherwise. Example: a_i;j is the sufrace gradient of a_i to the geometry. It is also possible to take the gradient to another geometry by appending the name of the geometry, which should exist as a variable, and an underscore directly after the comma of semicolon. Example: a_i,altgeom_j denotes the gradient of a_i to altgeom and the gradient axis has index j. Futhermore, it is possible to take the derivative to an argument by adding the argument with appropriate indices after the comma. Example: (?x^2)_,?x denotes the derivative of ?x^2 to ?x, which is equivalent to 2 ?x, and (?y_i ?y_i),?y_j is the derivative of ?y_i ?y_i to ?y_j, which is equivalent to 2 ?y_j.

  • The normal of the default geometry is denoted by n_i, where the index i may be replaced with an index of choice. The normal with respect to different geometry is denoted by appending an underscore with the name of the geometry right after n. Example: n_altgeom_j is the normal with respect to geometry altgeom.

  • A dirac is denoted by δ or $ and takes two indices. The shape of the dirac is deduced from the expression. Example: let A be a square matrix with three rows and columns, then δ_ij in (A_ij - λ δ_ij) x_j has three rows and columns as well.

  • An expression surrounded by square brackets or curly braces denotes the jump or mean, respectively, of the enclosed expression. Example: [ a_i ] denotes the jump of a_i and { a_i + b_i } denotes the mean of a_i + b_i.

  • A function call is denoted by a name — following the same rules as for a variable name — directly followed by the left parenthesis (, without a space. The arguments to the function are separated by a comma and at least one space. The function is applied pointwise to the arguments and all arguments should have the same shape. Example: f(x_i, y_i).denotes the call to function f with arguments x_i and y_i. Functions and variables share a namespace: defining a variable with the same name as a function renders the function inaccessible.

  • A stack of two or more arrays along an axis is denoted by a < followed by comma and space separated arrays followed by > and an index. If an argument does not have an axis with the specified stack index, the argument is expanded with an axis of length one. Beside the stack axis, all arguments should have the same shape. Example: <1, x_i>_i, with x a vector of length three, creates an array with components 1, x_0, x_1, x_2.

Parameters
  • expression (str) – The expression to parse. See expression for the expression syntax.

  • variables (dict of str and nutils.function.Array pairs) – A dict of variable names and array pairs. All variables used in the expression should exist in variables.

  • functions (dict of str and int pairs) – A dict of function names and number of arguments pairs. All functions used in the expression should exist in functions.

  • indices (str) – The indices used for aligning the resulting array. For example, let expression be 'a_ij'. If indices is 'ij', then the returned array is simply variables['a'], but if indices is 'ji' the transpose of variables['a'] is returned. All indices of the expression should be listed precisely once.

  • arg_shapes (dict of str and tuple or ints pairs) – A dict of argument names and shapes. If expression contains an argument not present in arg_shapes the shape will be decuded from the expression and added to a copy of arg_shapes.

  • default_geometry_name (str) – The name of the default geometry variable. When computing a gradient or the normal, e.g. 'f_,i' or 'n_i', this variable is used as the geometry, unless the geometry is explicitly mentioned in the expression. Default: 'x'.

Returns

  • ast (tuple) – The parsed expression as an abstract syntax tree (AST). The AST is a tuple of an opcode and arguments. The special opcode None indicates that the single argument is used verbatim. All other opcodes have AST as arguments. The following opcodes exist:

    (None, const)
    ('group', group)
    ('arg', name, *shape)
    ('substitute', array, arg, value)
    ('call', func, arg)
    ('eye', length)
    ('normal', geom)
    ('getitem', array, dim, index)
    ('trace', array, n1, n2)
    ('sum', array, axis)
    ('concatenate', *args)
    ('grad', array, geom)
    ('surfgrad', array, geom)
    ('derivative', func, target)
    ('append_axis', array, length)
    ('transpose', array, trans)
    ('jump', array)
    ('mean', array)
    ('neg', array)
    ('add', left, right)
    ('sub', left, right)
    ('mul', left, right)
    ('truediv', left, right)
    ('pow', left, right)
    
  • arg_shapes (dict of str and tuple of ints pairs) – A copy of arg_shapes updated with shapes of arguments present in this expression.