def test_embed_j_index_too_large(): h = [] j = {(0, 1): -1, (0, 2): 1} embeddings = ((0, 1), (2, )) adj = {(0, 1), (1, 2)} with pytest.raises(ValueError): embed_problem(h, j, embeddings, adj)
def test_embed_nonadj(): h = [] j = {(0, 1): 1} embeddings = ((0, 1), (3, 4)) adj = {(0, 1), (1, 2), (2, 3), (3, 4)} with pytest.raises(ValueError): embed_problem(h, j, embeddings, adj)
def test_embed_h_too_large(): h = [1, 2, 3] j = {} embeddings = ((0, 1), (2, )) adj = {(0, 1), (1, 2)} with pytest.raises(ValueError): embed_problem(h, j, embeddings, adj)
def test_embed_bad_chain(): h = [] j = {(0, 1): 1} embeddings = ((0, 2), (1, )) adj = {(0, 1), (1, 2)} with pytest.raises(ValueError): embed_problem(h, j, embeddings, adj)
def test_embed_clean_unused_variables(): h = [0, 0, -1, 0, 0, 0, 1, -2] j = {(1, 2): 1, (1, 3): 2, (2, 3): -2, (2, 7): 1, (3, 7): -1} embeddings = [[10, 11, 12], [5, 6, 7], [15, 14, 13], [4, 3], [0, 1, 2], [16, 17, 18], [8, 9], [20, 19]] adj = {(0, 1), (1, 2), (2, 0), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 10), (10, 9), (9, 8), (10, 11), (11, 12), (12, 10), (7, 14), (14, 15), (14, 13), (15, 3), (14, 16), (16, 17), (17, 18), (16, 18), (15, 19), (19, 20), (20, 3)} expected_h0 = [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -0.5, -0.5, 0.0, 0.0, 0.0, -1.0, -1.0 ] expected_j0 = { (4, 5): 2.0, (15, 19): 1.0, (7, 14): 1.0, (3, 20): -1.0, (3, 15): -2.0 } expected_jc = { (5, 6): -1.0, (14, 15): -1.0, (3, 4): -1.0, (6, 7): -1.0, (19, 20): -1.0 } expected_emb = [[10], [5, 6, 7], [15, 14], [4, 3], [0], [16], [9], [20, 19]] h0, j0, jc, emb = embed_problem(h, j, embeddings, adj, clean=True) assert h0 == expected_h0 assert j0 == expected_j0 assert jc == expected_jc assert emb == expected_emb
def test_embed_smear_jpos(): h = [-6, -2, 8] j = {(0, 1): 3, (1, 2): 1, (0, 2): -6} embeddings = ({0}, [1], {2}) adj = {(0, 1), (0, 2), (1, 2), (3, 0), (4, 3), (5, 1), (5, 6), (2, 7), (2, 8), (7, 8), (7, 9), (8, 9), (0, 7)} h_range = [-4, 1] j_range = [-6, 3] expected_h0 = [-3, -2, 2, -3, 0, 0, 0, 2, 2, 2] expected_j0 = {(0, 1): 3, (1, 2): 1, (0, 2): -3, (0, 7): -3} expected_jc = dict.fromkeys([(0, 3), (2, 7), (2, 8), (7, 8), (7, 9), (8, 9)], -1) expected_emb = [{0, 3}, {1}, {2, 7, 8, 9}] h0, j0, jc, emb = embed_problem(h, j, embeddings, adj, smear=True, h_range=h_range, j_range=j_range) assert [set(e) for e in emb] == expected_emb assert h0 == expected_h0 assert j0 == expected_j0 assert jc == expected_jc
def test_embed_smear_jneg(): h = [80, 100, -12] j = {(0, 1): -60, (1, 2): 8, (3, 2): 1} embeddings = ({0}, [1], {2}, (3, )) adj = {(0, 1), (1, 2), (2, 3)} | set( (x, y) for x in range(4) for y in range(4, 7)) h_range = [-1, 1] j_range = [-10, 12] expected_h0 = [80, 25, -12, 0, 25, 25, 25] expected_j0 = { (0, 1): -15, (0, 4): -15, (0, 5): -15, (0, 6): -15, (1, 2): 2, (2, 4): 2, (2, 5): 2, (2, 6): 2, (2, 3): 1 } expected_jc = dict.fromkeys([(1, 4), (1, 5), (1, 6)], -1) expected_emb = [{0}, {1, 4, 5, 6}, {2}, {3}] h0, j0, jc, emb = embed_problem(h, j, embeddings, adj, smear=True, h_range=h_range, j_range=j_range) assert [set(e) for e in emb] == expected_emb assert h0 == expected_h0 assert j0 == expected_j0 assert jc == expected_jc
def embed_problem_on_dwave(logical, optimization, verbosity, hw_adj_file): """Embed a logical problem in the D-Wave's physical topology. Return a physical Problem object.""" # Embed the problem. Abort on failure. find_dwave_embedding(logical, optimization, verbosity, hw_adj_file) try: h_range = qmasm.solver.properties["h_range"] j_range = qmasm.solver.properties["j_range"] except KeyError: h_range = [-1.0, 1.0] j_range = [-1.0, 1.0] weight_list = qmasm.dict_to_list(logical.weights) smearable = any([s != 0.0 for s in logical.strengths.values()]) try: [new_weights, new_strengths, new_chains, new_embedding] = embed_problem( weight_list, logical.strengths, logical.embedding, logical.hw_adj, True, smearable, h_range, j_range) except ValueError as e: qmasm.abend("Failed to embed the problem in the solver (%s)" % e) # Construct a physical Problem object. physical = copy.deepcopy(logical) physical.embedding = new_embedding physical.embedder_chains = set(new_chains) physical.h_range = h_range physical.j_range = j_range physical.strengths = new_strengths physical.weights = defaultdict(lambda: 0.0, {q: new_weights[q] for q in range(len(new_weights)) if new_weights[q] != 0.0}) physical.pinned = [] for l, v in logical.pinned: physical.pinned.extend([(p, v) for p in physical.embedding[l]]) return physical
def embed_problem_on_dwave(logical, optimize, verbosity): """Embed a logical problem in the D-Wave's physical topology. Return a physical Problem object.""" # Embed the problem. Abort on failure. find_dwave_embedding(logical, optimize, verbosity) try: h_range = qmasm.solver.properties["h_range"] j_range = qmasm.solver.properties["j_range"] except KeyError: h_range = [-1.0, 1.0] j_range = [-1.0, 1.0] weight_list = qmasm.dict_to_list(logical.weights) smearable = any([s != 0.0 for s in list(logical.strengths.values())]) try: [new_weights, new_strengths, new_chains, new_embedding] = embed_problem( weight_list, logical.strengths, logical.embedding, logical.hw_adj, True, smearable, h_range, j_range) except ValueError as e: qmasm.abend("Failed to embed the problem in the solver (%s)" % e) # Construct a physical Problem object. physical = copy.deepcopy(logical) physical.chains = new_chains physical.embedding = new_embedding physical.h_range = h_range physical.j_range = j_range physical.strengths = new_strengths physical.weights = defaultdict(lambda: 0.0, {q: new_weights[q] for q in range(len(new_weights)) if new_weights[q] != 0.0}) physical.pinned = [] for l, v in logical.pinned: physical.pinned.extend([(p, v) for p in physical.embedding[l]]) return physical
def sapi_refine_modularity( graph, solver, hardware_size, # max size subproblem ptn_variables, # ptn_variables[node] = 0,1,'free' num_reads, annealing_time, embeddings=False, # if false, get fast embedding ): sub_B_matrix, bias, constant = get_sub_mod_matrix(graph, ptn_variables) n = sub_B_matrix.shape[0] if n > hardware_size: print n, hardware_size raise ValueError('Number free variables exceeds hardware size') coupler = {} # we add negative because we maximize modularity bias = [-i for i in bias] for i in range(n - 1): for j in range(i + 1, n): coupler[(i, j)] = -sub_B_matrix.item((i, j)) coupler[(j, i)] = -sub_B_matrix.item((j, i)) A = get_hardware_adjacency(solver) #print "embedding..." if not embeddings: print 'finding embedding ....' embeddings = find_embedding(coupler, A, verbose=0, fast_embedding=True) (h0, j0, jc, new_emb) = embed_problem(bias, coupler, embeddings, A, clean=True, smear=True) emb_j = j0.copy() emb_j.update(jc) #print "On DWave..." result = solve_ising(solver, h0, emb_j, num_reads=num_reads, annealing_time=annealing_time) #print result #print "On DWave...COMPLETE" energies = result['energies'] #print energies #print result['solutions'] #print min(energies), max(energies) new_answer = unembed_answer(result['solutions'], new_emb, 'minimize_energy', bias, coupler) min_energy = 10**10 best_soln = [] for i, ans in enumerate(new_answer): soln = ans[0:n] assert 3 not in soln en = energies[i] if en < min_energy: #print 'energy', en min_energy = en best_soln = copy.deepcopy(soln) return get_new_partition(best_soln, ptn_variables)
def test_embed_bad_hj_range(): h = [] j = {(0, 1): 1} embeddings = [[0], [1]] adj = {(0, 1)} with pytest.raises(ValueError): embed_problem(h, j, embeddings, adj, smear=True, h_range=[0, 1]) with pytest.raises(ValueError): embed_problem(h, j, embeddings, adj, smear=True, h_range=[-1, 0]) with pytest.raises(ValueError): embed_problem(h, j, embeddings, adj, smear=True, j_range=[0, 1]) with pytest.raises(ValueError): embed_problem(h, j, embeddings, adj, smear=True, j_range=[-1, 0])
def sample(self, model, num_samples, temperature=1, batch_size=None, embedding=None): # Determine the batch size batch_size = batch_size or min(10000, num_samples) # Extract the model and get h and J formatted for D-Wave API h_dwave, J_dwave = model.as_dwave() # Find the embedding if embedding is None: embedding = self.find_best_embedding(J_dwave).data #self.info(embedding) # Transform J and h using found graph embedding # embed_model can still do some changes to the embedding h_embedded, J_embedded, J_couplings, final_embedding = embed_problem( h_dwave, J_dwave, embedding, adj=self.adjacency_matrix, h_range=(-2, 2), j_range=(-1, 1)) # Compute max coefficient max_coefficient = max([ abs(max(h_embedded)), abs(min(h_embedded)), abs(max(J_embedded.values())), abs(min(J_embedded.values())) ]) # Update J matrix J_embedded.update( {key: -1.0 * max_coefficient for key in J_couplings.keys()}) results = self.query_dwave(h_embedded, J_embedded, final_embedding, num_samples, temperature, batch_size) samples = [ IsingSample(model, assignment, occurences) for (assignment, occurences) in results ] # Return as a sorted list sorted_solutions = SamplePool(samples) return sorted_solutions
def test_embed_typical(): h = [1, 10] j = {(0, 1): 15, (2, 1): -8, (0, 2): 5, (2, 0): -2} embeddings = [[1], [2, 3], [0]] adj = {(0, 1), (1, 2), (2, 3), (3, 0), (2, 0)} expected_h0 = [0, 1, 5, 5] expected_j0 = {(0, 1): 3, (0, 2): -4, (0, 3): -4, (1, 2): 15} expected_jc = {(2, 3): -1} h0, j0, jc, emb = embed_problem(h, j, embeddings, adj) assert h0 == expected_h0 assert j0 == expected_j0 assert jc == expected_jc assert emb == embeddings
def embedding_example(): # formulate k_6 structured graph h = [1, 1, 1, 1, 1, 1] J = {(i, j): 1 for i in range(6) for j in range(i)} solver = local_connection.get_solver("c4-sw_optimize") A = get_hardware_adjacency(solver) # find and print embeddings for problem graph embeddings = find_embedding(J, A, verbose=1) print "embeddings are: ", embeddings # embed the problem into solver graph (h0, j0, jc, new_emb) = embed_problem(h, J, embeddings, A) print "embedded problem result:\nj0: ", j0 print "jc: ", jc # find unembedded results for chain strengths -0.5, -1.0, -2.0 for chain_strength in (-0.5, -1.0, -2.0): # set chain strength values jc = dict.fromkeys(jc, chain_strength) # create new J array concatenating j0 with jc emb_j = j0.copy() emb_j.update(jc) # solve embedded problem answer = solve_ising(solver, h0, emb_j, num_reads=10) # unembed and print result of the form: # solution [solution #] # var [var #] : [var value] ([qubit index] : [original qubit value] ...) result = unembed_answer(answer['solutions'], new_emb, broken_chains="minimize_energy", h=h, j=J) print "result for chain strength = ", chain_strength for i, (embsol, sol) in enumerate(zip(answer['solutions'], result)): print "solution", i for j, emb in enumerate(embeddings): print "var %d: %d (" % (j, sol[j]), for k in emb: print "%d:%d" % (k, embsol[k]), print ")"
def embed_problem(self, s, j): """ Use the new embedding to set up a new Ising model that we will actually send to the solver """ h = [] (h0, j0, jc, new_emb) = dw_embedding.embed_problem(h, j, self._emb, self._A) if self._verbose: print "h0:", h0 print "j0:", j0 print "jc:", jc print "new embedding:", new_emb # scale the network edge weights, j0, by s before adding the chain weights, jc. j_emb = {t: s * j0[t] for t in j0} j_emb.update(jc) if self._verbose: print "new j (s scaled):", j_emb return Ising(h0, j_emb, new_emb, j)
def test_embed_clean(): h = [-2, 4, -5, 14] j = {(0, 1): 2, (1, 2): -3, (2, 3): -18, (3, 0): -7} embeddings = [[7, 4], [1, 9], (0, 2), {3, 5, 6, 8}] adj = {(0, 2), (2, 9), (9, 1), (1, 7), (7, 4), (4, 3), (3, 5), (5, 2), (0, 7), (4, 9), (3, 2), (5, 8), (8, 6), (6, 1), (8, 9)} expected_h0 = [0, 2, -5, 7, -1, 7, 0, -1, 0, 2] expected_j0 = { (1, 7): 1, (4, 9): 1, (2, 9): -3, (2, 3): -9, (2, 5): -9, (3, 4): -7 } expected_jc = dict.fromkeys([(4, 7), (1, 9), (3, 5)], -1) expected_emb = [[7, 4], [1, 9], [2], [3, 5]] h0, j0, jc, emb = embed_problem(h, j, embeddings, adj, clean=True) assert h0 == expected_h0 assert j0 == expected_j0 assert jc == expected_jc assert emb == expected_emb
def test_embed_smear_empty_j(): h = [1, 2, 3] j = {} embeddings = [[0], [1], [2]] adj = [(0, 1), (0, 2), (2, 1)] h_range = [-1, 1] j_range = [-30, 30] expected_h0 = [1, 2, 3] expected_j0 = {} expected_jc = {} expected_emb = [{0}, {1}, {2}] h0, j0, jc, emb = embed_problem(h, j, embeddings, adj, smear=True, h_range=h_range, j_range=j_range) assert [set(e) for e in emb] == expected_emb assert h0 == expected_h0 assert j0 == expected_j0 assert jc == expected_jc
def test_embed_trivial(): h0, j0, jc, emb = embed_problem([], {}, [], []) assert h0 == [] assert j0 == {} assert jc == {} assert emb == []
def solvequbo(self): # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # EMBEDDING: # gets the hardware adjacency for the solver in use. self.Adjacency = get_hardware_adjacency(self.solver) # gets the embedding for the D-Wave hardware self.Embedding = find_embedding(self.qubo_dict, self.Adjacency) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # CONVERSIONS AND RESCALING: # convert qubo to ising (self.h, self.J, self.ising_offset) = qubo_to_ising(self.qubo_dict) # Even though auto_scale = TRUE, we are rescaling values # Normalize h and J to be between +/-1 self.h_max = max(map(abs, self.h)) if len(self.J.values()) > 0: j_max = max([abs(x) for x in self.J.values()]) else: j_max = 1 # In [0,1], this scales down J values to be less than jc j_scale = 0.8 # Use the largest large value if self.h_max > j_max: j_max = self.h_max # This is the actual scaling rescale = j_scale / j_max self.h1 = map(lambda x: rescale * x, self.h) if len(self.J.values()) > 0: self.J1 = {key: rescale * val for key, val in self.J.items()} else: self.J1 = self.J # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # EMBEDDING: # gets the hardware adjacency for the solver in use. self.Adjacency = get_hardware_adjacency(self.solver) # gets the embedding for the D-Wave hardware self.Embedding = find_embedding(self.qubo_dict, self.Adjacency) # Embed the rescale values into the hardware graph [self.h0, self.j0, self.jc, self.Embedding ] = embed_problem(self.h1, self.J1, self.Embedding, self.Adjacency, self.clean, self.smear, self.h_range, self.J_range) # embed_problem returns two J's, one for the biases from your problem, one for the chains. self.j0.update(self.jc) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # SOLVE PROBLEM ON D-WAVE: # generate the embedded solution to the ising problem. self.dwave_return = solve_ising(self.solver, self.h0, self.j0, **self.params) #print("dwave_return") #print(self.dwave_return['solutions']) # the unembedded answer to the ising problem. unembed = np.array( unembed_answer(self.dwave_return['solutions'], self.Embedding, broken_chains="minimize_energy", h=self.h, j=self.J)) #[0] # convert ising string to qubo string ising_ans = [ list(filter(lambda a: a != 3, unembed[i])) for i in range(len(unembed)) ] #print(ising_ans) #print("ISING ANS") # Because the problem is unembedded, the energy will be different for the embedded, and unembedded problem. # ising_energies = dwave_return['energies'] self.h_energy = [ sum(self.h1[v] * val for v, val in enumerate(unembed[i])) for i in range(len(unembed)) ] self.J_energy = [ sum(self.J1[(u, v)] * unembed[i, u] * unembed[i, v] for u, v in self.J1) for i in range(len(unembed)) ] self.ising_energies = np.array(self.h_energy) + np.array(self.J_energy) #print(self.h_energy) #print(self.J_energy) #print(self.ising_energies) #print("ENERGIES") # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # CONVERT ANSWER WITH ENERGY TO QUBO FORM: # Rescale and add back in the ising_offset and another constant self.dwave_energies = self.ising_energies / rescale + self.ising_offset #[map(lambda x: (x / rescale + self.ising_offset), self.ising_energies[i]) for i in range(len(self.ising_energies))] # QUBO RESULTS: self.qubo_ans = ( np.array(ising_ans) + 1 ) / 2 #[map(lambda x: (x + 1) / 2, ising_ans[i]) for i in range(len(ising_ans))]
def sample_ising(self, h, J, embedding_tag=None, **sapi_kwargs): """Embeds the given problem using sapi's find_embedding then invokes the given sampler to solve it. Args: h (dict/list): The linear terms in the Ising problem. If a dict, should be of the form {v: bias, ...} where v is a variable in the Ising problem, and bias is the linear bias associated with v. If a list, should be of the form [bias, ...] where the indices of the biases are the variables in the Ising problem. J (dict): A dictionary of the quadratic terms in the Ising problem. Should be of the form {(u, v): bias} where u, v are variables in the Ising problem and bias is the quadratic bias associated with u, v. embedding_tag: Allows the user to specify a tag for the generated embedding. Useful for when the user wishes to submit multiple problems with the same logical structure. Additional keyword parameters are the same as for SAPI's solve_ising function, see QUBIST documentation. Returns: :class:`dimod.SpinResponse`: The unembedded samples. Examples: >>> sampler = sapi.EmbeddingComposite(sapi.SAPILocalSampler('c4-sw_optimize')) >>> response = sampler.sample_ising({}, {(0, 1): 1, (0, 2): 1, (1, 2): 1}) Using the embedding_tag, the embedding is generated only once. >>> h = {0: .1, 1: 1.3, 2: -1.} >>> J = {(0, 1): 1, (1, 2): 1, (0, 2): 1} >>> sampler = sapi.EmbeddingComposite(sapi.SAPILocalSampler('c4-sw_optimize')) >>> response0 = sampler.sample_ising(h, J, embedding_tag='K3') >>> response1 = sampler.sample_ising(h, J, embedding_tag='K3') """ # get the sampler that is used by the composite sampler = self._child # the ising_index_labels decorator converted the keys of h to be indices 0, n-1 # sapi wants h to be a list, so let's make that conversion, using the keys as # the indices. h_list = [h[v] for v in range(len(h))] # get the structure of the child sampler. The first value are the nodes which # we don't need, the second is the set of edges available. (__, edgeset) = sampler.structure if embedding_tag is None or embedding_tag not in self.cached_embeddings: # we have not previously cached an embedding so we need to determine it # get the adjacency structure of our problem S = set(J) S.update({(v, v) for v in h}) # embed our adjacency structure, S, into the edgeset of the sampler. embeddings = find_embedding(S, edgeset) # sometimes it fails, often because the problem is too large if J and not embeddings: raise Exception('No embedding found') # now it is possible that h_list might include nodes not in embedding, so let's # handle that case here if len(h_list) > len(embeddings): emb_qubits = set().union(*embeddings) while len(h_list) > len(embeddings): for v in sampler.solver.properties['qubits']: if v not in emb_qubits: embeddings.append([v]) emb_qubits.add(v) break if embedding_tag is not None: # save the embedding for posterity self.cached_embeddings[embedding_tag] = embeddings else: # the user has asserted that we can reuse a previously created embedding embeddings = self.cached_embeddings[embedding_tag] # embed the problem h0, j0, jc, new_emb = embed_problem(h_list, J, embeddings, edgeset) # combine jc and j0 emb_j = j0.copy() emb_j.update(jc) # pass the chains we made into the sampler if it wants them if 'chains' in sampler.solver.properties['parameters'] and 'chains' not in sapi_kwargs: sapi_kwargs['chains'] = new_emb # invoke the child sampler emb_response = sampler.sample_ising(h0, emb_j, **sapi_kwargs) # we need the samples back into lists for the unembed_answer function answers = [[sample[i] for i in range(len(sample))] for sample in emb_response] # unemnbed solutions = unembed_answer(answers, new_emb, 'minimize_energy', h_list, J) # and back once again into dicts for dimod... samples = ({v: sample[v] for v in h} for sample in solutions) sample_data = (data for __, data in emb_response.samples(data=True)) response = dimod.SpinResponse() response.add_samples_from(samples, sample_data=sample_data, h=h, J=J) return response
def dwave(pot, states): if pot['num vars'] > 0: solved = False const = 0 h_ = [] J_ = {} state = [] free_state = [] embedding = [] while not solved: try: #global solver #global adj #if solver == 0: sign_in() #should try to make it so there is a pool of pool_size connections that the various threads can use remote_connection = RemoteConnection(url, token) solver = remote_connection.get_solver(solver_name) adj = list(get_hardware_adjacency(solver)) if 'embedding' in pot: const, h_, j, prob_adj = dwave_prepare(pot) embedding = pot['embedding'] else: # if we're doing a new embedding for each f -> v in state i message, then we'll have frozen a variable # so we need to remap the variables, since otherwise the h will have a 0 for this variable, but the embedding won't consider it map_vars(pot) const, h_, j, prob_adj = dwave_prepare(pot) while len(embedding) == 0: embedding = find_embedding(prob_adj, adj).values() [h, J, chains, embedding] = embed_problem(h_, j, embedding, adj) s = 0.50 h = [a * s for a in h] for k in J: J[k] = J[k] * s for k in chains: if k in J: J[k] += chains[k] else: J[k] = chains[k] # Submit problem #print('submitting problem') submitted_problems = [ async_solve_ising(solver, h, J, num_reads=10000, num_spin_reversal_transforms=5, answer_mode='histogram', auto_scale=True) ] await_completion(submitted_problems, len(submitted_problems), float('180')) res = unembed_answer( submitted_problems[0].result()['solutions'], embedding, 'discard') if len(res) > 0: state = array(res[0]) solved = True except Exception as err: print(err) solved = False #sleep(30) # wait 30 seconds and retry if len(h_) != len(state): print(h_, len(h_)) print(state, len(state)) print(pot) J_, _ = dict_2_mat(j, len(h_)) energy = h_.dot(state) + state.dot(J_.dot(state.transpose())) + const #for v in sorted(free_state): # energy += pot[v]*free_state[v] # state = append(state, free_state[v]) return energy, state else: if 'const' in pot: return pot['const'], states[0] else: return 0, states[0]
h = [-1,0,0,0] connection = RemoteConnection(DWAVE_SAPI_URL, DWAVE_TOKEN) solver = connection.get_solver(DWAVE_SOLVER) # first get the adjacency matrix of the current hardware graph: adjacency = get_hardware_adjacency(solver) # Now let's try to find an embedding of our problem: embedding = find_embedding(J.keys(), adjacency) # We are now ready to embed our problem onto the graph: [h, j0, jc, embeddings] = embed_problem(h, J, embedding, adjacency) # j0 contains the original couplings that we defined and jc contains the couplings that enforce the integrity of the chains (they correlate the qubits within the chains). Thus, we need to combine them again into one big J dictionary: J = j0.copy() J.update(jc) # Now, we're ready to solve the embedded problem: params = {"answer_mode": 'histogram', "num_reads": 10000} raw_results = solve_ising(solver, h, J, **params) print 'Lowest energy found: {}'.format(raw_results['energies']) print 'Number of occurences: {}'.format(raw_results['num_occurrences']) unembedded_results = unembed_answer(raw_results['solutions'], embedding, broken_chains='vote')
#~ #~ Embedding a problem is accomplished by #~ #~ * if two qubits are in the same chain, and adjacent in `hardware_adj`, then #~ the coupler between them is set to -1. #~ * if two qubits are in different chains whose variables interact (all #~ pairs of variables interact in this particular example) then their #~ interaction is distributed among the couplers which have ends in both #~ chains. (that is, the sum of the coupler values is equal to the #~ corresponding :math:`J_{i,j}`) #~ * the variable biases are distributed among the qubit biases, #~ that is, the qubit biases in the chain corresponding to variable :math:`i` sum #~ to :math:`h_i`. #~ (emb_h, prob_J, chain_J, new_emb) = embed_problem(h, J, embedding, hardware_adj) #~ #~ Setting the chain strength #~ -------------------------- #~ #~ We're nearly ready to solve our problem, but first we need to combine the #~ problem interactions with the chain interactions. Above, we said that the #~ couplers between adjacent qubits in a chain are set to -1, but the story #~ is a little more interesting than that. #~ #~ The matter of chain interactions is still poorly-understood. One expects #~ better chain performance (that is, for qubits in chains to have the same #~ spin) with a higher chain strength, but if the chain strength is set too #~ high, then the problem interactions will suffer a loss of precision. A #~ plausible heuristic is to set the chain strength to :math:`\sqrt{n}` to
#~ Embedding a problem is accomplished by #~ #~ * if two qubits are in the same chain, and adjacent in `hardware_adj`, then #~ the coupler between them is set to -1. #~ * if two qubits are in different chains whose variables interact (all #~ pairs of variables interact in this particular example) then their #~ interaction is distributed among the couplers which have ends in both #~ chains. (that is, the sum of the coupler values is equal to the #~ corresponding :math:`J_{i,j}`) #~ * the variable biases are distributed among the qubit biases, #~ that is, the qubit biases in the chain corresponding to variable :math:`i` sum #~ to :math:`h_i`. #~ flat_embedding = embedding[0] + embedding[1] (emb_h, prob_J, chain_J, new_emb) = embed_problem(h, J, flat_embedding, hardware_adj) #~ #~ Setting the chain strength #~ -------------------------- #~ #~ We're nearly ready to solve our problem, but first we need to combine the #~ problem interactions with the chain interactions. Above, we said that the #~ couplers between adjacent qubits in a chain are set to -1, but the story #~ is a little more interesting than that. #~ #~ The matter of chain interactions is still poorly-understood. One expects #~ better chain performance (that is, for qubits in chains to have the same #~ spin) with a higher chain strength, but if the chain strength is set too #~ high, then the problem interactions will suffer a loss of precision. A #~ plausible heuristic is to set the chain strength to :math:`\sqrt{n}` to
def runDW(h, J, embedding, stop_point=0.25, num_reads=1000, coupling_init=1.0, coupling_increment=0.1, min_solver_calls=1, max_solver_calls=1000, method='vote', last=True, num_gauges=1, solver_name='NASA', annealing_time=20): ''' Submits an instance to DW. Parameters ----- h : list, a list of fields J : a dictionary, where keys are a tuple corresponding to the coupling embedding : a list of lists. Can use DW sapi to generate stop_point :float, default: 0.25. Stop increasing coupling strength when returns at least this fraction of solutions are unbroken. num_reads: int, default: 1000. The number of reads. coupling_init: float, default: 1.0. The initial value of coupling, the value of the ferromagnetic coupling between physical qubits. If number of unbroken of solutions is not at least stop_point, then the magnitude of coupling is incremented by coupling_increment. Note however, that the though we specify coupling_init as positive, the coupling is negative. For example, Suppose coupling_init=1.0, coupling_increment (defined below) is 0.1, and stop_point = 0.25. The initial physical ferromagnetic coupling strength will be -1.0. If stop_point isn't reached, coupling is incremented by 0.1, or in other words, the new chain strength is -1.1. coupling is incremented by coupling_increment until stop_point is reached. coupling_increment: float, default: 0.1. Increment of coupling strength, min_solver_calls: int, default: 1. The minimum number of solver calls. max_solver_calls: int, default: 1000. The maximum number of solver calls. method: str, 'minimize_energy', 'vote', or 'discard', default: 'minimize_energy' How to deal with broken chains. 'minimize_energy' uses the energy minimization decoding. 'vote' uses majority vote decoding. 'discard' discard broken chains. last: bool, default: True If True, return the last num_reads solutions. If False, return the first num_reads solutions. num_gauges: int, default: 1 Number of gauge transformations. solver_name: str, 'NASA', 'ISI', or 'DW', default: 'NASA' Which solver to use. 'NASA' uses NASA's DW2000Q. 'ISI' uses ISI's DW2X. 'DW' uses DW's DW2000Q. Returns ------- A tuple of sols, c, ratio sols: numpy ndarray, shape = [num_reads, num_spins] Solutions where each row is a set of spins (num_spins dependent on solver) c: float The final value of the coupling strength used ratio: float The final fraction of unbroken solutions returned at coupling_strength c ''' meths = ['discard', 'vote', 'minimize_energy'] assert (method in meths) solver = connectSolver(solver_name) A = get_hardware_adjacency(solver) # embed problem (h0, j0, jc, new_emb) = embed_problem(h, J, embedding, A) # scale problem maxjh = max(max(np.abs(h0)), max(np.abs(j0.values()))) h0 = [el / maxjh for el in h0] j0 = {ij: v / maxjh for ij, v in zip(j0.keys(), j0.values())} ratio = 0 sols = [] ncalls = 0 l = coupling_init print coupling_init jc = dict.fromkeys(jc, -l) emb_j = j0.copy() emb_j.update(jc) kwargs = { 'num_reads': num_reads, 'num_spin_reversal_transforms': num_gauges, 'answer_mode': 'raw', 'annealing_time': annealing_time } # iteratively increase ferromagentic strength until returns a certain ratio # of solutions where there are no broken chains while ratio <= stop_point and ncalls < max_solver_calls: jc = dict.fromkeys(jc, -l) emb_j = j0.copy() emb_j.update(jc) if solver_name == 'ISI': _check_wait() problem = async_solve_ising(solver, h0, emb_j, **kwargs) await_completion([problem], 1, 50000) answer = problem.result() result = unembed_answer(answer['solutions'], new_emb, broken_chains='discard', h=h, j=J) sols += result nSols = len(result) l = l + coupling_increment ratio = nSols / float(len(answer['solutions'])) ncalls = ncalls + 1 print ratio # Don't remember why do this. Maybe for good measure if method == 'discard': nAdd = int(1 / ratio) + 1 else: nAdd = 1 l = l - coupling_increment for n in range(nAdd): if solver_name == 'ISI': _check_wait() problem = async_solve_ising(solver, h0, emb_j, **kwargs) await_completion([problem], 1, 50000) answer = problem.result() result = unembed_answer(answer['solutions'], new_emb, broken_chains=method, h=h, j=J) sols += result if len(sols) < num_reads: # try one more time problem = async_solve_ising(solver, h0, emb_j, **kwargs) await_completion([problem], 1, 50000) answer = problem.result() result = unembed_answer(answer['solutions'], new_emb, broken_chains=method, h=h, j=J) sols += result if last: if len(sols) >= num_reads: sols = sols[-num_reads:] else: print 'WARNING! DID NOT COLLECT ENOUGH READS...continuing' else: sols = sols[:num_reads] return (np.array(sols, dtype=np.int8), l, ratio)
def anneal(C_i, C_ij, mu, sigma, l, strength_scale, energy_fraction, ngauges, max_excited_states): url = "https://usci.qcc.isi.edu/sapi" token = "your-token" h = np.zeros(len(C_i)) J = {} for i in range(len(C_i)): h_i = -2 * sigma[i] * C_i[i] for j in range(len(C_ij[0])): if j > i: J[(i, j)] = 2 * C_ij[i][j] * sigma[i] * sigma[j] h_i += 2 * (sigma[i] * C_ij[i][j] * mu[j]) h[i] = h_i vals = np.array(J.values()) cutoff = np.percentile(vals, AUGMENT_CUTOFF_PERCENTILE) to_delete = [] for k, v in J.items(): if v < cutoff: to_delete.append(k) for k in to_delete: del J[k] isingpartial = [] if FIXING_VARIABLES: Q, _ = ising_to_qubo(h, J) simple = fix_variables(Q, method='standard') new_Q = simple['new_Q'] print('new length', len(new_Q)) isingpartial = simple['fixed_variables'] if (not FIXING_VARIABLES) or len(new_Q) > 0: cant_connect = True while cant_connect: try: print('about to call remote') conn = dwave_sapi2.remote.RemoteConnection(url, token) solver = conn.get_solver("DW2X") print('called remote', conn) cant_connect = False except IOError: print('Network error, trying again', datetime.datetime.now()) time.sleep(10) cant_connect = True A = get_hardware_adjacency(solver) mapping = [] offset = 0 for i in range(len(C_i)): if i in isingpartial: mapping.append(None) offset += 1 else: mapping.append(i - offset) if FIXING_VARIABLES: new_Q_mapped = {} for (first, second), val in new_Q.items(): new_Q_mapped[(mapping[first], mapping[second])] = val h, J, _ = qubo_to_ising(new_Q_mapped) # run gauges nreads = 200 qaresults = np.zeros((ngauges * nreads, len(h))) for g in range(ngauges): embedded = False for attempt in range(5): a = np.sign(np.random.rand(len(h)) - 0.5) h_gauge = h * a J_gauge = {} for i in range(len(h)): for j in range(len(h)): if (i, j) in J: J_gauge[(i, j)] = J[(i, j)] * a[i] * a[j] embeddings = find_embedding(J.keys(), A) try: (h0, j0, jc, new_emb) = embed_problem(h_gauge, J_gauge, embeddings, A, True, True) embedded = True break except ValueError: # no embedding found print('no embedding found') embedded = False continue if not embedded: continue # adjust chain strength rescale_couplers = strength_scale * max( np.amax(np.abs(np.array(h0))), np.amax(np.abs(np.array(list(j0.values()))))) # print('scaling by', rescale_couplers) for k, v in j0.items(): j0[k] /= strength_scale for i in range(len(h0)): h0[i] /= strength_scale emb_j = j0.copy() emb_j.update(jc) print("Quantum annealing") try_again = True while try_again: try: qaresult = solve_ising(solver, h0, emb_j, num_reads=nreads, annealing_time=a_time, answer_mode='raw') try_again = False except: print('runtime or ioerror, trying again') time.sleep(10) try_again = True print("Quantum done") qaresult = np.array( unembed_answer(qaresult["solutions"], new_emb, 'vote', h_gauge, J_gauge)) qaresult = qaresult * a qaresults[g * nreads:(g + 1) * nreads] = qaresult if FIXING_VARIABLES: j = 0 for i in range(len(C_i)): if i in isingpartial: full_strings[:, i] = 2 * isingpartial[i] - 1 else: full_strings[:, i] = qaresults[:, j] j += 1 else: full_strings = qaresults s = full_strings energies = np.zeros(len(qaresults)) s[np.where(s > 1)] = 1.0 s[np.where(s < -1)] = -1.0 bits = len(s[0]) for i in range(bits): energies += 2 * s[:, i] * (-sigma[i] * C_i[i]) for j in range(bits): if j > i: energies += 2 * s[:, i] * s[:, j] * sigma[i] * sigma[ j] * C_ij[i][j] energies += 2 * s[:, i] * sigma[i] * C_ij[i][j] * mu[j] unique_energies, unique_indices = np.unique(energies, return_index=True) ground_energy = np.amin(unique_energies) # print('ground energy', ground_energy) if ground_energy < 0: threshold_energy = (1 - energy_fraction) * ground_energy else: threshold_energy = (1 + energy_fraction) * ground_energy lowest = np.where(unique_energies < threshold_energy) unique_indices = unique_indices[lowest] if len(unique_indices) > max_excited_states: sorted_indices = np.argsort( energies[unique_indices])[-max_excited_states:] unique_indices = unique_indices[sorted_indices] final_answers = full_strings[unique_indices] print('number of selected excited states', len(final_answers)) return final_answers else: final_answer = [] for i in range(len(C_i)): if i in isingpartial: final_answer.append(2 * isingpartial[i] - 1) final_answer = np.array(final_answer) return np.array([final_answer])
def runDW_batch(h, J, embedding, stop_point=0.25, num_reads=1000, coupling_init=1.0, coupling_increment=0.1, min_solver_calls=1, max_solver_calls=1000, method='vote', last=True, num_gauges=1, solver_name='NASA', returnProblems=True): ''' Submits an instance to DW as a batch. Note that when used, sometimes the solutions are markedly different than when use runDW (no batch). Generally using run_DW() seems to be a better idea Parameters ----- h : list of lists, with each list is a list of fields J : a list of dictionary, where keys are a tuple corresponding to the coupling. Should be the same length as h. embedding : a list of lists. Can use DW sapi to generate stop_point :float, default: 0.25. Stop increasing coupling strength when returns at least this fraction of solutions are unbroken. num_reads: int, default: 1000. The number of reads. coupling_init: float, default: 1.0. The initial value of coupling, the value of the ferromagnetic coupling between physical qubits. If number of unbroken of solutions is not at least stop_point, then the magnitude of coupling is incremented by coupling_increment. Note however, that the though we specify coupling_init as positive, the coupling is negative. For example, Suppose coupling_init=1.0, coupling_increment (defined below) is 0.1, and stop_point = 0.25. The initial physical ferromagnetic coupling strength will be -1.0. If stop_point isn't reached, coupling is incremented by 0.1, or in other words, the new chain strength is -1.1. coupling is incremented by coupling_increment until stop_point is reached. coupling_increment: float, default: 0.1. Increment of coupling strength, min_solver_calls: int, default: 1. The minimum number of solver calls. max_solver_calls: int, default: 1000. The maximum number of solver calls. method: str, 'minimize_energy', 'vote', or 'discard', default: 'minimize_energy' How to deal with broken chains. 'minimize_energy' uses the energy minimization decoding. 'vote' uses majority vote decoding. 'discard' discard broken chains. last: bool, default: True If True, return the last num_reads solutions. If False, return the first num_reads solutions. num_gauges: int, default: 1 Number of gauge transformations. solver_name: str, 'NASA', 'ISI', or 'DW', default: 'NASA' Which solver to use. 'NASA' uses NASA's DW2000Q. 'ISI' uses ISI's DW2X. 'DW' uses DW's DW2000Q. returnProblems: bool Determines what it returns. If True, return problems, new_emb. If False return solutions only Returns ------- if returnProblems is True, returns problems, new_emb (to be used with get_async_sols) problems: list list of problems from async_solve_ising new_emb: list list of embeddings returned from embed_problem if returnProblems is False, returns solutions sols: np array Array of solutions ''' meths = ['discard', 'vote', 'minimize_energy'] assert (method in meths) if solver_name == 'NASA': url = 'https://qfe.nas.nasa.gov/sapi' token = 'NASA-870f7ee194d029923ad8f9cd063de357ba53b838' remote_connection = RemoteConnection(url, token) solver = remote_connection.get_solver('C16') elif solver_name == 'ISI': url = 'https://usci.qcc.isi.edu/sapi' token = 'QUCB-089028555cb44b4f3da34cd4c6dd4a73ec859bc8' remote_connection = RemoteConnection(url, token) solver = remote_connection.get_solver('DW2X') elif solver_name == 'DW': url = 'https://cloud.dwavesys.com/sapi' token = 'usc-171bafd63a1b07635fd696db283ad4c28b820d14' remote_connection = RemoteConnection(url, token) solver = remote_connection.get_solver('DW_2000Q_2_1') else: NameError('Unrecognized solver name') A = get_hardware_adjacency(solver) h0 = [] j0 = [] jc = [] new_emb = [] for n in range(len(h)): (h0t, j0t, jct, new_embt) = embed_problem(h[0], J[0], embedding, A) maxjh = max(max(np.abs(h0t)), max(np.abs(j0t.values()))) h0t = [el / maxjh for el in h0t] j0t = {ij: v / maxjh for ij, v in zip(j0t.keys(), j0t.values())} h0.append(h0t) j0.append(j0t) jc.append(jct) new_emb.append(new_embt) ncalls = 0 sols = np.empty(len(h0), dtype=object) if isinstance(coupling_init, list): l = coupling_init else: l = [coupling_init] * len(h) print np.unique(l) kwargs = { 'num_reads': num_reads, 'num_spin_reversal_transforms': num_gauges, 'answer_mode': 'raw' } problem = [] for n in range(len(h0)): jct = dict.fromkeys(jc[n], -l[n]) emb_j = j0[n].copy() emb_j.update(jct) if solver_name == 'ISI': _check_wait() problem.append(async_solve_ising(solver, h0[n], emb_j, **kwargs)) await_completion(problem, len(h), 50000) if returnProblems: return problem, new_emb for n in range(len(h0)): answer = problem[n].result() sols[n] = np.array(unembed_answer(answer['solutions'], new_emb[n], broken_chains=method, h=h[n], j=J[n]), dtype=np.int8) # return problem,new_emb return np.array(sols)
S.append((i, j)) print S emb = embedding.find_embedding(S, A, verbose=1) print emb Q = {(0, 0): 1, (1, 1): 1, (2, 2): 1, (0, 1): 1, (0, 2): -2, (1, 2): -2} (h, j, ising_offset) = util.qubo_to_ising(Q) print "h:", h print "j:", j print "ising_offset:", ising_offset (h0, j0, jc, new_emb) = embedding.embed_problem(h, j, emb, A) print "h0:", h0 print "j0:", j0 print "jc:", jc print "new_emb:", new_emb emb_j = j0.copy() emb_j.update(jc) print "emb_j:", emb_j ans = core.solve_ising(solver, h0, emb_j, num_reads=1000) print ans # for x in ans['solutions']: # for y in new_emb: # print (x[y[0]]+1)/2