Ejemplo n.º 1
0
    def get_circuits(self, format='dag'):
        """Get the compiled circuits generated.

        Args:
            format (str, optional): "qasm" | "json" | "QuantumCircuit" 

        Returns:
           List of Compiled QuantumCircuit objects.
        """
        if format is 'qasm':
            qasm_list = []
            for circuit in self.circuit_list:
                qasm_list.append(circuit.qasm())
            return qasm_list
        elif format is 'json':
            json_list = []
            for circuit in self.circuit_list:
                node_circuit = qasm.Qasm(data=circuit.qasm()).parse()
                unrolled_circuit = unroll.Unroller(
                    node_circuit, unroll.JsonBackend(self.basis_gates))
                json_list.append(unrolled_circuit.execute().decode())
            return json_list
        elif format is 'QuantumCircuit':
            qc_list = []
            for circuit in self.circuit_list:
                node_circuit = qasm.Qasm(data=circuit.qasm()).parse()
                unrolled_circuit = unroll.Unroller(
                    node_circuit, unroll.CircuitBackend(self.basis_gates))
                qc_list.append(unrolled_circuit.execute())
            return qc_list
Ejemplo n.º 2
0
def direction_mapper(circuit_graph, coupling_graph, verbose=False):
    """Change the direction of CNOT gates to conform to CouplingGraph.

    circuit_graph = input Circuit
    coupling_graph = corresponding CouplingGraph
    verbose = optional flag to print more information

    Adds "h" to the circuit basis.

    Returns a Circuit object containing a circuit equivalent to
    circuit_graph but with CNOT gate directions matching the edges
    of coupling_graph. Raises an exception if the circuit_graph
    does not conform to the coupling_graph.
    """
    if "cx" not in circuit_graph.basis:
        return circuit_graph
    if circuit_graph.basis["cx"] != (2, 0, 0):
        raise QISKitException("cx gate has unexpected signature %s"
                              % circuit_graph.basis["cx"])
    flipped_qasm = "OPENQASM 2.0;\n" + \
                   "gate cx c,t { CX c,t; }\n" + \
                   "gate u2(phi,lambda) q { U(pi/2,phi,lambda) q; }\n" + \
                   "gate h a { u2(0,pi) a; }\n" + \
                   "gate cx_flipped a,b { h a; h b; cx b, a; h a; h b; }\n" + \
                   "qreg q[2];\n" + \
                   "cx_flipped q[0],q[1];\n"
    u = unroll.Unroller(Qasm(data=flipped_qasm).parse(),
                        unroll.CircuitBackend(["cx", "h"]))
    u.execute()
    flipped_cx_circuit = u.backend.circuit
    cx_node_list = circuit_graph.get_named_nodes("cx")
    cg_edges = coupling_graph.get_edges()
    for cx_node in cx_node_list:
        nd = circuit_graph.multi_graph.node[cx_node]
        cxedge = tuple(nd["qargs"])
        if cxedge in cg_edges:
            if verbose:
                print("cx %s[%d], %s[%d] -- OK" % (cxedge[0][0], cxedge[0][1],
                                                   cxedge[1][0], cxedge[1][1]))
            continue
        elif (cxedge[1], cxedge[0]) in cg_edges:
            circuit_graph.substitute_circuit_one(cx_node,
                                                 flipped_cx_circuit,
                                                 wires=[("q", 0), ("q", 1)])
            if verbose:
                print("cx %s[%d], %s[%d] -FLIP" % (cxedge[0][0], cxedge[0][1],
                                                   cxedge[1][0], cxedge[1][1]))
        else:
            raise QISKitException("circuit incompatible with CouplingGraph: "
                                  + "cx on %s" % cxedge)
    return circuit_graph
