def test_edge_initialize_raises_error_faulty_arguments(double_node_edge):
  node1 = double_node_edge.node1
  node2 = double_node_edge.node2
  with pytest.raises(ValueError):
    Edge(name="edge", node1=node1, node2=node2, axis1=0)
  with pytest.raises(ValueError):
    Edge(name="edge", node1=node1, axis1=0, axis2=0)
def test_edge_magic_xor(double_node_edge):
  node1 = double_node_edge.node1
  node2 = double_node_edge.node2
  edge1 = Edge(name="edge1", node1=node1, axis1=2)
  edge2 = Edge(name="edge2", node1=node2, axis1=2)
  edge = edge1 ^ edge2
  assert edge.node1 == node1
  assert edge.node2 == node2
def fixture_double_node_edge(backend):
  net = tensornetwork.TensorNetwork(backend=backend)
  tensor = net.backend.convert_to_tensor(np.ones((1, 2, 2)))
  node1 = Node(
      tensor=tensor, name="test_node1", axis_names=["a", "b", "c"], network=net)
  node2 = Node(
      tensor=tensor, name="test_node2", axis_names=["a", "b", "c"], network=net)
  net.connect(node1["b"], node2["b"])
  edge1 = Edge(name="edge", node1=node1, axis1=0)
  edge12 = Edge(name="edge", node1=node1, axis1=1, node2=node2, axis2=1)
  return DoubleNodeEdgeTensor(node1, node2, edge1, edge12, tensor)
def copy(nodes: Iterable[BaseNode],
         conjugate: bool = False) -> Tuple[dict, dict]:
    """Copy the given nodes and their edges.

  This will return a dictionary linking original nodes/edges 
  to their copies.

  Args:
    nodes: An `Iterable` (Usually a `List` or `Set`) of `Nodes`.
    conjugate: Boolean. Whether to conjugate all of the nodes
        (useful for calculating norms and reduced density
        matrices).

  Returns:
    A tuple containing:
      node_dict: A dictionary mapping the nodes to their copies.
      edge_dict: A dictionary mapping the edges to their copies.
  """
    #TODO: add support for copying CopyTensor
    if conjugate:
        node_dict = {
            node: Node(node.backend.conj(node.tensor),
                       name=node.name,
                       axis_names=node.axis_names,
                       backend=node.backend.name)
            for node in nodes
        }
    else:
        node_dict = {
            node: Node(node.tensor,
                       name=node.name,
                       axis_names=node.axis_names,
                       backend=node.backend.name)
            for node in nodes
        }
    edge_dict = {}
    for edge in get_all_edges(nodes):
        node1 = edge.node1
        axis1 = edge.node1.get_axis_number(edge.axis1)

        if not edge.is_dangling():
            node2 = edge.node2
            axis2 = edge.node2.get_axis_number(edge.axis2)
            new_edge = Edge(node_dict[node1], axis1, edge.name,
                            node_dict[node2], axis2)
            new_edge.set_signature(edge.signature)
        else:
            new_edge = Edge(node_dict[node1], axis1, edge.name)

        node_dict[node1].add_edge(new_edge, axis1)
        if not edge.is_dangling():
            node_dict[node2].add_edge(new_edge, axis2)
        edge_dict[edge] = new_edge
    return node_dict, edge_dict
Exemple #5
0
def copy(nodes: Iterable[AbstractNode],
         conjugate: bool = False) -> Tuple[dict, dict]:
    """Copy the given nodes and their edges.

  This will return a tuple linking original nodes/edges to their copies.
  If nodes A and B are connected but only A is passed in to be
  copied, the edge between them will become a dangling edge.

  Args:
    nodes: An Iterable (Usually a `list` or `set`) of `nodes`.
    conjugate: Boolean. Whether to conjugate all of the nodes
      (useful for calculating norms and reduced density matrices).

  Returns:
    A tuple containing:
      node_dict:
        A dictionary mapping the nodes to their copies.
      edge_dict:
        A dictionary mapping the edges to their copies.
  """
    node_dict = {}
    for node in nodes:
        node_dict[node] = node.copy(conjugate)
    edge_dict = {}
    for edge in get_all_edges(nodes):
        node1 = edge.node1
        axis1 = edge.node1.get_axis_number(edge.axis1)
        # edge dangling or node2 does not need to be copied
        if edge.is_dangling() or edge.node2 not in node_dict:
            new_edge = Edge(node_dict[node1], axis1, edge.name)
            node_dict[node1].add_edge(new_edge, axis1)
            edge_dict[edge] = new_edge
            continue

        node2 = edge.node2
        axis2 = edge.node2.get_axis_number(edge.axis2)
        # copy node2 but not node1
        if node1 not in node_dict:
            new_edge = Edge(node_dict[node2], axis2, edge.name)
            node_dict[node2].add_edge(new_edge, axis2)
            edge_dict[edge] = new_edge
            continue

        # both nodes should be copied
        new_edge = Edge(node_dict[node1], axis1, edge.name, node_dict[node2],
                        axis2)
        if not edge.is_trace():
            node_dict[node2].add_edge(new_edge, axis2)
            node_dict[node1].add_edge(new_edge, axis1)

        edge_dict[edge] = new_edge

    return node_dict, edge_dict
