attempt to autogen 3sat

This commit is contained in:
Daniel Tsvetkov 2020-02-21 15:35:40 +01:00
parent b6f54b2db4
commit 31b9b3640c
4 changed files with 183 additions and 16 deletions

101
3sat.py Normal file
View 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
View 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
View 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):
"""Grovers 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()

View File

@ -48,7 +48,7 @@ class Matrix(object):
def __eq__(self, other):
if isinstance(other, Complex):
return bool(np.allclose(self.m, other))
elif isinstance(other, TwoQubitPartial):
elif isinstance(other, PartialQubit):
return False
return np.allclose(self.m, other.m)
@ -291,16 +291,16 @@ class State(Vector):
# [0, 0, 1, 1, 0, 0, 1, 1]
partial_measurement_of_qbit = [int(b[qubit_n - 1]) for b in bin_repr]
# [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]
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
# 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]))
# TODO: This can be 0...
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
@ -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)
# _0.x(_0) * Matrix(I.m) + _1.x(_1) * Matrix(X.m)
class TwoQubitPartial(object):
class PartialQubit(object):
def __init__(self, rpr):
self.rpr = rpr
self.operator = None
@ -564,12 +564,12 @@ class TwoQubitPartial(object):
return str("-{}-".format(self.rpr))
C_partial = TwoQubitPartial("C")
x_partial = TwoQubitPartial("x")
C_partial = PartialQubit("C")
x_partial = PartialQubit("x")
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):
super().__init__(m, *args, **kwargs)
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)], ],
name="H")
CNOT = TwoQubitOperator([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0], ],
C_partial, x_partial, I, X)
CNOT = TwoQubitOperator([
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1],
[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):
@ -1037,7 +1049,7 @@ class QuantumCircuit(object):
self.add_row(row_data)
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
for partial in partials:
two_qubit_op = partial.operator
@ -1096,8 +1108,8 @@ class QuantumProcessor(object):
self.reset()
def compose_quantum_state(self, step):
if any([type(s) is TwoQubitPartial for s in step]):
two_qubit_gates = filter(lambda s: type(s) is TwoQubitPartial, step)
if any([type(s) is PartialQubit for s in step]):
two_qubit_gates = filter(lambda s: type(s) is PartialQubit, step)
state = []
for two_qubit_gate in two_qubit_gates:
two_qubit_gate.operator.verify_step(step)