Beispiel #1
0
    def test_matching_bqm(self):
        bqm = dnx.matching_bqm(self.graph)

        # the ground states should be exactly the matchings of G
        sampleset = dimod.ExactSolver().sample(bqm)

        for sample, energy in sampleset.data(['sample', 'energy']):
            edges = [v for v, val in sample.items() if val > 0]
            self.assertEqual(nx.is_matching(self.graph, edges), energy == 0)
            self.assertTrue(energy == 0 or energy >= 1)

            # while we're at it, test deprecated is_matching
            with self.assertWarns(DeprecationWarning):
                self.assertEqual(nx.is_matching(self.graph, edges),
                                 dnx.is_matching(edges))
Beispiel #2
0
    def test__maximal_matching_qubo(self):

        G = nx.complete_graph(5)
        B = 1  # magnitude arg for _maximal_matching_qubo

        edge_mapping = {edge: idx for idx, edge in enumerate(G.edges())}
        edge_mapping.update({(e1, e0): idx
                             for (e0, e1), idx in edge_mapping.items()})
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Q = _maximal_matching_qubo(G, edge_mapping, magnitude=B)

        # now for each combination of edges, we check that if the combination
        # is a maximal matching, it has energy magnitude * |edges|
        ground_energy = -1. * B * len(G.edges())
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            if dnx.is_maximal_matching(G, potential_matching):
                self.assertEqual(qubo_energy(Q, sample), ground_energy)
            elif not dnx.is_matching(potential_matching):
                # for now we don't care about these, they should be covered by the _matching_qubo
                # part of the QUBO function
                pass
            else:
                en = qubo_energy(Q, sample)

                gap = en - ground_energy
                if gap < infeasible_gap:
                    infeasible_gap = gap

        self.assertLessEqual(B, infeasible_gap)

        #
        # Another graph, Chimera tile this time
        #

        G = dnx.chimera_graph(1, 2, 2)
        B = 1  # magnitude arg for _maximal_matching_qubo

        edge_mapping = {edge: idx for idx, edge in enumerate(G.edges())}
        edge_mapping.update({(e1, e0): idx
                             for (e0, e1), idx in edge_mapping.items()})
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Q = _maximal_matching_qubo(G, edge_mapping, magnitude=B)

        # now for each combination of edges, we check that if the combination
        # is a maximal matching, it has energy magnitude * |edges|
        ground_energy = -1. * B * len(G.edges())
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            if dnx.is_maximal_matching(G, potential_matching):
                # print potential_matching, qubo_energy(Q, sample)
                self.assertLess(abs(qubo_energy(Q, sample) - ground_energy),
                                10**-8)
            elif not dnx.is_matching(potential_matching):
                # for now we don't care about these, they should be covered by the _matching_qubo
                # part of the QUBO function
                pass
            else:
                en = qubo_energy(Q, sample)

                gap = en - ground_energy
                if gap < infeasible_gap:
                    infeasible_gap = gap

        self.assertLessEqual(B - infeasible_gap, 10**-8)
Beispiel #3
0
    def test_min_maximal_matching_bug1(self):
        G = nx.Graph()
        G.add_nodes_from(range(7))
        G.add_edges_from([(0, 2), (0, 3), (0, 5), (0, 6), (1, 5), (2, 3),
                          (2, 4), (2, 5), (3, 4), (4, 6), (5, 6)])

        delta = max(G.degree(node) for node in G)  # maximum degree
        A = 1  # magnitude arg for _matching_qubo
        B = .75 * A / (delta - 2.)  # magnitude arg for _maximal_matching_qubo
        C = .5 * B

        edge_mapping = _edge_mapping(G)
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Qmm = _maximal_matching_qubo(G, edge_mapping, magnitude=B)
        Qm = _matching_qubo(G, edge_mapping, magnitude=A)
        Qmmm = {(v, v): C for v in edge_mapping.values()}
        Q = Qmm.copy()
        for edge, bias in Qm.items():
            Q[edge] += bias
        for edge, bias in Qmmm.items():
            Q[edge] += bias

        # now for each combination of edges, we check that if the combination
        # is a maximal matching, and if so that is has ground energy, else
        # there is an infeasible gap
        ground_energy = -1. * B * len(G.edges())  # from maximal matching
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            en_matching = qubo_energy(Qm, sample)
            en_maximal = qubo_energy(Qmm, sample)
            en_minimal = qubo_energy(Qmmm, sample)

            en = qubo_energy(Q, sample)

            self.assertLess(abs(en_matching + en_maximal + en_minimal - en),
                            10**-8)

            if dnx.is_maximal_matching(G, potential_matching):
                # if the sample is a maximal matching, then let's check each qubo
                # and combined together
                self.assertEqual(en_matching, 0.0)  # matching
                self.assertLess(abs(en_maximal - ground_energy), 10**-8)

            elif dnx.is_matching(potential_matching):
                # in this case we expect the energy contribution of Qm to be 0
                self.assertEqual(en_matching, 0.0)  # matching

                # but there should be a gap to Qmm, because the matching is not maximal
                self.assertGreater(en_maximal, ground_energy)

                gap = en_matching + en_maximal + en_minimal - ground_energy
                if gap < infeasible_gap:
                    infeasible_gap = gap
            else:
                # ok, these are not even matching
                self.assertGreater(en_matching,
                                   0)  # so matching energy should be > 0

                self.assertGreater(gap, 0)

                gap = en_matching + en_maximal + en_minimal - ground_energy
                if gap < infeasible_gap:
                    infeasible_gap = gap

        self.assertGreater(infeasible_gap, 0)

        # finally let's test it using the function
        matching = dnx.min_maximal_matching(G, ExactSolver())
        self.assertTrue(dnx.is_maximal_matching(G, matching))