def load_unroll_qasm_file(filename, basis_gates='u1,u2,u3,cx,id'):
    """Load qasm file and return unrolled circuit

    Args: 
        filename (str): a string for the filename including its location.
        basis_gates (str): basis to unroll circuit to.
    Returns:
        Returns a unrolled QuantumCircuit object
    """
    # create Program object Node (AST)
    program_node_circuit = qasm.Qasm(filename=filename).parse()
    unrolled_circuit = unroll.Unroller(
        program_node_circuit, unroll.CircuitBackend(basis_gates.split(",")))
    circuit_unrolled = unrolled_circuit.execute()
    return circuit_unrolled
    def get_circuits(self, format_='dag'):
        """Get the compiled circuits generated.

        Args:
            format_ (str, optional): "qasm" | "qobj" | "QuantumCircuit"

        Returns:
           list: List of Compiled QuantumCircuit objects.

        Raises:
            NameError: if the output format is not valid.
        """
        if format_ == 'qasm':
            qasm_list = []
            for circuit in self.circuit_list:
                qasm_list.append(circuit.qasm())
            return qasm_list
        elif format_ == 'qobj':
            json_list = []
            for circuit in self.circuit_list:
                node_circuit = qasm.Qasm(data=circuit.qasm()).parse()
                unrolled_circuit = unroll.Unroller(
                    node_circuit,
                    unroll.JsonBackend(self.basis_gates))
                json_list.append(unrolled_circuit.execute())
            return json_list
        elif format_ == 'QuantumCircuit':
            qc_list = []
            for circuit in self.circuit_list:
                node_circuit = qasm.Qasm(data=circuit.qasm()).parse()
                unrolled_circuit = unroll.Unroller(
                    node_circuit,
                    unroll.CircuitBackend(self.basis_gates))
                qc_list.append(unrolled_circuit.execute())
            return qc_list
        # elif format is 'dag':
        #     qc_list = []
        #     for circuit in self.circuit_list:
        #         node_circuit = qasm.Qasm(data=circuit.qasm()).parse()
        #         unrolled_circuit = unroll.Unroller(
        #             node_circuit,
        #             unroll.DAGBackend(self.basis_gates))
        #         qc_list.append(unrolled_circuit.execute())
        #     return qc_list
        else:
            raise NameError('Unrecognized circuit output format: "{}"'.format(
                format_))
    def setUp(self):
        self.seed = 88
        self.qasm_filename = self._get_resource_path('qasm/example.qasm')
        with open(self.qasm_filename, 'r') as qasm_file:
            self.qasm_text = qasm_file.read()
            self.qasm_ast = qasm.Qasm(data=self.qasm_text).parse()
            self.qasm_be = unroll.CircuitBackend(
                ['u1', 'u2', 'u3', 'id', 'cx'])
            self.qasm_circ = unroll.Unroller(self.qasm_ast,
                                             self.qasm_be).execute()
        qr = QuantumRegister(2, 'q')
        cr = ClassicalRegister(2, 'c')
        qc = QuantumCircuit(qr, cr)
        qc.h(qr[0])
        qc.measure(qr[0], cr[0])
        self.qc = qc

        # create qobj
        compiled_circuit1 = QobjExperiment.from_dict(
            transpile_dag(DAGCircuit.fromQuantumCircuit(self.qc),
                          format='json'))

        compiled_circuit2 = QobjExperiment.from_dict(
            transpile_dag(DAGCircuit.fromQuantumCircuit(self.qasm_circ),
                          format='json'))

        self.qobj = Qobj(qobj_id='test_qobj',
                         config=QobjConfig(shots=2000,
                                           memory_slots=1,
                                           max_credits=3,
                                           seed=1111),
                         experiments=[compiled_circuit1, compiled_circuit2],
                         header=QobjHeader(backend_name='qasm_simulator'))
        self.qobj.experiments[0].header.name = 'test_circuit1'
        self.qobj.experiments[0].config = QobjItem(
            basis_gates='u1,u2,u3,cx,id')
        self.qobj.experiments[1].header.name = 'test_circuit2'
        self.qobj.experiments[1].config = QobjItem(
            basis_gates='u1,u2,u3,cx,id')
        self.backend = QasmSimulator()
