def cluster_points(scattered_points, filename): # Set up problem # Note: max_distance gets used in division later on. Hence, the max(.., 1) # is used to prevent a division by zero coordinates = [Coordinate(x, y) for x, y in scattered_points] max_distance = max(get_max_distance(coordinates), 1) # Build constraints csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) # Apply constraint: coordinate can only be in one colour group choose_one_group = {(0, 0, 1), (0, 1, 0), (1, 0, 0)} for coord in coordinates: csp.add_constraint(choose_one_group, (coord.r, coord.g, coord.b)) # Build initial BQM bqm = dwavebinarycsp.stitch(csp) # Edit BQM to bias for close together points to share the same color for i, coord0 in enumerate(coordinates[:-1]): for coord1 in coordinates[i + 1:]: # Set up weight d = get_distance(coord0, coord1) / max_distance # rescale distance weight = -math.cos(d * math.pi) # Apply weights to BQM bqm.add_interaction(coord0.r, coord1.r, weight) bqm.add_interaction(coord0.g, coord1.g, weight) bqm.add_interaction(coord0.b, coord1.b, weight) # Edit BQM to bias for far away points to have different colors for i, coord0 in enumerate(coordinates[:-1]): for coord1 in coordinates[i + 1:]: # Set up weight # Note: rescaled and applied square root so that far off distances # are all weighted approximately the same d = math.sqrt(get_distance(coord0, coord1) / max_distance) weight = -math.tanh(d) * 0.1 # Apply weights to BQM bqm.add_interaction(coord0.r, coord1.b, weight) bqm.add_interaction(coord0.r, coord1.g, weight) bqm.add_interaction(coord0.b, coord1.r, weight) bqm.add_interaction(coord0.b, coord1.g, weight) bqm.add_interaction(coord0.g, coord1.r, weight) bqm.add_interaction(coord0.g, coord1.b, weight) # Submit problem to D-Wave sampler sampler = EmbeddingComposite(DWaveSampler(solver={'qpu': True})) #sampler = neal.SimulatedAnnealingSampler() sampleset = sampler.sample(bqm, chain_strength=4, num_reads=1000) best_sample = sampleset.first.sample # Visualize graph problem dwave.inspector.show(bqm, sampleset) # Visualize solution groupings = get_groupings(best_sample) visualize_groupings(groupings, filename) return groupings
def test_sample_instantiation(self): # Check that values have not been instantiated sampler = LazyEmbeddingComposite(MockSampler()) self.assertIsNone(sampler.embedding) self.assertIsNone(sampler.nodelist) self.assertIsNone(sampler.edgelist) self.assertIsNone(sampler.adjacency) self.assertIsNone(sampler.parameters) self.assertIsNone(sampler.properties) # Set up BQM and sample csp = dbc.ConstraintSatisfactionProblem(dbc.BINARY) csp.add_constraint(and_gate(['a', 'b', 'c'])) bqm = dbc.stitch(csp) sampler.sample(bqm) # Check that values have been populated self.assertIsNotNone(sampler.embedding) self.assertEqual(sampler.nodelist, ['a', 'b', 'c']) self.assertEqual(sampler.edgelist, [('a', 'b'), ('a', 'c'), ('b', 'c')]) self.assertEqual(sampler.adjacency, { 'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'} }) self.assertIsNotNone(sampler.parameters) self.assertIsNotNone(sampler.properties)
def test_eight_variable_constraint_smoketest(self): csp = dwavebinarycsp.ConstraintSatisfactionProblem( dwavebinarycsp.BINARY) variables = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] # this is reducible but for our purposes here that's fine def f(a, b, c, d, e, f, g, h): if a and b: return False if c and d: return False if e and f: return False return not (g and h) csp.add_constraint(f, variables) bqm = dwavebinarycsp.stitch(csp) resp = dimod.ExactSolver().sample(bqm) ground_energy = min(resp.record['energy']) for sample, energy in resp.data(['sample', 'energy']): if energy == ground_energy: self.assertTrue(csp.check(sample)) else: if abs(energy - ground_energy) < 2: # if classical gap is less than 2 self.assertTrue(csp.check(sample))
def test_returned_gap_with_aux(self): """Verify that stitch is only allowing gaps that satisfy min_classical_gap to be returned. In this case, by allowing an auxiliary variable, the min_classical_gap should be achieved and stitch should allow a bqm to be returned. """ csp = dwavebinarycsp.ConstraintSatisfactionProblem("SPIN") csp.add_constraint(operator.eq, ['a', 'b']) min_classical_gap = 3 # No aux case: max_graph_size=2 # Note: Should not be possible to satisfy min_classical_gap with self.assertRaises(dwavebinarycsp.exceptions.ImpossibleBQM): dwavebinarycsp.stitch(csp, min_classical_gap=min_classical_gap, max_graph_size=2) # One aux case: max_graph_size=3 # Note: min_classical_gap should be satisfied when we have three nodes bqm = dwavebinarycsp.stitch(csp, min_classical_gap=min_classical_gap, max_graph_size=3) # Verify one aux case sampleset = dimod.ExactSolver().sample(bqm) energy_array = sampleset.record['energy'] gap = max(energy_array) - min(energy_array) self.assertGreaterEqual(gap, min_classical_gap)
def __init__(self, job_dict, max_time=None): """ Args: job_dict: A dictionary. It describes the jobs that need to be scheduled. Namely, the dict key is the name of the job and the dict value is the ordered list of tasks that the job must do. (See Job Dict Details below.) max_time: An integer. The upper bound on the amount of time the schedule can take. Job Dict Details: The job_dict has the following format: {"job_name": [(machine_name, integer_time_duration_on_machine), ..], .. "another_job_name": [(some_machine, integer_time_duration_on_machine), ..]} A small job_dict example: jobs = {"job_a": [("mach_1", 2), ("mach_2", 2), ("mach_3", 2)], "job_b": [("mach_3", 3), ("mach_2", 1), ("mach_1", 1)], "job_c": [("mach_2", 2), ("mach_1", 3), ("mach_2", 1)]} """ self.tasks = [] self.last_task_indices = [] self.max_time = max_time # will get decremented by 1 for zero-indexing; see _process_data self.csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) # Populates self.tasks and self.max_time self._process_data(job_dict)
def solve(self, checkDeadloack=True): csp = dwavebinarycsp.ConstraintSatisfactionProblem( dwavebinarycsp.BINARY) for i in range(self.N): c = self.chopsticks[i] next_c = self.chopsticks[(i + 1) % self.N] vars = [c + '_R', c + '_L'] if checkDeadloack: csp.add_constraint(exactly1, vars) else: csp.add_constraint(atMost1, vars) phils = [c + '_R', next_c + '_L'] if checkDeadloack: csp.add_constraint(exactly1, phils) bqm = dwavebinarycsp.stitch(csp) sampler = self.getSampler() try: start = time.time() response = sampler.sample(bqm, num_reads=50) end = time.time() t = end - start sample = next(response.samples()) if not csp.check(sample): print("Failed to detect deadlock") t = 0 else: if self.draw: self.drawConfig(sample) except: t = -1 return t
def generate_dwavecsp(self): ''' returns: a weighted constraint matrix generated by dwave's algorithm ''' csp = dwavebinarycsp.ConstraintSatisfactionProblem('BINARY') def Aix_1(*args): return sum(list(args)) == 1 for i in range(1, self.n + 1): args = [] for k in range(1, self.k + 1): var_index = idx.index_1_q_to_l_1(i, k, self.k) - 1 args.append(var_index) csp.add_constraint(Aix_1, args) def Aix_le_s(*args): return sum(list(args)) <= self.bunch_size for k in range(1, self.k + 1): args = [] for i in range(1, self.n + 1): var_index = idx.index_1_q_to_l_1(i, k, self.k) - 1 args.append(var_index) print("adding %d inequality" % k) csp.add_constraint(Aix_le_s, args) print("stitching...") bqm = dwavebinarycsp.stitch(csp, max_graph_size=24) mtx = bqm.to_numpy_matrix() print(mtx) return 0
def __init__(self, n_rows, n_cols, start, end, walls): assert isinstance( n_rows, int) and n_rows > 0, "'n_rows' is not a positive integer".format( n_rows) assert isinstance( n_cols, int) and n_cols > 0, "'n_cols' is not a positive integer".format( n_cols) assert start != end, "'start' cannot be the same as 'end'" # Check label format assert_label_format_valid(start) assert_label_format_valid(end) for wall in walls: assert_label_format_valid(wall) # Instantiate self.n_rows = n_rows self.n_cols = n_cols self.start = start self.end = end self.walls = walls self.csp = dwavebinarycsp.ConstraintSatisfactionProblem( dwavebinarycsp.BINARY)
def __init__(self, job_dict, max_time=None, remove_impossible_times=True): super().__init__(job_dict=job_dict, max_time=max_time, remove_impossible_times=remove_impossible_times) self.csp = dwavebinarycsp.ConstraintSatisfactionProblem( dwavebinarycsp.BINARY) self.add_constraints()
def test_stitch_max_graph_size_is_1(self): csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) csp.add_constraint(operator.eq, ['a', 'b']) csp.add_constraint(operator.ne, ['b', 'c']) with self.assertRaises(dwavebinarycsp.exceptions.ImpossibleBQM): bqm = dwavebinarycsp.stitch(csp, max_graph_size=1)
def test_stitch_2sat(self): csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.SPIN) for v in range(10): csp.add_constraint(operator.eq, [v, v + 1]) bqm = stitcher.stitch(csp) self.assertTrue(all(bias == -1 for bias in bqm.quadratic.values())) self.assertTrue(all(bias == 0 for bias in bqm.linear.values()))
def new(self='BINARY'): """Create an empty constraint satisfaction problem. Args: self(dimod.vartype): A string describing the variable type (either SPIN or BINARY) (default 'BINARY') Returns: dwavebinarycsp.ConstraintSatisfactionProblem: An empty constraint satisfaction problem.""" # Return an empty CSP. return __dbc__.ConstraintSatisfactionProblem(self)
def test_stitch_constraint_too_large(self): csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) def f(*args): return all(args) csp.add_constraint(f, list('abcdefghijk')) # 11 variables with self.assertRaises(dwavebinarycsp.exceptions.ImpossibleBQM): bqm = dwavebinarycsp.stitch(csp, max_graph_size=8)
def test_csp_one_xor_impossible(self): csp = dwavebinarycsp.ConstraintSatisfactionProblem( dwavebinarycsp.BINARY) variables = ['a', 'b', 'c'] xor = dwavebinarycsp.factories.constraint.gates.xor_gate(variables) csp.add_constraint(xor) with self.assertRaises(pm.ImpossiblePenaltyModel): bqm = dwavebinarycsp.stitch(csp, max_graph_size=3)
def construct_xor_problem(size): if size < 2: size = 2 xor_constraints = [ p for p in list(itertools.product([0, 1], repeat=size)) if (p.count(1) % 2 == 1) ] csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) csp.add_constraint( dwavebinarycsp.Constraint.from_configurations( xor_constraints, ['q{}'.format(i) for i in range(size)], dwavebinarycsp.BINARY, name='XOR')) return csp
def construct_xor_gates_problem(num_inputs): if num_inputs < 2: num_inputs = 2 csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) csp.add_constraint(gates.xor_gate(['q0', 'q1', 'out0'], name='XOR0')) for i in range(2, num_inputs): csp.add_constraint( gates.xor_gate([ 'q{}'.format(i), 'out{}'.format(i - 2), 'out{}'.format(i - 1) ], name='XOR{}'.format(i - 1))) csp.add_constraint( lambda x: x, ['out{}'.format(num_inputs - 2)]) # last output must be True return csp
def scheduling(time, location, length, mandatory): if time: # Business hours return (location and mandatory) # In office and mandatory participation else: # Outside business hours return ((not location) and length) # Teleconference for a short duration import dwavebinarycsp csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) csp.add_constraint(scheduling, ['time', 'location', 'length', 'mandatory']) bqm = dwavebinarycsp.stitch(csp) bqm.linear {'length': -2.0, 'location': 2.0, 'mandatory': 0.0, 'time': 2.0} bqm.quadratic {('location', 'length'): 2.0, ('mandatory', 'length'): 0.0, ('mandatory', 'location'): -2.0, ('time', 'length'): 0.0, ('time', 'location'): -4.0, ('time', 'mandatory'): 0.0} from dimod.reference.samplers import ExactSolver sampler = ExactSolver() solution = sampler.sample(bqm) min_energy = next(solution.data(['energy']))[0] print(min_energy) -2.0 for sample, energy in solution.data(['sample', 'energy']): if energy == min_energy: time = 'business hours' if sample['time'] else 'evenings' location = 'office' if sample['location'] else 'home' length = 'short' if sample['length'] else 'long' mandatory = 'mandatory' if sample['mandatory'] else 'optional' print("During {} at {}, you can schedule a {} meeting that is {}".format(time, location, length, mandatory)) if energy == min_energy: time = 'business hours' if sample['time'] else 'evenings' location = 'office' if sample['location'] else 'home' length = 'short' if sample['length'] else 'long' mandatory = 'mandatory' if sample['mandatory'] else 'optional' print("During {} at {}, you can schedule a {} meeting that is {}".format(time, location, length, mandatory))
def test_same_embedding(self): sampler = LazyEmbeddingComposite(MockSampler()) # Set up Ising and sample h = {'a': 1, 'b': 1, 'c': 1} J = {('a', 'b'): 3, ('b', 'c'): -2, ('a', 'c'): 1} sampler.sample_ising(h, J) # Store embedding prev_embedding = sampler.embedding # Check that the same embedding is used csp2 = dbc.ConstraintSatisfactionProblem(dbc.BINARY) csp2.add_constraint(or_gate(['a', 'b', 'c'])) bqm2 = dbc.stitch(csp2) sampler.sample(bqm2) self.assertEqual(sampler.embedding, prev_embedding)
def test_attempt_on_difficult_problem(self): # Set up xor-gate # Note: penaltymodel-lp would need an auxiliary variable in order to handle this; # however, no auxiliaries are provided, hence, it should pass the problem to another # penalty model. nodes = ['a', 'b', 'c'] xor_gate_values = {(-1, -1, -1), (-1, 1, 1), (1, -1, 1), (1, 1, -1)} # penaltymodel-lp should not be able to handle an xor-gate with self.assertRaises(ValueError): lp.generate_bqm(nx.complete_graph(nodes), xor_gate_values, nodes) # Check that penaltymodel-lp is able to pass the problem to another penaltymodel csp = dbc.ConstraintSatisfactionProblem(dbc.SPIN) csp.add_constraint(xor_gate_values, ('a', 'b', 'c')) bqm = dbc.stitch( csp) # BQM created by a penaltymodel that is not penaltymodel-lp self.assertGreaterEqual(len(bqm.linear) + len(bqm.quadratic), 1) # Check BQM exists
def test_csp_one_xor(self): csp = dwavebinarycsp.ConstraintSatisfactionProblem( dwavebinarycsp.BINARY) variables = ['a', 'b', 'c'] xor = dwavebinarycsp.factories.constraint.gates.xor_gate(variables) csp.add_constraint(xor) bqm = dwavebinarycsp.stitch(csp) resp = dimod.ExactSolver().sample(bqm) ground_energy = min(resp.record['energy']) for sample, energy in resp.data(['sample', 'energy']): if energy == ground_energy: self.assertTrue(csp.check(sample)) else: if abs(energy - ground_energy) < 2: # if classical gap is less than 2 self.assertTrue(csp.check(sample))
def test_returned_gap(self): """Verify that stitch is only allowing gaps that satisfy min_classical_gap to be returned. """ # Set up CSP csp = dwavebinarycsp.ConstraintSatisfactionProblem("SPIN") csp.add_constraint(operator.ne, ['a', 'b']) # Show that CSP has a valid BQM small_gap = 2 bqm = dwavebinarycsp.stitch(csp, min_classical_gap=small_gap, max_graph_size=2) # Verify the gap based on returned bqm sampleset = dimod.ExactSolver().sample(bqm) energy_array = sampleset.record['energy'] gap = max(energy_array) - min(energy_array) self.assertGreaterEqual(gap, small_gap) # Same CSP with a larger min_classical_gap # Note: Even though there is a BQM for this CSP (shown above), stitch should throw an # exception because the BQM does not satisfy the following min_classical_gap requirement. with self.assertRaises(dwavebinarycsp.exceptions.ImpossibleBQM): dwavebinarycsp.stitch(csp, min_classical_gap=4, max_graph_size=2)
from dwave.system import DWaveSampler, EmbeddingComposite import dwave.inspector from dwavebinarycsp.factories import or_gate, and_gate, xor_gate import dwavebinarycsp as dbc def full_adder(c, in_a, in_b, cin, id): c.add_constraint(xor_gate([in_a, in_b, id + "_sum0"])) c.add_constraint(and_gate([in_a, in_b, id + "_carry0"])) c.add_constraint(xor_gate([id + "_sum0", cin, "sum" + id])) c.add_constraint(and_gate([id + "_sum0", cin, id + "_carry1"])) c.add_constraint(or_gate([id + "_carry0", id + "_carry1", id + "_cout"])) return c csp = dbc.ConstraintSatisfactionProblem("BINARY") csp = full_adder(csp, "a1", "b1", "cin", "0") csp = full_adder(csp, "a2", "b2", "0_cout", "1") csp = full_adder(csp, "a3", "b3", "1_cout", "2") csp = full_adder(csp, "a4", "b4", "2_cout", "3") csp = full_adder(csp, "a5", "b5", "3_cout", "4") csp = full_adder(csp, "a6", "b6", "4_cout", "5") csp = full_adder(csp, "a7", "b7", "5_cout", "6") csp = full_adder(csp, "a8", "b8", "6_cout", "7") csp = full_adder(csp, "a9", "b9", "7_cout", "8") csp = full_adder(csp, "a10", "b10", "8_cout", "9") for i in range(0, 9): csp.fix_variable("sum" + str(i), 1)
def cluster_points(scattered_points, filename, architecture): # Set up problem # Note: max_distance gets used in division later on. Hence, the max(.., 1) # is used to prevent a division by zero coordinates = [Coordinate(x, y) for x, y in scattered_points] max_distance = max(get_max_distance(coordinates), 1) # Build constraints csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) # Apply constraint: coordinate can only be in one colour group choose_one_group = {(0, 0, 1), (0, 1, 0), (1, 0, 0)} for coord in coordinates: csp.add_constraint(choose_one_group, (coord.r, coord.g, coord.b)) # Build initial BQM bqm = dwavebinarycsp.stitch(csp) # Edit BQM to bias for close together points to share the same color for i, coord0 in enumerate(coordinates[:-1]): for coord1 in coordinates[i + 1:]: # Set up weight d = get_distance(coord0, coord1) / max_distance # rescale distance weight = -math.cos(d * math.pi) # Apply weights to BQM bqm.add_interaction(coord0.r, coord1.r, weight) bqm.add_interaction(coord0.g, coord1.g, weight) bqm.add_interaction(coord0.b, coord1.b, weight) # Edit BQM to bias for far away points to have different colors for i, coord0 in enumerate(coordinates[:-1]): for coord1 in coordinates[i + 1:]: # Set up weight # Note: rescaled and applied square root so that far off distances # are all weighted approximately the same d = math.sqrt(get_distance(coord0, coord1) / max_distance) weight = -math.tanh(d) * 0.1 # Apply weights to BQM bqm.add_interaction(coord0.r, coord1.b, weight) bqm.add_interaction(coord0.r, coord1.g, weight) bqm.add_interaction(coord0.b, coord1.r, weight) bqm.add_interaction(coord0.b, coord1.g, weight) bqm.add_interaction(coord0.g, coord1.r, weight) bqm.add_interaction(coord0.g, coord1.b, weight) # Submit problem to D-Wave sampler if architecture == 'pegasus': solver = DWaveSampler(solver={ 'topology__type': 'pegasus', 'qpu': True }) print(solver.solver) sampler = EmbeddingComposite(solver) else: solver = DWaveSampler(solver={ 'topology__type': 'chimera', 'qpu': True }) print(solver.solver) sampler = EmbeddingComposite(solver) sampleset = sampler.sample(bqm, chain_strength=4, num_reads=1000, return_embedding=True) best_sample = sampleset.first.sample # Inspect the embedding embedding = sampleset.info['embedding_context']['embedding'] num_qubits = 0 for k in embedding.values(): num_qubits += len(k) print("Number of qubits used in embedding = " + str(num_qubits)) # Visualize graph problem dwave.inspector.show(bqm, sampleset) # Visualize solution groupings = get_groupings(best_sample) visualize_groupings(groupings, filename) # Print solution onto terminal # Note: This is simply a more compact version of 'best_sample' print(groupings)
NAND(x2,x3) == 1 NAND(x2,x4) == 1 NAND(x3,x5) == 1 CAUTION: If you are using a live QPU, it is possible that the stitch() and embedding will result in a physical configuration of qubits that does not provide any solutions. This is a problem with the tool chain, not the hardware. There is a great opportunity for someone to create a constraint solver plus embedder that prevents embeddings without solutions. Let's run our single-row solver and see how it works. ''' csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) # At least one qubit must be set csp.add_constraint(or4, ['x1', 'x2', 'x3', 'x4']) # No more than one qubit can be set csp.add_constraint(nand, ['x1', 'x2']) csp.add_constraint(nand, ['x1', 'x3']) csp.add_constraint(nand, ['x1', 'x4']) csp.add_constraint(nand, ['x2', 'x3']) csp.add_constraint(nand, ['x2', 'x4']) csp.add_constraint(nand, ['x3', 'x4']) bqm = dwavebinarycsp.stitch(csp) response = sampler.sample(bqm, num_reads=samples)
def cluster_points(scattered_points, filename): # Set up problem coordinates = [Coordinate(x, y) for x, y in scattered_points] max_distance = get_max_distance(coordinates) # Build constraints csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) # Apply constraint: coordinate can only be in one colour group choose_one_group = allowed_States(k) for coord in coordinates: mylist = list(vars(coord).values()) mylist.remove(coord.x) mylist.remove(coord.y) csp.add_constraint(choose_one_group, mylist) # Build initial BQM bqm = dwavebinarycsp.stitch(csp) # Edit BQM to bias for close together points to share the same color for i, coord0 in enumerate(coordinates[:-1]): for coord1 in coordinates[i + 1:]: # Set up weight d = get_distance(coord0, coord1) / max_distance # rescale distance weight = -math.cos(d * math.pi) # Apply weights to BQM for i in range(k): bqm.add_interaction(getattr(coord0, "x" + str(i)), getattr(coord1, "x" + str(i)), weight) # Edit BQM to bias for far away points to have different colors for i, coord0 in enumerate(coordinates[:-1]): for coord1 in coordinates[i + 1:]: # Set up weight # Note: rescaled and applied square root so that far off distances # are all weighted approximately the same d = math.sqrt(get_distance(coord0, coord1) / max_distance) weight = -math.tanh(d) * 0.1 # Apply weights to BQM for p in range(k): for m in range(k): if p != m: bqm.add_interaction(getattr(coord0, "x" + str(p)), getattr(coord1, "x" + str(m)), weight) # Submit problem to D-Wave sampler sampler = EmbeddingComposite(DWaveSampler(solver={'qpu': True})) sampleset = sampler.sample(bqm, chain_strength=4, num_reads=1000) best_sample = sampleset.first.sample # Visualize graph problem dwave.inspector.show(bqm, sampleset) # Visualize solution groupings = get_groupings(best_sample) visualize_groupings(groupings, filename) # Print solution onto terminal # Note: This is simply a more compact version of 'best_sample' print(groupings)
# The graphic below shows an AND gate and its truth table, which gives the gate's output, $x_3$, for all combinations of inputs $x_1, x_2$. # <img src="images/AND_TruthTableandGate.png" width=300x/> # It's clear from the table that our problem's constraint, $L = SW_1 \wedge SW_2$, and the AND gate's operation, $x_3 = x_1x_2$, are equivalent. We can express our constraint as an AND gate. # Ocean's [dwavebinarycsp](https://docs.ocean.dwavesys.com/projects/binarycsp/en/latest/) binary CSP tool provides factories for useful constraints such as logic gates. Run the cell below (by pressing the **Run** button with your mouse in the cell) to create a CSP with a constraint representing an AND gate. # In[ ]: import dwavebinarycsp as dbc # Add an AND gate as a constraint to CSP and_csp defined for binary variables and_gate = dbc.factories.and_gate(["x1", "x2", "x3"]) and_csp = dbc.ConstraintSatisfactionProblem('BINARY') and_csp.add_constraint(and_gate) # Test that for input x1,x2=1,1 the output is x3=1 (both switches on and light shining) and_csp.check({"x1": 1, "x2": 1, "x3": 1}) # True # ## Step 2: Convert to a BQM # The quantum computer solves binary quadratic models. Let's express our light-circuit CSP as a BQM. # An advantage of Formulation B is that BQMs are known for logic gates (you can find BQMs for gates in the D-Wave system documentation and see examples here: [Ocean software examples](https://docs.ocean.dwavesys.com/en/latest/getting_started.html#examples)). More than one BQM can represent our AND gate; it's just a polynomial of binary variables, with only linear and quadratic terms, that has lowest value for variables that match rows of the AND truth table. Ocean tools can do the math for you, but here let's first write out a BQM for our AND gate: $3x_3 + x_1x_2 - 2x_1x_3 - 2x_2x_3$. # To see that this BQM represents the AND gate, you can set its variables to the values of the AND truth table, for example $x_1, x_2, x_3=0,0,0$, and to non-valid values, such as $ x_1, x_2, x_3=0,0,1$. All the former should produce lower values than any of the latter. The code cell below does so for all possible configurations. # Run the next cell. In the printed output, the left column (under "E") is the BQM's value for the combinations of variables to the right (under "x1, x2, x3").
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # https://support.dwavesys.com/hc/en-us/community/posts/360016737274-Save-time-Reuse-your-embedding-when-possible import dwavebinarycsp as dbc import dwavebinarycsp.factories.constraint.gates as gates from dwave.system.composites import FixedEmbeddingComposite, EmbeddingComposite from dwave.system.samplers import DWaveSampler # Making two different BQMs (think: energy functions or optimization functions) csp1 = dbc.ConstraintSatisfactionProblem(dbc.BINARY) csp1.add_constraint(gates.and_gate(['a', 'b', 'c'])) bqm1 = dbc.stitch(csp1) csp2 = dbc.ConstraintSatisfactionProblem(dbc.BINARY) csp2.add_constraint(gates.or_gate(['a', 'b', 'c'])) bqm2 = dbc.stitch(csp2) # Using Embedding Composite sampler = EmbeddingComposite(DWaveSampler()) sampler.sample(bqm1) # Gets a new embedding for bqm1 sampler.sample(bqm2) # Gets a new embedding for bqm2 # Using Fixed Embedding Composite # Note: bqm1 and bqm2 can both be represented by the same graph - triangle graph. embedding = { 'a': [0, 4], 'b': [1], 'c': [5] } # Embedding the triangle graph using QPU indices
def get_bqm(shift_types, nurses, horizon, stitch_kwargs=None): csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) # one shift for same person per day for nurse in nurses.keys(): for day in range(horizon): labels = {get_label(nurse, day, st) for st in shift_types.keys()} csp.add_constraint(sum_to_one, labels) # no not_before violation allowed = {(0, 0), (1, 0), (0, 1)} for nurse in nurses.keys(): for day in range(horizon - 1): for st_key, st_value in shift_types.items(): for fst in st_value.not_before: csp.add_constraint( allowed, { get_label(nurse, day, st_key), get_label(nurse, day + 1, fst) }) # no more than maxShifts for nurse_key, nurse_value in nurses.items(): labels = set() for st in shift_types.keys(): for day in range(horizon): labels.add(get_label(nurse_key, day, st)) csp.add_constraint( lambda *args: le(nurse_value.maxShifts[st], sum(args)), labels) # max consecutive shifts for nurse_key, nurse_value in nurses.items(): labels = set() for day in range(horizon - (nurse_value.maxConsecutiveShifts + 1)): for i in range(nurse_value.maxConsecutiveShifts + 1): for st in shift_types.keys(): labels.add(get_label(nurse_key, day + 1, st)) csp.add_constraint( lambda *args: ge(nurse_value.maxConsecutiveShifts, sum(args)), labels) # min consecutive shifts for nurse_key, nurse_value in nurses.items(): labels = set() for day in range(horizon - (nurse_value.minConsecutiveShifts + 1)): for i in range(nurse_value.minConsecutiveShifts + 1): for st in shift_types.keys(): labels.add(get_label(nurse_key, day + 1, st)) csp.add_constraint( lambda *args: le(nurse_value.minConsecutiveShifts, sum(args)), labels) stitch_kwargs = {} if stitch_kwargs is None: stitch_kwargs = {} bqm = dwavebinarycsp.stitch(csp, **stitch_kwargs) pruned_variables = list(bqm.variables) print(pruned_variables) for nurse in nurses: for day in range(horizon): for st in shift_types.keys(): label = get_label(nurse, day, st) bias = 1 if label in pruned_variables: bqm.add_variable(label, bias) return bqm
# Calogero Zarbo, Docebo, 24-Mar-2019 # D-Wave Challenge 9 import dwavebinarycsp import dimod import minorminer from dwave.system.composites import FixedEmbeddingComposite, TilingComposite from dwave.system.samplers import DWaveSampler def not_all_equal(q1, q2, q3): return not ((q1 == q2) and (q2 == q3)) csp = dwavebinarycsp.ConstraintSatisfactionProblem(vartype=dimod.Vartype.SPIN) csp.add_constraint(not_all_equal, ['a', 'b', 'c']) csp.add_constraint(not_all_equal, ['c', 'd', 'e']) bqm = dwavebinarycsp.stitch(csp) chimera_cell = [(i, j + 4) for j in range(4) for i in range(4)] embeddings = [ minorminer.find_embedding(bqm.to_qubo()[0].keys(), chimera_cell) for i in range(100) ] min_emb = min(embeddings, key=lambda x: len(sum(x.values(), []))) print("Minimum embedding configuration:", min_emb) print("Minimum embedding length:", len(sum(min_emb.values(), []))) # Verification of the found embedding
def min_cost(s0,s1): global gcost j01 = -1 h0 = -0.5 h1 = 0 c=h0*s0+h1*s1+j01*s0*s1 if c<gcost: gcost=c return True else: return False # Method 1 - Solving as a Constraint Satisfaction Problem csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.SPIN) shots=100 csp.add_constraint(min_cost,['s1','s2']) bqm1 = dwavebinarycsp.stitch(csp, min_classical_gap=2, max_graph_size=8) sampler1 = EmbeddingComposite(DWaveSampler()) response1 = sampler1.sample(bqm1, num_reads=shots) print('************ Method 1 - Constaint Satisfaction Problem - Results ************** \n') for res in response1.data(['sample', 'energy', 'num_occurrences']): print('|s1 = %s |s2 = %s | Energy = %f | Probability = %f %% ' % (res.sample['s1'],res.sample['s2'], res.energy, res.num_occurrences*100/shots)) # Method 1 - Solving as a Binary Quadratic Model Problem j01=-1 h0=-0.5 h1=0