Beispiel #4
0
    def test_maximal_matching_combined_qubo_bug1(self):

        # a graph that was not working
        G = nx.Graph()
        G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7])
        G.add_edges_from([(0, 1), (0, 3), (1, 3), (1, 4), (1, 6), (1, 7),
                          (2, 3), (2, 5), (2, 7), (3, 5), (3, 6), (4, 5),
                          (4, 6), (4, 7), (5, 7)])
        delta = max(G.degree(node) for node in G)  # maximum degree
        A = 1  # magnitude arg for _matching_qubo
        B = .95 * A / (delta - 2.)  # magnitude arg for _maximal_matching_qubo

        edge_mapping = _edge_mapping(G)
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Qmm = _maximal_matching_qubo(G, edge_mapping,
                                     magnitude=B)  # Q is a defaultdict
        Qm = _matching_qubo(G, edge_mapping, magnitude=A)
        Q = Qmm.copy()
        for edge, bias in Qm.items():
            Q[edge] += bias
        Q = dict(
            Q
        )  # we are not necessarily sure that the given sampler can handle a defaultdict
        Qmm = dict(Qmm)

        # now for each combination of edges, we check that if the combination
        # is a maximal matching, and if so that is has ground energy, else
        # there is an infeasible gap
        ground_energy = -1. * B * len(G.edges())  # from maximal matching
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            en_matching = qubo_energy(Qm, sample)
            en_maximal = qubo_energy(Qmm, sample)
            en = qubo_energy(Q, sample)

            self.assertLess(abs(en_matching + en_maximal - en), 10**-8)

            if dnx.is_maximal_matching(G, potential_matching):
                # if the sample is a maximal matching, then let's check each qubo
                # and combined together
                self.assertEqual(en_matching, 0.0)  # matching
                self.assertLess(abs(en_maximal - ground_energy), 10**-8)

            elif dnx.is_matching(potential_matching):
                # in this case we expect the energy contribution of Qm to be 0
                self.assertEqual(en_matching, 0.0)  # matching

                # but there should be a gap to Qmm, because the matching is not maximal
                self.assertGreater(en_maximal, ground_energy)

                gap = en_matching + en_maximal - ground_energy
                if gap < infeasible_gap:
                    infeasible_gap = gap
            else:
                # ok, these are not even matching
                self.assertGreater(en_matching,
                                   0)  # so matching energy should be > 0

                self.assertGreater(gap, 0)

                gap = en_matching + en_maximal - ground_energy
                if gap < infeasible_gap:
                    infeasible_gap = gap

        self.assertGreater(infeasible_gap, 0)
Beispiel #5
0
    def test__matching_qubo(self):
        # _matching_qubo creates a qubo that gives a matching for the given graph.
        # let's check that the solutions are all matchings

        G = nx.complete_graph(5)
        MAG = .75  # magnitude arg for _matching_qubo

        edge_mapping = {edge: idx for idx, edge in enumerate(G.edges())}
        edge_mapping.update({(e1, e0): idx
                             for (e0, e1), idx in edge_mapping.items()})
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Q = _matching_qubo(G, edge_mapping, magnitude=MAG)

        # now for each combination of ege, we check that if the combination
        # is a matching, it has qubo_energy 0, otherwise greater than 0. Which
        # is the desired behaviour
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            if dnx.is_matching(potential_matching):
                self.assertEqual(qubo_energy(Q, sample), 0.)
            else:
                en = qubo_energy(Q, sample)
                if en < infeasible_gap:
                    infeasible_gap = en
                self.assertGreaterEqual(en, MAG)

        self.assertEqual(MAG, infeasible_gap)

        #
        # Another graph, Chimera tile this time
        #

        G = dnx.chimera_graph(1, 1, 4)
        MAG = .67

        edge_mapping = {edge: idx for idx, edge in enumerate(G.edges())}
        edge_mapping.update({(e1, e0): idx
                             for (e0, e1), idx in edge_mapping.items()})
        inv_edge_mapping = {idx: edge for edge, idx in edge_mapping.items()}

        Q = _matching_qubo(G, edge_mapping, magnitude=MAG)

        # now for each combination of ege, we check that if the combination
        # is a matching, it has qubo_energy 0, otherwise greater than 0. Which
        # is the desired behaviour
        infeasible_gap = float('inf')
        for edge_vars in powerset(set(edge_mapping.values())):

            # get the matching from the variables
            potential_matching = {inv_edge_mapping[v] for v in edge_vars}

            # get the sample from the edge_vars
            sample = {v: 0 for v in edge_mapping.values()}
            for v in edge_vars:
                sample[v] = 1

            if dnx.is_matching(potential_matching):
                self.assertEqual(qubo_energy(Q, sample), 0.)
            else:
                en = qubo_energy(Q, sample)
                if en < infeasible_gap:
                    infeasible_gap = en
                self.assertGreaterEqual(en, MAG)

        self.assertEqual(MAG, infeasible_gap)