Example #1
0
def _inner_out_flow_constraint_hamiltonian(graph: nx.DiGraph,
                                           node) -> Hamiltonian:
    r"""Calculates the inner portion of the Hamiltonian in :func:`out_flow_constraint`.
    For a given :math:`i`, this function returns:

    .. math::

        d_{i}^{out}(d_{i}^{out} - 2)\mathbb{I}
        - 2(d_{i}^{out}-1)\sum_{j,(i,j)\in E}\hat{Z}_{ij} +
        ( \sum_{j,(i,j)\in E}\hat{Z}_{ij} )^{2}

    Args:
        graph (nx.DiGraph): the directed graph specifying possible edges
        node: a fixed node

    Returns:
        qml.Hamiltonian: The inner part of the out-flow constraint Hamiltonian.
    """
    coeffs = []
    ops = []

    edges_to_qubits = edges_to_wires(graph)
    out_edges = graph.out_edges(node)
    d = len(out_edges)

    for edge in out_edges:
        wire = (edges_to_qubits[edge], )
        coeffs.append(1)
        ops.append(qml.PauliZ(wire))

    coeffs, ops = _square_hamiltonian_terms(coeffs, ops)

    for edge in out_edges:
        wire = (edges_to_qubits[edge], )
        coeffs.append(-2 * (d - 1))
        ops.append(qml.PauliZ(wire))

    coeffs.append(d * (d - 2))
    ops.append(qml.Identity(0))

    H = Hamiltonian(coeffs, ops)
    H.simplify()
    # store the valuable information that all observables are in one commuting group
    H.grouping_indices = [list(range(len(H.ops)))]

    return H
Example #2
0
def _inner_net_flow_constraint_hamiltonian(graph: nx.DiGraph,
                                           node) -> Hamiltonian:
    r"""Calculates the squared inner portion of the Hamiltonian in :func:`net_flow_constraint`.


    For a given :math:`i`, this function returns:

    .. math::

        \left((d_{i}^{\rm out} - d_{i}^{\rm in})\mathbb{I} -
        \sum_{j, (i, j) \in E} Z_{ij} + \sum_{j, (j, i) \in E} Z_{ji} \right)^{2}.

    Args:
        graph (nx.DiGraph): the directed graph specifying possible edges
        node: a fixed node

    Returns:
        qml.Hamiltonian: The inner part of the net-flow constraint Hamiltonian.
    """
    edges_to_qubits = edges_to_wires(graph)

    coeffs = []
    ops = []

    out_edges = graph.out_edges(node)
    in_edges = graph.in_edges(node)

    coeffs.append(len(out_edges) - len(in_edges))
    ops.append(qml.Identity(0))

    for edge in out_edges:
        wires = (edges_to_qubits[edge], )
        coeffs.append(-1)
        ops.append(qml.PauliZ(wires))

    for edge in in_edges:
        wires = (edges_to_qubits[edge], )
        coeffs.append(1)
        ops.append(qml.PauliZ(wires))

    coeffs, ops = _square_hamiltonian_terms(coeffs, ops)
    H = Hamiltonian(coeffs, ops)
    H.simplify()
    # store the valuable information that all observables are in one commuting group
    H.grouping_indices = [list(range(len(H.ops)))]
    return H
Example #3
0
def _inner_net_flow_constraint_hamiltonian(graph: Union[nx.DiGraph,
                                                        rx.PyDiGraph],
                                           node: int) -> Hamiltonian:
    r"""Calculates the squared inner portion of the Hamiltonian in :func:`net_flow_constraint`.


    For a given :math:`i`, this function returns:

    .. math::

        \left((d_{i}^{\rm out} - d_{i}^{\rm in})\mathbb{I} -
        \sum_{j, (i, j) \in E} Z_{ij} + \sum_{j, (j, i) \in E} Z_{ji} \right)^{2}.

    Args:
        graph (nx.DiGraph or rx.PyDiGraph): the directed graph specifying possible edges
        node: a fixed node

    Returns:
        qml.Hamiltonian: The inner part of the net-flow constraint Hamiltonian.
    """
    if not isinstance(graph, (nx.DiGraph, rx.PyDiGraph)):
        raise ValueError(
            f"Input graph must be a nx.DiGraph or rx.PyDiGraph, got {type(graph).__name__}"
        )

    edges_to_qubits = edges_to_wires(graph)

    coeffs = []
    ops = []

    is_rx = isinstance(graph, rx.PyDiGraph)

    out_edges = graph.out_edges(node)
    in_edges = graph.in_edges(node)

    # To ensure out_edges and in_edges methods in both RX and NX return
    # the lists of edges in the same order, we sort results.
    if is_rx:
        out_edges = sorted(out_edges)
        in_edges = sorted(in_edges)

    # In RX each node is assigned to an integer index starting from 0;
    # thus, we use the following lambda function to get node-values.
    get_nvalues = lambda T: (graph.nodes().index(T[0]), graph.nodes().index(T[
        1])) if is_rx else T

    coeffs.append(len(out_edges) - len(in_edges))
    ops.append(qml.Identity(0))

    for edge in out_edges:
        if len(edge) > 2:
            edge = tuple(edge[:2])
        wires = (edges_to_qubits[get_nvalues(edge)], )
        coeffs.append(-1)
        ops.append(qml.PauliZ(wires))

    for edge in in_edges:
        if len(edge) > 2:
            edge = tuple(edge[:2])
        wires = (edges_to_qubits[get_nvalues(edge)], )
        coeffs.append(1)
        ops.append(qml.PauliZ(wires))

    coeffs, ops = _square_hamiltonian_terms(coeffs, ops)
    H = Hamiltonian(coeffs, ops)
    H.simplify()
    # store the valuable information that all observables are in one commuting group
    H.grouping_indices = [list(range(len(H.ops)))]
    return H