def test_clique(self): N = 5 graph = retworkx.PyGraph() graph.extend_from_edge_list([(i, j) for i in range(N) for j in range(N) if i < j]) complement_graph = retworkx.complement(graph) self.assertEqual(graph.nodes(), complement_graph.nodes()) self.assertEqual(0, len(complement_graph.edges()))
def test_multigraph(self): graph = retworkx.PyGraph(multigraph=True) graph.extend_from_edge_list([(0, 0), (0, 1), (1, 1), (2, 2), (1, 0)]) expected_graph = retworkx.PyGraph(multigraph=True) expected_graph.extend_from_edge_list([(0, 2), (1, 2)]) complement_graph = retworkx.complement(graph) self.assertTrue( retworkx.is_isomorphic( expected_graph, complement_graph, ))
def test_empty(self): N = 5 graph = retworkx.PyGraph() graph.add_nodes_from([i for i in range(N)]) expected_graph = retworkx.PyGraph() expected_graph.extend_from_edge_list([(i, j) for i in range(N) for j in range(N) if i < j]) complement_graph = retworkx.complement(graph) self.assertTrue( retworkx.is_isomorphic( expected_graph, complement_graph, ))
def test_complement(self): N = 8 graph = retworkx.PyGraph() graph.extend_from_edge_list([(j, i) for i in range(N) for j in range(N) if i < j and (i + j) % 3 == 0]) expected_graph = retworkx.PyGraph() expected_graph.extend_from_edge_list([(i, j) for i in range(N) for j in range(N) if i < j and (i + j) % 3 != 0]) complement_graph = retworkx.complement(graph) self.assertTrue( retworkx.is_isomorphic( expected_graph, complement_graph, ))
def test_null_graph(self): graph = retworkx.PyGraph() complement_graph = retworkx.complement(graph) self.assertEqual(0, len(complement_graph.nodes())) self.assertEqual(0, len(complement_graph.edges()))
def max_clique(graph: Union[nx.Graph, rx.PyGraph], constrained: bool = True): r"""Returns the QAOA cost Hamiltonian and the recommended mixer corresponding to the Maximum Clique problem, for a given graph. The goal of Maximum Clique is to find the largest `clique <https://en.wikipedia.org/wiki/Clique_(graph_theory)>`__ of a graph --- the largest subgraph such that all vertices are connected by an edge. Args: graph (nx.Graph or rx.PyGraph): a graph whose edges define the pairs of vertices on which each term of the Hamiltonian acts constrained (bool): specifies the variant of QAOA that is performed (constrained or unconstrained) Returns: (.Hamiltonian, .Hamiltonian): The cost and mixer Hamiltonians .. UsageDetails:: There are two variations of QAOA for this problem, constrained and unconstrained: **Constrained** .. note:: This method of constrained QAOA was introduced by Hadfield, Wang, Gorman, Rieffel, Venturelli, and Biswas in arXiv:1709.03489. The Maximum Clique cost Hamiltonian for constrained QAOA is defined as: .. math:: H_C \ = \ \displaystyle\sum_{v \in V(G)} Z_{v}, where :math:`V(G)` is the set of vertices of the input graph, and :math:`Z_i` is the Pauli-Z operator applied to the :math:`i`-th vertex. The returned mixer Hamiltonian is :func:`~qaoa.bit_flip_mixer` applied to :math:`\bar{G}`, the complement of the graph. .. note:: **Recommended initialization circuit:** Each wire in the :math:`|0\rangle` state. **Unconstrained** The Maximum Clique cost Hamiltonian for unconstrained QAOA is defined as: .. math:: H_C \ = \ 3 \sum_{(i, j) \in E(\bar{G})} (Z_i Z_j \ - \ Z_i \ - \ Z_j) \ + \ \displaystyle\sum_{i \in V(G)} Z_i where :math:`V(G)` is the set of vertices of the input graph :math:`G`, :math:`E(\bar{G})` is the set of edges of the complement of :math:`G`, and :math:`Z_i` is the Pauli-Z operator applied to the :math:`i`-th vertex. The returned mixer Hamiltonian is :func:`~qaoa.x_mixer` applied to all wires. .. note:: **Recommended initialization circuit:** Even superposition over all basis states. """ if not isinstance(graph, (nx.Graph, rx.PyGraph)): raise ValueError( f"Input graph must be a nx.Graph or rx.PyGraph, got {type(graph).__name__}" ) graph_nodes = graph.nodes() graph_complement = (rx.complement(graph) if isinstance(graph, rx.PyGraph) else nx.complement(graph)) if constrained: cost_h = bit_driver(graph_nodes, 1) cost_h.grouping_indices = [list(range(len(cost_h.ops)))] return (cost_h, qaoa.bit_flip_mixer(graph_complement, 0)) cost_h = 3 * edge_driver(graph_complement, ["10", "01", "00"]) + bit_driver(graph_nodes, 1) mixer_h = qaoa.x_mixer(graph_nodes) # store the valuable information that all observables are in one commuting group cost_h.grouping_indices = [list(range(len(cost_h.ops)))] return (cost_h, mixer_h)