Ejemplo n.º 6
0
def optimize_1q_gates(circuit):
    """Simplify runs of single qubit gates in the QX basis.

    Return a new circuit that has been optimized.
    """
    qx_basis = ["u1", "u2", "u3", "cx", "id"]
    urlr = unroll.Unroller(Qasm(data=circuit.qasm(qeflag=True)).parse(),
                           unroll.CircuitBackend(qx_basis))
    urlr.execute()
    unrolled = urlr.backend.circuit

    runs = unrolled.collect_runs(["u1", "u2", "u3", "id"])
    for run in runs:
        qname = unrolled.multi_graph.node[run[0]]["qargs"][0]
        right_name = "u1"
        right_parameters = (0.0, 0.0, 0.0)  # (theta, phi, lambda)
        for node in run:
            nd = unrolled.multi_graph.node[node]
            assert nd["condition"] is None, "internal error"
            assert len(nd["qargs"]) == 1, "internal error"
            assert nd["qargs"][0] == qname, "internal error"
            left_name = nd["name"]
            assert left_name in ["u1", "u2", "u3", "id"], "internal error"
            if left_name == "u1":
                left_parameters = (0.0, 0.0, float(nd["params"][0]))
            elif left_name == "u2":
                left_parameters = (math.pi / 2, float(nd["params"][0]),
                                   float(nd["params"][1]))
            elif left_name == "u3":
                left_parameters = tuple(map(float, nd["params"]))
            else:
                left_name = "u1"  # replace id with u1
                left_parameters = (0.0, 0.0, 0.0)
            # Compose gates
            name_tuple = (left_name, right_name)
            if name_tuple == ("u1", "u1"):
                # u1(lambda1) * u1(lambda2) = u1(lambda1 + lambda2)
                right_parameters = (0.0, 0.0, right_parameters[2] +
                                    left_parameters[2])
            elif name_tuple == ("u1", "u2"):
                # u1(lambda1) * u2(phi2, lambda2) = u2(phi2 + lambda1, lambda2)
                right_parameters = (math.pi / 2, right_parameters[1] +
                                    left_parameters[2], right_parameters[2])
            elif name_tuple == ("u2", "u1"):
                # u2(phi1, lambda1) * u1(lambda2) = u2(phi1, lambda1 + lambda2)
                right_name = "u2"
                right_parameters = (math.pi / 2, left_parameters[1],
                                    right_parameters[2] + left_parameters[2])
            elif name_tuple == ("u1", "u3"):
                # u1(lambda1) * u3(theta2, phi2, lambda2) =
                #     u3(theta2, phi2 + lambda1, lambda2)
                right_parameters = (right_parameters[0], right_parameters[1] +
                                    left_parameters[2], right_parameters[2])
            elif name_tuple == ("u3", "u1"):
                # u3(theta1, phi1, lambda1) * u1(lambda2) =
                #     u3(theta1, phi1, lambda1 + lambda2)
                right_name = "u3"
                right_parameters = (left_parameters[0], left_parameters[1],
                                    right_parameters[2] + left_parameters[2])
            elif name_tuple == ("u2", "u2"):
                # Using Ry(pi/2).Rz(2*lambda).Ry(pi/2) =
                #    Rz(pi/2).Ry(pi-2*lambda).Rz(pi/2),
                # u2(phi1, lambda1) * u2(phi2, lambda2) =
                #    u3(pi - lambda1 - phi2, phi1 + pi/2, lambda2 + pi/2)
                right_name = "u3"
                right_parameters = (math.pi - left_parameters[2] -
                                    right_parameters[1], left_parameters[1] +
                                    math.pi / 2, right_parameters[2] +
                                    math.pi / 2)
            else:
                # For composing u3's or u2's with u3's, use
                # u2(phi, lambda) = u3(pi/2, phi, lambda)
                # together with the qiskit.mapper.compose_u3 method.
                right_name = "u3"
                right_parameters = compose_u3(left_parameters[0],
                                              left_parameters[1],
                                              left_parameters[2],
                                              right_parameters[0],
                                              right_parameters[1],
                                              right_parameters[2])
            # Here down, when we simplify, we add f(theta) to lambda to correct
            # the global phase when f(theta) is 2*pi. This isn't necessary but
            # the other steps preserve the global phase, so we continue.
            epsilon = 1e-9  # for comparison with zero
            # Y rotation is 0 mod 2*pi, so the gate is a u1
            if abs(right_parameters[0] % 2.0 * math.pi) < epsilon \
               and right_name != "u1":
                right_name = "u1"
                right_parameters = (0.0, 0.0, right_parameters[1] +
                                    right_parameters[2] +
                                    right_parameters[0])
            # Y rotation is pi/2 or -pi/2 mod 2*pi, so the gate is a u2
            if right_name == "u3":
                # theta = pi/2 + 2*k*pi
                if abs((right_parameters[0] - math.pi / 2) % 2.0 * math.pi) \
                   < epsilon:
                    right_name = "u2"
                    right_parameters = (math.pi / 2, right_parameters[1],
                                        right_parameters[2] +
                                        (right_parameters[0] - math.pi / 2))
                # theta = -pi/2 + 2*k*pi
                if abs((right_parameters[0] + math.pi / 2) % 2.0 * math.pi) \
                   < epsilon:
                    right_name = "u2"
                    right_parameters = (math.pi / 2, right_parameters[1] +
                                        math.pi, right_parameters[2] -
                                        math.pi + (right_parameters[0] +
                                                   math.pi / 2))
            # u1 and lambda is 0 mod 4*pi so gate is nop
            if right_name == "u1" and \
               abs(right_parameters[2] % 4.0 * math.pi) < epsilon:
                right_name = "nop"
        # Replace the data of the first node in the run
        new_params = []
        if right_name == "u1":
            new_params.append(right_parameters[2])
        if right_name == "u2":
            new_params = [right_parameters[1], right_parameters[2]]
        if right_name == "u3":
            new_params = list(right_parameters)
        nx.set_node_attributes(unrolled.multi_graph, 'name',
                               {run[0]: right_name})
        nx.set_node_attributes(unrolled.multi_graph, 'params',
                               {run[0]: tuple(map(str, new_params))})
        # Delete the other nodes in the run
        for node in run[1:]:
            unrolled._remove_op_node(node)
        if right_name == "nop":
            unrolled._remove_op_node(run[0])
    return unrolled
