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 random_xorsat(num_variables, num_clauses, vartype=dimod.BINARY, satisfiable=True): """todo""" if num_variables < 3: raise ValueError("a xor problem needs at least 3 variables") if num_clauses > 8 * _nchoosek(num_variables, 3): # 8 different negation patterns raise ValueError("too many clauses") # also checks the vartype argument csp = ConstraintSatisfactionProblem(vartype) variables = list(range(num_variables)) constraints = set() if satisfiable: values = tuple(vartype.value) planted_solution = {v: choice(values) for v in variables} configurations = [(0, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0)] while len(constraints) < num_clauses: # because constraints are hashed on configurations/variables, and because the inputs # to xor can be swapped without loss of generality, we can order them x, y, z = sample(variables, 3) if y > x: x, y = y, x # get the constraint const = xor_gate([x, y, z], vartype=vartype) # pick (uniformly) a configuration and determine which variables we need to negate to # match the chosen configuration config = choice(configurations) for idx, v in enumerate(const.variables): if config[idx] != (planted_solution[v] > 0): const.flip_variable(v) assert const.check(planted_solution) constraints.add(const) else: while len(constraints) < num_clauses: # because constraints are hashed on configurations/variables, and because the inputs # to xor can be swapped without loss of generality, we can order them x, y, z = sample(variables, 3) if y > x: x, y = y, x # get the constraint const = xor_gate([x, y, z], vartype=vartype) # randomly flip each variable in the constraint for idx, v in enumerate(const.variables): if random() > .5: const.flip_variable(v) assert const.check(planted_solution) constraints.add(const) for const in constraints: csp.add_constraint(const) # in case any variables didn't make it in for v in variables: csp.add_variable(v) return csp
def random_xorsat(num_variables, num_clauses, vartype=dimod.BINARY, satisfiable=True): """Random XOR constraint satisfaction problem. Args: num_variables (integer): Number of variables (at least three). num_clauses (integer): Number of constraints that together constitute the constraint satisfaction problem. vartype (Vartype, optional, default='BINARY'): Variable type. Accepted input values: * Vartype.SPIN, 'SPIN', {-1, 1} * Vartype.BINARY, 'BINARY', {0, 1} satisfiable (bool, optional, default=True): True if the CSP can be satisfied. Returns: CSP (:obj:`.ConstraintSatisfactionProblem`): CSP that is satisfied when its variables are assigned values that satisfy a XOR satisfiability problem. Examples: This example creates a CSP with 5 variables and two random constraints and checks whether a particular assignment of variables satisifies it. >>> import dwavebinarycsp >>> import dwavebinarycsp.factories as sat >>> csp = sat.random_xorsat(5, 2) >>> csp.constraints # doctest: +SKIP [Constraint.from_configurations(frozenset({(1, 0, 0), (1, 1, 1), (0, 1, 0), (0, 0, 1)}), (4, 3, 0), Vartype.BINARY, name='XOR (0 flipped)'), Constraint.from_configurations(frozenset({(1, 1, 0), (0, 1, 1), (0, 0, 0), (1, 0, 1)}), (2, 0, 4), Vartype.BINARY, name='XOR (2 flipped) (0 flipped)')] >>> csp.check({0: 1, 1: 0, 2: 0, 3: 1, 4: 1}) # doctest: +SKIP True """ if num_variables < 3: raise ValueError("a xor problem needs at least 3 variables") if num_clauses > 8 * _nchoosek(num_variables, 3): # 8 different negation patterns raise ValueError("too many clauses") # also checks the vartype argument csp = ConstraintSatisfactionProblem(vartype) variables = list(range(num_variables)) constraints = set() if satisfiable: values = tuple(vartype.value) planted_solution = {v: choice(values) for v in variables} configurations = [(0, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0)] while len(constraints) < num_clauses: # because constraints are hashed on configurations/variables, and because the inputs # to xor can be swapped without loss of generality, we can order them x, y, z = sample(variables, 3) if y > x: x, y = y, x # get the constraint const = xor_gate([x, y, z], vartype=vartype) # pick (uniformly) a configuration and determine which variables we need to negate to # match the chosen configuration config = choice(configurations) for idx, v in enumerate(const.variables): if config[idx] != (planted_solution[v] > 0): const.flip_variable(v) assert const.check(planted_solution) constraints.add(const) else: while len(constraints) < num_clauses: # because constraints are hashed on configurations/variables, and because the inputs # to xor can be swapped without loss of generality, we can order them x, y, z = sample(variables, 3) if y > x: x, y = y, x # get the constraint const = xor_gate([x, y, z], vartype=vartype) # randomly flip each variable in the constraint for idx, v in enumerate(const.variables): if random() > .5: const.flip_variable(v) assert const.check(planted_solution) constraints.add(const) for const in constraints: csp.add_constraint(const) # in case any variables didn't make it in for v in variables: csp.add_variable(v) return csp
ge gt For the full-adder we will use: inputs (a, b, Cin) outputs (s, cOut) For the intermediate variables we will use: (xor1, xor2, and1, and2, or1) However, s and xor2 are the same, and cOut and or1 are the same. See this image for a graphical view of this circuit: https://upload.wikimedia.org/wikipedia/commons/5/57/Fulladder.gif """ csp.add_constraint(gates.xor_gate(['a', 'b', 'xor1'])) # xor(a,b) = xor1 csp.add_constraint(gates.xor_gate(['xor1', 'cIn', 's'])) # xor(xor1,cIn) = s csp.add_constraint(gates.and_gate(['xor1', 'cIn', 'and1'])) # and(xor1,cIn) = and1 csp.add_constraint(gates.and_gate(['a', 'b', 'and2'])) # and(a,b) = and2 csp.add_constraint(gates.or_gate(['and1', 'and2', 'cOut'])) # or(and1,and2) = cOut # This is an example of an assert I used to ensure my constraints above # faithfully reproduced the full-adder I want to implement. # https://docs.ocean.dwavesys.com/projects/binarycsp/en/latest/reference/generated/dwavebinarycsp.ConstraintSatisfactionProblem.check.html assert csp.check({ 'a': 1, 'and1': 0,
For the intermediate variables we will use: (and1, and2, and3, and4, xor1, and5, xor2, and6) However, we will drop some of the intermediate variables because: c0 = and2, c1 = xor1, c2 = xor2, c3 = and6 See this image for a graphical view of this circuit: https://en.wikipedia.org/wiki/Binary_multiplier#/media/File:Binary_multi1.jpg """ csp.add_constraint(gates.and_gate(['a0', 'b1', 'and1' ])) # and(a0, b1) = and1 csp.add_constraint(gates.and_gate(['a0', 'b0', 'c0' ])) # and(a0, b0) = c0 csp.add_constraint(gates.and_gate(['a1', 'b0', 'and3' ])) # and(a1, b0) = and3 csp.add_constraint(gates.and_gate(['a1', 'b1', 'and4' ])) # and(a1, b1) = and4 csp.add_constraint(gates.xor_gate(['and1', 'and3', 'c1' ])) # xor(and1, and3) = c1 csp.add_constraint(gates.and_gate(['and1', 'and3', 'and5' ])) # and(and1, and3) = and5 csp.add_constraint(gates.xor_gate(['and5', 'and4', 'c2' ])) # xor(and5, and4) = c2 csp.add_constraint(gates.and_gate(['and5', 'and4', 'c3' ])) # and(and5, and4) = c3 """ Now that we have defined the gates for our 2 by 2 multiplier, we need to fix the output because we want to factor a number. In this case, we want to factor the number 9, which is 1001 in binary. There are several ways to fix the number, and each way impacts performance and correctness differently. Option 1: (the option we will pick) For each qubit we want to fix, set a constraint with operator.truth or operator.not_. "truth" will fix the qubit to 1, and "not_" will fix the
## the answer, by linking it to the "energy level" of a system. ## The D-Wave website contqins an extensive set of tools, documentation, ## and learning materials to help you get started. ## Required imports import dwavebinarycsp import dwavebinarycsp.factories.constraint.gates as gates import operator from dimod.reference.samplers import ExactSolver ## Set up the logic gates, exactly as shown in Figure 10-7 of the book. csp = dwavebinarycsp.ConstraintSatisfactionProblem(dwavebinarycsp.BINARY) csp.add_constraint(gates.or_gate(['boxA', 'boxB', 'AorB'])) # OR gate csp.add_constraint(operator.ne, ['boxA', 'notA']) # NOT gate csp.add_constraint(gates.xor_gate(['AorB', 'notA', 'notAxorAorB'])) # XOR gate csp.add_constraint(operator.ne, ['notAxorAorB', 'result']) # NOT gate csp.add_constraint(operator.eq, ['result', 'one']) # Specify that the result should be one csp.fix_variable( 'one', 1) # We could fix 'result' directly, but this is handy for printing bqm = dwavebinarycsp.stitch(csp) ## Run the solver sampler = ExactSolver() response = sampler.sample(bqm) ## Print all of the results for datum in response.data(['sample', 'energy']): print(datum.sample, datum.energy)