gem package¶
Submodules¶
gem.coffee module¶
This module contains an implementation of the COFFEE optimisation algorithm operating on a GEM representation.
This file is NOT for code generation as a COFFEE AST.
- gem.coffee.optimise_monomial_sum(monomial_sum, linear_indices)[source]¶
Choose optimal common atomic subexpressions and factorise a
MonomialSum
object to create a GEM expression.- Parameters:
monomial_sum – a
MonomialSum
objectlinear_indices – tuple of linear indices
- Returns:
factorised GEM expression
gem.flop_count module¶
This file contains all the necessary functions to accurately count the total number of floating point operations for a given script.
- gem.flop_count.count_flops(impero_c)[source]¶
An approximation to flops required for a scheduled impero_c tree.
- Parameters:
impero_c – a
Impero_C
object.- Returns:
approximate flop count for the tree.
- gem.flop_count.expression_flops(expression, temporaries, top=False)[source]¶
An approximation to flops required for each expression.
- Parameters:
expression – GEM expression.
temporaries – Expressions that are assigned to temporaries
top – are we at the root?
- Returns:
flop count for the expression
- gem.flop_count.flops(expr, temporaries)[source]¶
- gem.flop_count.flops(expr: Failure, temporaries)
- gem.flop_count.flops(expr: VariableIndex, temporaries)
- gem.flop_count.flops(expr: Index, temporaries)
- gem.flop_count.flops(expr: Literal, temporaries)
- gem.flop_count.flops(expr: Zero, temporaries)
- gem.flop_count.flops(expr: Delta, temporaries)
- gem.flop_count.flops(expr: Identity, temporaries)
- gem.flop_count.flops(expr: Variable, temporaries)
- gem.flop_count.flops(expr: ListTensor, temporaries)
- gem.flop_count.flops(expr: LogicalOr, temporaries)
- gem.flop_count.flops(expr: LogicalAnd, temporaries)
- gem.flop_count.flops(expr: LogicalNot, temporaries)
- gem.flop_count.flops(expr: Product, temporaries)
- gem.flop_count.flops(expr: MaxValue, temporaries)
- gem.flop_count.flops(expr: MinValue, temporaries)
- gem.flop_count.flops(expr: MathFunction, temporaries)
- gem.flop_count.flops(expr: Comparison, temporaries)
- gem.flop_count.flops(expr: Division, temporaries)
- gem.flop_count.flops(expr: Sum, temporaries)
- gem.flop_count.flops(expr: Power, temporaries)
- gem.flop_count.flops(expr: Conditional, temporaries)
- gem.flop_count.flops(expr: FlexiblyIndexed, temporaries)
- gem.flop_count.flops(expr: Indexed, temporaries)
- gem.flop_count.flops(expr: IndexSum, temporaries)
- gem.flop_count.flops(expr: Inverse, temporaries)
- gem.flop_count.flops(expr: Solve, temporaries)
- gem.flop_count.flops(expr: ComponentTensor, temporaries)
- gem.flop_count.statement(tree, temporaries)[source]¶
- gem.flop_count.statement(tree: Block, temporaries)
- gem.flop_count.statement(tree: For, temporaries)
- gem.flop_count.statement(tree: Initialise, temporaries)
- gem.flop_count.statement(tree: Accumulate, temporaries)
- gem.flop_count.statement(tree: Return, temporaries)
- gem.flop_count.statement(tree: ReturnAccumulate, temporaries)
- gem.flop_count.statement(tree: Evaluate, temporaries)
gem.gem module¶
GEM is the intermediate language of TSFC for describing tensor-valued mathematical expressions and tensor operations. It is similar to Einstein’s notation.
- Its design was heavily inspired by UFL, with some major differences:
GEM has got nothing FEM-specific.
In UFL free indices are just unrolled shape, thus UFL is very restrictive about operations on expressions with different sets of free indices. GEM is much more relaxed about free indices.
Similarly to UFL, all GEM nodes have ‘shape’ and ‘free_indices’ attributes / properties. Unlike UFL, however, index extents live on the Index objects in GEM, not on all the nodes that have those free indices.
- class gem.gem.Concatenate(*args, **kwargs)[source]¶
Bases:
Node
Flattens and concatenates GEM expressions by shape.
Similar to what UFL MixedElement does to value shape. For example, if children have shapes (2, 2), (), and (3,) then the concatenated expression has shape (8,).
- children¶
- property shape¶
- class gem.gem.Failure(*args, **kwargs)[source]¶
Bases:
Terminal
Abstract class for failure GEM nodes.
- exception¶
- shape¶
- class gem.gem.FlexiblyIndexed(*args, **kwargs)[source]¶
Bases:
Scalar
Flexible indexing of :py:class:`Variable`s to implement views and reshapes (splitting dimensions only).
- children¶
- dim2idxs¶
- indirect_children¶
- class gem.gem.Identity(*args, **kwargs)[source]¶
Bases:
Constant
Identity matrix
- property array¶
- dim¶
- property shape¶
- class gem.gem.Index(name=None, extent=None)[source]¶
Bases:
IndexBase
Free index
- count¶
- extent¶
- name¶
- class gem.gem.Indexed(*args, **kwargs)[source]¶
Bases:
Scalar
- children¶
- indirect_children¶
- multiindex¶
- class gem.gem.Inverse(*args, **kwargs)[source]¶
Bases:
Node
The inverse of a square matrix.
- children¶
- shape¶
- class gem.gem.ListTensor(*args, **kwargs)[source]¶
Bases:
Node
- array¶
- property children¶
- get_hash()[source]¶
Hash function.
This is the method to potentially override in derived classes, not
__hash__()
.
- reconstruct(*args)[source]¶
Reconstructs the node with new children from ‘args’. Non-child data are copied from ‘self’.
Returns a new object.
- property shape¶
- class gem.gem.Literal(*args, **kwargs)[source]¶
Bases:
Constant
Tensor-valued constant
- array¶
- get_hash()[source]¶
Hash function.
This is the method to potentially override in derived classes, not
__hash__()
.
- is_equal(other)[source]¶
Equality predicate.
This is the method to potentially override in derived classes, not
__eq__()
or__ne__()
.
- property shape¶
- property value¶
- class gem.gem.Node(*args, **kwargs)[source]¶
Bases:
Node
Abstract GEM node class.
- property T¶
- dtype¶
- free_indices¶
- class gem.gem.OrientationVariableIndex(expression)[source]¶
Bases:
VariableIndex
,Orientation
VariableIndex representing a fiat orientation.
Notes¶
In the current implementation, we need to extract VariableIndex.expression as index arithmetic is not supported (indices are not Node).
- expression¶
- class gem.gem.Solve(*args, **kwargs)[source]¶
Bases:
Node
Solution of a square matrix equation with (potentially) multiple right hand sides.
Represents the X obtained by solving AX = B.
- children¶
- shape¶
- class gem.gem.Variable(*args, **kwargs)[source]¶
Bases:
Terminal
Symbolic variable tensor
- name¶
- shape¶
- class gem.gem.VariableIndex(expression)[source]¶
Bases:
IndexBase
An index that is constant during a single execution of the kernel, but whose value is not known at compile time.
- expression¶
- class gem.gem.Zero(*args, **kwargs)[source]¶
Bases:
Constant
Symbolic zero tensor
- shape¶
- property value¶
- gem.gem.as_gem(expr)[source]¶
Attempt to convert an expression into GEM of scalar type.
Parameters¶
- exprNode or Number
The expression.
Returns¶
- Node
A GEM representation of the expression.
Raises¶
- ValueError
If conversion was not possible.
- gem.gem.index_sum(expression, indices)[source]¶
Eliminates indices from the free indices of an expression by summing over them. Skips any index that is not a free index of the expression.
- gem.gem.indices(n)[source]¶
Make some
Index
objects.- Parameters:
n – The number of indices to make.
- Returns:
A tuple of n
Index
objects.
- gem.gem.partial_indexed(tensor, indices)[source]¶
Generalised indexing into a tensor by eating shape off the front. The number of indices may be less than or equal to the rank of the tensor, so the result may have a non-empty shape.
- Parameters:
tensor – tensor-valued GEM expression
indices – indices, at most as many as the rank of the tensor
- Returns:
a potentially tensor-valued expression
gem.impero module¶
Impero is a helper AST for generating C code (or equivalent, e.g. COFFEE) from GEM. An Impero expression is a proper tree, not directed acyclic graph (DAG). Impero is a helper AST, not a standalone language; it is incomplete without GEM as its terminals refer to nodes from GEM expressions.
- Trivia:
Impero helps translating GEM into an imperative language.
Byzantine units in Age of Empires II sometimes say ‘Impero?’ (Command?) after clicking on them.
- class gem.impero.Accumulate(indexsum)[source]¶
Bases:
Terminal
Accumulate terms into an
gem.IndexSum
.- indexsum¶
- class gem.impero.Block(statements)[source]¶
Bases:
Node
An ordered set of Impero expressions. Corresponds to a curly braces block in C.
- children¶
- class gem.impero.Evaluate(expression)[source]¶
Bases:
Terminal
Assign the value of a GEM expression to a temporary.
- expression¶
- class gem.impero.For(index, statement)[source]¶
Bases:
Node
For loop with an index which stores its extent, and a loop body expression which is usually a
Block
.- children¶
- index¶
- class gem.impero.Initialise(indexsum)[source]¶
Bases:
Terminal
Initialise an
gem.IndexSum
.- indexsum¶
- class gem.impero.Noop(expression)[source]¶
Bases:
Terminal
No-op terminal. Does not generate code, but wraps a GEM expression to have a loop shape, thus affects loop fusion.
- expression¶
- class gem.impero.Return(variable, expression)[source]¶
Bases:
Terminal
Save value of GEM expression into an lvalue. Used to “return” values from a kernel.
- expression¶
- loop_shape(free_indices)[source]¶
Gives the loop shape, an ordering of indices for an Impero terminal.
- Parameters:
free_indices – a callable mapping of GEM expressions to ordered free indices.
- variable¶
- class gem.impero.ReturnAccumulate(variable, indexsum)[source]¶
Bases:
Terminal
Accumulate an
gem.IndexSum
directly into a return variable.- indexsum¶
- loop_shape(free_indices)[source]¶
Gives the loop shape, an ordering of indices for an Impero terminal.
- Parameters:
free_indices – a callable mapping of GEM expressions to ordered free indices.
- variable¶
gem.impero_utils module¶
Utilities for building an Impero AST from an ordered list of terminal Impero operations, and for building any additional data required for straightforward C code generation.
What this module does is independent of the generated code target.
- class gem.impero_utils.ImperoC(tree, temporaries, declare, indices)¶
Bases:
tuple
- declare¶
Alias for field number 2
- indices¶
Alias for field number 3
- temporaries¶
Alias for field number 1
- tree¶
Alias for field number 0
- gem.impero_utils.collect_temporaries(tree)[source]¶
Collects GEM expressions to assign to temporaries from a list of Impero terminals.
- gem.impero_utils.compile_gem(assignments, prefix_ordering, remove_zeros=False, emit_return_accumulate=True)[source]¶
Compiles GEM to Impero.
- Parameters:
assignments – list of (return variable, expression DAG root) pairs
prefix_ordering – outermost loop indices
remove_zeros – remove zero assignment to return variables
emit_return_accumulate – emit ReturnAccumulate nodes (see
emit_operations()
)? If False, split into Accumulate/Return pairs. Set to False if the output tensor of kernels is not guaranteed to be zero on entry.
- gem.impero_utils.inline_temporaries(expressions, ops)[source]¶
Inline temporaries which could be inlined without blowing up the code.
- Parameters:
expressions – a multi-root GEM expression DAG, used for reference counting
ops – ordered list of Impero terminals
- Returns:
a filtered
ops
, without the unnecessary :class:`impero.Evaluate`s
- gem.impero_utils.make_index_orderer(index_ordering)[source]¶
Returns a function which given a set of indices returns those indices in the order as they appear in
index_ordering
.
- gem.impero_utils.make_loop_tree(ops, get_indices, level=0)[source]¶
Creates an Impero AST with loops from a list of operations and their respective free indices.
- Parameters:
ops – a list of Impero terminal nodes
get_indices – callable mapping from GEM nodes to an ordering of free indices
level – depth of loop nesting
- Returns:
Impero AST with loops, without declarations
- gem.impero_utils.make_prefix_ordering(indices, prefix_ordering)[source]¶
Creates an ordering of
indices
which starts with those indices inprefix_ordering
.
- gem.impero_utils.place_declarations(tree, temporaries, get_indices)[source]¶
Determines where and how to declare temporaries for an Impero AST.
- Parameters:
tree – Impero AST to determine the declarations for
temporaries – list of GEM expressions which are assigned to temporaries
get_indices – callable mapping from GEM nodes to an ordering of free indices
- gem.impero_utils.preprocess_gem(expressions, replace_delta=True, remove_componenttensors=True)[source]¶
Lower GEM nodes that cannot be translated to C directly.
- gem.impero_utils.temp_refcount(temporaries, op)[source]¶
Collects the number of times temporaries are referenced when generating code for an Impero terminal.
- Parameters:
temporaries – set of temporaries
op – Impero terminal
- Returns:
collections.Counter
object mapping some of elements fromtemporaries
to the number of times they will referenced fromop
gem.interpreter module¶
An interpreter for GEM trees.
- gem.interpreter.evaluate(expressions, bindings=None)[source]¶
Evaluate some GEM expressions given variable bindings.
- Parameters:
expressions – A single GEM expression, or iterable of expressions to evaluate.
bindings – An optional dict mapping GEM
gem.Variable
nodes to data.
- Returns:
a list of the evaluated expressions.
gem.node module¶
Generic abstract node class and utility functions for creating expression DAG languages.
- class gem.node.Memoizer(function)[source]¶
Bases:
object
Caching wrapper for functions with overridable recursive calls. The lifetime of the cache is the lifetime of the object instance.
- Parameters:
function – a function with parameters (value, rec), where
rec
is expected to be a function used for recursive calls.- Returns:
a function with working recursion and caching
- class gem.node.MemoizerArg(function)[source]¶
Bases:
object
Caching wrapper for functions with overridable recursive calls and an argument. The lifetime of the cache is the lifetime of the object instance.
- Parameters:
function – a function with parameters (value, rec, arg), where
rec
is expected to be a function used for recursive calls.- Returns:
a function with working recursion and caching
- class gem.node.Node[source]¶
Bases:
object
Abstract node class.
Nodes are not meant to be modified.
A node can reference other nodes; they are called children. A node might contain data, or reference other objects which are not themselves nodes; they are not called children.
Both the children (if any) and non-child data (if any) are required to create a node, or determine the equality of two nodes. For reconstruction, however, only the new children are necessary.
- get_hash()[source]¶
Hash function.
This is the method to potentially override in derived classes, not
__hash__()
.
- hash_value¶
- gem.node.collect_refcount(expression_dags)[source]¶
Collects reference counts for a multi-root expression DAG.
Notes¶
This function also collects reference counts of nodes in index expressions (e.g., VariableIndex`s); see ``_make_traversal_children()`.
- gem.node.noop_recursive(function)[source]¶
No-op wrapper for functions with overridable recursive calls.
- Parameters:
function – a function with parameters (value, rec), where
rec
is expected to be a function used for recursive calls.- Returns:
a function with working recursion and nothing fancy
- gem.node.noop_recursive_arg(function)[source]¶
No-op wrapper for functions with overridable recursive calls and an argument.
- Parameters:
function – a function with parameters (value, rec, arg), where
rec
is expected to be a function used for recursive calls.- Returns:
a function with working recursion and nothing fancy
- gem.node.post_traversal(expression_dags)[source]¶
Post-order traversal of the nodes of expression DAGs.
Notes¶
This function also walks through nodes in index expressions (e.g., VariableIndex`s); see ``_make_traversal_children()`.
- gem.node.pre_traversal(expression_dags)[source]¶
Pre-order traversal of the nodes of expression DAGs.
Notes¶
This function also walks through nodes in index expressions (e.g., VariableIndex`s); see ``_make_traversal_children()`.
gem.optimise module¶
A set of routines implementing various transformations on GEM expressions.
- gem.optimise.associate(operator, operands)[source]¶
Apply associativity rules to construct an operation-minimal expression tree.
For best performance give factors that have different set of free indices.
- Parameters:
operator – associative binary operator
operands – list of operands
- Returns:
(reduced expression, # of floating-point operations)
- gem.optimise.constant_fold_zero(exprs)[source]¶
Produce symbolic zeros from Literals
- Parameters:
exprs – An iterable of gem expressions.
- Returns:
A list of gem expressions where any Literal containing only zeros is replaced by symbolic Zero of the appropriate shape.
We need a separate path for ListTensor so that its reconstruct method will not be called when the new children are `Zero()`s; otherwise Literal `0`s would be reintroduced.
- gem.optimise.contraction(expression, ignore=None)[source]¶
Optimise the contractions of the tensor product at the root of the expression, including:
IndexSum-Delta cancellation
Sum factorisation
- Parameters:
ignore – Optional set of indices to ignore when applying sum factorisation (otherwise all summation indices will be considered). Use this if your expression has many contraction indices.
This routine was designed with finite element coefficient evaluation in mind.
- gem.optimise.delta_elimination(sum_indices, factors)[source]¶
IndexSum-Delta cancellation.
- Parameters:
sum_indices – free indices for contractions
factors – product factors
- Returns:
optimised (sum_indices, factors)
- gem.optimise.ffc_rounding(expression, epsilon)[source]¶
Perform FFC rounding of FIAT tabulation matrices on the literals of a GEM expression.
- Parameters:
expression – GEM expression
epsilon – tolerance limit for rounding
- gem.optimise.filtered_replace_indices(node, self, subst)[source]¶
Wrapper for
replace_indices()
. At each call removes substitution rules that do not apply.
- gem.optimise.literal_rounding(node, self)[source]¶
- gem.optimise.literal_rounding(node: Node, self)
- gem.optimise.literal_rounding(node: Literal, self)
Perform FFC rounding of FIAT tabulation matrices on the literals of a GEM expression.
- Parameters:
node – root of the expression
self – function for recursive calls
- gem.optimise.make_product(factors, sum_indices=())[source]¶
Constructs an operation-minimal (tensor) product of GEM expressions.
- gem.optimise.make_renamer(rename_map)[source]¶
Creates a function for renaming indices when expanding products of IndexSums, i.e. applying to following rule:
(sum_i a_i)*(sum_i b_i) ===> sum_{i,i’} a_i*b_{i’}
- Parameters:
rename_map – An rename map for renaming indices the same way as functions returned by other calls of this function.
- Returns:
A function that takes an iterable of indices to rename, and returns (renamed indices, applier), where applier is a function that remap the free indices of GEM expressions from the old to the new indices.
- gem.optimise.remove_componenttensors(expressions)[source]¶
Removes all ComponentTensors in multi-root expression DAG.
- gem.optimise.replace_division(expressions)[source]¶
Replace divisions with multiplications in expressions
- gem.optimise.replace_indices(node, self, subst)[source]¶
- gem.optimise.replace_indices(node: Node, self, arg)
- gem.optimise.replace_indices(node: Delta, self, subst)
- gem.optimise.replace_indices(node: Indexed, self, subst)
- gem.optimise.replace_indices(node: FlexiblyIndexed, self, subst)
Replace free indices in a GEM expression.
- Parameters:
node – root of the expression
self – function for recursive calls
subst – tuple of pairs; each pair is a substitution rule with a free index to replace and an index to replace with.
- gem.optimise.select_expression(expressions, index)[source]¶
Select an expression from a list of expressions with an index. Semantically equivalent to
partial_indexed(ListTensor(expressions), (index,))
but has a much more optimised implementation.
- Parameters:
expressions – a list of expressions of the same shape
index – an index (free, fixed or variable)
- Returns:
an expression of the same shape as the given expressions
- gem.optimise.sum_factorise(sum_indices, factors)[source]¶
Optimise a tensor product through sum factorisation.
- Parameters:
sum_indices – free indices for contractions
factors – product factors
- Returns:
optimised GEM expression
- gem.optimise.traverse_product(expression, stop_at=None, rename_map=None)[source]¶
Traverses a product tree and collects factors, also descending into tensor contractions (IndexSum). The nominators of divisions are also broken up, but not the denominators.
- Parameters:
expression – a GEM expression
stop_at – Optional predicate on GEM expressions. If specified and returns true for some subexpression, that subexpression is not broken into further factors even if it is a product-like expression.
rename_map – an rename map for consistent index renaming
- Returns:
(sum_indices, terms) - sum_indices: list of indices to sum over - terms: list of product terms
- gem.optimise.traverse_sum(expression, stop_at=None)[source]¶
Traverses a summation tree and collects summands.
- Parameters:
expression – a GEM expression
stop_at – Optional predicate on GEM expressions. If specified and returns true for some subexpression, that subexpression is not broken into further summands even if it is an addition.
- Returns:
list of summand expressions
- gem.optimise.unroll_indexsum(expressions, predicate)[source]¶
Unrolls IndexSums below a specified extent.
- Parameters:
expressions – list of expression DAGs
predicate – a predicate function on
Index
objects that tells whether to unroll a particular index
- Returns:
list of expression DAGs with some unrolled IndexSums
gem.pprint module¶
Pretty-printing GEM expressions.
gem.refactorise module¶
Data structures and algorithms for generic expansion and refactorisation.
- gem.refactorise.ATOMIC = 'atomic'¶
Label: the expression need not be broken up into smaller parts
- gem.refactorise.COMPOUND = 'compound'¶
Label: the expression must be broken up into smaller parts
- exception gem.refactorise.FactorisationError[source]¶
Bases:
Exception
Raised when factorisation fails to achieve some desired form.
- class gem.refactorise.Monomial(sum_indices, atomics, rest)¶
Bases:
tuple
Monomial type, representation of a tensor product with some distinguished factors (called atomics).
sum_indices: indices to sum over
atomics: tuple of expressions classified as ATOMIC
rest: a single expression classified as OTHER
A
Monomial
is a structured description of the expression:IndexSum(reduce(Product, atomics, rest), sum_indices)
- atomics¶
Alias for field number 1
- rest¶
Alias for field number 2
- sum_indices¶
Alias for field number 0
- class gem.refactorise.MonomialSum[source]¶
Bases:
object
Represents a sum of :py:class:`Monomial`s.
The set of
Monomial
summands are represented as a mapping from a pair of unorderedsum_indices
and unorderedatomics
to arest
GEM expression. This representation makes it easier to merge similar monomials.- add(sum_indices, atomics, rest)[source]¶
Updates the
MonomialSum
adding a new monomial.
- gem.refactorise.OTHER = 'other'¶
Label: the expression is irrelevant with regards to refactorisation
- gem.refactorise.collect_monomials(expressions, classifier)[source]¶
Refactorises expressions into a sum-of-products form, using distributivity rules (i.e. a*(b + c) -> a*b + a*c). Expansion proceeds until all “compound” expressions are broken up.
- Parameters:
expressions – GEM expressions to refactorise
classifier – a function that can classify any GEM expression as
ATOMIC
,COMPOUND
, orOTHER
. This classification drives the factorisation.
- Returns:
list of :py:class:`MonomialSum`s
- Raises:
FactorisationError – Failed to break up some “compound” expressions with expansion.
gem.scheduling module¶
Schedules operations to evaluate a multi-root expression DAG, forming an ordered list of Impero terminals.
- class gem.scheduling.OrderedDefaultDict(factory, *args, **kwargs)[source]¶
Bases:
OrderedDict
A dictionary that provides a default value and ordered iteration.
- Parameters:
factory – The callable used to create the default value.
See
collections.OrderedDict
for description of the remaining arguments.
- class gem.scheduling.Queue(callback)[source]¶
Bases:
object
Special queue for operation scheduling. GEM / Impero nodes are inserted when they are ready to be scheduled, i.e. any operation which depends on the operation to be inserted must have been scheduled already. This class implements a heuristic for ordering operations within the constraints in a way which aims to achieve maximum loop fusion to minimise the size of temporaries which need to be introduced.
- class gem.scheduling.ReferenceStager(reference_count, callback)[source]¶
Bases:
object
Provides staging for nodes in reference counted expression DAGs. A callback function is called once the reference count is exhausted.
- gem.scheduling.emit_operations(assignments, get_indices, emit_return_accumulate=True)[source]¶
Makes an ordering of operations to evaluate a multi-root expression DAG.
- Parameters:
assignments – Iterable of (variable, expression) pairs. The value of expression is written into variable upon execution.
get_indices – mapping from GEM nodes to an ordering of free indices
emit_return_accumulate – emit ReturnAccumulate nodes? Set to False if the output variables are not guaranteed zero on entry to the kernel.
- Returns:
list of Impero terminals correctly ordered to evaluate the assignments
gem.unconcatenate module¶
Utility functions for decomposing Concatenate nodes.
The exported functions are flatten and unconcatenate. - flatten: destroys the structure preserved within Concatenate nodes,
essentially reducing FInAT provided tabulations to what FIAT could have provided, so old code can continue to work.
- unconcatenate: split up (variable, expression) pairs along
Concatenate nodes, thus recovering the structure within them, yet eliminating the Concatenate nodes.
Let us see an example on unconcatenate. Let us consider the form
div(v) * dx
where v is an RTCF7 test function. This means that the assembled local vector has 8 * 7 + 7 * 8 = 112 entries. So the compilation of the form starts with a single assignment pair [(v, e)]. v is now the indexed return variable, something equivalent to
Indexed(Variable(‘A’, (112,)), (j,))
where j is the basis function index of the argument. e is just a GEM quadrature expression with j as its only free index. This will contain the tabulation of the RTCF7 element, which will cause something like
C_j := Indexed(Concatenate(A, B), (j,))
to appear as a subexpression in e. unconcatenate splits e along C_j into e_1 and e_2 such that
e_1 := e /. C_j -> A_{ja1,ja2}, and e_2 := e /. C_j -> B_{jb1,jb2}.
The split indices ja1, ja2, jb1, and jb2 have extents 8, 7, 7, and 8 respectively (see the RTCF7 element construction above). So the result of unconcatenate will be the list of pairs
[(v_1, e_2), (v_2, e_2)]
where v_1 is the first 56 entries of v, reshaped as an 8 x 7 matrix, indexed with (ja1, ja2), and similarly, v_2 is the second 56 entries of v, reshaped as a 7 x 8 matrix, indexed with (jb1, jb2).
The unconcatenated form allows for sum factorisation of tensor product elements as usual. This pair splitting is also applicable to coefficient evaluation: take the local basis function coefficients as the variable, the FInAT tabulation of the element as the expression, and apply “matrix-vector multifunction” for each pair after unconcatenation, and then add up the results.
- gem.unconcatenate.flatten(expressions)[source]¶
Flatten Concatenate nodes, and destroy the structure they express.
- Parameters:
expressions – a multi-root expression DAG
- gem.unconcatenate.unconcatenate(pairs, cache=None)[source]¶
Splits a list of (indexed variable, expression) pairs along
Concatenate
nodes embedded in the expressions.- Parameters:
pairs – list of (indexed variable, expression) pairs
cache – index splitting cache
dict
(optional)
- Returns:
list of (indexed variable, expression) pairs
gem.utils module¶
- class gem.utils.DynamicallyScoped(default_value=<object object>)[source]¶
Bases:
object
A dynamically scoped variable.
- property value¶
- exception gem.utils.UnsetVariableError[source]¶
Bases:
LookupError
- gem.utils.groupby(iterable, key=None)[source]¶
Groups objects by their keys.
- Parameters:
iterable – an iterable
key – key function
- Returns:
list of (group key, list of group members) pairs
- gem.utils.make_proxy_class(name, cls)[source]¶
Constructs a proxy class for a given class.
- Parameters:
name – name of the new proxy class
cls – the wrapee class to create a proxy for
- gem.utils.safe_repr(obj: Any) str [source]¶
- gem.utils.safe_repr(text: str) str
- gem.utils.safe_repr(num: Integral) str
- gem.utils.safe_repr(num: Real) str
- gem.utils.safe_repr(array: ndarray) str
- gem.utils.safe_repr(list_: list) str
- gem.utils.safe_repr(tuple_: tuple) str
Return a ‘safe’ repr for an object, accounting for floating point error.
Parameters¶
- obj :
The object to produce a repr for.
Returns¶
- str :
A repr for the object.