Exemple #6
0
def redirect_edge(edge: Edge, new_node: AbstractNode,
                  old_node: AbstractNode) -> None:
    """
  Redirect `edge` from `old_node` to `new_node`.
  Routine updates `new_node` and `old_node`.
  `edge` is added to `new_node`, `old_node` gets a
  new Edge instead of `edge`.

  Args:
    edge: An Edge.
    new_node: The new `Node` object.
    old_node: The old `Node` object.

  Returns:
    None

  Raises:
    ValueError: if `edge` does not point to `old_node`.
  """
    if not edge.is_trace():
        if edge.is_dangling():
            if edge.node1 is not old_node:
                raise ValueError(f"edge {edge} is not pointing "
                                 f"to old_node {old_node}")
            edge.node1 = new_node
            axis = edge.axis1
        else:
            if edge.node1 is old_node:
                edge.node1 = new_node
                axis = edge.axis1
            elif edge.node2 is old_node:
                edge.node2 = new_node
                axis = edge.axis2
            else:
                raise ValueError(f"edge {edge} is not pointing "
                                 f"to old_node {old_node}")
        new_node.add_edge(edge, axis, True)
        new_edge = Edge(old_node, axis)
        old_node.add_edge(new_edge, axis, True)
    else:
        if edge.node1 is not old_node:
            raise ValueError(f"edge {edge} is not pointing "
                             f"to old_node {old_node}")
        edge.node1 = new_node
        edge.node2 = new_node
        axis1 = edge.axis1
        axis2 = edge.axis2
        new_node.add_edge(edge, axis1, True)
        new_node.add_edge(edge, axis2, True)
        new_edge = Edge(old_node, axis1, None, old_node, axis2)
        old_node.add_edge(new_edge, axis1, True)
        old_node.add_edge(new_edge, axis2, True)
def fixture_double_node_edge(backend):
    tensor = np.ones((1, 2, 2))
    node1 = Node(tensor=tensor,
                 name="test_node1",
                 axis_names=["a", "b", "c"],
                 backend=backend)
    node2 = Node(tensor=tensor,
                 name="test_node2",
                 axis_names=["a", "b", "c"],
                 backend=backend)
    tn.connect(node1["b"], node2["b"])
    edge1 = Edge(name="edge", node1=node1, axis1=0)
    edge12 = Edge(name="edge", node1=node1, axis1=1, node2=node2, axis2=1)
    return DoubleNodeEdgeTensor(node1, node2, edge1, edge12, tensor)
def fixture_single_node_edge(backend):
    tensor = np.ones((1, 2, 2))
    node = Node(tensor=tensor,
                name="test_node",
                axis_names=["a", "b", "c"],
                backend=backend)
    edge = Edge(name="edge", node1=node, axis1=0)
    return SingleNodeEdgeTensor(node, edge, tensor)
def test_node_add_edge_raises_error_mismatch_rank(single_node_edge):
  node = single_node_edge.node
  edge = single_node_edge.edge
  with pytest.raises(ValueError):
    node.add_edge(edge, axis=-1)
  edge = Edge(name="edge", node1=node, axis1=0)
  with pytest.raises(ValueError):
    node.add_edge(edge, axis=3)
def fixture_single_node_edge(backend):
  net = tensornetwork.TensorNetwork(backend=backend)
  tensor = np.ones((1, 2, 2))
  tensor = net.backend.convert_to_tensor(tensor)
  node = Node(
      tensor=tensor, name="test_node", axis_names=["a", "b", "c"], network=net)
  edge = Edge(name="edge", node1=node, axis1=0)
  return SingleNodeEdgeTensor(node, edge, tensor)
def test_node_reorder_edges_raise_error_wrong_edges(single_node_edge):
  node = single_node_edge.node
  e0 = node[0]
  e1 = node[1]
  e2 = node[2]
  edge = Edge(name="edge", node1=node, axis1=0)
  with pytest.raises(ValueError) as e:
    node.reorder_edges([e0])
  assert "Missing edges that belong to node found:" in str(e.value)
  with pytest.raises(ValueError) as e:
    node.reorder_edges([e0, e1, e2, edge])
  assert "Additional edges that do not belong to node found:" in str(e.value)
