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
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
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