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 object

  • linear_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.flops_componenttensor(expr, temporaries)[source]
gem.flop_count.flops_conditional(expr, temporaries)[source]
gem.flop_count.flops_failure(expr, temporaries)[source]
gem.flop_count.flops_indexed(expr, temporaries)[source]
gem.flop_count.flops_indexsum(expr, temporaries)[source]
gem.flop_count.flops_inverse(expr, temporaries)[source]
gem.flop_count.flops_oneplus(expr, temporaries)[source]
gem.flop_count.flops_power(expr, temporaries)[source]
gem.flop_count.flops_product(expr, temporaries)[source]
gem.flop_count.flops_solve(expr, temporaries)[source]
gem.flop_count.flops_zero(expr, temporaries)[source]
gem.flop_count.flops_zeroplus(expr, temporaries)[source]
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.flop_count.statement_accumulate(tree, temporaries)[source]
gem.flop_count.statement_block(tree, temporaries)[source]
gem.flop_count.statement_evaluate(tree, temporaries)[source]
gem.flop_count.statement_for(tree, temporaries)[source]
gem.flop_count.statement_initialise(tree, temporaries)[source]
gem.flop_count.statement_return(tree, temporaries)[source]
gem.flop_count.statement_returnaccumulate(tree, temporaries)[source]

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.Comparison(*args, **kwargs)[source]

Bases: Scalar

children
operator
class gem.gem.ComponentTensor(*args, **kwargs)[source]

Bases: Node

children
multiindex
shape
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.Conditional(*args, **kwargs)[source]

Bases: Node

children
shape
class gem.gem.Delta(*args, **kwargs)[source]

Bases: Scalar, Terminal

i
j
class gem.gem.Division(*args, **kwargs)[source]

Bases: Scalar

children
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
index_ordering()[source]

Running indices in the order of indexing in this node.

indirect_children
class gem.gem.FloorDiv(*args, **kwargs)[source]

Bases: Scalar

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
set_extent(value)[source]
class gem.gem.IndexSum(*args, **kwargs)[source]

Bases: Scalar

children
multiindex
class gem.gem.Indexed(*args, **kwargs)[source]

Bases: Scalar

children
index_ordering()[source]

Running indices in the order of indexing in this node.

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__().

is_equal(other)[source]

Common subexpression eliminating equality predicate.

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.LogicalAnd(*args, **kwargs)[source]

Bases: Scalar

children
class gem.gem.LogicalNot(*args, **kwargs)[source]

Bases: Scalar

children
class gem.gem.LogicalOr(*args, **kwargs)[source]

Bases: Scalar

children
class gem.gem.MathFunction(*args, **kwargs)[source]

Bases: Scalar

children
name
class gem.gem.MaxValue(*args, **kwargs)[source]

Bases: Scalar

children
class gem.gem.MinValue(*args, **kwargs)[source]

Bases: Scalar

children
class gem.gem.Node(*args, **kwargs)[source]

Bases: Node

Abstract GEM node class.

property T
dtype
free_indices
static inherit_dtype_from_children(children)[source]
is_equal(other)[source]

Common subexpression eliminating equality predicate.

When two (sub)expressions are equal, the children of one object are reassigned to the children of the other, so some duplicated subexpressions are eliminated.

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.Power(*args, **kwargs)[source]

Bases: Scalar

children
class gem.gem.Product(*args, **kwargs)[source]

Bases: Scalar

children
class gem.gem.Remainder(*args, **kwargs)[source]

Bases: Scalar

children
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.Sum(*args, **kwargs)[source]

Bases: Scalar

children
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.extract_type(expressions, klass)[source]

Collects objects of type klass in expressions.

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.gem.reshape(expression, *shapes)[source]

Reshape a variable (splitting indices only).

Parameters:
  • expression – view of a Variable

  • shapes – one shape tuple for each dimension of the variable.

gem.gem.view(expression, *slices)[source]

View a part of a shaped object.

Parameters:
  • expression – a node that has a shape

  • slices – one slice object for each dimension of the 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
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.

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
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.

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
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.

class gem.impero.Node[source]

Bases: Node

Base class of all Impero nodes

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
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.

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
class gem.impero.Terminal[source]

Bases: Node

Abstract class for terminal Impero nodes

children = ()
abstractmethod 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.

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

exception gem.impero_utils.NoopError[source]

Bases: Exception

No operations in the kernel.

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 in prefix_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 from temporaries to the number of times they will referenced from op

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
is_equal(other)[source]

Equality predicate.

This is the method to potentially override in derived classes, not __eq__() or __ne__().

reconstruct(*args)[source]

Reconstructs the node with new children from ‘args’. Non-child data are copied from ‘self’.

Returns a new object.

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.node.reuse_if_untouched(node, self)[source]

Reuse if untouched recipe

gem.node.reuse_if_untouched_arg(node, self, arg)[source]

Reuse if touched recipe propagating an extra argument

gem.node.traversal(expression_dags)

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.aggressive_unroll(expression)[source]

Aggressively unrolls all loop structures.

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.literal_rounding_literal(node, self)[source]
gem.optimise.make_product(factors, sum_indices=())[source]

Constructs an operation-minimal (tensor) product of GEM expressions.

gem.optimise.make_rename_map()[source]

Creates an rename map for reusing the same index renames.

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.make_sum(summands)[source]

Constructs an operation-minimal sum of GEM expressions.

gem.optimise.remove_componenttensors(expressions)[source]

Removes all ComponentTensors in multi-root expression DAG.

gem.optimise.replace_delta(expressions)[source]

Lowers all Deltas in a 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.replace_indices_delta(node, self, subst)[source]
gem.optimise.replace_indices_flexiblyindexed(node, self, subst)[source]
gem.optimise.replace_indices_indexed(node, self, subst)[source]
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.

class gem.pprint.Context[source]

Bases: object

expression(expr)[source]
force_expression(expr)[source]
index(index)[source]
gem.pprint.make_decl(node, name, ctx)[source]
gem.pprint.pprint(expression_dags, context=<gem.pprint.Context object>)[source]
gem.pprint.to_str(expr, ctx, prec=None, top=False)[source]

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 unordered sum_indices and unordered atomics to a rest GEM expression. This representation makes it easier to merge similar monomials.

add(sum_indices, atomics, rest)[source]

Updates the MonomialSum adding a new monomial.

static product(*args, **kwargs)[source]

Product of multiple :py:class:`MonomialSum`s

static sum(*args)[source]

Sum of multiple :py:class:`MonomialSum`s

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, or OTHER. 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.

insert(indices, elem)[source]

Insert element into queue.

Parameters:
  • indices – loop indices used by the scheduling heuristic

  • elem – element to be scheduled

process()[source]

Pops elements from the queue and calls the callback function on them until the queue is empty. The callback function can insert further elements into the queue.

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.

decref(o)[source]

Decreases the reference count of a node, and possibly triggering a callback (when the reference count drops to zero).

empty()[source]

All reference counts 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.scheduling.handle(ops, push, decref, node)[source]

Helper function for scheduling

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.

let(value)[source]
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.

Module contents