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