cotengra#

Hyper optimized contraction trees for large tensor networks and einsums.

Subpackages#

Submodules#

Package Contents#

Classes#

ContractionTree

Binary tree representing a tensor network contraction.

ContractionTreeCompressed

A contraction tree for compressed contractions. Currently the only

ContractionTreeMulti

Binary tree representing a tensor network contraction.

HyperGraph

Simple hypergraph builder and writer.

SliceFinder

An object to help find the best indices to slice over in order to reduce

QuickBBOptimizer

FlowCutterOptimizer

HyperCompressedOptimizer

A compressed contraction path optimizer that samples a series of ordered

HyperMultiOptimizer

A path optimizer that samples a series of contraction trees

HyperOptimizer

A path optimizer that samples a series of contraction trees

ReusableHyperCompressedOptimizer

Like HyperCompressedOptimizer but it will re-instantiate the

ReusableHyperOptimizer

Like HyperOptimizer but it will re-instantiate the optimizer

AutoHQOptimizer

An optimizer that automatically chooses between optimal and

AutoOptimizer

An optimizer that automatically chooses between optimal and

Functions#

get_hypergraph(inputs[, output, size_dict, accel])

Single entry-point for creating a, possibly accelerated, HyperGraph.

array_contract_expression(inputs[, output, size_dict, ...])

Get an callable 'expression' that will contract tensors with indices and

array_contract_path(inputs[, output, size_dict, ...])

Find only the contraction path for the specific contraction, with fast

array_contract_tree(inputs[, output, size_dict, ...])

Get the ContractionTree for the tensor contraction specified by

array_contract(arrays, inputs[, output, optimize, ...])

Perform the tensor contraction specified by inputs, output and

einsum_expression(*args[, optimize, constants, cache])

Get an callable 'expression' that will contract tensors with shapes

einsum_tree(*args[, optimize, canonicalize, ...])

Get the ContractionTree for the einsum equation eq and

einsum(*args[, optimize, cache_expression, backend])

Perform an einsum contraction, using cotengra, using strategy given by

register_preset(preset, optimizer[, register_opt_einsum])

Register a preset optimizer.

optimize_quickbb(inputs, output, size_dict[, ...])

optimize_flowcutter(inputs, output, size_dict[, ...])

get_hyper_space()

hash_contraction(inputs, output, size_dict[, method])

Compute a hash for a particular contraction geometry.

list_hyper_functions()

Return a list of currently registered hyper contraction finders.

plot_contractions(tree[, order, color_size, ...])

plot_contractions_alt(tree[, x, y, color, size, ...])

plot_scatter(self[, x, y, figsize])

plot_scatter_alt(self[, x, y, color, color_scheme, ...])

Plot the trials total flops vs max size.

plot_slicings(slice_finder[, color_scheme, ...])

plot_slicings_alt(slice_finder[, color_scheme, ...])

plot_tree(tree[, layout, hypergraph_layout, ...])

Plot a contraction tree using matplotlib.

plot_tree_ring(tree, **kwargs)

plot_tree_tent(tree, **kwargs)

plot_tree_span(tree, **kwargs)

plot_trials(self[, y, figsize])

plot_trials_alt(self[, y, width, height])

Plot the trials interactively using altair.

get_symbol(i)

Get the symbol corresponding to int i - runs through the usual 52

get_symbol_map(inputs)

Get a mapping of arbitrary hashable 'indices' to single unicode symbols,

hyper_optimize(inputs, output, size_dict[, memory_limit])

Attributes#

auto_hq_optimize

auto_optimize

greedy_optimize

optimal_optimize

optimal_outer_optimize

UniformOptimizer

Does no gaussian process tuning by default, just randomly samples - requires

QuasiRandOptimizer

Does no gaussian process tuning by default, just randomly samples but in a

contract_expression

Alias for cotengra.einsum_expression().

contract

Functionality relating to actually contracting.

class cotengra.ContractionTree(inputs, output, size_dict, track_childless=False, track_flops=False, track_write=False, track_size=False)[source]#

Binary tree representing a tensor network contraction.

Parameters:
  • inputs (sequence of str) – The list of input tensor’s indices.

  • output (str) – The output indices.

  • size_dict (dict[str, int]) – The size of each index.

  • track_childless (bool, optional) – Whether to dynamically keep track of which nodes are childless. Useful if you are ‘divisively’ building the tree.

  • track_flops (bool, optional) – Whether to dynamically keep track of the total number of flops. If False You can still compute this once the tree is complete.

  • track_write (bool, optional) – Whether to dynamically keep track of the total number of elements written. If False You can still compute this once the tree is complete.

  • track_size (bool, optional) – Whether to dynamically keep track of the largest tensor so far. If False You can still compute this once the tree is complete.

children#

Mapping of each node to two children.

Type:

dict[node, tuple[node]]

info#

Information about the tree nodes. The key is the set of inputs (a set of inputs indices) the node contains. Or in other words, the subgraph of the node. The value is a dictionary to cache information about effective ‘leg’ indices, size, flops of formation etc.

Type:

dict[node, dict]

property nslices#

Simple alias for how many independent contractions this tree represents overall.

property nchunks#

The number of ‘chunks’ - determined by the number of sliced output indices.

contraction_cost_compressed[source]#
remove_ind_[source]#
restore_ind_[source]#
subtree_reconfigure_[source]#
subtree_reconfigure_forest_[source]#
slice_[source]#
slice_and_reconfigure_[source]#
slice_and_reconfigure_forest_[source]#
compressed_reconfigure_[source]#
windowed_reconfigure_[source]#
path[source]#
ssa_path[source]#
path_surface[source]#
ssa_path_surface[source]#
plot_ring[source]#
plot_tent[source]#
plot_span[source]#
plot_flat[source]#
plot_rubberband[source]#
plot_contractions[source]#
plot_contractions_alt[source]#
set_state_from(other)[source]#

Set the internal state of this tree to that of other.

copy()[source]#

Create a copy of this ContractionTree.

node_to_terms(node)[source]#

Turn a node – a frozen set of ints – into the corresponding terms – a sequence of sets of str corresponding to input indices.

gen_leaves()[source]#

Generate the nodes representing leaves of the contraction tree, i.e. of size 1 each corresponding to a single input tensor.

classmethod from_path(inputs, output, size_dict, *, path=None, ssa_path=None, check=False, **kwargs)[source]#

Create a (completed) ContractionTree from the usual inputs plus a standard contraction path or ‘ssa_path’ - you need to supply one.

classmethod from_info(info, **kwargs)[source]#

Create a ContractionTree from an opt_einsum.PathInfo object.

classmethod from_eq(eq, size_dict, **kwargs)[source]#

Create a empty ContractionTree directly from an equation and set of shapes.

Parameters:
  • eq (str) – The einsum string equation.

  • size_dict (dict[str, int]) – The size of each index.

get_eq()[source]#

Get the einsum equation corresponding to this tree. Note that this is the total (or original) equation, so includes indices which have been sliced.

Returns:

eq

Return type:

str

get_shapes()[source]#

Get the shapes of the input tensors corresponding to this tree.

Returns:

shapes

Return type:

tuple[tuple[int]]

get_inputs_sliced()[source]#

Get the input indices corresponding to a single slice of this tree, i.e. with sliced indices removed.

Returns:

inputs

Return type:

tuple[tuple[str]]

get_output_sliced()[source]#

Get the output indices corresponding to a single slice of this tree, i.e. with sliced indices removed.

Returns:

output

Return type:

tuple[str]

get_eq_sliced()[source]#

Get the einsum equation corresponding to a single slice of this tree, i.e. with sliced indices removed.

Returns:

eq

Return type:

str

get_shapes_sliced()[source]#

Get the shapes of the input tensors corresponding to a single slice of this tree, i.e. with sliced indices removed.

Returns:

shapes

Return type:

tuple[tuple[int]]

classmethod from_edge_path(edge_path, inputs, output, size_dict, check=False, **kwargs)[source]#

Create a ContractionTree from an edge elimination ordering.

_add_node(node, check=False)[source]#
_remove_node(node)[source]#

Remove node from this tree and update the flops and maximum size if tracking them respectively. Inplace operation.

get_legs(node)[source]#

Get the effective ‘outer’ indices for the collection of tensors in node.

get_involved(node)[source]#

Get all the indices involved in the formation of subgraph node.

get_removed(node)[source]#

Get the indices that will be removed by the creation of node.

get_size(node)[source]#

Get the tensor size of node.

get_flops(node)[source]#

Get the FLOPs for the pairwise contraction that will create node.

get_can_dot(node)[source]#

Get whether this contraction can be performed as a dot product (i.e. with tensordot), or else requires einsum, as it has indices that don’t appear exactly twice in either the inputs or the output.

get_inds(node)[source]#

Get the indices of this node - an ordered string version of get_legs that starts with tree.inputs and maintains the order they appear in each contraction ‘ABC,abc->ABCabc’, to match tensordot.

get_tensordot_axes(node)[source]#

Get the axes arg for a tensordot ocontraction that produces node. The pairs are sorted in order of appearance on the left input.

get_tensordot_perm(node)[source]#

Get the permutation required, if any, to bring the tensordot output of this nodes contraction into line with self.get_inds(node).