Exemple #12
0
def nodes_from_json(
        json_str: str) -> Tuple[List[AbstractNode], Dict[str, Tuple[Edge]]]:
    """
  Create a tensor network from a JSON string representation of a tensor network.
  
  Args:
    json_str: A string representing a JSON serialized tensor network.
    
  Returns:
    A list of nodes making up the tensor network.
    A dictionary of {str -> (edge,)} bindings. All dictionary values are tuples
      of Edges.
    
  """
    network_dict = json.loads(json_str)
    nodes = []
    node_ids = {}
    edge_lookup = {}
    edge_binding = {}
    for n in network_dict['nodes']:
        node = Node.from_serial_dict(n['attributes'])
        nodes.append(node)
        node_ids[n['id']] = node
    for e in network_dict['edges']:
        e_nodes = [node_ids.get(n_id) for n_id in e['node_ids']]
        axes = e['attributes']['axes']
        edge = Edge(node1=e_nodes[0],
                    axis1=axes[0],
                    node2=e_nodes[1],
                    axis2=axes[1],
                    name=e['attributes']['name'])
        edge_lookup[e['id']] = edge
        for node, axis in zip(e_nodes, axes):
            if node is not None:
                node.add_edge(edge, axis, override=True)
    for k, v in network_dict.get('edge_binding', {}).items():
        for e_id in v:
            edge_binding[k] = edge_binding.get(k, ()) + (edge_lookup[e_id], )

    return nodes, edge_binding
Exemple #13
0
def copy(nodes: Iterable[BaseNode],
         conjugate: bool = False) -> Tuple[dict, dict]:
  """Copy the given nodes and their edges.

  This will return a dictionary linking original nodes/edges 
  to their copies. If nodes A and B are connected but only A is passed in to be
  copied, the edge between them will become a dangling edge.

  Args:
    nodes: An `Iterable` (Usually a `List` or `Set`) of `Nodes`.
    conjugate: Boolean. Whether to conjugate all of the nodes
        (useful for calculating norms and reduced density
        matrices).

  Returns:
    A tuple containing:
      node_dict: A dictionary mapping the nodes to their copies.
      edge_dict: A dictionary mapping the edges to their copies.
  """
  #TODO: add support for copying CopyTensor
  if conjugate:
    node_dict = {
        node: Node(
            node.backend.conj(node.tensor),
            name=node.name,
            axis_names=node.axis_names,
            backend=node.backend) for node in nodes
    }
  else:
    node_dict = {
        node: Node(
            node.tensor,
            name=node.name,
            axis_names=node.axis_names,
            backend=node.backend) for node in nodes
    }
  edge_dict = {}
  for edge in get_all_edges(nodes):
    node1 = edge.node1
    axis1 = edge.node1.get_axis_number(edge.axis1)
    # edge dangling or node2 does not need to be copied
    if edge.is_dangling() or edge.node2 not in node_dict:
      new_edge = Edge(node_dict[node1], axis1, edge.name)
      node_dict[node1].add_edge(new_edge, axis1)
      edge_dict[edge] = new_edge
      continue

    node2 = edge.node2
    axis2 = edge.node2.get_axis_number(edge.axis2)
    # copy node2 but not node1
    if node1 not in node_dict:
      new_edge = Edge(node_dict[node2], axis2, edge.name)
      node_dict[node2].add_edge(new_edge, axis2)
      edge_dict[edge] = new_edge
      continue

    # both nodes should be copied
    new_edge = Edge(node_dict[node1], axis1, edge.name, node_dict[node2], axis2)
    new_edge.set_signature(edge.signature)
    node_dict[node2].add_edge(new_edge, axis2)
    node_dict[node1].add_edge(new_edge, axis1)
    edge_dict[edge] = new_edge

  return node_dict, edge_dict
def test_edge_is_being_used_false(single_node_edge):
  node = single_node_edge.node
  edge2 = Edge(name="edge", node1=node, axis1=0)
  assert not edge2.is_being_used()
def test_edge_is_trace_true(single_node_edge):
  node = single_node_edge.node
  edge = Edge(name="edge", node1=node, axis1=1, node2=node, axis2=2)
  assert edge.is_trace()
def test_edge_name_throws_type_error(single_node_edge, name):
  with pytest.raises(TypeError):
    Edge(node1=single_node_edge.node, axis1=0, name=name)
def test_edge_signature_setter_disabled_throws_error(single_node_edge):
  edge = Edge(node1=single_node_edge.node, axis1=0)
  edge.is_disabled = True
  with pytest.raises(ValueError):
    edge.signature = "signature"
def test_edge_node1_throws_value_error(single_node_edge):
  edge = Edge(node1=single_node_edge.node, axis1=0, name="edge")
  edge._node1 = None
  err_msg = "node1 for edge 'edge' no longer exists."
  with pytest.raises(ValueError, match=err_msg):
    edge.node1
def test_edge_set_name_throws_type_error(single_node_edge, name):
  edge = Edge(node1=single_node_edge.node, axis1=0)
  with pytest.raises(TypeError):
    edge.set_name(name)