From 17f9de403e8bcca407b0e1e0feffd4063ae81bc9 Mon Sep 17 00:00:00 2001 From: Andrew Cross Date: Wed, 19 Apr 2017 23:11:59 -0400 Subject: [PATCH] first pass at swap mapper, bugs fixed --- qiskit/circuit/_circuit.py | 204 ++++++++++++++++++++-------- qiskit/localize/__init__.py | 1 + qiskit/localize/_coupling.py | 71 +++++----- qiskit/localize/_layout.py | 248 +++++++++++++++++++++++++++++++++++ qiskit/qasm/_qasmparser.py | 2 +- rippleadd.py | 9 +- testscripts/localize.py | 29 +--- testscripts/test7.qasm | 11 ++ 8 files changed, 452 insertions(+), 123 deletions(-) create mode 100644 qiskit/localize/_layout.py create mode 100644 testscripts/test7.qasm diff --git a/qiskit/circuit/_circuit.py b/qiskit/circuit/_circuit.py index 84af5c4e28..34d631ed13 100644 --- a/qiskit/circuit/_circuit.py +++ b/qiskit/circuit/_circuit.py @@ -69,6 +69,10 @@ class Circuit: # Output precision for printing floats self.prec = 10 + def get_qubits(self): + """Return a list of qubits as (qreg, index) pairs.""" + return [(k, i) for k, v in self.qregs.items() for i in range(v)] + def rename_register(self, regname, newname): """Rename a classical or quantum register throughout the circuit. @@ -652,65 +656,108 @@ class Circuit: out += "\n{\n" + self.gates[name]["body"].qasm() + "}" return out - def qasm(self, qeflag=False): + def qasm(self, decls_only=False, add_swap=False, + no_decls=False, qeflag=False, aliases=None): """Return a string containing QASM for this circuit. if qeflag is True, add a line to include "qelib1.inc" and only generate gate code for gates not in qelib1. + + if no_decls is True, only print the instructions. + + if aliases is not None, aliases contains a dict mapping + the current qubits in the circuit to new qubit names. + We will deduce the register names and sizes from aliases. + + if decls_only is True, only print the declarations. + + if add_swap is True, add the definition of swap in terms of + cx if necessary. """ - printed_gates = [] - out = "OPENQASM 2.0;\n" - if qeflag: - out += "include \"qelib1.inc\";\n" - for k, v in sorted(self.qregs.items()): - out += "qreg %s[%d];\n" % (k, v) - for k, v in sorted(self.cregs.items()): - out += "creg %s[%d];\n" % (k, v) - omit = ["U", "CX", "measure", "reset", "barrier"] - if qeflag: - qelib = ["u3", "u2", "u1", "cx", "id", "x", "y", "z", "h", - "s", "sdg", "t", "tdg", "cz", "cy", "ccx", "cu1", "cu3"] - omit.extend(qelib) - printed_gates.extend(qelib) - for k in self.basis.keys(): - if k not in omit: - if not self.gates[k]["opaque"]: - calls = self.gates[k]["body"].calls() - for c in calls: - if c not in printed_gates: - out += self._gate_string(c) + "\n" - printed_gates.append(c) - if k not in printed_gates: - out += self._gate_string(k) + "\n" - printed_gates.append(k) - ts = nx.topological_sort(self.G) - for n in ts: - nd = self.G.node[n] - if nd["type"] == "op": - if nd["condition"] is not None: - out += "if(%s==%d) " \ - % (nd["condition"][0], nd["condition"][1]) - if len(nd["cargs"]) == 0: - nm = nd["name"] - qarg = ",".join(map(lambda x: "%s[%d]" % (x[0], x[1]), - nd["qargs"])) - if len(nd["params"]) > 0: - param = ",".join(nd["params"]) - out += "%s(%s) %s;\n" % (nm, param, qarg) + # Rename qregs if necessary + if aliases: + qregdata = {} + for q in aliases.values(): + if q[0] not in qregdata: + qregdata[q[0]] = q[1] + 1 + elif qregdata[q[0]] < q[1] + 1: + qregdata[q[0]] = q[1] + 1 + else: + qregdata = self.qregs + # Write top matter + if no_decls: + out = "" + else: + printed_gates = [] + out = "OPENQASM 2.0;\n" + if qeflag: + out += "include \"qelib1.inc\";\n" + for k, v in sorted(qregdata.items()): + out += "qreg %s[%d];\n" % (k, v) + for k, v in sorted(self.cregs.items()): + out += "creg %s[%d];\n" % (k, v) + omit = ["U", "CX", "measure", "reset", "barrier"] + if qeflag: + qelib = ["u3", "u2", "u1", "cx", "id", "x", "y", "z", "h", + "s", "sdg", "t", "tdg", "cz", "cy", "ccx", "cu1", + "cu3"] + omit.extend(qelib) + printed_gates.extend(qelib) + for k in self.basis.keys(): + if k not in omit: + if not self.gates[k]["opaque"]: + calls = self.gates[k]["body"].calls() + for c in calls: + if c not in printed_gates: + out += self._gate_string(c) + "\n" + printed_gates.append(c) + if k not in printed_gates: + out += self._gate_string(k) + "\n" + printed_gates.append(k) + if add_swap and not qeflag and "cx" not in self.basis: + out += "gate cx a,b { CX a,b; }\n" + if add_swap and "swap" not in self.basis: + out += "gate swap a,b { cx a,b; cx b,a; cx a,b; }\n" + # Write the instructions + if not decls_only: + ts = nx.topological_sort(self.G) + for n in ts: + nd = self.G.node[n] + if nd["type"] == "op": + if nd["condition"] is not None: + out += "if(%s==%d) " \ + % (nd["condition"][0], nd["condition"][1]) + if len(nd["cargs"]) == 0: + nm = nd["name"] + if aliases: + qarglist = map(lambda x: aliases[x], nd["qargs"]) + else: + qarglist = nd["qargs"] + qarg = ",".join(map(lambda x: "%s[%d]" % (x[0], x[1]), + qarglist)) + if len(nd["params"]) > 0: + param = ",".join(nd["params"]) + out += "%s(%s) %s;\n" % (nm, param, qarg) + else: + out += "%s %s;\n" % (nm, qarg) else: - out += "%s %s;\n" % (nm, qarg) - else: - if nd["name"] == "measure": - assert len(nd["cargs"]) == 1 and \ - len(nd["qargs"]) == 1 and \ - len(nd["params"]) == 0, "bad node data" - out += "measure %s[%d] -> %s[%d];\n" \ - % (nd["qargs"][0][0], - nd["qargs"][0][1], - nd["cargs"][0][0], - nd["cargs"][0][1]) - else: - assert False, "bad node data" + if nd["name"] == "measure": + assert len(nd["cargs"]) == 1 and \ + len(nd["qargs"]) == 1 and \ + len(nd["params"]) == 0, "bad node data" + qname = nd["qargs"][0][0] + qindex = nd["qargs"][0][1] + if aliases: + newq = aliases[(qname, qindex)] + qname = newq[0] + qindex = newq[1] + out += "measure %s[%d] -> %s[%d];\n" \ + % (qname, + qindex, + nd["cargs"][0][0], + nd["cargs"][0][1]) + else: + assert False, "bad node data" return out def _check_wires_list(self, wires, name, input_circuit): @@ -1022,6 +1069,10 @@ class Circuit: earliest layer at index 0. The layers are constructed using a greedy algorithm. Each returned layer is a dict containing {"graph": circuit graph, "partition": list of qubit lists}. + + TODO: Gates that use the same cbits will end up in different + layers as this is currently implemented. This is may not be + the desired behavior. """ layers_list = [] # node_map contains an input node or previous layer node for @@ -1048,6 +1099,7 @@ class Circuit: # foreground node we can add to the current layer. ops_touched = {} wires_loop = list(wires_with_ops_remaining) + emit = False for w in wires_loop: oe = list(filter(lambda x: x[2]["name"] == w, self.G.out_edges(nbunch=[node_map[w]], @@ -1083,10 +1135,52 @@ class Circuit: for v in itertools.chain(qa, ca, cob): node_map[v] = nxt_nd_idx # Add operation to partition - support_list.append(list(set(qa) | set(ca) | set(cob))) - if support_list: + if nxt_nd["name"] != "barrier": + # support_list.append(list(set(qa) | set(ca) | + # set(cob))) + support_list.append(list(set(qa))) + emit = True + if emit: l_dict = {"graph": new_layer, "partition": support_list} layers_list.append(l_dict) + emit = False else: assert not wires_with_ops_remaining, "not finished but empty?" return layers_list + + def serial_layers(self): + """Return a list of layers for all gates of this circuit. + + A serial layer is a circuit with one gate. The layers have the + same structure as in layers(). + """ + layers_list = [] + ts = nx.topological_sort(self.G) + for n in ts: + nxt_nd = self.G.node[n] + if nxt_nd["type"] == "op": + new_layer = Circuit() + for k, v in self.qregs.items(): + new_layer.add_qreg(k, v) + for k, v in self.cregs.items(): + new_layer.add_creg(k, v) + new_layer.basis = copy.deepcopy(self.basis) + new_layer.gates = copy.deepcopy(self.gates) + # Save the support of the operation we add to the layer + support_list = [] + # Operation data + qa = copy.copy(nxt_nd["qargs"]) + ca = copy.copy(nxt_nd["cargs"]) + pa = copy.copy(nxt_nd["params"]) + co = copy.copy(nxt_nd["condition"]) + cob = self._bits_in_condition(co) + # Add node to new_layer + new_layer.apply_operation_back(nxt_nd["name"], + qa, ca, pa, co) + # Add operation to partition + if nxt_nd["name"] != "barrier": + # support_list.append(list(set(qa) | set(ca) | set(cob))) + support_list.append(list(set(qa))) + l_dict = {"graph": new_layer, "partition": support_list} + layers_list.append(l_dict) + return layers_list diff --git a/qiskit/localize/__init__.py b/qiskit/localize/__init__.py index d7d90193db..12e19827d5 100644 --- a/qiskit/localize/__init__.py +++ b/qiskit/localize/__init__.py @@ -1 +1,2 @@ from ._coupling import Coupling +from ._layout import swap_mapper diff --git a/qiskit/localize/_coupling.py b/qiskit/localize/_coupling.py index 391bfed291..07c3fa8183 100644 --- a/qiskit/localize/_coupling.py +++ b/qiskit/localize/_coupling.py @@ -9,7 +9,6 @@ onto a device with this coupling. Author: Andrew Cross """ import networkx as nx -import numpy as np from ._couplingerror import CouplingError @@ -32,6 +31,8 @@ class Coupling: """ # self.qubits is dict from qubit (regname,idx) tuples to node indices self.qubits = {} + # self.index_to_qubit is a dict from node indices to qubits + self.index_to_qubit = {} # self.node_counter is integer counter for labeling nodes self.node_counter = 0 # self.G is the coupling digraph @@ -39,9 +40,6 @@ class Coupling: # self.dist is a dict of dicts from node pairs to distances # it must be computed, it is the distance on the digraph self.dist = None - # self.hdist is a dict of dicts from node pairs to distances - # it must be computed, it is a heuristic distance function - self.hdist = None # Add edges to the graph if the couplingstr is present if couplingstr is not None: edge_list = couplingstr.split(';') @@ -52,6 +50,23 @@ class Coupling: vtuple0 = (vertex0[0], int(vertex0[1])) vtuple1 = (vertex1[0], int(vertex1[1])) self.add_edge(vtuple0, vtuple1) + self.compute_distance() + + def size(self): + """Return the number of qubits in this graph.""" + return len(self.qubits) + + def get_qubits(self): + """Return the qubits in this graph as (qreg, index) tuples.""" + return list(self.qubits.keys()) + + def get_edges(self): + """Return a list of edges in the coupling graph. + + Each edge is a pair of qubits and each qubit is a tuple (qreg, index). + """ + return list(map(lambda x: (self.index_to_qubit[x[0]], + self.index_to_qubit[x[1]]), self.G.edges())) def add_qubit(self, name): """ @@ -66,6 +81,7 @@ class Coupling: self.G.add_node(self.node_counter) self.G.node[self.node_counter]["name"] = name self.qubits[name] = self.node_counter + self.index_to_qubit[self.node_counter] = name def add_edge(self, s_name, d_name): """ @@ -75,15 +91,9 @@ class Coupling: d_name = destination qubit tuple """ if s_name not in self.qubits: - self.node_counter += 1 - self.G.add_node(self.node_counter) - self.G.node[self.node_counter]["name"] = s_name - self.qubits[s_name] = self.node_counter + self.add_qubit(s_name) if d_name not in self.qubits: - self.node_counter += 1 - self.G.add_node(self.node_counter) - self.G.node[self.node_counter]["name"] = d_name - self.qubits[d_name] = self.node_counter + self.add_qubit(d_name) self.G.add_edge(self.qubits[s_name], self.qubits[d_name]) def connected(self): @@ -94,53 +104,38 @@ class Coupling: """ return nx.is_weakly_connected(self.G) - def compute_distance(self, randomize=False): + def compute_distance(self): """ Compute the distance function on pairs of nodes. The distance map self.dist is computed from the graph using - all_pairs_shortest_path_length. The distance map self.hdist is also - computed. If randomize is False, we use self.dist. Otherwise, we use - Sergey Bravyi's randomization heuristic. + all_pairs_shortest_path_length. """ if not self.connected(): raise CouplingError("coupling graph not connected") lengths = nx.all_pairs_shortest_path_length(self.G.to_undirected()) self.dist = {} - self.hdist = {} for i in self.qubits.keys(): self.dist[i] = {} - self.hdist[i] = {} for j in self.qubits.keys(): self.dist[i][j] = lengths[self.qubits[i]][self.qubits[j]] - self.hdist[i][j] = self.dist[i][j] - if randomize: - for i in self.qubits.keys(): - for j in self.qubits.keys(): - scale = (1.0 + np.random.normal(0.0, 1.0/len(self.qubits))) - self.hdist[i][j] = scale * self.dist[i][j]**2 - self.hdist[j][i] = self.hdist[i][j] - def distance(self, q1, q2, h=False): - """ - Return the distance between qubit q1 to qubit q2. - - We look this up in self.dist if h is False and in self.hdist - if h is True. - """ + def distance(self, q1, q2): + """Return the distance between qubit q1 to qubit q2.""" if self.dist is None: raise CouplingError("distance has not been computed") if q1 not in self.qubits: raise CouplingError("%s not in coupling graph" % q1) if q2 not in self.qubits: raise CouplingError("%s not in coupling graph" % q2) - if h: - return self.hdist[q1][q2] - else: - return self.dist[q1][q2] + return self.dist[q1][q2] def __str__(self): """Return a string representation of the coupling graph.""" - s = "%s" % self.qubits - s += "\n%s" % self.G.edges() + s = "qubits: " + s += ", ".join(["%s[%d] @ %d" % (k[0], k[1], v) + for k, v in self.qubits.items()]) + s += "\nedges: " + s += ", ".join(["%s[%d]-%s[%d]" % (e[0][0], e[0][1], e[1][0], e[1][1]) + for e in self.get_edges()]) return s diff --git a/qiskit/localize/_layout.py b/qiskit/localize/_layout.py new file mode 100644 index 0000000000..65ead82ec7 --- /dev/null +++ b/qiskit/localize/_layout.py @@ -0,0 +1,248 @@ +""" +Layout object to represent placement of data qubits onto physical qubits. + +Author: Andrew Cross +""" +import sys +import copy +import numpy as np +from qiskit import QISKitException +from qiskit.qasm import Qasm +import qiskit.unroll as unroll + + +def layer_permutation(layer_partition, layout, qubit_subset, coupling, trials): + """Find a swap circuit that implements a permutation for this layer. + + The goal is to swap qubits such that qubits in the same two qubit gates + are adjacent. + + The layer_partition is a list of (qu)bit lists and each qubit is a + tuple (qreg, index). + The layout is a dict mapping qubits in the circuit to qubits in the + coupling graph and represents the current positions of the data. + The qubit_subset is the subset of qubits in the coupling graph that + we have chosen to map into. + The coupling is a CouplingGraph. + TRIALS is the number of attempts the randomized algorithm makes. + + Returns: success_flag, best_circ, best_d, best_layout + + If success_flag is True, then best_circ contains an OPENQASM string with + the swap circuit, best_d contains the depth of the swap circuit, and + best_layout contains the new positions of the data qubits after the + swap circuit has been applied. + """ + rev_layout = {b: a for a, b in layout.items()} + gates = [] + for layer in layer_partition: + if len(layer) > 2: + raise QISKitException("Layer contains >2 qubit gates") + elif len(layer) == 2: + gates.append(tuple(layer)) + + # Begin loop over trials of randomized algorithm + n = coupling.size() + best_d = sys.maxsize # initialize best depth + best_circ = None # initialize best swap circuit + best_layout = None # initialize best final layout + for trial in range(trials): + + trial_layout = copy.deepcopy(layout) + rev_trial_layout = copy.deepcopy(rev_layout) + trial_circ = "" + + # Compute Sergey's randomized distance + xi = {} + for i in coupling.get_qubits(): + xi[i] = {} + for i in coupling.get_qubits(): + for j in coupling.get_qubits(): + scale = 1.0 + np.random.normal(0.0, 1.0/n) + xi[i][j] = scale * coupling.distance(i, j)**2 + xi[j][i] = xi[i][j] + + # Loop over depths d up to a max depth of 2n+1 + for d in range(1, 2*n+1): + circ = "" + # Set of available qubits + qubit_set = set(qubit_subset) + # While there are still qubits available + while qubit_set: + # Compute the objective function + min_cost = sum([xi[trial_layout[g[0]]][trial_layout[g[1]]] + for g in gates]) + # Try to decrease objective function + progress_made = False + # Loop over edges of coupling graph + for e in coupling.get_edges(): + # Are the qubits available? + if e[0] in qubit_set and e[1] in qubit_set: + # Try this edge to reduce the cost + new_layout = copy.deepcopy(trial_layout) + new_layout[rev_trial_layout[e[0]]] = e[1] + new_layout[rev_trial_layout[e[1]]] = e[0] + rev_new_layout = copy.deepcopy(rev_trial_layout) + rev_new_layout[e[0]] = rev_trial_layout[e[1]] + rev_new_layout[e[1]] = rev_trial_layout[e[0]] + # Compute the objective function + new_cost = sum([xi[new_layout[g[0]]][new_layout[g[1]]] + for g in gates]) + # Record progress if we succceed + if new_cost < min_cost: + progress_made = True + min_cost = new_cost + opt_layout = new_layout + rev_opt_layout = rev_new_layout + opt_edge = e + + # Were there any good choices? + if progress_made: + qubit_set.remove(opt_edge[0]) + qubit_set.remove(opt_edge[1]) + trial_layout = opt_layout + rev_trial_layout = rev_opt_layout + circ += "swap %s[%d],%s[%d]; " % (opt_edge[0][0], + opt_edge[0][1], + opt_edge[1][0], + opt_edge[1][1]) + else: + break + + # We have either run out of qubits or failed to improve + # Compute the coupling graph distance + dist = sum([coupling.distance(trial_layout[g[0]], + trial_layout[g[1]]) for g in gates]) + # If all gates can be applied now, we are finished + # Otherwise we need to consider a deeper swap circuit + if dist == len(gates): + trial_circ = circ + break + + # Either we have succeeded at some depth d < dmax or failed + dist = sum([coupling.distance(trial_layout[g[0]], + trial_layout[g[1]]) for g in gates]) + if dist == len(gates): + if d < best_d: + best_circ = trial_circ + best_layout = trial_layout + best_d = min(best_d, d) + + if best_circ is None: + return False, None, None, None + else: + return True, best_circ, best_d, best_layout + + +def swap_mapper(circuit_graph, coupling_graph, + initial_layout=None, + basis="cx,u1,u2,u3", verbose=False): + """Map a Circuit onto a CouplingGraph using swap gates. + + circuit_graph = input Circuit + coupling_graph = CouplingGraph to map onto + initial_layout = dict from qubits of circuit_graph to qubits + of coupling_graph (optional) + basis = basis string specifying basis of output Circuit + verbose = optional flag to print more information + + Returns a Circuit object containing a circuit equivalent to + circuit_graph that respects couplings in coupling_graph. + """ + if circuit_graph.width() > coupling_graph.size(): + raise QISKitException("Not enough qubits in CouplingGraph") + + # Schedule the input circuit + layerlist = circuit_graph.layers() + if verbose: + print("schedule:") + for i in range(len(layerlist)): + print(" %d: %s" % (i, layerlist[i]["partition"])) + + # Check input layout and create default layout if necessary + if initial_layout is not None: + circ_qubits = circuit_graph.get_qubits() + coup_qubits = coupling_graph.get_qubits() + qubit_subset = [] + for k, v in initial_layout.values(): + qubit_subset.append(v) + if k not in circ_qubits: + raise QISKitException("initial_layout qubit %s[%d] not " + + "in input Circuit" % (k[0], k[1])) + if v not in coup_qubits: + raise QISKitException("initial_layout qubit %s[%d] not " + + " in input CouplingGraph" % (k[0], k[1])) + else: + # Supply a default layout + qubit_subset = coupling_graph.get_qubits() + qubit_subset = qubit_subset[0:circuit_graph.width()] + initial_layout = {a: b for a, b in + zip(circuit_graph.get_qubits(), qubit_subset)} + + # Find swap circuit to preceed to each layer of input circuit + layout = copy.deepcopy(initial_layout) + openqasm_output = "" + first_layer = True + for i in range(len(layerlist)): + success_flag, best_circ, best_d, best_layout \ + = layer_permutation(layerlist[i]["partition"], layout, + qubit_subset, coupling_graph, 20) + if not success_flag: + if verbose: + print("swap_mapper: failed, layer %d, " % i, + " contention? retrying sequentially") + serial_layerlist = layerlist[i]["graph"].serial_layers() + for j in range(len(serial_layerlist)): + success_flag, best_circ, best_d, best_layout \ + = layer_permutation(serial_layerlist[j]["partition"], + layout, qubit_subset, coupling_graph, 20) + if not success_flag: + raise QISKitException("swap_mapper failed: " + + "layer %d, sublayer %d" % (i, j) + + ", \"%s\"" % + serial_layerlist[j]["graph"].qasm( + no_decls=True, + aliases=layout)) + else: + layout = best_layout + if first_layer: + initial_layout = layout + openqasm_output += circuit_graph.qasm(add_swap=True, + decls_only=True, + aliases=layout) + openqasm_output += serial_layerlist[j]["graph"].qasm( + no_decls=True, + aliases=layout) + first_layer = False + else: + if verbose: + print("swap_mapper: layer %d (%d), depth %d" + % (i, j, best_d)) + if best_circ != "": + openqasm_output += best_circ + openqasm_output += serial_layerlist[j]["graph"].qasm( + no_decls=True, + aliases=layout) + else: + layout = best_layout + if first_layer: + initial_layout = layout + openqasm_output += circuit_graph.qasm(add_swap=True, + decls_only=True, + aliases=layout) + openqasm_output += layerlist[i]["graph"].qasm(no_decls=True, + aliases=layout) + first_layer = False + else: + if verbose: + print("swap_mapper: layer %s, depth %d" % (i, best_d)) + if best_circ != "": + openqasm_output += best_circ + openqasm_output += layerlist[i]["graph"].qasm(no_decls=True, + aliases=layout) + # Parse openqasm_output into Circuit object + basis += ",swap" + ast = Qasm(data=openqasm_output).parse() + u = unroll.Unroller(ast, unroll.CircuitBackend(basis.split(","))) + u.execute() + return u.be.C diff --git a/qiskit/qasm/_qasmparser.py b/qiskit/qasm/_qasmparser.py index 145bc47fee..f78a3cadf6 100644 --- a/qiskit/qasm/_qasmparser.py +++ b/qiskit/qasm/_qasmparser.py @@ -694,7 +694,7 @@ class QasmParser(object): ''' opaque : OPAQUE id gate_scope bit_list ''' - p[0] = Opaque([p[2], p[4]]) + p[0] = node.Opaque([p[2], p[4]]) if p[2].name in self.external_functions: raise QasmException("OPAQUE names cannot be reserved words. " + "Received '" + p[2].name + "'") diff --git a/rippleadd.py b/rippleadd.py index 86542852a7..bcc1fa90c8 100644 --- a/rippleadd.py +++ b/rippleadd.py @@ -37,6 +37,7 @@ def unmajority(p, a, b, c): # something like p = Program(c1, c2, c3) # circ.QuantumRegister("a", n) + n = 8 a = QuantumRegister("a", n) @@ -83,7 +84,7 @@ print("width = %d" % C.width()) print("bits = %d" % C.num_cbits()) print("factors = %d" % C.num_tensor_factors()) -# print("") -# print("Unrolled OPENQASM") -# print("-----------------------") -# print(C.qasm(qeflag=True)) +print("") +print("Unrolled OPENQASM") +print("-----------------------") +print(C.qasm(qeflag=True)) diff --git a/testscripts/localize.py b/testscripts/localize.py index ee5d262fea..5d2c1f14e0 100644 --- a/testscripts/localize.py +++ b/testscripts/localize.py @@ -49,29 +49,8 @@ c = make_unrolled_circuit(sys.argv[1], basis) # Second, create the coupling graph coupling = localize.Coupling(couplingstr) +print("coupling = \n%s" % coupling) -print("CouplingGraph is = \n%s" % coupling) - -if not coupling.connected(): - print("Coupling graph must be connected") - sys.exit(1) - -print("input circuit is = \n%s" % c.qasm()) -print("circuit depth = %d" % c.depth()) - -# Here down is hacking for now; not done - -coupling.compute_distance() -for q1 in coupling.qubits.keys(): - for q2 in coupling.qubits.keys(): - print("%s[%d] -> %s[%d]: %f" % (q1[0], q1[1], q2[0], q2[1], - coupling.distance(q1, q2))) - -layerlist = c.layers() -print("len(layerlist) = %d" % len(layerlist)) -print("partition:") -for i in range(len(layerlist)): - print(" %d: %s" % (i, layerlist[i]["partition"])) -for i in range(len(layerlist)): - print("------------ layer %d ------------" % i) - print("%s" % layerlist[i]["graph"].qasm()) +# Third, do the mapping +c_prime = localize.swap_mapper(c, coupling) +print("c_prime.qasm() = \n%s" % c_prime.qasm(qeflag=True)) diff --git a/testscripts/test7.qasm b/testscripts/test7.qasm new file mode 100644 index 0000000000..4aa2874bc4 --- /dev/null +++ b/testscripts/test7.qasm @@ -0,0 +1,11 @@ +OPENQASM 2.0; +include "qelib1.inc"; +qreg q[5]; +creg c[5]; +cx q[0],q[4]; +cx q[1],q[2]; +cx q[2],q[3]; +cx q[3],q[4]; +ccx q[0],q[1],q[2]; +measure q -> c; +if(c==1) reset q;