get_einsum_eq(node)[source]#

Get the einsum string describing the contraction that produces node, unlike get_inds the characters are mapped into [a-zA-Z], for compatibility with numpy.einsum for example.

get_centrality(node)[source]#
total_flops(dtype=None)[source]#

Sum the flops contribution from every node in the tree.

Parameters:

dtype ({'float', 'complex', None}, optional) – Scale the answer depending on the assumed data type.

total_write()[source]#

Sum the total amount of memory that will be created and operated on.

total_cost(factor=DEFAULT_COMBO_FACTOR, combine=sum)[source]#
max_size()[source]#

The size of the largest intermediate tensor.

peak_size(order=None)[source]#

Get the peak concurrent size of tensors needed - this depends on the traversal order, i.e. the exact contraction path, not just the contraction tree.

contract_stats(force=False)[source]#

Simulteneously compute the total flops, write and size of the contraction tree. This is more efficient than calling each of the individual methods separately. Once computed, each quantity is then automatically tracked.

Returns:

stats – The total flops, write and size.

Return type:

dict[str, int]

arithmetic_intensity()[source]#

The ratio of total flops to total write - the higher the better for extracting good computational performance.

contraction_scaling()[source]#

This is computed simply as the maximum number of indices involved in any single contraction, which will match the scaling assuming that all dimensions are equal.

contraction_cost(log=None)[source]#

Get the total number of scalar operations ~ time complexity.

contraction_width(log=2)[source]#

Get log2 of the size of the largest tensor.

compressed_contract_stats(chi, order='surface_order', compress_late=False)[source]#
total_flops_compressed(chi, order='surface_order', compress_late=False, dtype=None)[source]#

Estimate the total flops for a compressed contraction of this tree with maximum bond size chi. This includes basic estimates of the ops to perform contractions, QRs and SVDs.

total_write_compressed(chi, order='surface_order', compress_late=False, accel='auto')[source]#

Compute the total size of all intermediate tensors when a compressed contraction is performed with maximum bond size chi, ordered by order. This is relevant maybe for time complexity and e.g. autodiff space complexity (since every intermediate is kept).

total_cost_compressed(chi, order='surface_order', compress_late=False, factor=DEFAULT_COMBO_FACTOR)[source]#
max_size_compressed(chi, order='surface_order', compress_late=False)[source]#

Compute the maximum sized tensor produced when a compressed contraction is performed with maximum bond size chi, ordered by order. This is close to the ideal space complexity if only tensors that are being directly operated on are kept in memory.

peak_size_compressed(chi, order='surface_order', compress_late=False, accel='auto')[source]#

Compute the peak size of combined intermediate tensors when a compressed contraction is performed with maximum bond size chi, ordered by order. This is the practical space complexity if one is not swapping intermediates in and out of memory.

contraction_width_compressed(chi, order='surface_order', compress_late=False)[source]#

Compute log2 of the maximum sized tensor produced when a compressed contraction is performed with maximum bond size chi, ordered by order.

contract_nodes_pair(x, y, legs=None, cost=None, size=None, check=False)[source]#

Contract node x with node y in the tree to create a new parent node, which is returned.

Parameters:
  • x (frozenset[int]) – The first node to contract.

  • y (frozenset[int]) – The second node to contract.

  • legs (dict[str, int], optional) – The effective ‘legs’ of the new node if already known. If not given, this is computed from the inputs of x and y.

  • cost (int, optional) – The cost of the contraction if already known. If not given, this is computed from the inputs of x and y.

  • size (int, optional) – The size of the new node if already known. If not given, this is computed from the inputs of x and y.

  • check (bool, optional) – Whether to check the inputs are valid.

Returns:

parent – The new parent node of x and y.

Return type:

frozenset[int]

contract_nodes(nodes, optimize='auto-hq', check=False, extra_opts=None)[source]#

Contract an arbitrary number of nodes in the tree to build up a subtree. The root of this subtree (a new intermediate) is returned.

is_complete()[source]#

Check every node has two children, unless it is a leaf.

get_default_order()[source]#
_traverse_ordered(order)[source]#

Traverse the tree in the order that minimizes order(node), but still constrained to produce children before parents.

traverse(order=None)[source]#

Generate, in order, all the node merges in this tree. Non-recursive! This ensures children are always visited before their parent.

Parameters:

order (None or callable, optional) – How to order the contractions within the tree. If a callable is given (which should take a node as its argument), try to contract nodes that minimize this function first.

Returns:

The bottom up ordered sequence of tree merges, each a tuple of (parent, left_child, right_child).

Return type:

generator[tuple[node]]

See also

descend

descend(mode='dfs')[source]#

Generate, from root to leaves, all the node merges in this tree. Non-recursive! This ensures parents are visited before their children.

Parameters:

mode ({'dfs', bfs}, optional) – How expand from a parent.

Returns:

The top down ordered sequence of tree merges, each a tuple of (parent, left_child, right_child).

Return type:

