#!/usr/bin/env python3 from util import SAT2QUBO as s2q from util import randomSAT as rs from util import queries from util import graph from util import script import networkx as nx import dwave_networkx as dnx import minorminer from dwave_qbsolv import QBSolv import dimod from dwave.system.composites import FixedEmbeddingComposite from neal import SimulatedAnnealingSampler import matplotlib.pyplot as plt import seaborn as sns import numpy as np import re from tqdm import tqdm def frange(start, stop, steps): while start < stop: yield start start += steps def test_kv_range(): k = 75 v = 40 data = { "p_node_counts" : [], "wmis_node_counts" : [], "p_conn_counts" : [], "wmis_conn_counts" : [], "p_avrg_connectivity" : [], "wmis_avrg_connectivity" : [], "a_arr" : [], "k_arr" : [] } target = dnx.chimera_graph(25, 25, 4) print(target.number_of_nodes()) for r in range(2): #for k in range(50, 5001, 50): for a in frange(0.5, 8, 0.5): #v = int(k/4) #a = k/v #v = int(k/a) k = int(a*v) print("k={} v={} k/v={}".format(k, v, k/v)) ksatInstance = rs.generateRandomKSAT(k, v, 3) p_qubo = s2q.WMISdictQUBO_2(ksatInstance) wmis_qubo = s2q.WMISdictQUBO(ksatInstance) qg = nx.Graph() for coupler, energy in wmis_qubo.items(): if coupler[0] != coupler[1]: qg.add_edge(coupler[0], coupler[1], weight=energy) ig = nx.Graph() for coupler, energy in p_qubo.items(): if coupler[0] != coupler[1]: ig.add_edge(coupler[0], coupler[1], weight=energy) p_node_count = ig.number_of_nodes(); p_conn_count = ig.number_of_edges(); wmis_node_count = qg.number_of_nodes(); wmis_conn_count = qg.number_of_edges(); print("p_qubo nodes= {}".format(p_node_count)); print("wwmis qubo nodes= {}".format(wmis_node_count)); print("nodes= {}".format(p_node_count / wmis_node_count)); data["p_node_counts"].append(p_node_count) data["wmis_node_counts"].append(wmis_node_count) data["p_conn_counts"].append(p_conn_count) data["wmis_conn_counts"].append(wmis_conn_count) print("calculating connectivity...") data["p_avrg_connectivity"].append(nx.edge_connectivity(ig)) print("calculating connectivity...") data["wmis_avrg_connectivity"].append(nx.edge_connectivity(qg)) data["a_arr"].append(k/v) data["k_arr"].append(k) print() sns.set() ax = sns.scatterplot(x="a_arr", y="p_node_counts", data=data, label="p_qubo") ax.set(xlabel='k/v', ylabel='used verticies') ax = sns.scatterplot(x="a_arr", y="wmis_node_counts", data=data, ax=ax, label="wmis_qubo") plt.show() ax = sns.scatterplot(x="a_arr", y="p_conn_counts", data=data, label="p_qubo") ax.set(xlabel='k/v', ylabel='used edges') ax = sns.scatterplot(x="a_arr", y="wmis_conn_counts", data=data, ax=ax, label="wmis_qubo") plt.show() ax = sns.scatterplot(x="a_arr", y="p_avrg_connectivity", data=data, label="p_qubo") ax.set(xlabel='k/v', ylabel='avrg connectivity') ax = sns.scatterplot(x="a_arr", y="wmis_avrg_connectivity", data=data, ax=ax, label="wmis_qubo") plt.show() def test_kv_range_emb(): k = 75 data = { "p_node_counts" : [], "wmis_node_counts" : [], "p_conn_counts" : [], "wmis_conn_counts" : [], "a_arr" : [], "k_arr" : [] } target = dnx.chimera_graph(25, 25, 4) print(target.number_of_nodes()) for r in range(2): #for k in range(50, 5001, 50): for a in frange(3.5, 5.5, 0.1): #v = int(k/4) #a = k/v v = int(k/a) print("k={} v={} k/v={}".format(k, v, k/v)) ksatInstance = rs.generateRandomKSAT(k, v, 3) p_qubo = s2q.WMISdictQUBO_2(ksatInstance) wmis_qubo = s2q.WMISdictQUBO(ksatInstance) qg = nx.Graph() for coupler, energy in wmis_qubo.items(): if coupler[0] != coupler[1]: qg.add_edge(coupler[0], coupler[1], weight=energy) ig = nx.Graph() for coupler, energy in p_qubo.items(): if coupler[0] != coupler[1]: ig.add_edge(coupler[0], coupler[1], weight=energy) qemb = minorminer.find_embedding(qg.edges(), target.edges(), return_overlap=True, threads=8) print("wmis emb. found: {}".format(qemb[1])) iemb = minorminer.find_embedding(ig.edges(), target.edges(), return_overlap=True, threads=8) print("primitive emb. found: {}".format(iemb[1])) if qemb[1] == 0 or iemb[1] == 0: print() continue p_node_count = 0; p_conn_count = 0; used_nodes = [] for var, chain in iemb[0].items(): used_nodes.extend(chain) p_node_count = len(np.unique(used_nodes)) wmis_node_count = 0; wmis_conn_count = 0; used_nodes = [] for var, chain in qemb[0].items(): used_nodes.extend(chain) wmis_node_count = len(np.unique(used_nodes)) #print("p_qubo: nodes={} connections={}".format(p_node_count, p_conn_count)) #print("wmis_qubo: nodes={} connections={}".format(wmis_node_count, wmis_conn_count)) print("p_qubo nodes= {}".format(p_node_count)); print("wwmis qubo nodes= {}".format(wmis_node_count)); print("nodes= {}".format(p_node_count / wmis_node_count)); #print("conns= {}".format(p_conn_count / wmis_conn_count)); data["p_node_counts"].append(p_node_count) data["wmis_node_counts"].append(wmis_node_count) data["p_conn_counts"].append(p_conn_count) data["wmis_conn_counts"].append(wmis_conn_count) data["a_arr"].append(k/v) data["k_arr"].append(k) print() sns.set() ax = sns.scatterplot(x="a_arr", y="p_node_counts", data=data, label="p_qubo") ax.set(xlabel='k/v', ylabel='used verticies after embedding') ax = sns.scatterplot(x="a_arr", y="wmis_node_counts", data=data, ax=ax, label="wmis_qubo") plt.show() def test_k_range(): k = 75 data = { "p_node_counts" : [], "wmis_node_counts" : [], "p_conn_counts" : [], "wmis_conn_counts" : [], "a_arr" : [], "k_arr" : [] } target = dnx.chimera_graph(25, 25, 4) print(target.number_of_nodes()) for r in range(2): for k in range(15, 76, 1): v = int(k/4) print("k={} v={} k/v={}".format(k, v, k/v)) ksatInstance = rs.generateRandomKSAT(k, v, 3) p_qubo = s2q.primitiveQUBO(ksatInstance) wmis_qubo = s2q.WMISdictQUBO(ksatInstance) qg = nx.Graph() for coupler, energy in wmis_qubo.items(): if coupler[0] != coupler[1]: qg.add_edge(coupler[0], coupler[1], weight=energy) ig = nx.Graph() for coupler, energy in p_qubo.items(): if coupler[0] != coupler[1]: ig.add_edge(coupler[0], coupler[1], weight=energy) qemb = minorminer.find_embedding(qg.edges(), target.edges(), return_overlap=True, threads=8) print("wmis emb. found: {}".format(qemb[1])) iemb = minorminer.find_embedding(ig.edges(), target.edges(), return_overlap=True, threads=8) print("primitive emb. found: {}".format(iemb[1])) if qemb[1] == 0 or iemb[1] == 0: print() continue p_node_count = 0; p_conn_count = 0; used_nodes = [] for var, chain in iemb[0].items(): used_nodes.extend(chain) p_node_count = len(np.unique(used_nodes)) wmis_node_count = 0; wmis_conn_count = 0; used_nodes = [] for var, chain in qemb[0].items(): used_nodes.extend(chain) wmis_node_count = len(np.unique(used_nodes)) #print("p_qubo: nodes={} connections={}".format(p_node_count, p_conn_count)) #print("wmis_qubo: nodes={} connections={}".format(wmis_node_count, wmis_conn_count)) print("p_qubo nodes= {}".format(p_node_count)); print("wwmis qubo nodes= {}".format(wmis_node_count)); print("nodes= {}".format(p_node_count / wmis_node_count)); #print("conns= {}".format(p_conn_count / wmis_conn_count)); data["p_node_counts"].append(p_node_count) data["wmis_node_counts"].append(wmis_node_count) data["p_conn_counts"].append(p_conn_count) data["wmis_conn_counts"].append(wmis_conn_count) data["a_arr"].append(k/v) data["k_arr"].append(k) print() sns.set() ax = sns.scatterplot(x="k_arr", y="p_node_counts", data=data, label="p_qubo") ax.set(xlabel='k', ylabel='used verticies after embedding') ax = sns.scatterplot(x="k_arr", y="wmis_node_counts", data=data, ax=ax, label="wmis_qubo") plt.show() def medianChainLength(emb): chl = [] for chain in emb.values(): chl.append(len(chain)) sns.distplot(chl) plt.show() return np.mean(chl) def test2(): sat = rs.generateRandomKSAT(42, 10, 3) print(sat.toString()) qubo = s2q.WMISdictQUBO(sat) #ising = s2q.primitiveQUBO_8(sat) ising = s2q.WMISdictQUBO_2(sat) qg = nx.Graph() for coupler, energy in qubo.items(): if coupler[0] != coupler[1]: qg.add_edge(coupler[0], coupler[1], weight=energy) ig = nx.Graph() for coupler, energy in ising.items(): if coupler[0] != coupler[1]: ig.add_edge(coupler[0], coupler[1], weight=energy) #plt.ion() print(qg.number_of_nodes(), qg.number_of_edges()) print(ig.number_of_nodes(), ig.number_of_edges()) target = dnx.chimera_graph(16, 16, 4) #nx.draw_shell(qg, with_labels=True, node_size=50) #nx.draw_shell(ig, with_labels=True, node_size=50) eg = ig emb = minorminer.find_embedding(eg.edges(), target.edges(), return_overlap=True, threads=8) print(emb[1]) for node, chain in emb[0].items(): print(node, chain) print("avrg chain length = {}".format(medianChainLength(emb[0]))) dnx.draw_chimera_embedding(G=target, emb=emb[0], embedded_graph=eg, show_labels=True) plt.show() def test3(): sat = rs.generateRandomKSAT(42, 10, 3) print(sat.toString()) ising = s2q.primitiveQUBO(sat) h = {} J = {} for coupler, energy in ising.items(): if coupler[0] == coupler[1]: h[coupler[0]] = energy else: J[coupler] = energy res = QBSolv().sample_ising(h, J, find_max=False) sample = list(res.samples())[0] extracted = {} r = re.compile("c\d+_l-?\d*") for label, assignment in sample.items(): if r.fullmatch(label): extracted[tuple(re.split(r"\_l", label[1:]))] = assignment model = [True for i in range(len(extracted))] assignments = {} for label, assignment in extracted.items(): clause = int(label[0]) lit = int(label[1]) var = abs(lit) if lit < 0: assignment *= -1 if var in assignments: assignments[var].append(assignment) else: assignments[var] = [assignment] conflicts = False for var, a in assignments.items(): if abs(np.sum(a)) != len(a): conflicts = True print("conflicts - no solution found") print(var, np.sort(a)) if conflicts: return model = [True for i in range(sat.getNumberOfVariables())] for var, assignment in assignments.items(): model[var - 1] = True if assignment[0] > 0 else False print(model, sat.checkAssignment(model)) def test3_3(): sat = rs.generateRandomKSAT(42, 10, 3) print(sat.toString()) #ising = s2q.primitiveQUBO_8(sat) ising = s2q.WMISdictQUBO_2(sat) #ising = {} #ising[("x1", "z1")] = +2 #ising[("x2", "z2")] = +2 #ising[("z1", "z2")] = +2 #ising[("z1", "z1")] = -2 #ising[("z2", "z2")] = -2 #ising[("x1", "z3")] = -2 #ising[("x2", "z3")] = -2 #ising[("x3", "z3")] = +2 #ising[("z3", "z3")] = +2 h, J = graph.split_ising(ising) #res = QBSolv().sample_ising(h, J, find_max=False) res = QBSolv().sample_qubo(ising, find_max=False) #res = dimod.ExactSolver().sample_ising(h, J) #res = dimod.ExactSolver().sample_qubo(ising) sample = res.first.sample print(res.truncate(50)) #print(res.truncate(10)) assignments = {} vars = set() for node, energy in sample.items(): if node[0] == "x": lit = int(node[1:]) vars.add(abs(lit)) assignments[lit] = energy conflicts = set() for var in vars: if var in assignments and -var in assignments: if assignments[var] == assignments[-var]: print("conflict at var: {}".format(var)) conflicts.add(var) #if conflicts: # return model = [True for i in range(len(vars))] for var in vars: if var in assignments: model[var - 1] = True if assignments[var] == 1 else False elif -var in assignments: model[var - 1] = True if assignments[-var] == 0 else False print() print(model) print() print(sat.checkAssignment(model)) print() degrees = sat.getDegreesOfVariables() for var in conflicts: node_var = "x{}".format(var) node_nvar = "x{}".format(-var) print("var {}: deg={}, coupler={}, e={}, ne={}" .format(var, degrees[var], ising[(node_var, node_nvar)], assignments[var], assignments[-var])) def test3_4(): sat_count = 0 steps = 200 for i in tqdm(range(steps)): sat = rs.generateRandomKSAT(35, 10, 3) ising = s2q.WMISdictQUBO_2(sat) res = QBSolv().sample_qubo(ising, find_max=False) #res = dimod.ExactSolver().sample_qubo(ising) sample = res.first.sample assignments = {} vars = set() for node, energy in sample.items(): if node[0] == "x": lit = int(node[1:]) vars.add(abs(lit)) assignments[lit] = energy model = [True for i in range(len(vars))] for var in vars: if var in assignments: model[var - 1] = True if assignments[var] == 1 else False elif -var in assignments: model[var - 1] = True if assignments[-var] == 0 else False if sat.checkAssignment(model): sat_count += 1 print("sat percentage: {}".format(sat_count / steps)) def test_wmis(): sat_count = 0 #steps = 100 steps = 1 for i in tqdm(range(steps)): sat = rs.generateRandomKSAT(35, 10, 3) target = dnx.chimera_graph(16, 16, 4) qubo = s2q.WMISdictQUBO(sat) qg = nx.Graph() for coupler, energy in qubo.items(): if coupler[0] != coupler[1]: qg.add_edge(coupler[0], coupler[1], weight=energy) qemb = minorminer.find_embedding(qg.edges(), target.edges(), return_overlap=True) chimera_sampler = dimod.StructureComposite(SimulatedAnnealingSampler(), target.nodes(), target.edges()) solver = FixedEmbeddingComposite(chimera_sampler, qemb[0]) res = solver.sample_qubo(__negate_qubo(qubo)) #res = solver.sample_qubo(qubo) #res = dimod.ExactSolver().sample_qubo(ising) sample = res.first.sample model = script.majority_vote_sample(sample) print("energy={}".format(res.first.energy)) if sat.checkAssignment(model): sat_count += 1 print("sat percentage: {}".format(sat_count / steps)) def test4(): sat = rs.generateRandomKSAT(50, 13, 3) print(sat.toString()) qubo = s2q.WMISdictQUBO(sat) ising = s2q.primitiveQUBO(sat) qg = nx.Graph() for coupler, energy in qubo.items(): if coupler[0] != coupler[1]: qg.add_edge(coupler[0], coupler[1], weight=energy) ig = nx.Graph() for coupler, energy in ising.items(): if coupler[0] != coupler[1]: ig.add_edge(coupler[0], coupler[1], weight=energy) #plt.ion() print(qg.number_of_nodes(), qg.number_of_edges()) print(ig.number_of_nodes(), ig.number_of_edges()) target = dnx.chimera_graph(12, 12, 4) #nx.draw_shell(qg, with_labels=True, node_size=50) #nx.draw_shell(ig, with_labels=True, node_size=50) print() print("wmis:") qemb = minorminer.find_embedding(qg.edges(), target.edges(), return_overlap=True) print(qemb[1]) print("median chain length = {}".format(medianChainLength(qemb[0]))) used_nodes = [] for var, chain in qemb[0].items(): used_nodes.extend(chain) used_nodes = np.unique(used_nodes) print("used nodes (embedding) = {}".format(len(used_nodes))) print() print("primitves:") iemb = minorminer.find_embedding(ig.edges(), target.edges(), return_overlap=True) print(iemb[1]) print("median chain length = {}".format(medianChainLength(iemb[0]))) used_nodes = [] for var, chain in iemb[0].items(): used_nodes.extend(chain) used_nodes = np.unique(used_nodes) print("used nodes (embedding) = {}".format(len(used_nodes))) def __negate_qubo(qubo): negative_qubo = {} for coupler, energy in qubo.items(): negative_qubo[coupler] = -1 * energy return negative_qubo #test3_4() #test2() #test_kv_range test_wmis()