This commit is contained in:
Tom
2019-04-02 13:16:26 +02:00
parent 05451ccbcd
commit d5982763f8
41 changed files with 2850 additions and 124 deletions

View File

@@ -11,7 +11,7 @@ __EDGE_WEIGHT__ = -2
def WMISdictQUBO(kSATInstance):
quboInstance = {}
for clauseIndex in tqdm(range(kSATInstance.getNumberOfClauses())):
for clauseIndex in range(kSATInstance.getNumberOfClauses()):
clause = kSATInstance.getClause(clauseIndex)
# build triangles
@@ -31,6 +31,76 @@ def WMISdictQUBO(kSATInstance):
quboInstance[(conflict[0], conflict[1])] = __EDGE_WEIGHT__
return quboInstance
# only 3sat
def primitiveQUBO(sat):
quboInstance = {}
chains = {}
for clauseIndex in range(sat.getNumberOfClauses()):
clause = sat.getClause(clauseIndex);
#build clause primitives
lit1 = "c{}_l{}".format(clauseIndex, clause[0])
lit2 = "c{}_l{}".format(clauseIndex, clause[1])
lit3 = "c{}_l{}".format(clauseIndex, clause[2])
aux1 = "a{}_{}".format(clauseIndex, 1)
aux2 = "a{}_{}".format(clauseIndex, 2)
aux3 = "a{}_{}".format(clauseIndex, 3)
aux4 = "a{}_{}".format(clauseIndex, 4)
quboInstance[(lit1, lit1)] = 1;
quboInstance[(lit2, lit2)] = 1;
quboInstance[(lit3, lit3)] = 1;
quboInstance[(aux1, aux1)] = -2;
quboInstance[(aux2, aux2)] = 1;
quboInstance[(aux3, aux3)] = -2;
quboInstance[(aux4, aux4)] = -2;
quboInstance[(lit1, lit2)] = 1;
quboInstance[(lit1, aux1)] = -2;
quboInstance[(lit2, aux1)] = -2;
quboInstance[(aux1, aux2)] = -2;
quboInstance[(aux2, aux3)] = -2;
quboInstance[(aux2, lit3)] = 1;
quboInstance[(lit3, aux3)] = -2;
quboInstance[(aux3, aux4)] = -2;
if clause[0] in chains:
chains[clause[0]].append(lit1)
else:
chains[clause[0]] = [lit1]
if clause[1] in chains:
chains[clause[1]].append(lit2)
else:
chains[clause[1]] = [lit2]
if clause[2] in chains:
chains[clause[2]].append(lit3)
else:
chains[clause[2]] = [lit3]
#build chains
longestChain = 0;
for lit, nodes in chains.items():
if len(nodes) > longestChain:
longestChain = len(nodes)
if lit > 0 and -1 * lit in chains:
quboInstance[(chains[lit][0], chains[-1*lit][0])] = 2
print("longest chain = {}".format(longestChain))
for nodes in chains.values():
while len(nodes) > 1:
quboInstance[(nodes[0], nodes[1])] = -2;
nodes.pop(0)
return quboInstance
class QuboWriter:
def __init__(self, qubo):

18
util/graph.py Normal file
View File

@@ -0,0 +1,18 @@
import networkx as nx
def qubo_to_nx_graph(qubo):
graph = nx.Graph()
for coupler, energy in qubo.items():
if coupler[0] != coupler[1]:
graph.add_edge(coupler[0], coupler[1], weight=energy)
return graph
def negate_qubo(qubo):
negative_qubo = {}
for coupler, energy in qubo.items():
negative_qubo[coupler] = -1 * energy
return negative_qubo

View File

@@ -154,8 +154,16 @@ class kSAT:
def writeJSONLike(self):
jsonLike = {}
jsonLike["clauses"] = self.__clauses
jsonLike["clauses"] = []
for clause in self.__clauses:
tmpClause = []
for literal in clause:
tmpClause.append(int(literal))
jsonLike["clauses"].append(tmpClause)
return jsonLike
def readJSONLike(self, jsonLike):

264
util/queries.py Normal file
View File