generator[tuple[node]

See also

traverse

get_subtree(node, size, search='bfs')[source]#

Get a subtree spanning down from node which will have size leaves (themselves not necessarily leaves of the actual tree).

Parameters:
  • node (node) – The node of the tree to start with.

  • size (int) – How many subtree leaves to aim for.

  • search ({'bfs', 'dfs', 'random'}, optional) –

    How to build the tree:

    • ’bfs’: breadth first expansion

    • ’dfs’: depth first expansion (largest nodes first)

    • ’random’: random expansion

Returns:

  • sub_leaves (tuple[node]) – Nodes which are subtree leaves.

  • branches (tuple[node]) – Nodes which are between the subtree leaves and root.

remove_ind(ind, project=None, inplace=False)[source]#

Remove (i.e. by default slice) index ind from this contraction tree, taking care to update all relevant information about each node.

restore_ind(ind, inplace=False)[source]#

Restore (unslice or un-project) index ind to this contraction tree, taking care to update all relevant information about each node.

Parameters:
  • ind (str) – The index to restore.

  • inplace (bool, optional) – Whether to perform the restoration inplace or not.

Return type:

ContractionTree

calc_subtree_candidates(pwr=2, what='flops')[source]#
subtree_reconfigure(subtree_size=8, subtree_search='bfs', weight_what='flops', weight_pwr=2, select='max', maxiter=500, seed=None, minimize='flops', optimize=None, inplace=False, progbar=False)[source]#

Reconfigure subtrees of this tree with locally optimal paths.

Parameters:
  • subtree_size (int, optional) – The size of subtree to consider. Cost is exponential in this.

  • subtree_search ({'bfs', 'dfs', 'random'}, optional) –

    How to build the subtrees:

    • ’bfs’: breadth-first-search creating balanced subtrees

    • ’dfs’: depth-first-search creating imbalanced subtrees

    • ’random’: random subtree building

  • weight_what ({'flops', 'size'}, optional) – When assessing nodes to build and optimize subtrees from whether to score them by the (local) contraction cost, or tensor size.

  • weight_pwr (int, optional) – When assessing nodes to build and optimize subtrees from, how to scale their score into a probability: score**(1 / weight_pwr). The larger this is the more explorative the algorithm is when select='random'.

  • select ({'max', 'min', 'random'}, optional) –

    What order to select node subtrees to optimize:

    • ’max’: choose the highest score first

    • ’min’: choose the lowest score first

    • ’random’: choose randomly weighted on score – see weight_pwr.

  • maxiter (int, optional) – How many subtree optimizations to perform, the algorithm can terminate before this if all subtrees have been optimized.

  • seed (int, optional) – A random seed (seeds python system random module).

  • minimize ({'flops', 'size'}, optional) – Whether to minimize with respect to contraction flops or size.

  • inplace (bool, optional) – Whether to perform the reconfiguration inplace or not.

  • progbar (bool, optional) – Whether to show live progress of the reconfiguration.

Return type:

ContractionTree

subtree_reconfigure_forest(num_trees=8, num_restarts=10, restart_fraction=0.5, subtree_maxiter=100, subtree_size=10, subtree_search=('random', 'bfs'), subtree_select=('random',), subtree_weight_what=('flops', 'size'), subtree_weight_pwr=(2,), parallel='auto', parallel_maxiter_steps=4, minimize='flops', progbar=False, inplace=False)[source]#

‘Forested’ version of subtree_reconfigure which is more explorative and can be parallelized. It stochastically generates a ‘forest’ reconfigured trees, then only keeps some fraction of these to generate the next forest.

Parameters:
  • num_trees (int, optional) – The number of trees to reconfigure at each stage.

  • num_restarts (int, optional) – The number of times to halt, prune and then restart the tree reconfigurations.

  • restart_fraction (float, optional) – The fraction of trees to keep at each stage and generate the next forest from.

  • subtree_maxiter (int, optional) – Number of subtree reconfigurations per step. num_restarts * subtree_maxiter is the max number of total subtree reconfigurations for the final tree produced.

  • subtree_size (int, optional) – The size of subtrees to search for and reconfigure.

  • subtree_search (tuple[{'random', 'bfs', 'dfs'}], optional) – Tuple of options for the search kwarg of ContractionTree.subtree_reconfigure() to randomly sample.

  • subtree_select (tuple[{'random', 'max', 'min'}], optional) – Tuple of options for the select kwarg of ContractionTree.subtree_reconfigure() to randomly sample.

  • subtree_weight_what (tuple[{'flops', 'size'}], optional) – Tuple of options for the weight_what kwarg of ContractionTree.subtree_reconfigure() to randomly sample.

  • subtree_weight_pwr (tuple[int], optional) – Tuple of options for the weight_pwr kwarg of ContractionTree.subtree_reconfigure() to randomly sample.

  • parallel ('auto', False, True, int, or distributed.Client) – Whether to parallelize the search.

  • parallel_maxiter_steps (int, optional) – If parallelizing, how many steps to break each reconfiguration into in order to evenly saturate many processes.

  • minimize ({'flops', 'size', ..., Objective}, optional) – Whether to minimize the total flops or maximum size of the contraction tree.

  • progbar (bool, optional) – Whether to show live progress.

  • inplace (bool, optional) – Whether to perform the subtree reconfiguration inplace.

Return type:

ContractionTree

slice(target_size=None, target_overhead=None, target_slices=None, temperature=0.01, minimize='flops', allow_outer=True, max_repeats=16, inplace=False)[source]#

Slice this tree (turn some indices into indices which are explicitly summed over rather than being part of contractions). The indices are stored in tree.sliced_inds, and the contraction width updated to take account of the slicing. Calling tree.contract(arrays) moreover which automatically perform the slicing and summation.

Parameters:
  • target_size (int, optional) – The target number of entries in the largest tensor of the sliced contraction. The search algorithm will terminate after this is reached.

  • target_slices (int, optional) – The target or minimum number of ‘slices’ to consider - individual contractions after slicing indices. The search algorithm will terminate after this is breached.

  • target_overhead (float, optional) – The target increase in total number of floating point operations. For example, a value of 2.0 will terminate the search just before the cost of computing all the slices individually breaches twice that of computing the original contraction all at once.

  • temperature (float, optional) – How much to randomize the repeated search.

  • minimize ({'flops', 'size', ..., Objective}, optional) – Which metric to score the overhead increase against.

  • allow_outer (bool, optional) – Whether to allow slicing of outer indices.

  • max_repeats (int, optional) – How many times to repeat the search with a slight randomization.

  • inplace (bool, optional) – Whether the remove the indices from this tree inplace or not.

Return type:

ContractionTree

slice_and_reconfigure(target_size, step_size=2, temperature=0.01, minimize='flops', allow_outer=True, max_repeats=16, reconf_opts=None, progbar=False, inplace=False)[source]#

Interleave slicing (removing indices into an exterior sum) with subtree reconfiguration to minimize the overhead induced by this slicing.

Parameters:
  • target_size (int) – Slice the tree until the maximum intermediate size is this or smaller.

  • step_size (int, optional) – The minimum size reduction to try and achieve before switching to a round of subtree reconfiguration.

  • temperature (float, optional) – The temperature to supply to SliceFinder for searching for indices.

  • minimize ({'flops', 'size', ..., Objective}, optional) – The metric to minimize when slicing and reconfiguring subtrees.

  • max_repeats (int, optional) – The number of slicing attempts to perform per search.

  • progbar (bool, optional) – Whether to show live progress.

  • inplace (bool, optional) – Whether to perform the slicing and reconfiguration inplace.

  • reconf_opts (None or dict, optional) – Supplied to ContractionTree.subtree_reconfigure() or ContractionTree.subtree_reconfigure_forest(), depending on ‘forested’ key value.

slice_and_reconfigure_forest(target_size, step_size=2, num_trees=8, restart_fraction=0.5, temperature=0.02, max_repeats=32, minimize='flops', allow_outer=True, parallel='auto', progbar=False, inplace=False, reconf_opts=None)[source]#

‘Forested’ version of ContractionTree.slice_and_reconfigure(). This maintains a ‘forest’ of trees with different slicing and subtree reconfiguration attempts, pruning the worst at each step and generating a new forest from the best.

Parameters:
  • target_size (int) – Slice the tree until the maximum intermediate size is this or smaller.

  • step_size (int, optional) – The minimum size reduction to try and achieve before switching to a round of subtree reconfiguration.

  • num_restarts (int, optional) – The number of times to halt, prune and then restart the tree reconfigurations.

  • restart_fraction (float, optional) – The fraction of trees to keep at each stage and generate the next forest from.

  • temperature (float, optional) – The temperature at which to randomize the sliced index search.

  • max_repeats (int, optional) – The number of slicing attempts to perform per search.

  • parallel ('auto', False, True, int, or distributed.Client) – Whether to parallelize the search.

  • progbar (bool, optional) – Whether to show live progress.

  • inplace (bool, optional) – Whether to perform the slicing and reconfiguration inplace.

  • reconf_opts (None or dict, optional) – Supplied to ContractionTree.slice_and_reconfigure().

Return type:

ContractionTree

compressed_reconfigure(minimize, order_only=False, max_nodes='auto', max_time=None, local_score=None, exploration_power=0, best_score=None, progbar=False, inplace=False)[source]#

Reconfigure this tree according to peak_size_compressed.

Parameters:
  • chi (int) – The maximum bond dimension to consider.

  • order_only (bool, optional) – Whether to only consider the ordering of the current tree contractions, or all possible contractions, starting with the current.

  • max_nodes (int, optional) – Set the maximum number of contraction steps to consider.

  • max_time (float, optional) – Set the maximum time to spend on the search.

  • local_score (callable, optional) –

    A function that assigns a score to a potential contraction, with a lower score giving more priority to explore that contraction earlier. It should have signature:

    local_score(step, new_score, dsize, new_size)
    

    where step is the number of steps so far, new_score is the score of the contraction so far, dsize is the change in memory by the current step, and new_size is the new memory size after contraction.

  • exploration_power (float, optional) – If not 0.0, the inverse power to which the step is raised in the default local score function. Higher values favor exploring more promising branches early on - at the cost of increased memory. Ignored if local_score is supplied.

  • best_score (float, optional) – Manually specify an upper bound for best score found so far.

  • progbar (bool, optional) – If True, display a progress bar.

  • inplace (bool, optional) – Whether to perform the reconfiguration inplace on this tree.

Return type:

ContractionTree

windowed_reconfigure(minimize, order_only=False, window_size=20, max_iterations=100, max_window_tries=1000, score_temperature=0.0, queue_temperature=1.0, scorer=None, queue_scorer=None, seed=None, inplace=False, progbar=False, **kwargs)[source]#
flat_tree(order=None)[source]#

Create a nested tuple representation of the contraction tree like:

((0, (1, 2)), ((3, 4), ((5, (6, 7)), (8, 9))))

Such that the contraction will progress like:

((0, (1, 2)), ((3, 4), ((5, (6, 7)), (8, 9))))
((0, 12), (34, ((5, 67), 89)))
(012, (34, (567, 89)))
(012, (34, 56789))
(012, 3456789)
0123456789

Where each integer represents a leaf (i.e. single element node).

get_leaves_ordered()[source]#

Return the list of leaves as ordered by the contraction tree.

Return type:

tuple[frozenset[str]]

get_path(order=None)[source]#

Generate a standard path from the contraction tree.

get_numpy_path(order=None)[source]#

Generate a path compatible with the optimize kwarg of numpy.einsum.

get_ssa_path(order=None)[source]#

Generate a ssa path from the contraction tree.

surface_order(node)[source]#
set_surface_order_from_path(ssa_path)[source]#
get_path_surface()[source]#
get_ssa_path_surface()[source]#
get_spans()[source]#

Get all (which could mean none) potential embeddings of this contraction tree into a spanning tree of the original graph.

Return type:

tuple[dict[frozenset[int], frozenset[int]]]

compute_centralities(combine='mean')[source]#

Compute a centrality for every node in this contraction tree.

get_hypergraph(accel=False)[source]#

Get a hypergraph representing the uncontracted network (i.e. the leaves).

reset_contraction_indices()[source]#

Reset all information regarding the explicit contraction indices ordering.

sort_contraction_indices(priority='flops', make_output_contig=True, make_contracted_contig=True, reset=True)[source]#

Set explicit orders for the contraction indices of this self to optimize for one of two things: contiguity in contracted (‘k’) indices, or contiguity of left and right output (‘m’ and ‘n’) indices.

Parameters:
  • priority ({'flops', 'size', 'root', 'leaves'}, optional) – Which order to process the intermediate nodes in. Later nodes re-sort previous nodes so are more likely to keep their ordering. E.g. for ‘flops’ the mostly costly contracton will be process last and thus will be guaranteed to have its indices exactly sorted.

  • make_output_contig (bool, optional) – When processing a pairwise contraction, sort the parent contraction indices so that the order of indices is the order they appear from left to right in the two child (input) tensors.

  • make_contracted_contig (bool, optional) – When processing a pairwise contraction, sort the child (input) tensor indices so that all contracted indices appear contiguously.

  • reset (bool, optional) – Reset all indices to the default order before sorting.

print_contractions(sort=None, show_brackets=True)[source]#

Print each pairwise contraction, with colorized indices (if colorama is installed), and other information.

get_contractor(order=None, prefer_einsum=False, strip_exponent=False, implementation=None, autojit=False)[source]#

Get a reusable function which performs the contraction corresponding to this tree, cached.

Parameters:
  • tree (ContractionTree) – The contraction tree.

  • order (str or callable, optional) – Supplied to ContractionTree.traverse(), the order in which to perform the pairwise contractions given by the tree.

  • prefer_einsum (bool, optional) – Prefer to use einsum for pairwise contractions, even if tensordot can perform the contraction.

  • strip_exponent (bool, optional) – If True, the function will strip the exponent from the output array and return it separately.

  • implementation (str or tuple[callable, callable], optional) –

    What library to use to actually perform the contractions. Options are:

    • None: let cotengra choose.

    • ”autoray”: dispatch with autoray, using the tensordot and einsum implementation of the backend.

    • ”cotengra”: use the tensordot and einsum implementation of cotengra, which is based on batch matrix multiplication. This is faster for some backends like numpy, and also enables libraries which don’t yet provide tensordot and einsum to be used.

    • ”cuquantum”: use the cuquantum library to perform the whole contraction (not just individual contractions).

    • tuple[callable, callable]: manually supply the tensordot and einsum implementations to use.

  • autojit (bool, optional) – If True, use autoray.autojit() to compile the contraction function.

Returns:

fn – The contraction function, with signature fn(*arrays).

Return type:

callable

contract_core(arrays, order=None, prefer_einsum=False, strip_exponent=False, check_zero=False, backend=None, implementation=None, autojit=False, progbar=False)[source]#

Contract arrays with this tree. The order of the axes and output is assumed to be that of tree.inputs and tree.output, but with sliced indices removed. This functon contracts the core tree and thus if indices have been sliced the arrays supplied need to be sliced as well.

Parameters:
  • arrays (sequence of array) – The arrays to contract.

  • order (str or callable, optional) – Supplied to ContractionTree.traverse().

  • prefer_einsum (bool, optional) – Prefer to use einsum for pairwise contractions, even if tensordot can perform the contraction.

  • backend (str, optional) – What library to use for einsum and transpose, will be automatically inferred from the arrays if not given.

  • autojit (bool, optional) – Whether to use autoray.autojit to jit compile the expression.

  • progbar (bool, optional) – Show progress through the contraction.

slice_key(i, strides=None)[source]#

Get the combination of sliced index values for overall slice i.

Parameters:

i (int) – The overall slice index.

Returns:

key – The value each sliced index takes for slice i.

Return type:

dict[str, int]

slice_arrays(arrays, i)[source]#

Take arrays and slice the relevant inputs according to tree.sliced_inds and the dynary representation of i.

contract_slice(arrays, i, **kwargs)[source]#

Get slices i of arrays and then contract them.

gather_slices(slices, backend=None, progbar=False)[source]#

Gather all the output contracted slices into a single full result. If none of the sliced indices appear in the output, then this is a simple sum - otherwise the slices need to be partially summed and partially stacked.

gen_output_chunks(arrays, with_key=False, progbar=False, **contract_opts)[source]#

Generate each output chunk of the contraction - i.e. take care of summing internally sliced indices only first. This assumes that the sliced_inds are sorted by whether they appear in the output or not (the default order). Useful for performing some kind of reduction over the final tensor object like fn(x).sum() without constructing the entire thing.

Parameters:
  • arrays (sequence of array) – The arrays to contract.

  • with_key (bool, optional) – Whether to yield the output index configuration key along with the chunk.

  • progbar (bool, optional) – Show progress through the contraction chunks.

Yields:
  • chunk (array) – A chunk of the contracted result.

  • key (dict[str, int]) – The value each sliced output index takes for this chunk.

contract(arrays, order=None, prefer_einsum=False, strip_exponent=False, check_zero=False, backend=None, implementation='auto', autojit=False, progbar=False)[source]#

Contract arrays with this tree. This function takes unsliced arrays and handles the slicing, contractions and gathering. The order of the axes and output is assumed to match that of tree.inputs and tree.output.

Parameters:
  • arrays (sequence of array) – The arrays to contract.

  • order (str or callable, optional) – Supplied to ContractionTree.traverse().

  • prefer_einsum (bool, optional) – Prefer to use einsum for pairwise contractions, even if tensordot can perform the contraction.

  • strip_exponent (bool, optional) – If True, eagerly strip the exponent (in log10) from intermediate tensors to control numerical problems from leaving the range of the datatype. This method then returns the scaled ‘mantissa’ output array and the exponent separately.

  • check_zero (bool, optional) – If True, when strip_exponent=True, explicitly check for zero-valued intermediates that would otherwise produce nan, instead terminating early if encounteredand returning (0.0, 0.0).

  • backend (str, optional) – What library to use for tensordot, einsum and transpose, it will be automatically inferred from the input arrays if not given.

  • autojit (bool, optional) – Whether to use the ‘autojit’ feature of autoray to compile the contraction expression.

  • progbar (bool, optional) – Whether to show a progress bar.

Returns:

  • output (array) – The contracted output, it will be scaled if strip_exponent==True.

  • exponent (float) – The exponent of the output in base 10, returned only if strip_exponent==True.

contract_mpi(arrays, comm=None, root=None, **kwargs)[source]#

Contract the slices of this tree and sum them in parallel - assuming we are already running under MPI.

Parameters:
  • arrays (sequence of array) – The input (unsliced arrays)

  • comm (None or mpi4py communicator) – Defaults to mpi4py.MPI.COMM_WORLD if not given.

  • root (None or int, optional) – If root=None, an Allreduce will be performed such that every process has the resulting tensor, else if an integer e.g. root=0, the result will be exclusively gathered to that process using Reduce, with every other process returning None.

  • kwargs – Supplied to contract_slice().

plot_hypergraph(**kwargs)[source]#
__repr__()[source]#

Return repr(self).

class cotengra.ContractionTreeCompressed(inputs, output, size_dict, track_childless=False, track_flops=False, track_write=False, track_size=False)[source]#

Bases: ContractionTree

A contraction tree for compressed contractions. Currently the only difference is that this defaults to the ‘surface’ traversal ordering.

total_flops[source]#
total_write[source]#
total_cost[source]#
max_size[source]#
peak_size[source]#
contraction_cost[source]#
contraction_width[source]#
total_flops_exact[source]#
total_write_exact[source]#
total_cost_exact[source]#
max_size_exact[source]#
peak_size_exact[source]#
classmethod from_path(inputs, output, size_dict, *, path=None, ssa_path=None, check=False, **kwargs)[source]#

Create a (completed) ContractionTreeCompressed from the usual inputs plus a standard contraction path or ‘ssa_path’ - you need to supply one. This also set the default ‘surface’ traversal ordering to be the initial path.

get_default_order()[source]#
abstract get_contractor(*_, **__)[source]#

Get a reusable function which performs the contraction corresponding to this tree, cached.

Parameters:
  • tree (ContractionTree) – The contraction tree.

  • order (str or callable, optional) – Supplied to ContractionTree.traverse(), the order in which to perform the pairwise contractions given by the tree.

  • prefer_einsum (bool, optional) – Prefer to use einsum for pairwise contractions, even if tensordot can perform the contraction.

  • strip_exponent (bool, optional) – If True, the function will strip the exponent from the output array and return it separately.

  • implementation (str or tuple[callable, callable], optional) –

    What library to use to actually perform the contractions. Options are:

    • None: let cotengra choose.

    • ”autoray”: dispatch with autoray, using the tensordot and einsum implementation of the backend.

    • ”cotengra”: use the tensordot and einsum implementation of cotengra, which is based on batch matrix multiplication. This is faster for some backends like numpy, and also enables libraries which don’t yet provide tensordot and einsum to be used.

    • ”cuquantum”: use the cuquantum library to perform the whole contraction (not just individual contractions).

    • tuple[callable, callable]: manually supply the tensordot and einsum implementations to use.

  • autojit (bool, optional) – If True, use autoray.autojit() to compile the contraction function.

Returns:

fn – The contraction function, with signature fn(*arrays).

Return type:

callable

class cotengra.ContractionTreeMulti(inputs, output, size_dict, track_childless=False, track_flops=False, track_write=False, track_size=False)[source]#

Bases: ContractionTree

Binary tree representing a tensor network contraction.

Parameters:
  • inputs (sequence of str) – The list of input tensor’s indices.

  • output (str) – The output indices.

  • size_dict (dict[str, int]) – The size of each index.

  • track_childless (bool, optional) – Whether to dynamically keep track of which nodes are childless. Useful if you are ‘divisively’ building the tree.

  • track_flops (bool, optional) – Whether to dynamically keep track of the total number of flops. If False You can still compute this once the tree is complete.

  • track_write (bool, optional) – Whether to dynamically keep track of the total number of elements written. If False You can still compute this once the tree is complete.

  • track_size (bool, optional) – Whether to dynamically keep track of the largest tensor so far. If False You can still compute this once the tree is complete.

children#

Mapping of each node to two children.

Type:

dict[node, tuple[node]]

info#

Information about the tree nodes. The key is the set of inputs (a set of inputs indices) the node contains. Or in other words, the subgraph of the node. The value is a dictionary to cache information about effective ‘leg’ indices, size, flops of formation etc.

Type:

dict[node, dict]

set_varmults(varmults)[source]#
get_varmults()[source]#
set_numconfigs(numconfigs)[source]#
get_numconfigs()[source]#
class cotengra.HyperGraph(inputs, output=None, size_dict=None)[source]#

Simple hypergraph builder and writer.

Parameters:
  • inputs (sequence of list[str] or dict[int, list[str]]) – The nodes. If given as a dict, the keys will be taken as the node enumeration rather than range(len(inputs)).

  • output (str, optional) – Output indices.

  • size_dict (dict[str, int], optional) – Size of each index.

nodes#

Mapping of node to the list of edges incident to it.

Type:

dict[int, list[str]]

edges#

Mapping of hyper edges to list of nodes it is incident to.

Type:

dict[str, list[int]]

num_nodes#

The number of nodes.

Type:

int

num_edges#

The number of hyper-edges.

Type:

int

property num_nodes#
property num_edges#
__slots__ = ('inputs', 'output', 'size_dict', 'nodes', 'edges', 'node_counter')#
plot[source]#
copy()[source]#

Copy this HyperGraph.

classmethod from_edges(edges, output=(), size_dict=())[source]#
get_num_nodes()[source]#
get_num_edges()[source]#
__len__()[source]#
edges_size(es)[source]#

Get the combined, i.e. product, size of all edges in es.

bond_size(i, j)[source]#

Get the combined, i.e. product, size of edges shared by nodes i and j.

node_size(i)[source]#

Get the size of the term represented by node i.

neighborhood_size(nodes)[source]#

Get the size of nodes in the immediate neighborhood of nodes.

contract_pair_cost(i, j)[source]#

Get the cost of contracting nodes i and j - the product of the dimensions of the indices involved.

neighborhood_compress_cost(chi, nodes)[source]#
total_node_size()[source]#

Get the total size of all nodes.

output_nodes()[source]#

Get the nodes with output indices.

neighbors(i)[source]#

Get the neighbors of node i.

neighbor_edges(i)[source]#

Get the edges incident to all neighbors of node i, (including its own edges).

has_node(i)[source]#

Does this hypergraph have node i?

get_node(i)[source]#

Get the edges node i is incident to.

get_edge(e)[source]#

Get the nodes edge e is incident to.

has_edge(e)[source]#

Does this hypergraph have edge e?

next_node()[source]#

Get the next available node identifier.

add_node(inds, node=None)[source]#

Add a node with inds, and optional identifier node. The identifier will be generated if not given and returned.

remove_node(i)[source]#

Remove node i from this hypergraph.

remove_edge(e)[source]#

Remove edge e from this hypergraph.

contract(i, j, node=None)[source]#

Combine node i and node j.

compress(chi, edges=None)[source]#

‘Compress’ multiedges, combining their size up to a maximum of chi.

compute_contracted_inds(nodes)[source]#

Generate the output indices if one were to contract nodes.

candidate_contraction_size(i, j, chi=None)[source]#

Get the size of the node created if i and j were contracted, optionally including the effect of first compressing bonds to size chi.

all_shortest_distances(nodes=None)[source]#
all_shortest_distances_condensed(nodes=None)[source]#
simple_distance(region, p=2)[source]#

Compute a simple distance metric from nodes in region to all others. Unlike graph distance, relative connectedness is taken into account.

simple_closeness(p=0.75, mu=0.5)[source]#

Compute a rough hypergraph ‘closeness’.

Parameters:
  • p (float, optional) – Once any node has had H.num_nodes**p visitors terminate. Set greater than 1.0 for no limit (slower).

  • mu (float, optional) – Let the visitor score decay with this power. The higher this is, the more local connectivity is favored.

Returns:

scores – The simple hypergraph closenesses - higher being more central.

Return type:

dict[int, float]

simple_centrality(r=None, smoothness=2, **closeness_opts)[source]#

A simple algorithm for large hypergraph centrality. First we find a rough closeness centrality, then relax / smooth this by nodes iteratively radiating their centrality to their neighbors.

Parameters:
  • r (None or int, optional) – Number of iterations. Defaults to max(10, int(self.num_nodes**0.5)).

  • smoothness (float, optional) – The smoothness. In conjunction with a high value of r this will create a smooth gradient from one of the hypergraph to the other.

  • closeness_opts – Supplied to HyperGraph.simple_closeness as the starting point.

Return type:

dict[int, float]

compute_loops(start=None, max_loop_length=None)[source]#

Generate all loops up to a certain length in this hypergraph.

Parameters:
  • start (sequence of int, optional) – Only generate loops including these nodes, defaults to all.

  • max_loop_length (None or int, optional) – The maximum loop length to search for. If None, then this is set automatically by the length of the first loop found.

Yields:

loop (tuple[int]) – A set of nodes that form a loop.

get_laplacian()[source]#

Get the graph Laplacian.

get_resistance_distances()[source]#

Get the resistance distance between all nodes of the raw graph.

resistance_centrality(rescale=True)[source]#

Compute the centrality in terms of the total resistance distance to all other nodes.

to_networkx(as_tree_leaves=False)[source]#

Convert to a networkx Graph, with hyperedges represented as nodes.

Parameters:

as_tree_leaves (bool, optional) – If true, then the nodes are converted to ‘tree leaf’ form, i.e. map node i to frozenset([i]), to match the nodes in a ContractionTree.

compute_weights(weight_edges='const', weight_nodes='const')[source]#
__repr__()[source]#

Return repr(self).

cotengra.get_hypergraph(inputs, output=None, size_dict=None, accel=False)[source]#

Single entry-point for creating a, possibly accelerated, HyperGraph.

cotengra.array_contract_expression(inputs, output=None, size_dict=None, shapes=None, optimize='auto', constants=None, canonicalize=True, cache=True, **kwargs)[source]#

Get an callable ‘expression’ that will contract tensors with indices and shapes described by inputs and size_dict to output. The optimize kwarg can be a path, optimizer or also a contraction tree. In the latter case sliced indices for example will be used if present. The same is true if optimize is an optimizer that can directly produce ContractionTree instances (i.e. has a .search() method).

Parameters:
  • inputs (Sequence[Sequence[Hashable]]) – The inputs terms.

  • output (Sequence[Hashable]) – The output term.

  • size_dict (dict[Hashable, int]) – The size of each index.

  • optimize (str, path_like, PathOptimizer, or ContractionTree) –

    The optimization strategy to use. This can be:

    • A string preset, e.g. 'auto', 'greedy', 'optimal'.

    • A PathOptimizer instance.

    • An explicit path, e.g. [(0, 1), (2, 3), ...].

    • An explicit ContractionTree instance.

    If the optimizer provides sliced indices they will be used.

  • constants (dict[int, array_like], optional) – A mapping of constant input positions to constant arrays. If given, the final expression will take only the remaining non-constant tensors as inputs. Note this is a different format to the constants kwarg of einsum_expression() since it also provides the constant arrays.

  • implementation (str or tuple[callable, callable], optional) –

    What library to use to actually perform the contractions. Options are:

    • None: let cotengra choose.

    • ”autoray”: dispatch with autoray, using the tensordot and

      einsum implementation of the backend.

    • ”cotengra”: use the tensordot and einsum implementation

      of cotengra, which is based on batch matrix multiplication. This is faster for some backends like numpy, and also enables libraries which don’t yet provide tensordot and einsum to be used.

    • ”cuquantum”: use the cuquantum library to perform the whole

      contraction (not just individual contractions).

    • tuple[callable, callable]: manually supply the tensordot and

      einsum implementations to use.

  • autojit (bool, optional) – If True, use autoray.autojit() to compile the contraction function.

  • via (tuple[callable, callable], optional) – If given, the first function will be applied to the input arrays and the second to the output array. For example, moving the tensors from CPU to GPU and back.

  • sort_contraction_indices (bool, optional) – If True, call tree.sort_contraction_indices() before constructing the contraction function.

  • cache (bool, optional) – If True, cache the contraction expression. This negates the overhead of pathfinding and building the expression when a contraction is performed multiple times. Only for hashable optimize objects.

Returns:

expr – A callable, signature expr(*arrays) that will contract arrays with shapes shapes.

Return type:

callable

cotengra.array_contract_path(inputs, output=None, size_dict=None, shapes=None, optimize='auto', canonicalize=True, cache=True)[source]#

Find only the contraction path for the specific contraction, with fast dispatch of optimize, which can be a preset, path, tree, cotengra optimizer or opt_einsum optimizer. The raw path is a more compact representation of the core tree structure but contains less information on its own, for example sliced indices are not included.

Parameters:
  • inputs (Sequence[Sequence[Hashable]]) – The inputs terms.

  • output (Sequence[Hashable], optional) – The output term.

  • size_dict (dict[Hashable, int], optional) – The size of each index, if given, shapes is ignored.

  • shapes (Sequence[tuple[int]], optional) – The shape of each input array. Needed if size_dict not supplied.

  • optimize (str, path_like, PathOptimizer, or ContractionTree) –

    The optimization strategy to use. This can be:

    • A string preset, e.g. 'auto', 'greedy', 'optimal'.

    • A PathOptimizer instance.

    • An explicit path, e.g. [(0, 1), (2, 3), ...].

    • An explicit ContractionTree instance.

  • canonicalize (bool, optional) – If True, canonicalize the inputs and output so that the indices are relabelled 'a', 'b', 'c', ..., etc. in the order they appear.

  • cache (bool, optional) – If True, cache the path for the contraction, so that if the same pathfinding is performed multiple times the overhead is negated. Only for hashable optimize objects.

Returns:

path – The contraction path, whose interpretation is thus: the input tensors are assumed to be stored in a list, i.e. indexed by range(N). Each contraction in the path is a set of indices, the tensors at these locations should be popped from the list and then the result of the contraction appended.

Return type:

tuple[tuple[int]]

cotengra.array_contract_tree(inputs, output=None, size_dict=None, shapes=None, optimize='auto', canonicalize=True, sort_contraction_indices=False)[source]#

Get the ContractionTree for the tensor contraction specified by inputs, output and size_dict, with optimization strategy given by optimize. The tree can be used to inspect and also perform the contraction.

Parameters:
  • inputs (Sequence[Sequence[Hashable]]) – The inputs terms.

  • output (Sequence[Hashable], optional) – The output term.

  • size_dict (dict[Hashable, int], optional) – The size of each index, if given, shapes is ignored.

  • shapes (Sequence[tuple[int]], optional) – The shape of each input array. Needed if size_dict not supplied.

  • optimize (str, path_like, PathOptimizer, or ContractionTree) –

    The optimization strategy to use. This can be:

    • A string preset, e.g. 'auto', 'greedy', 'optimal'.

    • A PathOptimizer instance.

    • An explicit path, e.g. [(0, 1), (2, 3), ...].

    • An explicit ContractionTree instance.

  • canonicalize (bool, optional) – If True, canonicalize the inputs and output so that the indices are relabelled 'a', 'b', 'c', ..., etc. in the order they appear.

  • sort_contraction_indices (bool, optional) – If True, call tree.sort_contraction_indices().

Return type:

ContractionTree

cotengra.array_contract(arrays, inputs, output=None, optimize='auto', cache_expression=True, backend=None, **kwargs)[source]#

Perform the tensor contraction specified by inputs, output and size_dict, using strategy given by optimize. By default the path finding and expression building is cached, so that if the a matching contraction is performed multiple times the overhead is negated.

Parameters:
  • arrays (Sequence[array_like]) – The arrays to contract.

  • inputs (Sequence[Sequence[Hashable]]) – The inputs terms.

  • output (Sequence[Hashable]) – The output term.

  • optimize (str, path_like, PathOptimizer, or ContractionTree) –

    The optimization strategy to use. This can be:

    • A string preset, e.g. 'auto', 'greedy', 'optimal'.

    • A PathOptimizer instance.

    • An explicit path, e.g. [(0, 1), (2, 3), ...].

    • An explicit ContractionTree instance.

    If the optimizer provides sliced indices they will be used.

  • cache_expression (bool, optional) – If True, cache the expression used to contract the arrays. This negates the overhead of pathfinding and building the expression when a contraction is performed multiple times. Only for hashable optimize objects.

  • backend (str, optional) – If given, the explicit backend to use for the contraction, by default the backend is dispatched automatically.

  • kwargs – Passed to array_contract_expression().

Return type:

array_like

cotengra.einsum_expression(*args, optimize='auto', constants=None, cache=True, **kwargs)[source]#

Get an callable ‘expression’ that will contract tensors with shapes shapes according to equation eq. The optimize kwarg can be a path, optimizer or also a contraction tree. In the latter case sliced indices for example will be used if present. The same is true if optimize is an optimizer that can directly produce ContractionTree instances (i.e. has a .search() method).

Parameters:
  • eq (str) – The equation to use for contraction, for example 'ab,bc->ac'. The output will be automatically computed if not supplied, but Ellipses (’…’) are not supported.

  • shapes (Sequence[tuple[int]]) – The shapes of the tensors to contract, or the constant tensor itself if marked as constant in constants.

  • optimize (str, path_like, PathOptimizer, or ContractionTree) –

    The optimization strategy to use. This can be:

    • A string preset, e.g. 'auto', 'greedy', 'optimal'.

    • A PathOptimizer instance.

    • An explicit path, e.g. [(0, 1), (2, 3), ...].

    • An explicit ContractionTree instance.

    If the optimizer provides sliced indices they will be used.

  • constants (Sequence of int, optional) – The indices of tensors to treat as constant, the final expression will take the remaining non-constant tensors as inputs. Note this is a different format to the constants kwarg of array_contract_expression() since the actual constant arrays are inserted into shapes.

  • implementation (str or tuple[callable, callable], optional) –

    What library to use to actually perform the contractions. Options are:

    • None: let cotengra choose.

    • ”autoray”: dispatch with autoray, using the tensordot and

      einsum implementation of the backend.

    • ”cotengra”: use the tensordot and einsum implementation

      of cotengra, which is based on batch matrix multiplication. This is faster for some backends like numpy, and also enables libraries which don’t yet provide tensordot and einsum to be used.

    • ”cuquantum”: use the cuquantum library to perform the whole

      contraction (not just individual contractions).

    • tuple[callable, callable]: manually supply the tensordot and

      einsum implementations to use.

  • autojit (bool, optional) – If True, use autoray.autojit() to compile the contraction function.

  • via (tuple[callable, callable], optional) – If given, the first function will be applied to the input arrays and the second to the output array. For example, moving the tensors from CPU to GPU and back.

  • sort_contraction_indices (bool, optional) – If True, call tree.sort_contraction_indices() before constructing the contraction function.

  • cache (bool, optional) – If True, cache the contraction expression. This negates the overhead of pathfinding and building the expression when a contraction is performed multiple times. Only for hashable optimize objects.

Returns:

expr – A callable, signature expr(*arrays) that will contract arrays with shapes matching shapes.

Return type:

callable

cotengra.einsum_tree(*args, optimize='auto', canonicalize=False, sort_contraction_indices=False)[source]#

Get the ContractionTree for the einsum equation eq and optimization strategy optimize. The tree can be used to inspect and also perform the contraction.

Parameters:
  • eq (str) – The equation to use for contraction, for example 'ab,bc->ac'.

  • shapes (Sequence[tuple[int]]) – The shape of each input array.

  • optimize (str, path_like, PathOptimizer, or ContractionTree) –

    The optimization strategy to use. This can be:

    • A string preset, e.g. 'auto', 'greedy', 'optimal'.

    • A PathOptimizer instance.

    • An explicit path, e.g. [(0, 1), (2, 3), ...].

    • An explicit ContractionTree instance.

  • canonicalize (bool, optional) – If True, canonicalize the inputs and output so that the indices are relabelled 'a', 'b', 'c', ..., etc. in the order they appear.

  • sort_contraction_indices (bool, optional) – If True, call tree.sort_contraction_indices().

Return type:

ContractionTree

cotengra.einsum(*args, optimize='auto', cache_expression=True, backend=None, **kwargs)[source]#

Perform an einsum contraction, using cotengra, using strategy given by optimize. By default the path finding and expression building is cached, so that if a matching contraction is performed multiple times the overhead is negated.

Parameters:
  • eq (str) – The equation to use for contraction, for example 'ab,bc->ac'.

  • arrays (Sequence[array_like]) – The arrays to contract.

  • optimize (str, path_like, PathOptimizer, or ContractionTree) –

    The optimization strategy to use. This can be:

    • A string preset, e.g. 'auto', 'greedy', 'optimal'.

    • A PathOptimizer instance.

    • An explicit path, e.g. [(0, 1), (2, 3), ...].

    • An explicit ContractionTree instance.

    If the optimizer provides sliced indices they will be used.

  • cache_expression (bool, optional) – If True, cache the expression used to contract the arrays. This negates the overhead of pathfinding and building the expression when a contraction is performed multiple times. Only for hashable optimize objects.

  • backend (str, optional) – If given, the explicit backend to use for the contraction, by default the backend is dispatched automatically.

  • kwargs – Passed to array_contract_expression().

Return type:

array_like

cotengra.register_preset(preset, optimizer, register_opt_einsum='auto')[source]#

Register a preset optimizer.

class cotengra.SliceFinder(tree_or_info, target_size=None, target_overhead=None, target_slices=None, temperature=0.01, minimize='flops', allow_outer=True)[source]#

An object to help find the best indices to slice over in order to reduce the memory footprint of a contraction as much as possible whilst introducing as little extra overhead. It searches for and stores ContractionCosts.

Parameters:
  • tree_or_info (ContractionTree or opt_einsum.PathInfo) – Object describing the target full contraction to slice.

  • target_size (int, optional) – The target number of entries in the largest tensor of the sliced contraction. The search algorithm will terminate after this is reached.

  • target_slices (int, optional) – The target or minimum number of ‘slices’ to consider - individual contractions after slicing indices. The search algorithm will terminate after this is breached.

  • target_overhead (float, optional) – The target increase in total number of floating point operations. For example, a value of 2.0 will terminate the search just before the cost of computing all the slices individually breaches twice that of computing the original contraction all at once.

  • temperature (float, optional) – When sampling combinations of indices, how far to randomly stray from what looks like the best (local) choice.

plot_slicings[source]#
plot_slicings_alt[source]#
_maybe_default(attr, value)[source]#
best(k=None, target_size=None, target_overhead=None, target_slices=None)[source]#

Return the best contraction slicing, subject to target filters.

trial(target_size=None, target_overhead=None, target_slices=None, temperature=None)[source]#

A single slicing attempt, greedily select indices from the popular pool, subject to the score function, terminating when any of the target criteria are met.

search(max_repeats=16, temperature=None, target_size=None, target_overhead=None, target_slices=None)[source]#

Repeat trial several times and return the best found so far.

class cotengra.QuickBBOptimizer(max_time=10, executable='quickbb_64', seed=None)[source]#

Bases: cotengra.oe.PathOptimizer

run_quickbb(fname, outfile, statfile, max_time=None)[source]#
build_tree(inputs, output, size_dict)[source]#
__call__(inputs, output, size_dict, memory_limit=None)[source]#
cotengra.optimize_quickbb(inputs, output, size_dict, memory_limit=None, max_time=60, seed=None)[source]#
class cotengra.FlowCutterOptimizer(max_time=10, seed=None, executable='flow_cutter_pace17')[source]#

Bases: cotengra.oe.PathOptimizer

run_flowcutter(file, max_time=None)[source]#
compute_edge_path(lg)[source]#
build_tree(inputs, output, size_dict, memory_limit=None)[source]#
__call__(inputs, output, size_dict, memory_limit=None)[source]#
cotengra.optimize_flowcutter(inputs, output, size_dict, memory_limit=None, max_time=10, seed=None)[source]#
cotengra.get_hyper_space()[source]#
cotengra.hash_contraction(inputs, output, size_dict, method='a')[source]#

Compute a hash for a particular contraction geometry.

class cotengra.HyperCompressedOptimizer(chi=None, methods=('greedy-compressed', 'greedy-span', 'kahypar-agglom'), minimize='peak-compressed', **kwargs)[source]#

Bases: HyperOptimizer

A compressed contraction path optimizer that samples a series of ordered contraction trees while optimizing the hyper parameters used to generate them.

Parameters:
  • chi (None or int, optional) – The maximum bond dimension to compress to. If None then use the square of the largest existing dimension. If minimize is specified as a full scoring function, this is ignored.

  • methods (None or sequence[str] or str, optional) – Which method(s) to use from list_hyper_functions().

  • minimize (str, Objective or callable, optional) – How to score each trial, used to train the optimizer and rank the results. If a custom callable, it should take a trial dict as its argument and return a single float.

  • max_repeats (int, optional) – The maximum number of trial contraction trees to generate. Default: 128.

  • max_time (None or float, optional) – The maximum amount of time to run for. Use None for no limit. You can also set an estimated execution ‘rate’ here like 'rate:1e9' that will terminate the search when the estimated FLOPs of the best contraction found divided by the rate is greater than the time spent searching, allowing quick termination on easy contractions.

  • parallel ('auto', False, True, int, or distributed.Client) – Whether to parallelize the search.

  • slicing_opts (dict, optional) – If supplied, once a trial contraction path is found, try slicing with the given options, and then update the flops and size of the trial with the sliced versions.

  • slicing_reconf_opts (dict, optional) – If supplied, once a trial contraction path is found, try slicing interleaved with subtree reconfiguation with the given options, and then update the flops and size of the trial with the sliced and reconfigured versions.

  • reconf_opts (dict, optional) – If supplied, once a trial contraction path is found, try subtree reconfiguation with the given options, and then update the flops and size of the trial with the reconfigured versions.

  • optlib ({'baytune', 'nevergrad', 'chocolate', 'skopt'}, optional) – Which optimizer to sample and train with.

  • space (dict, optional) – The hyper space to search, see get_hyper_space for the default.

  • score_compression (float, optional) – Raise scores to this power in order to compress or accentuate the differences. The lower this is, the more the selector will sample from various optimizers rather than quickly specializing.

  • max_training_steps (int, optional) – The maximum number of trials to train the optimizer with. Setting this can be helpful when the optimizer itself becomes costly to train (e.g. for Gaussian Processes).

  • progbar (bool, optional) – Show live progress of the best contraction found so far.

  • optlib_opts – Supplied to the hyper-optimizer library initialization.

compressed = True#
multicontraction = False#
class cotengra.HyperMultiOptimizer(methods=None, minimize='flops', max_repeats=128, max_time=None, parallel='auto', slicing_opts=None, slicing_reconf_opts=None, reconf_opts=None, optlib=None, space=None, score_compression=0.75, on_trial_error='warn', max_training_steps=None, progbar=False, **optlib_opts)[source]#

Bases: HyperOptimizer

A path optimizer that samples a series of contraction trees while optimizing the hyper parameters used to generate them.

Parameters:
  • methods (None or sequence[str] or str, optional) – Which method(s) to use from list_hyper_functions().

  • minimize (str, Objective or callable, optional) – How to score each trial, used to train the optimizer and rank the results. If a custom callable, it should take a trial dict as its argument and return a single float.

  • max_repeats (int, optional) – The maximum number of trial contraction trees to generate. Default: 128.

  • max_time (None or float, optional) – The maximum amount of time to run for. Use None for no limit. You can also set an estimated execution ‘rate’ here like 'rate:1e9' that will terminate the search when the estimated FLOPs of the best contraction found divided by the rate is greater than the time spent searching, allowing quick termination on easy contractions.

  • parallel ('auto', False, True, int, or distributed.Client) – Whether to parallelize the search.

  • slicing_opts (dict, optional) – If supplied, once a trial contraction path is found, try slicing with the given options, and then update the flops and size of the trial with the sliced versions.

  • slicing_reconf_opts (dict, optional) – If supplied, once a trial contraction path is found, try slicing interleaved with subtree reconfiguation with the given options, and then update the flops and size of the trial with the sliced and reconfigured versions.

  • reconf_opts (dict, optional) – If supplied, once a trial contraction path is found, try subtree reconfiguation with the given options, and then update the flops and size of the trial with the reconfigured versions.

  • optlib ({'baytune', 'nevergrad', 'chocolate', 'skopt'}, optional) – Which optimizer to sample and train with.

  • space (dict, optional) – The hyper space to search, see get_hyper_space for the default.

  • score_compression (float, optional) – Raise scores to this power in order to compress or accentuate the differences. The lower this is, the more the selector will sample from various optimizers rather than quickly specializing.

  • on_trial_error ({'warn', 'raise', 'ignore'}, optional) – What to do if a trial fails. If 'warn' (default), a warning will be printed and the trial will be given a score of inf. If 'raise' the error will be raised. If 'ignore' the trial will be given a score of inf silently.

  • max_training_steps (int, optional) – The maximum number of trials to train the optimizer with. Setting this can be helpful when the optimizer itself becomes costly to train (e.g. for Gaussian Processes).

  • progbar (bool, optional) – Show live progress of the best contraction found so far.

  • optlib_opts – Supplied to the hyper-optimizer library initialization.

compressed = False#
multicontraction = True#
class cotengra.HyperOptimizer(methods=None, minimize='flops', max_repeats=128, max_time=None, parallel='auto', slicing_opts=None, slicing_reconf_opts=None, reconf_opts=None, optlib=None, space=None, score_compression=0.75, on_trial_error='warn', max_training_steps=None, progbar=False, **optlib_opts)[source]#

Bases: cotengra.oe.PathOptimizer

A path optimizer that samples a series of contraction trees while optimizing the hyper parameters used to generate them.

Parameters:
  • methods (None or sequence[str] or str, optional) – Which method(s) to use from list_hyper_functions().

  • minimize (str, Objective or callable, optional) – How to score each trial, used to train the optimizer and rank the results. If a custom callable, it should take a trial dict as its argument and return a single float.

  • max_repeats (int, optional) – The maximum number of trial contraction trees to generate. Default: 128.

  • max_time (None or float, optional) – The maximum amount of time to run for. Use None for no limit. You can also set an estimated execution ‘rate’ here like 'rate:1e9' that will terminate the search when the estimated FLOPs of the best contraction found divided by the rate is greater than the time spent searching, allowing quick termination on easy contractions.

  • parallel ('auto', False, True, int, or distributed.Client) – Whether to parallelize the search.

  • slicing_opts (dict, optional) – If supplied, once a trial contraction path is found, try slicing with the given options, and then update the flops and size of the trial with the sliced versions.

  • slicing_reconf_opts (dict, optional) – If supplied, once a trial contraction path is found, try slicing interleaved with subtree reconfiguation with the given options, and then update the flops and size of the trial with the sliced and reconfigured versions.

  • reconf_opts (dict, optional) – If supplied, once a trial contraction path is found, try subtree reconfiguation with the given options, and then update the flops and size of the trial with the reconfigured versions.

  • optlib ({'baytune', 'nevergrad', 'chocolate', 'skopt'}, optional) – Which optimizer to sample and train with.

  • space (dict, optional) – The hyper space to search, see get_hyper_space for the default.

  • score_compression (float, optional) – Raise scores to this power in order to compress or accentuate the differences. The lower this is, the more the selector will sample from various optimizers rather than quickly specializing.

  • on_trial_error ({'warn', 'raise', 'ignore'}, optional) – What to do if a trial fails. If 'warn' (default), a warning will be printed and the trial will be given a score of inf. If 'raise' the error will be raised. If 'ignore' the trial will be given a score of inf silently.

  • max_training_steps (int, optional) – The maximum number of trials to train the optimizer with. Setting this can be helpful when the optimizer itself becomes costly to train (e.g. for Gaussian Processes).

  • progbar (bool, optional) – Show live progress of the best contraction found so far.

  • optlib_opts – Supplied to the hyper-optimizer library initialization.

property minimize#
property parallel#
property tree#
property path#
compressed = False#
multicontraction = False#
plot_trials[source]#
plot_trials_alt[source]#
plot_scatter[source]#
plot_scatter_alt[source]#
setup(inputs, output, size_dict)[source]#
_maybe_cancel_futures()[source]#
_maybe_report_result(setting, trial)[source]#
_gen_results(repeats, trial_fn, trial_args)[source]#
_get_and_report_next_future()[source]#
_gen_results_parallel(repeats, trial_fn, trial_args)[source]#
search(inputs, output, size_dict)[source]#

Run this optimizer and return the ContractionTree for the best path it finds.

get_tree()[source]#

Return the ContractionTree for the best path found.

__call__(inputs, output, size_dict, memory_limit=None)[source]#

opt_einsum interface, returns direct path.

get_trials(sort=None)[source]#
print_trials(sort=None)[source]#
to_df()[source]#

Create a single pandas.DataFrame with all trials and scores.

to_dfs_parametrized()[source]#

Create a pandas.DataFrame for each method, with all parameters and scores for each trial.

cotengra.list_hyper_functions()[source]#

Return a list of currently registered hyper contraction finders.

class cotengra.ReusableHyperCompressedOptimizer(chi=None, methods=('greedy-compressed', 'greedy-span', 'kahypar-agglom'), minimize='peak-compressed', **kwargs)[source]#

Bases: ReusableHyperOptimizer

Like HyperCompressedOptimizer but it will re-instantiate the optimizer whenever a new contraction is detected, and also cache the paths found.

Parameters:
  • chi (None or int, optional) – The maximum bond dimension to compress to. If None then use the square of the largest existing dimension. If minimize is specified as a full scoring function, this is ignored.

  • directory (None, True, or str, optional) – If specified use this directory as a persistent cache. If True auto generate a directory in the current working directory based on the options which are most likely to affect the path (see ReusableHyperOptimizer.get_path_relevant_opts).

  • overwrite (bool, optional) – If True, the optimizer will always run, overwriting old results in the cache. This can be used to update paths without deleting the whole cache.

  • set_surface_order (bool, optional) – If True, when reloading a path to turn into a ContractionTree, the ‘surface order’ of the path (used for compressed paths), will be set manually to the order the disk path is.

  • hash_method ({'a', 'b', ...}, optional) – The method used to hash the contraction tree. The default, 'a', is faster hashwise but doesn’t recognize when indices are permuted.

  • cache_only (bool, optional) – If True, the optimizer will only use the cache, and will raise KeyError if a contraction is not found.

  • opt_kwargs – Supplied to HyperCompressedOptimizer.

suboptimizer[source]#
set_surface_order = True#
class cotengra.ReusableHyperOptimizer(*, directory=None, overwrite=False, hash_method='a', cache_only=False, **opt_kwargs)[source]#

Bases: cotengra.oe.PathOptimizer

Like HyperOptimizer but it will re-instantiate the optimizer whenever a new contraction is detected, and also cache the paths (and sliced indices) found.

Parameters:
  • directory (None, True, or str, optional) – If specified use this directory as a persistent cache. If True auto generate a directory in the current working directory based on the options which are most likely to affect the path (see ReusableHyperOptimizer.get_path_relevant_opts).

  • overwrite (bool, optional) – If True, the optimizer will always run, overwriting old results in the cache. This can be used to update paths without deleting the whole cache.

  • set_surface_order (bool, optional) – If True, when reloading a path to turn into a ContractionTree, the ‘surface order’ of the path (used for compressed paths), will be set manually to the order the disk path is.

  • hash_method ({'a', 'b', ...}, optional) – The method used to hash the contraction tree. The default, 'a', is faster hashwise but doesn’t recognize when indices are permuted.

  • cache_only (bool, optional) – If True, the optimizer will only use the cache, and will raise KeyError if a contraction is not found.

  • opt_kwargs – Supplied to HyperOptimizer.

property last_opt#
suboptimizer[source]#
set_surface_order = False#
get_path_relevant_opts()[source]#

Get a frozenset of the options that are most likely to affect the path. These are the options that we use when the directory name is not manually specified.

auto_hash_path_relevant_opts()[source]#

Automatically hash the path relevant options used to create the optimizer.

hash_query(inputs, output, size_dict)[source]#

Hash the contraction specification, returning this and whether the contraction is already present as a tuple.

_compute_path(inputs, output, size_dict)[source]#
update_from_tree(tree, overwrite=True)[source]#

Explicitly add the contraction that tree represents into the cache. For example, if you have manually improved it via reconfing. If overwrite=False and the contracton is present already then do nothing.

__call__(inputs, output, size_dict, memory_limit=None)[source]#
search(inputs, output, size_dict)[source]#
cleanup()[source]#
cotengra.auto_hq_optimize#
cotengra.auto_optimize#
class cotengra.AutoHQOptimizer(**kwargs)[source]#

Bases: AutoOptimizer

An optimizer that automatically chooses between optimal and hyper-optimization, designed for everyday use on harder contractions or those that will be repeated many times, and thus warrant a more extensive search.

class cotengra.AutoOptimizer(optimal_cutoff=250, minimize='combo', cache=True, **hyperoptimizer_kwargs)[source]#

Bases: cotengra.oe.PathOptimizer

An optimizer that automatically chooses between optimal and hyper-optimization, designed for everyday use.

_get_optimizer_hyper_threadsafe()[source]#
search(inputs, output, size_dict, **kwargs)[source]#
__call__(inputs, output, size_dict, **kwargs)[source]#
cotengra.greedy_optimize#
cotengra.optimal_optimize#
cotengra.optimal_outer_optimize#
cotengra.plot_contractions(tree, order=None, color_size=(0.6, 0.4, 0.7), color_cost=(0.3, 0.7, 0.5), figsize=(8, 3))[source]#
cotengra.plot_contractions_alt(tree, x='peak-size', y='flops', color='stage', size='scaling', width=400, height=400, point_opacity=0.8, color_scheme='lightmulti', x_scale='log', y_scale='log', color_scale='log', size_scale='linear')[source]#
cotengra.plot_scatter(self, x='size', y='flops', figsize=(5, 5))[source]#
cotengra.plot_scatter_alt(self, x='size', y='flops', color='run:Q', color_scheme='purplebluegreen', shape='method:N', width=400, height=400)[source]#

Plot the trials total flops vs max size.

cotengra.plot_slicings(slice_finder, color_scheme='RdYlBu_r', relative_flops=False, figsize=(6, 3), point_opacity=0.8)[source]#
cotengra.plot_slicings_alt(slice_finder, color_scheme='redyellowblue', relative_flops=False)[source]#
cotengra.plot_tree(tree, layout='ring', hypergraph_layout='auto', hypergraph_layout_opts=None, k=0.01, iterations=500, span=None, order=None, order_y_pow=1.0, edge_scale=1.0, node_scale=1.0, highlight=(), edge_color='size', edge_colormap='GnBu', edge_max_width=None, node_colormap='YlOrRd', node_color='flops', node_max_size=None, figsize=(5, 5), raw_edge_color=None, raw_edge_alpha=None, tree_root_height=True, tree_alpha=0.8, colorbars=True, plot_raw_graph=True, plot_leaf_labels=False, ax=None)[source]#

Plot a contraction tree using matplotlib.

cotengra.plot_tree_ring(tree, **kwargs)[source]#
cotengra.plot_tree_tent(tree, **kwargs)[source]#
cotengra.plot_tree_span(tree, **kwargs)[source]#
cotengra.plot_trials(self, y='score', figsize=(8, 3), **kwargs)[source]#
cotengra.plot_trials_alt(self, y=None, width=800, height=300)[source]#

Plot the trials interactively using altair.

cotengra.get_symbol(i)[source]#

Get the symbol corresponding to int i - runs through the usual 52 letters before resorting to unicode characters, starting at chr(192) and skipping surrogates.

Examples

get_symbol(2) #> ‘c’

get_symbol(200) #> ‘Ŕ’

get_symbol(20000) #> ‘京’

cotengra.get_symbol_map(inputs)[source]#

Get a mapping of arbitrary hashable ‘indices’ to single unicode symbols, matching the canonicalization of the expression.

cotengra.UniformOptimizer#

Does no gaussian process tuning by default, just randomly samples - requires no optimization library.

cotengra.QuasiRandOptimizer#

Does no gaussian process tuning by default, just randomly samples but in a more ‘even’ way than purely random - requires chocolate.

cotengra.contract_expression[source]#

Alias for cotengra.einsum_expression().

cotengra.contract[source]#

Alias for cotengra.einsum().

cotengra.hyper_optimize(inputs, output, size_dict, memory_limit=None, **opts)[source]#