attempt to autogen 3sat
This commit is contained in:
parent
b6f54b2db4
commit
31b9b3640c
101
3sat.py
Normal file
101
3sat.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import inspect
|
||||||
|
import itertools
|
||||||
|
import random
|
||||||
|
|
||||||
|
from grover import classical_func_search
|
||||||
|
|
||||||
|
|
||||||
|
class X(object):
|
||||||
|
""""""
|
||||||
|
|
||||||
|
def __init__(self, i):
|
||||||
|
self.i = i
|
||||||
|
|
||||||
|
|
||||||
|
class SAT(object):
|
||||||
|
def __init__(self, predicates=3):
|
||||||
|
self.and_clauses = []
|
||||||
|
self.and_clauses_funcs = []
|
||||||
|
self.predicates = predicates
|
||||||
|
|
||||||
|
def or_(self, or_clauses):
|
||||||
|
def inner_or_(params):
|
||||||
|
for or_clause in or_clauses:
|
||||||
|
yes_no, var = or_clause[0], or_clause[1].i - 1
|
||||||
|
if yes_no(params[var]):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
return inner_or_
|
||||||
|
|
||||||
|
def and_(self, and_clauses):
|
||||||
|
def inner_and_(params):
|
||||||
|
for and_clause in and_clauses:
|
||||||
|
if and_clause(params):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
return inner_and_
|
||||||
|
|
||||||
|
def yes(self, x):
|
||||||
|
return x
|
||||||
|
|
||||||
|
def no(self, x):
|
||||||
|
return not x
|
||||||
|
|
||||||
|
def generate(self, ands=1):
|
||||||
|
params = [X(i) for i in range(1, self.predicates + 1)]
|
||||||
|
|
||||||
|
def or_clause(or_clauses):
|
||||||
|
def inner_or_clause(params):
|
||||||
|
return self.or_(or_clauses)(params)
|
||||||
|
|
||||||
|
return inner_or_clause
|
||||||
|
|
||||||
|
for _ in range(ands):
|
||||||
|
or_clauses = list(zip(random.choices([self.yes, self.no], k=3), random.sample(params, k=3)))
|
||||||
|
self.and_clauses.append(or_clauses)
|
||||||
|
self.and_clauses_funcs.append(or_clause(or_clauses))
|
||||||
|
|
||||||
|
def inner_generate(args):
|
||||||
|
return self.and_(self.and_clauses_funcs)(args)
|
||||||
|
|
||||||
|
self.inner = inner_generate
|
||||||
|
|
||||||
|
def __call__(self, args):
|
||||||
|
self.inner(args)
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
for j, _or_clause in enumerate(self.and_clauses):
|
||||||
|
for i, predicate in enumerate(_or_clause):
|
||||||
|
if i == 0:
|
||||||
|
print("( ", end='')
|
||||||
|
trueness, var = predicate
|
||||||
|
if trueness == self.yes:
|
||||||
|
print("x_{}".format(var.i), end='')
|
||||||
|
else:
|
||||||
|
print("¬x_{}".format(var.i), end='')
|
||||||
|
if i + 1 != len(_or_clause):
|
||||||
|
print(" ∨ ", end='')
|
||||||
|
if j + 1 != len(self.and_clauses):
|
||||||
|
print(" ) ∧ ")
|
||||||
|
else:
|
||||||
|
print(" )")
|
||||||
|
|
||||||
|
|
||||||
|
def classical_3sat(func):
|
||||||
|
# Generate all possible true/false tupples for the 3-sat problem
|
||||||
|
input_range = list(itertools.product([True, False], repeat=func.predicates))
|
||||||
|
random.shuffle(input_range)
|
||||||
|
return classical_func_search(func, input_range)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
gen_3sat = SAT(predicates=6)
|
||||||
|
gen_3sat.generate(ands=1)
|
||||||
|
gen_3sat.show()
|
||||||
|
print(classical_3sat(gen_3sat))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
9
compiler.py
Normal file
9
compiler.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from lib_q_computer_math import s
|
||||||
|
|
||||||
|
|
||||||
|
def int_to_state(i):
|
||||||
|
return s("|{}>".format(bin(i)))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(int_to_state(42))
|
45
grover.py
Normal file
45
grover.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# http://twistedoakstudios.com/blog/Post2644_grovers-quantum-search-algorithm
|
||||||
|
import inspect
|
||||||
|
import itertools
|
||||||
|
import random
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
|
||||||
|
def classical_func_search(func, input_range):
|
||||||
|
"""Grover’s algorithm takes a function, searches through
|
||||||
|
the implicit list of possible inputs to that function, and
|
||||||
|
returns inputs that causes the function to return true.
|
||||||
|
"""
|
||||||
|
rv = []
|
||||||
|
for i, params in enumerate(input_range):
|
||||||
|
result = func(params)
|
||||||
|
if result:
|
||||||
|
rv.append(params)
|
||||||
|
return rv
|
||||||
|
|
||||||
|
|
||||||
|
def _3sat(x1, x2, x3):
|
||||||
|
# https://cstheory.stackexchange.com/questions/38538/oracle-construction-for-grovers-algorithm
|
||||||
|
# 3-SAT from here: https://qiskit.org/textbook/ch-applications/satisfiability-grover.html
|
||||||
|
return (not x1 or not x2 or not x3) and \
|
||||||
|
(x1 or not x2 or x3) and \
|
||||||
|
(x1 or x2 or not x3) and \
|
||||||
|
(x1 or not x2 or not x3) and \
|
||||||
|
(not x1 or x2 or x3)
|
||||||
|
|
||||||
|
|
||||||
|
def classical_3sat(func):
|
||||||
|
# Generate all possible true/false tupples for the 3-sat problem
|
||||||
|
sig = inspect.signature(func)
|
||||||
|
params = sig.parameters
|
||||||
|
input_range = list(itertools.product([True, False], repeat=len(params)))
|
||||||
|
random.shuffle(input_range)
|
||||||
|
return classical_func_search(func, input_range)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
pprint(classical_3sat(_3sat))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -48,7 +48,7 @@ class Matrix(object):
|
|||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if isinstance(other, Complex):
|
if isinstance(other, Complex):
|
||||||
return bool(np.allclose(self.m, other))
|
return bool(np.allclose(self.m, other))
|
||||||
elif isinstance(other, TwoQubitPartial):
|
elif isinstance(other, PartialQubit):
|
||||||
return False
|
return False
|
||||||
return np.allclose(self.m, other.m)
|
return np.allclose(self.m, other.m)
|
||||||
|
|
||||||
@ -291,16 +291,16 @@ class State(Vector):
|
|||||||
# [0, 0, 1, 1, 0, 0, 1, 1]
|
# [0, 0, 1, 1, 0, 0, 1, 1]
|
||||||
partial_measurement_of_qbit = [int(b[qubit_n - 1]) for b in bin_repr]
|
partial_measurement_of_qbit = [int(b[qubit_n - 1]) for b in bin_repr]
|
||||||
# [0, 1, 4, 5]
|
# [0, 1, 4, 5]
|
||||||
indexes_for_p_0 = [i for i, index in enumerate(partial_measurement_of_qbit) if index==0]
|
indexes_for_p_0 = [i for i, index in enumerate(partial_measurement_of_qbit) if index == 0]
|
||||||
weights_0 = [self.get_prob(j) for j in indexes_for_p_0]
|
weights_0 = [self.get_prob(j) for j in indexes_for_p_0]
|
||||||
choices_0 = [format_str.format(i) for i in indexes_for_p_0]
|
choices_0 = [format_str.format(i) for i in indexes_for_p_0]
|
||||||
measurement_result = random.choices(choices_0, weights_0)[0][qubit_n-1]
|
measurement_result = random.choices(choices_0, weights_0)[0][qubit_n - 1]
|
||||||
# TODO: Verify if this is the correct collapse to lower dimension after partial measurement
|
# TODO: Verify if this is the correct collapse to lower dimension after partial measurement
|
||||||
# https://www.youtube.com/watch?v=MG_9JWsrKtM&list=PL1826E60FD05B44E4&index=16
|
# https://www.youtube.com/watch?v=MG_9JWsrKtM&list=PL1826E60FD05B44E4&index=16
|
||||||
normalization_factor = np.sqrt(np.sum([self.m[i][0] for i in indexes_for_p_0]))
|
normalization_factor = np.sqrt(np.sum([self.m[i][0] for i in indexes_for_p_0]))
|
||||||
# TODO: This can be 0...
|
# TODO: This can be 0...
|
||||||
self.m = [
|
self.m = [
|
||||||
[(self.m[i][0]**2)/normalization_factor] for i in indexes_for_p_0
|
[(self.m[i][0] ** 2) / normalization_factor] for i in indexes_for_p_0
|
||||||
]
|
]
|
||||||
return measurement_result
|
return measurement_result
|
||||||
|
|
||||||
@ -555,7 +555,7 @@ class HermitianOperator(LinearTransformation, HermitianMatrix):
|
|||||||
# np.kron(np.outer(_0.m, _0.m), np.eye(2)) + np.kron(np.outer(_1.m, _1.m), X.m)
|
# np.kron(np.outer(_0.m, _0.m), np.eye(2)) + np.kron(np.outer(_1.m, _1.m), X.m)
|
||||||
# _0.x(_0) * Matrix(I.m) + _1.x(_1) * Matrix(X.m)
|
# _0.x(_0) * Matrix(I.m) + _1.x(_1) * Matrix(X.m)
|
||||||
|
|
||||||
class TwoQubitPartial(object):
|
class PartialQubit(object):
|
||||||
def __init__(self, rpr):
|
def __init__(self, rpr):
|
||||||
self.rpr = rpr
|
self.rpr = rpr
|
||||||
self.operator = None
|
self.operator = None
|
||||||
@ -564,12 +564,12 @@ class TwoQubitPartial(object):
|
|||||||
return str("-{}-".format(self.rpr))
|
return str("-{}-".format(self.rpr))
|
||||||
|
|
||||||
|
|
||||||
C_partial = TwoQubitPartial("C")
|
C_partial = PartialQubit("C")
|
||||||
x_partial = TwoQubitPartial("x")
|
x_partial = PartialQubit("x")
|
||||||
|
|
||||||
|
|
||||||
class TwoQubitOperator(UnitaryOperator):
|
class TwoQubitOperator(UnitaryOperator):
|
||||||
def __init__(self, m: ListOrNdarray, A: TwoQubitPartial, B: TwoQubitPartial,
|
def __init__(self, m: ListOrNdarray, A: PartialQubit, B: PartialQubit,
|
||||||
A_p: UnitaryOperator, B_p: UnitaryOperator, *args, **kwargs):
|
A_p: UnitaryOperator, B_p: UnitaryOperator, *args, **kwargs):
|
||||||
super().__init__(m, *args, **kwargs)
|
super().__init__(m, *args, **kwargs)
|
||||||
A.operator, B.operator = self, self
|
A.operator, B.operator = self, self
|
||||||
@ -697,11 +697,23 @@ H = UnitaryOperator([[1 / np.sqrt(2), 1 / np.sqrt(2)],
|
|||||||
[1 / np.sqrt(2), -1 / np.sqrt(2)], ],
|
[1 / np.sqrt(2), -1 / np.sqrt(2)], ],
|
||||||
name="H")
|
name="H")
|
||||||
|
|
||||||
CNOT = TwoQubitOperator([[1, 0, 0, 0],
|
CNOT = TwoQubitOperator([
|
||||||
[0, 1, 0, 0],
|
[1, 0, 0, 0],
|
||||||
[0, 0, 0, 1],
|
[0, 1, 0, 0],
|
||||||
[0, 0, 1, 0], ],
|
[0, 0, 0, 1],
|
||||||
C_partial, x_partial, I, X)
|
[0, 0, 1, 0],
|
||||||
|
], C_partial, x_partial, I, X)
|
||||||
|
|
||||||
|
# TOFFOLLI_GATE = ThreeQubitOperator([
|
||||||
|
# [1, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
# [0, 1, 0, 0, 0, 0, 0, 0],
|
||||||
|
# [0, 0, 1, 0, 0, 0, 0, 0],
|
||||||
|
# [0, 0, 0, 1, 0, 0, 0, 0],
|
||||||
|
# [0, 0, 0, 0, 1, 0, 0, 0],
|
||||||
|
# [0, 0, 0, 0, 0, 1, 0, 0],
|
||||||
|
# [0, 0, 0, 0, 0, 0, 0, 1],
|
||||||
|
# [0, 0, 0, 0, 0, 0, 1, 0],
|
||||||
|
# ], C_partial, C_partial, x_partial, I, I, X)
|
||||||
|
|
||||||
|
|
||||||
def assert_raises(exception, msg, callable, *args, **kwargs):
|
def assert_raises(exception, msg, callable, *args, **kwargs):
|
||||||
@ -1037,7 +1049,7 @@ class QuantumCircuit(object):
|
|||||||
self.add_row(row_data)
|
self.add_row(row_data)
|
||||||
|
|
||||||
def compose_quantum_state(self, step):
|
def compose_quantum_state(self, step):
|
||||||
partials = [op for op in step if isinstance(op, TwoQubitPartial)]
|
partials = [op for op in step if isinstance(op, PartialQubit)]
|
||||||
# TODO: No more than 1 TwoQubitGate **OR** UnitaryOperator can be used in a step
|
# TODO: No more than 1 TwoQubitGate **OR** UnitaryOperator can be used in a step
|
||||||
for partial in partials:
|
for partial in partials:
|
||||||
two_qubit_op = partial.operator
|
two_qubit_op = partial.operator
|
||||||
@ -1096,8 +1108,8 @@ class QuantumProcessor(object):
|
|||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def compose_quantum_state(self, step):
|
def compose_quantum_state(self, step):
|
||||||
if any([type(s) is TwoQubitPartial for s in step]):
|
if any([type(s) is PartialQubit for s in step]):
|
||||||
two_qubit_gates = filter(lambda s: type(s) is TwoQubitPartial, step)
|
two_qubit_gates = filter(lambda s: type(s) is PartialQubit, step)
|
||||||
state = []
|
state = []
|
||||||
for two_qubit_gate in two_qubit_gates:
|
for two_qubit_gate in two_qubit_gates:
|
||||||
two_qubit_gate.operator.verify_step(step)
|
two_qubit_gate.operator.verify_step(step)
|
||||||
|
Loading…
Reference in New Issue
Block a user