@@ -0,0 +1,264 @@
from .kSAT import kSAT
import bson
class Instance_scope_query:
def __init__(self, database):
self.__database = database
self.__query = None
def query(self, scope):
self.__query = self.__database["experiment_scopes"].aggregate([
{
"$match": {"_id": scope}
},
{
"$unwind": "$instances"
},
{
"$lookup":
{
"from": "instances",
"localField": "instances",
"foreignField": "_id",
"as": "instance"
}
},
{
"$unwind": "$instance"
},
{
"$replaceRoot": {"newRoot": "$instance"}
}
])
def __iter__(self):
return self
def __next__(self):
document = self.__query.next()
return self.__document_to_sat(document)
def __document_to_sat(self, document):
sat = kSAT()
for clause in document["clauses"]:
sat.addClause(clause);
return sat, document["_id"]
class WMIS_scope_query_raw:
def __init__(self, database):
self.__database = database
self.__query = None
def query(self, scope):
self.__query = self.__database["experiment_scopes"].aggregate([
{
"$match": {"_id": scope}
},
{
"$unwind": "$instances"
},
{
"$lookup":
{
"from": "wmis_qubos",
"localField": "instances",
"foreignField": "instance",
"as": "qubo"
}
},
{
"$unwind": "$qubo"
},
{
"$replaceRoot": {"newRoot": "$qubo"}
}
])
def __iter__(self):
return self
def __next__(self):
return self.__query.next()
class WMIS_scope_query (WMIS_scope_query_raw):
def __next__(self):
doc = super(WMIS_scope_query, self).__next__()
return read_raw_qubo(doc["qubo"]), doc["_id"]
class WMIS_solver_input_scope_query_raw:
def __init__(self, database):
self.__database = database
self.__query = None
def query(self, scope, solver_graph_id):
self.__query = self.__database["experiment_scopes"].aggregate([
{
"$match": {"_id": scope}
},
{
"$unwind": "$instances"
},
{
"$project": {"instance_id": "$instances"}
},
{
"$lookup":
{
"from": "wmis_qubos",
"localField": "instance_id",
"foreignField": "instance",
"as": "wmis_qubo"
}
},
{
"$unwind": "$wmis_qubo"
},
{
"$lookup":
{
"from": "embeddings",
"let":
{
"qubo_id": "$wmis_qubo._id",
"solver_graph_id": bson.ObjectId(solver_graph_id)
},
"pipeline":
[
{
"$match":
{
"$expr":
{
"$and":
[
{"$eq": ["$qubo", "$$qubo_id"]},
{"$eq": ["$solver_graph", "$$solver_graph_id"]}
]
}
}
},
{
"$project": { "list": "$embeddings" }
}
],
"as": "embeddings"
}
},
{
"$match": {"embeddings": {"$exists": True, "$not": {"$size": 0}}}
},
{
"$unwind": "$embeddings"
},
{
"$project":
{
"_id": False,
"instance_id": True,
"wmis_qubo": True,
"embeddings": True
}
}
])
def __iter__(self):
return self
def __next__(self):
return self.__query.next()
class WMIS_solver_input_scope_query (WMIS_solver_input_scope_query_raw):
def __next__(self):
doc = super(WMIS_solver_input_scope_query, self).__next__()
data = {}
data["instance_id"] = doc["instance_id"]
data["qubo_id"] = doc["wmis_qubo"]["_id"]
data["qubo"] = read_raw_qubo(doc["wmis_qubo"]["qubo"])
data["embeddings_id"] = doc["embeddings"]["_id"]
data["embeddings"] = []
for raw_emb in doc["embeddings"]["list"]:
data["embeddings"].append(read_raw_embedding(raw_emb))
return data
def load_embedding(collection, qubo_id, solver_graph_id):
doc = collection.find_one(
{
"qubo": bson.ObjectId(qubo_id),
"solver_graph": bson.ObjectId(solver_graph_id)
}
)
if doc == None:
return None
if doc["embeddings"] == None:
return None
if len(doc["embeddings"]) == 0:
return None
return read_raw_embedding(doc["embeddings"][0])
def get_id_of_solver_graph(collection, nx_graph_data):
doc = collection.find_one({"data": nx_graph_data})
if doc == None:
return None
return doc["_id"]
def load_WMIS_qubo_of_instance(collection, instance_id):
doc = load_WMIS_qubo_of_instance_raw(collection, instance_id)
if doc == None:
return None
return read_raw_qubo(doc["qubo"]), doc["_id"]
def get_WMIS_qubo_id_of_instance(collection, instance_id):
doc = load_WMIS_qubo_of_instance_raw(collection, instance_id)
if doc == None:
return None
return doc["_id"]
def load_WMIS_qubo_of_instance_raw(collection, instance_id):
return collection.find_one({"instance": bson.ObjectId(instance_id)})
def read_raw_qubo(raw_qubo):
qubo = {}
for entry in raw_qubo:
energy = entry[1]
raw_coupler = entry[0]
node1 = tuple(raw_coupler[0])
node2 = tuple(raw_coupler[1])
qubo[(node1, node2)] = energy
return qubo
def read_raw_embedding(raw_embedding):
emb = {}
for entry in raw_embedding:
emb[tuple(entry[0])] = entry[1]
return emb

