def connect_to_dwave(): """ Establish a connection to the D-Wave, and use this to talk to a solver. We rely on the qOp infrastructure to set the environment variables properly. """ try: url = os.environ["DW_INTERNAL__HTTPLINK"] token = os.environ["DW_INTERNAL__TOKEN"] proxy = os.environ["DW_INTERNAL__HTTPPROXY"] conn = RemoteConnection(url, token, proxy) except KeyError: url = "<local>" token = "<N/A>" conn = local_connection except IOError as e: qasm.abend("Failed to establish a remote connection (%s)" % e) try: qasm.solver_name = os.environ["DW_INTERNAL__SOLVER"] except: # Solver was not specified: Use the first available solver. qasm.solver_name = conn.solver_names()[0] try: qasm.solver = conn.get_solver(qasm.solver_name) except KeyError: qasm.abend("Failed to find solver %s on connection %s" % (qasm.solver_name, url))
def submit_dwave_problem(physical, samples, anneal_time): "Submit a QMI to the D-Wave." # Submit a QMI to the D-Wave and get back a list of solution vectors. solver_params = dict(chains=physical.embedding, num_reads=samples, annealing_time=anneal_time) while True: # Repeatedly remove parameters the particular solver doesn't like until # it actually works -- or fails for a different reason. try: answer = solve_ising(qasm.solver, physical.weights, physical.strengths, **solver_params) break except ValueError as e: # Is there a better way to extract the failing symbol than a regular # expression match? bad_name = re.match(r'"(.*?)"', str(e)) if bad_name == None: raise e del solver_params[bad_name.group(1)] except RuntimeError as e: qasm.abend(e) # Discard solutions with broken pins or broken chains. solutions = answer["solutions"] valid_solns = [s for s in solutions if solution_is_intact(physical, s)] final_answer = unembed_answer(valid_solns, physical.embedding, broken_chains="discard") return answer, final_answer
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 = qasm.solver.properties["h_range"] j_range = qasm.solver.properties["j_range"] except KeyError: h_range = [-1.0, 1.0] j_range = [-1.0, 1.0] weight_list = [logical.weights[q] for q in range(qasm.next_sym_num + 1)] 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: qasm.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.weight_list = weight_list physical.weights = new_weights physical.pinned = [] for l, v in logical.pinned: physical.pinned.extend([(p, v) for p in physical.embedding[l]]) return physical
def error_in_line(self, msg): if self.lineno == None: qasm.abend(msg) else: sys.stderr.write('%s:%d: error: %s\n' % (self.filename, self.lineno, msg)) sys.exit(1)
def parse_files(file_list): "Parse a list of file(s) into an internal representation." if file_list == []: # No files were specified: Read from standard input. parse_file("<stdin>", sys.stdin) if current_macro[0] != None: error_in_line("Unterminated definition of macro %s" % current_macro[0]) else: # Files were specified: Process each in turn. for infilename in file_list: try: infile = open(infilename) except IOError: qasm.abend('Failed to open %s for input' % infilename) parse_file(infilename, infile) if current_macro[0] != None: error_in_line("Unterminated definition of macro %s" % current_macro[0]) infile.close()
def parse_pin(pin): "Parse a pin statement passed on the command line." for pstr in pin: lhs_rhs = pstr.split(":=") if len(lhs_rhs) != 2: qasm.abend('Failed to parse --pin="%s"' % pstr) lhs = lhs_rhs[0].strip().split() rhs = [] for r in lhs_rhs[1].strip().upper().split(): try: rhs.append(str2bool[r]) except KeyError: for subr in r: try: rhs.append(str2bool[subr]) except KeyError: qasm.abend('Failed to parse --pin="%s"' % pstr) if len(lhs) != len(rhs): qasm.abend( 'Different number of left- and right-hand-side values in --pin="%s" (%d vs. %d)' % (pstr, len(lhs), len(rhs))) for l, r in zip(lhs, rhs): qasm.program.append(Pin("[command line]", 1, l, r))
def find_dwave_embedding(logical, optimize, verbosity): """Find an embedding of a logical problem in the D-Wave's physical topology. Store the embedding within the Problem object.""" edges = logical.strengths.keys() edges.sort() try: hw_adj = get_hardware_adjacency(qasm.solver) except KeyError: # The Ising heuristic solver is an example of a solver that lacks a # fixed hardware representation. We therefore assert that the hardware # exactly matches the problem'input graph. hw_adj = edges # Determine the edges of a rectangle of cells we want to use. L, M, N = qasm.chimera_topology(qasm.solver) L2 = 2 * L ncells = (qasm.next_sym_num + 1) // L2 if optimize: edgey = max(int(math.sqrt(ncells)), 1) edgex = max((ncells + edgey - 1) // edgey, 1) else: edgey = N edgex = M # Announce what we're about to do. if verbosity >= 2: sys.stderr.write( "Embedding the logical adjacency within the physical topology.\n\n" ) # Repeatedly expand edgex and edgey until the embedding works. while edgex <= M and edgey <= N: # Retain adjacencies only within the rectangle. alt_hw_adj = [] for q1, q2 in hw_adj: c1 = q1 // L2 if c1 % M >= edgex: continue if c1 // M >= edgey: continue c2 = q2 // L2 if c2 % M >= edgex: continue if c2 // M >= edgey: continue alt_hw_adj.append((q1, q2)) alt_hw_adj = set(alt_hw_adj) # Try to find an embedding. if verbosity >= 2: sys.stderr.write(" Trying a %dx%d unit-cell embedding ... " % (edgex, edgey)) status_file = tempfile.NamedTemporaryFile(mode="w", delete=False) stdout_fd = os.dup(sys.stdout.fileno()) os.dup2(status_file.fileno(), sys.stdout.fileno()) embedding = find_embedding(edges, alt_hw_adj, verbose=1) sys.stdout.flush() os.dup2(stdout_fd, sys.stdout.fileno()) status_file.close() if len(embedding) > 0: sys.stderr.write("succeeded\n\n") else: sys.stderr.write("failed\n\n") with open(status_file.name, "r") as status: for line in status: sys.stderr.write(" %s" % line) sys.stderr.write("\n") os.remove(status_file.name) else: embedding = find_embedding(edges, alt_hw_adj, verbose=0) if len(embedding) > 0: # Success! break # Failure -- increase edgex or edgey and try again. if edgex < edgey: edgex += 1 else: edgey += 1 if not (edgex <= M and edgey <= N): qasm.abend("Failed to embed the problem") # Store in the logical problem additional information about the embedding. logical.embedding = embedding logical.hw_adj = alt_hw_adj logical.edges = edges
def parse_file(infilename, infile): global macros, current_macro, aliases, target, filename, lineno filename = infilename for line in infile: # Split the line into fields and apply text aliases. lineno += 1 if line.strip() == "": continue fields = shlex.split(line, True) for i in range(len(fields)): try: fields[i] = aliases[fields[i]] except KeyError: pass # Process the line. if len(fields) == 0: # Ignore empty lines. continue elif len(fields) >= 2 and fields[0] == "!include": # "!include" "<filename>" -- process a named auxiliary file. incname = string.join(fields[1:], " ") if len(incname) >= 2 and incname[0] == "<" and incname[-1] == ">": # Search QASMPATH for the filename. incname = incname[1:-1] try: qasmpath = string.split(os.environ["QASMPATH"], ":") qasmpath.append(".") except KeyError: qasmpath = ["."] found_incname = find_file_in_path(qasmpath, incname) if found_incname != None: incname = found_incname elif len(incname) >= 2: # Search only the current directory for the filename. found_incname = find_file_in_path(["."], incname) if found_incname != None: incname = found_incname try: incfile = open(incname) except IOError: qasm.abend('Failed to open %s for input' % incname) parse_file(incname, incfile) incfile.close() elif len(fields) == 2: if fields[0] == "!begin_macro": # "!begin_macro" <name> -- begin a macro definition. name = fields[1] if macros.has_key(name): error_in_line("Macro %s is multiply defined" % name) if current_macro[0] != None: error_in_line("Nested macros are not supported") current_macro = (name, []) target = current_macro[1] elif fields[0] == "!end_macro": # "!end_macro" <name> -- end a macro definition. name = fields[1] if current_macro[0] == None: error_in_line( "Ended macro %s with no corresponding begin" % name) if current_macro[0] != name: error_in_line("Ended macro %s after beginning macro %s" % (name, current_macro[0])) macros[name] = current_macro[1] target = qasm.program current_macro = (None, []) else: # <symbol> <weight> -- increment a symbol's point weight. try: val = float(fields[1]) except ValueError: error_in_line( 'Failed to parse "%s %s" as a symbol followed by a numerical weight' % (fields[0], fields[1])) target.append(Weight(filename, lineno, fields[0], val)) elif len(fields) == 3: if fields[1] == "=": # <symbol_1> = <symbol_2> -- create a chain between <symbol_1> and # <symbol_2>. target.append(Chain(filename, lineno, fields[0], fields[2])) elif fields[1] == ":=": # <symbol> := <value> -- force symbol <symbol> to have value # <value>. try: goal = str2bool[fields[2].upper()] except KeyError: error_in_line( 'Right-hand side ("%s") must be a Boolean value' % fields[2]) target.append(Pin(filename, lineno, fields[0], goal)) elif fields[1] == "<->": # <symbol_1> <-> <symbol_2> -- make <symbol_1> an alias of # <symbol_2>. target.append(Alias(filename, lineno, fields[0], fields[2])) elif fields[0] == "!use_macro": # "!use_macro" <macro_name> <instance_name> -- instantiate # a macro using <instance_name> as each variable's prefix. name = fields[1] try: target.append( MacroUse(filename, lineno, name, macros[name], fields[2] + ".")) except KeyError: error_in_line("Unknown macro %s" % name) elif fields[0] == "!alias": # "!alias" <symbol> <text> -- replace a field of <symbol> with # <text>. aliases[fields[1]] = fields[2] elif is_float(fields[2]): # <symbol_1> <symbol_2> <strength> -- increment a coupler strength. try: strength = float(fields[2]) except ValueError: error_in_line('Failed to parse "%s" as a number' % fields[2]) target.append( Strength(filename, lineno, fields[0], fields[1], strength)) else: # Three fields but none of the above cases error_in_line('Cannot parse "%s"' % line) else: # Neither two nor three fields error_in_line('Cannot parse "%s"' % line)