def test_large(self): # submit large CQMs of binary, spin, integer and mixed num_variables = 5000 objectives = dict() objectives['binary'] = dimod.BQM(num_variables, 'BINARY') objectives['spin'] = dimod.BQM(num_variables, 'SPIN') objectives['integer'] = integer = dimod.QM() integer.add_variables_from('INTEGER', range(num_variables)) objectives['mixed'] = mixed = dimod.QM() mixed.add_variables_from('INTEGER', range(num_variables // 3)) mixed.add_variables_from( 'SPIN', range(mixed.num_variables, mixed.num_variables + (num_variables // 3))) mixed.add_variables_from('BINARY', range(mixed.num_variables, num_variables)) for vartype, model in objectives.items(): with self.subTest(f"one constraint, vartype={vartype}"): cqm = dimod.ConstrainedQuadraticModel() cqm.set_objective(model) cqm.add_constraint(model, rhs=1, sense='==') sampleset = sampler.sample_cqm(cqm) self.assertConsistent(cqm, sampleset) with self.subTest(f"no constraints, vartype={vartype}"): cqm = dimod.ConstrainedQuadraticModel() cqm.set_objective(model) sampleset = sampler.sample_cqm(cqm) self.assertConsistent(cqm, sampleset)
def test_small(self): # submit 3-variable CQMs of binary, spin, integer and mixed objectives = dict() objectives['binary'] = dimod.BQM({'a': 1, 'b': 1, 'c': 1}, {}, 0, 'BINARY') objectives['spin'] = dimod.BQM({'a': 1, 'b': 1, 'c': 1}, {}, 0, 'SPIN') objectives['integer'] = integer = dimod.QM() integer.add_variables_from('INTEGER', 'abc') objectives['mixed'] = mixed = dimod.QM() mixed.add_variable('BINARY', 'a') mixed.add_variable('SPIN', 'b') mixed.add_variable('INTEGER', 'c') for vartype, model in objectives.items(): with self.subTest(f"one constraint, vartype={vartype}"): cqm = dimod.ConstrainedQuadraticModel() cqm.set_objective(model) cqm.add_constraint(model, rhs=1, sense='==') sampleset = sampler.sample_cqm(cqm) self.assertConsistent(cqm, sampleset) with self.subTest(f"no constraints, vartype={vartype}"): cqm = dimod.ConstrainedQuadraticModel() cqm.set_objective(model) sampleset = sampler.sample_cqm(cqm) self.assertConsistent(cqm, sampleset)
def test_several_terms(self): poly = {(0, 1, 2): -1, (1, 2, 3): 1, (0, 2, 3): .5, (0,): .4, (): .5} cqm = make_quadratic_cqm(poly, dimod.SPIN, cqm=dimod.ConstrainedQuadraticModel()) variables = set().union(*poly) aux_variables = tuple(set(cqm.variables) - variables) variables = tuple(variables) self.assertTrue(aux_variables) for config in itertools.product((-1, 1), repeat=len(variables)): sample = dict(zip(variables, config)) energy = poly_energy(sample, poly) reduced_energies = [] for aux_config in itertools.product((-1, 1), repeat=len(aux_variables)): aux_sample = dict(zip(aux_variables, aux_config)) aux_sample.update(sample) if cqm.check_feasible(aux_sample): reduced_energies.append(cqm.objective.energy(aux_sample)) self.assertAlmostEqual(energy, min(reduced_energies))
def test_quad_to_linear(self): J = {(0, 1): -1, (0, 1, 2): 1, (0, 1, 3): 1} h = {} off = .5 poly = J.copy() poly.update({(v,): bias for v, bias in h.items()}) poly[()] = off cqm0 = dimod.ConstrainedQuadraticModel() cqm0.set_objective(dimod.BinaryQuadraticModel.from_ising(h, {}, off)) cqm = make_quadratic_cqm(J, dimod.SPIN, cqm=cqm0) variables = set(h).union(*J) aux_variables = tuple(set(cqm.variables) - variables) variables = tuple(variables) self.assertTrue(aux_variables) for config in itertools.product((-1, 1), repeat=len(variables)): sample = dict(zip(variables, config)) energy = poly_energy(sample, poly) reduced_energies = [] for aux_config in itertools.product((-1, 1), repeat=len(aux_variables)): aux_sample = dict(zip(aux_variables, aux_config)) aux_sample.update(sample) if cqm.check_feasible(aux_sample): reduced_energies.append(cqm.objective.energy(aux_sample)) self.assertAlmostEqual(energy, min(reduced_energies))
def test_sample_CONSTRAINED_MIXED(self): # Using various Vartypes, including the `add_discrete` method cqm = dimod.ConstrainedQuadraticModel() x = {(u, v): dimod.Binary((u, v)) for u, v in product(['u1', 'u2'], range(3))} cqm.add_discrete([('u1', v) for v in range(3)], label='u1') cqm.add_discrete([('u2', v) for v in range(3)], label='u2') y, z = dimod.Spin('y'), dimod.Integer('z', lower_bound=1, upper_bound=3) obj1 = x[('u1', 0)] * y - x[('u2', 1)] * y obj2 = x[('u1', 0)] * z + 2 * x[('u1', 2)] * x[('u2', 2)] cqm.set_objective(obj1 + obj2) cqm.add_constraint(z == 2) response = dimod.ExactCQMSolver().sample_cqm(cqm) # every possible combination should be present, respecting the discrete constraints self.assertEqual(len(response), 54) self.assertEqual(response.record.sample.shape, (54, len(cqm.variables))) # only 18 samples should be feasible feasible_responses = response.filter(lambda d: d.is_feasible) self.assertEqual(len(feasible_responses), 18) dimod.testing.assert_sampleset_energies_cqm(response, cqm)
def test_linear_constraints(self): num_constraints = 100000 x = dimod.Binary('x') cqm = dimod.ConstrainedQuadraticModel() for _ in range(num_constraints): cqm.add_constraint(x == 1) sampler.sample_cqm(cqm).resolve() # smoke test
def test_kwargs(self): bqm = dimod.BinaryQuadraticModel({}, {}, 0.0, dimod.SPIN) with self.assertWarns(SamplerUnknownArgWarning): sampleset = dimod.ExactSolver().sample(bqm, a=1, b="abc") dqm = dimod.DiscreteQuadraticModel() with self.assertWarns(SamplerUnknownArgWarning): sampleset = dimod.ExactDQMSolver().sample_dqm(dqm, a=1, b="abc") cqm = dimod.ConstrainedQuadraticModel() with self.assertWarns(SamplerUnknownArgWarning): sampleset = dimod.ExactCQMSolver().sample_cqm(cqm, a=1, b="abc")
def test_sample_CONSTRAINED_SPIN(self): # using Spin variables, with inequality constraint: cqm = dimod.ConstrainedQuadraticModel() x, y, z = dimod.Spin('x'), dimod.Spin('y'), dimod.Spin('z') cqm.set_objective(x * y + 2 * y * z) cqm.add_constraint(x * y <= 0) response = dimod.ExactCQMSolver().sample_cqm(cqm) # every possible combination should be present self.assertEqual(len(response), 8) self.assertEqual(response.record.sample.shape, (8, len(cqm.variables))) # four samples should be feasible feasible_responses = response.filter(lambda d: d.is_feasible) self.assertEqual(len(feasible_responses), 4) dimod.testing.assert_sampleset_energies_cqm(response, cqm)
def test_sample_CONSTRAINED_INTEGER(self): # using Integer variables, with inequality constraint: cqm = dimod.ConstrainedQuadraticModel() x, y, z = dimod.Integer( 'x', lower_bound=1, upper_bound=3), dimod.Integer( 'y', lower_bound=4, upper_bound=5), dimod.Integer('z', lower_bound=-2, upper_bound=1) cqm.set_objective(x * y + 2 * y * z) cqm.add_constraint(x * z >= 1) response = dimod.ExactCQMSolver().sample_cqm(cqm) # every possible combination should be present self.assertEqual(len(response), 24) self.assertEqual(response.record.sample.shape, (24, len(cqm.variables))) # only six samples should be feasible feasible_responses = response.filter(lambda d: d.is_feasible) self.assertEqual(len(feasible_responses), 6) dimod.testing.assert_sampleset_energies_cqm(response, cqm)
def test_empty(self): cqm = make_quadratic_cqm({}, dimod.SPIN) self.assertTrue(cqm.is_almost_equal(dimod.ConstrainedQuadraticModel()))
def graph_partition_cqm(G, num_partitions): """Find a constrained quadratic model for the graph's partitions. Defines an CQM with ground states corresponding to a balanced k-partition of G and uses the sampler to sample from it. A k-partition is a collection of k subsets of the vertices of G such that each vertex is in exactly one subset, and the number of edges between vertices in different subsets is as small as possible. If G is a weighted graph, the sum of weights over those edges are minimized. Parameters ---------- G : NetworkX graph The graph to partition. num_partitions : int The number of subsets in the desired partition. Returns ------- cqm : :class:`dimod.ConstrainedQuadraticModel` A constrained quadratic model with ground states corresponding to a partition problem. The nodes of `G` are discrete logical variables of the CQM, where the cases are the different partitions the node can be assigned to. The objective is given as the number of edges connecting nodes in different partitions. """ partition_size = G.number_of_nodes() / num_partitions partitions = range(num_partitions) cqm = dimod.ConstrainedQuadraticModel() # Variables will be added using the discrete method in CQM x = {vk: dimod.Binary(vk) for vk in itertools.product(G.nodes, partitions)} for v in G.nodes: cqm.add_discrete(((v, k) for k in partitions), label=v) if not math.isclose(partition_size, int(partition_size)): # if number of nodes don't divide into num_partitions, # accept partitions of size ceil() or floor() floor, ceil = int(partition_size), int(partition_size + 1) for k in partitions: cqm.add_constraint(dimod.quicksum( (x[u, k] for u in G.nodes)) >= floor, label='equal_partition_low_%s' % k) cqm.add_constraint(dimod.quicksum( (x[u, k] for u in G.nodes)) <= ceil, label='equal_partition_high_%s' % k) else: # each partition must have partition_size elements for k in partitions: cqm.add_constraint(dimod.quicksum( (x[u, k] for u in G.nodes)) == int(partition_size), label='equal_partition_%s' % k) cuts = 0 for (u, v, d) in G.edges(data=True): for k in partitions: w = d.get('weight', 1) cuts += w * x[u, k] * x[v, k] if cuts: cqm.set_objective(-cuts) return cqm
def test_sample_CONSTRAINED_empty(self): cqm = dimod.ConstrainedQuadraticModel() response = dimod.ExactCQMSolver().sample_cqm(cqm) self.assertEqual(response.record.sample.shape, (0, 0))