View File

@@ -3,6 +3,7 @@
import numpy as np
import random
from . import kSAT
import math
def generateRandomKSAT(numberOfClauses,
numberOfVariables,
@@ -24,7 +25,7 @@ def generateRandomKSAT(numberOfClauses,
clauses[clauseIndex].append(varIndex + 1)
#fill in the missing bindings
for clause in clauses:
for clauseIndex, clause in enumerate(clauses):
tmpClause = []
clauseIsUnique = False
@@ -44,9 +45,13 @@ def generateRandomKSAT(numberOfClauses,
for i in range(len(tmpClause)):
tmpClause[i] *= random.choice([-1, 1])
tmpClause = list(np.sort(tmpClause))
if tmpClause not in clauses:
clauseIsUnique = True
clauses[clauseIndex] = tmpClause
instance.addClause(tmpClause)
return instance
@@ -64,3 +69,23 @@ def __getVariablesNotYetInClause(clause, numberOfTotalVars):
missingVariables += list(range(prevVar, numberOfTotalVars + 1))
return missingVariables
def number_of_possible_clauses(number_of_variables, variables_per_clause):
return int(__binom(number_of_variables, variables_per_clause)
* __number_of_sign_placements(variables_per_clause))
def __binom(n, k):
if n == k:
return 1
elif k == 1:
return n
else:
return math.factorial(n) / (math.factorial(k) * math.factorial(n - k))
def __number_of_sign_placements(variables_per_clause):
result = 0;
for i in range(variables_per_clause + 1):
result += __binom(variables_per_clause, i)
return result

View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python3
from . import randomSAT
class Random_instance_pool:
def __init__(self, parameter_range):
self.__parameter_range = parameter_range
def __iter__(self):
return self
def __next__(self):
params = self.__parameter_range.next()
return randomSAT.generateRandomKSAT(params.number_of_clauses,
params.number_of_variables,
params.variables_per_clause)
class Instance_parameters:
def __init__(self,
number_of_clauses,
number_of_variables,
variables_per_clause = 3):
self.number_of_clauses = number_of_clauses
self.number_of_variables = number_of_variables
self.variables_per_clause = variables_per_clause
def __str__(self):
return ("number of clauses: {}\n"
"number of variables: {}\n"
"variables per clause: {}").format(self.number_of_clauses,
self.number_of_variables,
self.variables_per_clause)
class Instance_parameter_variable_range:
def __init__(self, start_parameter, variable_range):
self.start_parameter = start_parameter
self.__variable_range = variable_range
def __iter__(self):
return self
def __next__(self):
self.start_parameter.number_of_variables = self.__variable_range.next()
return self.start_parameter
def next(self):
return self.__next__()
class Manual_range:
def __init__(self, start, stop, step = 1):
self.start = start
self.stop = stop
self.step = step
self.__current = start
def __iter__(self):
return self
def __next__(self):
if self.__current >= self.stop:
raise StopIteration
self.__current += self.step
return self.__current
def next(self):
return self.__next__()

View File

@@ -1,6 +1,15 @@
import configparser
import os
import argparse
import pymongo
import ssl
import mysql.connector
import networkx as nx
from . import queries
from . import graph
import minorminer
from tqdm import tqdm
def readConfig(configFilePath):
config = configparser.ConfigParser()
@@ -84,4 +93,177 @@ class ArgParser:
return tmpValue
def getDBContext(dbConfigPath):
dbContext = {}
dbContext["client"] = connect_to_instance_pool(dbConfigPath)
dbContext["db"] = dbContext["client"]["experiments"]
dbContext["instances"] = dbContext["db"]["instances"]
dbContext["experimentScopes"] = dbContext["db"]["experiment_scopes"]
return dbContext
def connect_to_instance_pool(dbConfigPath):
dbConf = readConfig(dbConfigPath)
client = pymongo.MongoClient(
"mongodb://%s:%s@%s:%s/%s"
% ( dbConf["INSTANCE_POOL"]["user"],
dbConf["INSTANCE_POOL"]["pw"],
dbConf["INSTANCE_POOL"]["url"],
dbConf["INSTANCE_POOL"]["port"],
dbConf["INSTANCE_POOL"]["database"]),
ssl=True,
ssl_cert_reqs=ssl.CERT_NONE)
return client[dbConf["INSTANCE_POOL"]["database"]]
def connect_to_experimetns_db(dbConfigPath):
dbConfig = readConfig(dbConfigPath)
return mysql.connector.connect(
host=dbConfig["EXPERIMENT_DB"]["url"],
port=dbConfig["EXPERIMENT_DB"]["port"],
user=dbConfig["EXPERIMENT_DB"]["user"],
password=dbConfig["EXPERIMENT_DB"]["pw"],
database=dbConfig["EXPERIMENT_DB"]["database"]
)
def frange(start, stop, steps):
while start < stop:
yield start
start += steps
def create_experiment_scope(db, description, name):
experimentScope = {}
experimentScope["instances"] = []
experimentScope["description"] = description
experimentScope["_id"] = name.strip()
db["experiment_scopes"].insert_one(experimentScope)
def write_instance_to_pool_db(db, instance):
instance_document = instance.writeJSONLike()
result = db["instances"].insert_one(instance_document)
return result.inserted_id
def add_instance_to_experiment_scope(db, scope_name, instance_id):
db["experiment_scopes"].update_one(
{"_id": scope_name},
{"$push": {"instances": instance_id}}
)
def write_qubo_to_pool_db(collection, qubo, sat_instance_id):
doc = {}
doc["instance"] = sat_instance_id
doc["description"] = {"<qubo>": "<entrys>",
"<entrys>": "<entry><entrys> | <entry> | \"\"",
"<entry>": "<coupler><energy>",
"<energy>": "<real_number>",
"<coupler>": "<node><node>",
"<node>": "<clause><literal>",
"<clause>": "<natural_number>",
"<literal>": "<integer>"}
doc["qubo"] = __qubo_to_JSON(qubo)
collection.insert_one(doc)
def __qubo_to_JSON(qubo):
quboJSON = []
for coupler, value in qubo.items():
quboJSON.append([coupler, float(value)])
return quboJSON
def write_wmis_embedding_to_pool_db(collection, qubo_id, solver_graph_id, embedding):
if not __embedding_entry_exists(collection, qubo_id, solver_graph_id):
__prepare_new_wmis_embedding_entry(collection, qubo_id, solver_graph_id)
collection.update_one(
{"qubo": qubo_id, "solver_graph": solver_graph_id},
{"$push": {"embeddings": __embedding_to_array(embedding)}}
)
def __embedding_entry_exists(collection, qubo_id, solver_graph_id):
filter = {"qubo": qubo_id, "solver_graph": solver_graph_id}
if collection.count_documents(filter) > 0:
return True
return False
def __prepare_new_wmis_embedding_entry(collection, qubo_id, solver_graph_id):
doc = {}
doc["qubo"] = qubo_id
doc["solver_graph"] = solver_graph_id
doc["description"] = {"<embedding>": "<chains>",
"<chains>": "<chain><chains> | \"\"",
"<chain>" : "<original_node><chimera_nodes>",
"<chimera_nodes>": "<chimera_node><chimera_nodes> | \"\""}
doc["embeddings"] = []
collection.insert_one(doc)
def __embedding_to_array(embedding):
emb_arr = []
for node, chain in embedding.items():
emb_arr.append([node, chain])
return emb_arr
def write_solver_graph_to_pool_db(collection, graph):
data = nx.node_link_data(graph)
id = queries.get_id_of_solver_graph(collection, data)
if id != None:
return id
doc = {}
doc["data"] = data
return collection.insert_one(doc).inserted_id
def find_wmis_embeddings_for_scope(db, scope, solver_graph):
solver_graph_id = write_solver_graph_to_pool_db(db["solver_graphs"],
solver_graph)
qubos = queries.WMIS_scope_query(db)
qubos.query(scope)
for qubo, qubo_id in tqdm(qubos):
if not __embedding_entry_exists(db["embeddings"], qubo_id, solver_graph_id):
nx_qubo = graph.qubo_to_nx_graph(qubo)
emb = minorminer.find_embedding(nx_qubo.edges(),
solver_graph.edges(),
return_overlap=True)
if emb[1] == 1:
write_wmis_embedding_to_pool_db(db["embeddings"],
qubo_id,
solver_graph_id,
emb[0])
def save_simulated_annealing_result(collection, result, solver_input, emb_list_index):
doc = {}
doc["data"] = result.to_serializable()
doc["instance"] = solver_input["instance_id"]
doc["embedding"] = {
"embedding_id": solver_input["embeddings_id"],
"list_index": emb_list_index
}
collection.insert_one(doc)