def _base_nodes(
        nodes: Iterable[BaseNode],
        algorithm: utils.Algorithm,
        output_edge_order: Optional[Sequence[Edge]] = None) -> BaseNode:
    """Base method for all `opt_einsum` contractors.

  Args:
    nodes: A collection of connected nodes.
    algorithm: `opt_einsum` contraction method to use.
    output_edge_order: An optional list of edges. Edges of the
      final node in `nodes_set`
      are reordered into `output_edge_order`;
      if final node has more than one edge,
      `output_edge_order` must be pronvided.

  Returns:
    Final node after full contraction.
  """
    nodes_set = set(nodes)
    check_connected(nodes_set)
    edges = get_all_edges(nodes_set)
    #output edge order has to be determinded before any contraction
    #(edges are refreshed after contractions)
    if output_edge_order is None:
        output_edge_order = list(get_subgraph_dangling(nodes))
        if len(output_edge_order) > 1:
            raise ValueError(
                "The final node after contraction has more than "
                "one remaining edge. In this case `output_edge_order` "
                "has to be provided.")

    if set(output_edge_order) != get_subgraph_dangling(nodes):
        raise ValueError("output edges are not equal to the remaining "
                         "non-contracted edges of the final node.")

    for edge in edges:
        if not edge.is_disabled:  #if its disabled we already contracted it
            if edge.is_trace():
                nodes_set.remove(edge.node1)
                nodes_set.add(contract_parallel(edge))

    if len(nodes_set) == 1:
        # There's nothing to contract.
        return list(nodes_set)[0].reorder_edges(output_edge_order)

    # Then apply `opt_einsum`'s algorithm
    path, nodes = utils.get_path(nodes_set, algorithm)
    for a, b in path:
        new_node = nodes[a] @ nodes[b]
        nodes.append(new_node)
        nodes = utils.multi_remove(nodes, [a, b])

    # if the final node has more than one edge,
    # output_edge_order has to be specified
    final_node = nodes[0]  # nodes were connected, we checked this
    final_node.reorder_edges(output_edge_order)
    return final_node
Esempio n. 2
0
    def check_network(self) -> None:
        """Check that the network has the expected dimensionality.

    This checks that all input and output edges are dangling and that
    there are no other dangling edges (except any specified in
    `ignore_edges`). If not, an exception is raised.
    """
        for (i, e) in enumerate(self.out_edges):
            if not e.is_dangling():
                raise ValueError("Output edge {} is not dangling!".format(i))
        for (i, e) in enumerate(self.in_edges):
            if not e.is_dangling():
                raise ValueError("Input edge {} is not dangling!".format(i))
        for e in self.ignore_edges:
            if not e.is_dangling():
                raise ValueError(
                    "ignore_edges contains non-dangling edge: {}".format(
                        str(e)))

        known_edges = set(self.in_edges) | set(
            self.out_edges) | self.ignore_edges
        all_dangling_edges = get_subgraph_dangling(self.nodes)
        if known_edges != all_dangling_edges:
            raise ValueError(
                "The network includes unexpected dangling edges (that "
                "are not members of ignore_edges).")
Esempio n. 3
0
def _get_path_nodes(nodes: Iterable[BaseNode], algorithm: Algorithm
                   ) -> Tuple[List[Tuple[int, int]], List[BaseNode]]:
  """Calculates the contraction paths using `opt_einsum` methods.

  Args:
    nodes: An iterable of nodes.
    algorithm: `opt_einsum` method to use for calculating the contraction path.

  Returns:
    The optimal contraction path as returned by `opt_einsum`.
  """
  sorted_nodes = sorted(nodes, key=lambda n: n.signature)

  input_sets = [set(node.edges) for node in sorted_nodes]
  output_set = get_subgraph_dangling(nodes)
  size_dict = {edge: edge.dimension for edge in get_all_edges(nodes)}

  return algorithm(input_sets, output_set, size_dict), sorted_nodes
Esempio n. 4
0
def get_path(
        nodes: Iterable[AbstractNode], algorithm: Algorithm
) -> Tuple[List[Tuple[int, int]], List[AbstractNode]]:
    """Calculates the contraction paths using `opt_einsum` methods.

  Args:
    nodes: An iterable of nodes.
    algorithm: `opt_einsum` method to use for calculating the contraction path.

  Returns:
    The optimal contraction path as returned by `opt_einsum`.
  """
    nodes = list(nodes)
    input_sets = [set(node.edges) for node in nodes]
    output_set = get_subgraph_dangling(nodes)
    size_dict = {edge: edge.dimension for edge in get_all_edges(nodes)}

    return algorithm(input_sets, output_set, size_dict), nodes