Ejemplo n.º 7
0
def swap_mapper(circuit_graph, coupling_graph,
                initial_layout=None,
                basis="cx,u1,u2,u3,id", 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, and
    a layout dict mapping qubits of circuit_graph into qubits
    of coupling_graph. The layout may differ from the initial_layout
    if the first layer of gates cannot be executed on the
    initial_layout.
    """
    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" % (v[0], v[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  # True until first layer is output
    first_swapping_layer = True  # True until first swap layer is output
    # Iterate over layers
    for i in range(len(layerlist)):
        # Attempt to find a permutation for this layer
        success_flag, best_circ, best_d, best_layout, trivial_flag \
            = layer_permutation(layerlist[i]["partition"], layout,
                                qubit_subset, coupling_graph, 20)
        # If this fails, try one gate at a time in this layer
        if not success_flag:
            if verbose:
                print("swap_mapper: failed, layer %d, " % i,
                      " retrying sequentially")
            serial_layerlist = layerlist[i]["graph"].serial_layers()
            # Go through each gate in the layer
            for j in range(len(serial_layerlist)):
                success_flag, best_circ, best_d, best_layout, trivial_flag \
                    = layer_permutation(serial_layerlist[j]["partition"],
                                        layout, qubit_subset, coupling_graph,
                                        20)
                # Give up if we fail again
                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:
                    # Update the qubit positions each iteration
                    layout = best_layout
                    if best_d == 0:
                        # Output qasm without swaps
                        if first_layer:
                            openqasm_output += circuit_graph.qasm(
                                add_swap=True,
                                decls_only=True,
                                aliases=layout)
                            first_layer = False
                        if not trivial_flag and first_swapping_layer:
                            initial_layout = layout
                            first_swapping_layer = False
                    else:
                        # Output qasm with swaps
                        if first_layer:
                            openqasm_output += circuit_graph.qasm(
                                add_swap=True,
                                decls_only=True,
                                aliases=layout)
                            first_layer = False
                            initial_layout = layout
                            first_swapping_layer = False
                        else:
                            if not first_swapping_layer:
                                if verbose:
                                    print("swap_mapper: layer %d (%d), depth %d"
                                          % (i, j, best_d))
                                openqasm_output += best_circ
                            else:
                                initial_layout = layout
                                first_swapping_layer = False
                        openqasm_output += serial_layerlist[j]["graph"].qasm(
                                    no_decls=True,
                                    aliases=layout)
        else:
            # Update the qubit positions each iteration
            layout = best_layout
            if best_d == 0:
                # Output qasm without swaps
                if first_layer:
                    openqasm_output += circuit_graph.qasm(
                                add_swap=True,
                                decls_only=True,
                                aliases=layout)
                    first_layer = False
                if not trivial_flag and first_swapping_layer:
                    initial_layout = layout
                    first_swapping_layer = False
            else:
                # Output qasm with swaps
                if first_layer:
                    openqasm_output += circuit_graph.qasm(
                                add_swap=True,
                                decls_only=True,
                                aliases=layout)
                    first_layer = False
                    initial_layout = layout
                    first_swapping_layer = False
                else:
                    if not first_swapping_layer:
                        if verbose:
                            print("swap_mapper: layer %d, depth %d"
                                  % (i, best_d))
                        openqasm_output += best_circ
                    else:
                        initial_layout = layout
                        first_swapping_layer = False
            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.backend.circuit, initial_layout