Branch and Bound¶
Branch and bound algorithm for optimal contraction of a tensor network.
- class mrmustard.path.branch_and_bound.Graph(*args, backend=None, **kwargs)[source]¶
Power pack for nx.DiGraph with additional attributes and methods.
- Parameters:
solution (tuple[Edge, ...]) – The sequence of edges contracted to obtain this graph.
costs (tuple[int, ...]) – The costs of contracting each edge in the current solution.
- property cost: int¶
Returns the total cost of the graph.
- component(n)[source]¶
Returns the
GraphComponentassociated with a node.- Parameters:
n – The node index.
- Return type:
- components()[source]¶
Yields the
GraphComponentsassociated with the nodes.- Return type:
Generator[GraphComponent, None, None]
- optimize_fock_shapes(components, verbose=False)[source]¶
Optimizes the Fock shapes of the components in this circuit. It starts by matching the existing connected wires and keeps the smaller shape, then it enforces the BSgate symmetry (conservation of photon number) to further reduce the shapes across the circuit. This operation acts in place.
- Parameters:
components (list[CircuitComponent])
verbose (bool)
- class mrmustard.path.branch_and_bound.GraphComponent(ansatz, wires, shape, name='', cost=0)[source]¶
A lightweight “CircuitComponent” without the actual ansatz. Basically a wrapper around Wires, so that it can emulate components in a circuit. It exposes the ansatz, wires, shape, name and cost of obtaining the component from previous contractions.
- Parameters:
ansatz (str) – The name of the ansatz of the component.
wires (Wires) – The wires of the component.
shape (list[int]) – The fock shape of the component.
name (str) – The name of the component.
cost (int) – The cost of obtaining this component.
- classmethod from_circuitcomponent(c)[source]¶
Creates a GraphComponent from a CircuitComponent.
- Parameters:
c (CircuitComponent) – A CircuitComponent.
- contraction_cost(other)[source]¶
Returns the computational cost in approx FLOPS for contracting this component with another one.
Three cases are possible:
1. If both components are in Fock ansatz the cost is the product of the values along both shapes, counting only once the shape of the contracted indices. E.g. a tensor with shape (20,30,40) contracts its 1,2 indices with the 0,1 indices of a tensor with shape (30,40,50,60). The cost is 20 x 30 x 40 x 50 x 60 = 72_000_000 (note 30,40 were counted only once).
2. If the ansatze are a mix of Bargmann and Fock, we add the cost of converting the Bargmann to Fock, which is the product of the shape of the Bargmann component.
3. If both are in Bargmann ansatz, the contraction can be a simple a Gaussian integral which scales like the cube of the number of contracted indices, i.e. ~ just 8 in the example above.
- Parameters:
other (GraphComponent) – GraphComponent
- Returns:
contraction cost in approx FLOPS
- Return type:
int
- mrmustard.path.branch_and_bound.assign_costs(graph, debug=0)[source]¶
Assigns to each edge in the graph the cost of contracting the two nodes it connects.
- Parameters:
graph (Graph) – A graph.
debug (int) – Whether to print debug information
- Return type:
None
- mrmustard.path.branch_and_bound.children(graph, cost_bound)[source]¶
Returns a set of graphs obtained by contracting each edge. Only graphs with a cost below
cost_boundare returned. Two nodes are contracted by removing the edge between them and merging the two nodes into a single node. The shape of the new node is the union of the shapes of the two nodes without the wires that were contracted (this is all handled by the wires).
- mrmustard.path.branch_and_bound.contract(graph, edge, debug=0)[source]¶
Contracts an edge in a graph and returns the contracted graph. Makes a copy of the original graph.
- mrmustard.path.branch_and_bound.grandchildren(graph, cost_bound)[source]¶
A set of grandchildren constructed from each child’s children. Only grandchildren with a cost below
cost_boundare returned. Note that children without further children are included, so with a single call to this function we get all the descendants up to the grandchildren level including leaf nodes whether they are children or grandchildren.
- mrmustard.path.branch_and_bound.heuristic(graph, code, verbose)[source]¶
Simplifies the graph by contracting all pairs of nodes that match the given pattern.
- mrmustard.path.branch_and_bound.optimal_contraction(graph, n_init, heuristics, verbose)[source]¶
Finds the optimal path to contract a graph.
- Parameters:
graph (Graph) – The graph to contract.
n_init (int) – The number of random contractions to find an initial cost upper bound.
heuristics (tuple[str, ...]) – A sequence of patterns to reduce in order.
verbose (bool) – Whether to print the progress.
- Returns:
The optimally contracted graph with associated cost and solution
- Return type:
- mrmustard.path.branch_and_bound.optimize_fock_shapes(graph, iteration, verbose)[source]¶
Iteratively optimizes the Fock shapes of the components in the graph.
- mrmustard.path.branch_and_bound.parse_components(components)[source]¶
Parses a list of CircuitComponents into a Graph.
Each node in the graph corresponds to a GraphComponent and an edge between two nodes indicates that the GraphComponents are connected in the circuit. Whether they are connected by one wire or by many, in the graph they will have a single edge between them.
- Parameters:
components (list[CircuitComponent]) – A list of CircuitComponents.
- Return type:
- mrmustard.path.branch_and_bound.random_solution(graph)[source]¶
Returns a random solution to contract a given graph.
- mrmustard.path.branch_and_bound.validate_components(components)[source]¶
Raises an error if the components will not contract correctly.
- Parameters:
components (list[CircuitComponent]) – A list of CircuitComponents.
- Return type:
None