Пример #1
0
 def check_exact_decomposition(self, target_unitary, decomposer, tolerance=1.e-7):
     """Check exact decomposition for a particular target"""
     with self.subTest(unitary=target_unitary, decomposer=decomposer):
         decomp_circuit = decomposer(target_unitary)
         result = execute(decomp_circuit, UnitarySimulatorPy()).result()
         decomp_unitary = Operator(result.get_unitary())
         result = execute(decomp_circuit, UnitarySimulatorPy()).result()
         decomp_unitary = result.get_unitary()
         target_unitary *= la.det(target_unitary)**(-0.25)
         decomp_unitary *= la.det(decomp_unitary)**(-0.25)
         maxdists = [np.max(np.abs(target_unitary + phase*decomp_unitary))
                     for phase in [1, 1j, -1, -1j]]
         maxdist = np.min(maxdists)
         self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist))
Пример #2
0
    def test_cx_equivalence_2cx_random(self):
        """Check random circuits with  2 cx
        gates locally equivalent to some
        circuit with 2 cx.
        """
        qr = QuantumRegister(2, name='q')
        qc = QuantumCircuit(qr)

        rnd = 2 * np.pi * np.random.random(size=3)
        qc.u3(rnd[0], rnd[1], rnd[2], qr[0])
        rnd = 2 * np.pi * np.random.random(size=3)
        qc.u3(rnd[0], rnd[1], rnd[2], qr[1])

        qc.cx(qr[1], qr[0])

        rnd = 2 * np.pi * np.random.random(size=3)
        qc.u3(rnd[0], rnd[1], rnd[2], qr[0])
        rnd = 2 * np.pi * np.random.random(size=3)
        qc.u3(rnd[0], rnd[1], rnd[2], qr[1])

        qc.cx(qr[0], qr[1])

        rnd = 2 * np.pi * np.random.random(size=3)
        qc.u3(rnd[0], rnd[1], rnd[2], qr[0])
        rnd = 2 * np.pi * np.random.random(size=3)
        qc.u3(rnd[0], rnd[1], rnd[2], qr[1])

        sim = UnitarySimulatorPy()
        U = execute(qc, sim).result().get_unitary()
        self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(U), 2)
Пример #3
0
    def test_2q_local_invariance_simple(self):
        """Check the local invariance parameters
        for known simple cases.
        """
        sim = UnitarySimulatorPy()

        qr = QuantumRegister(2, name='q')
        qc = QuantumCircuit(qr)
        U = execute(qc, sim).result().get_unitary()
        vec = two_qubit_local_invariants(U)
        assert_allclose(vec, [1, 0, 3])

        qr = QuantumRegister(2, name='q')
        qc = QuantumCircuit(qr)
        qc.cx(qr[1], qr[0])
        U = execute(qc, sim).result().get_unitary()
        vec = two_qubit_local_invariants(U)
        assert_allclose(vec, [0, 0, 1])

        qr = QuantumRegister(2, name='q')
        qc = QuantumCircuit(qr)
        qc.cx(qr[1], qr[0])
        qc.cx(qr[0], qr[1])
        U = execute(qc, sim).result().get_unitary()
        vec = two_qubit_local_invariants(U)
        assert_allclose(vec, [0, 0, -1])

        qr = QuantumRegister(2, name='q')
        qc = QuantumCircuit(qr)
        qc.swap(qr[1], qr[0])
        U = execute(qc, sim).result().get_unitary()
        vec = two_qubit_local_invariants(U)
        assert_allclose(vec, [-1, 0, -3])
Пример #4
0
    def test_cx_equivalence_3cx_random(self, rnd, seed):
        """Check random circuits with 3 cx gates are outside the 0, 1, and 2 qubit regions.
        """
        qr = QuantumRegister(2, name='q')
        qc = QuantumCircuit(qr)

        qc.u3(rnd[0], rnd[1], rnd[2], qr[0])
        qc.u3(rnd[3], rnd[4], rnd[5], qr[1])

        qc.cx(qr[1], qr[0])

        qc.u3(rnd[6], rnd[7], rnd[8], qr[0])
        qc.u3(rnd[9], rnd[10], rnd[11], qr[1])

        qc.cx(qr[0], qr[1])

        qc.u3(rnd[12], rnd[13], rnd[14], qr[0])
        qc.u3(rnd[15], rnd[16], rnd[17], qr[1])

        qc.cx(qr[1], qr[0])

        qc.u3(rnd[18], rnd[19], rnd[20], qr[0])
        qc.u3(rnd[21], rnd[22], rnd[23], qr[1])

        sim = UnitarySimulatorPy()
        unitary = execute(qc, sim, seed_simulator=seed).result().get_unitary()
        self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 3)
Пример #5
0
    def test_cx_equivalence_2cx(self, seed=2):
        """Check circuits with  2 cx gates locally equivalent to some circuit with 2 cx.
        """
        state = np.random.default_rng(seed)
        rnd = 2 * np.pi * state.random(size=18)

        qr = QuantumRegister(2, name='q')
        qc = QuantumCircuit(qr)

        qc.u(rnd[0], rnd[1], rnd[2], qr[0])
        qc.u(rnd[3], rnd[4], rnd[5], qr[1])

        qc.cx(qr[1], qr[0])

        qc.u(rnd[6], rnd[7], rnd[8], qr[0])
        qc.u(rnd[9], rnd[10], rnd[11], qr[1])

        qc.cx(qr[0], qr[1])

        qc.u(rnd[12], rnd[13], rnd[14], qr[0])
        qc.u(rnd[15], rnd[16], rnd[17], qr[1])

        sim = UnitarySimulatorPy()
        unitary = execute(qc, sim).result().get_unitary()
        self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 2)
        self.assertTrue(Operator(two_qubit_cnot_decompose(unitary)).equiv(unitary))
Пример #6
0
 def check_two_qubit_weyl_decomposition(self,
                                        target_unitary,
                                        tolerance=1.e-7):
     """Check TwoQubitWeylDecomposition() works for a given operator"""
     with self.subTest(unitary=target_unitary):
         decomp = TwoQubitWeylDecomposition(target_unitary)
         q = QuantumRegister(2)
         decomp_circuit = QuantumCircuit(q)
         decomp_circuit.append(UnitaryGate(decomp.K2r), [q[0]])
         decomp_circuit.append(UnitaryGate(decomp.K2l), [q[1]])
         decomp_circuit.append(
             UnitaryGate(Ud(decomp.a, decomp.b, decomp.c)), [q[0], q[1]])
         decomp_circuit.append(UnitaryGate(decomp.K1r), [q[0]])
         decomp_circuit.append(UnitaryGate(decomp.K1l), [q[1]])
         result = execute(decomp_circuit, UnitarySimulatorPy()).result()
         decomp_unitary = result.get_unitary()
         target_unitary *= la.det(target_unitary)**(-0.25)
         decomp_unitary *= la.det(decomp_unitary)**(-0.25)
         maxdists = [
             np.max(np.abs(target_unitary + phase * decomp_unitary))
             for phase in [1, 1j, -1, -1j]
         ]
         maxdist = np.min(maxdists)
         self.assertTrue(
             np.abs(maxdist) < tolerance,
             "Worst distance {}".format(maxdist))
Пример #7
0
    def test_cx_equivalence_3cx(self, seed=3):
        """Check circuits with 3 cx gates are outside the 0, 1, and 2 qubit regions.
        """
        state = np.random.default_rng(seed)
        rnd = 2 * np.pi * state.random(size=24)

        qr = QuantumRegister(2, name='q')
        qc = QuantumCircuit(qr)

        qc.u(rnd[0], rnd[1], rnd[2], qr[0])
        qc.u(rnd[3], rnd[4], rnd[5], qr[1])

        qc.cx(qr[1], qr[0])

        qc.u(rnd[6], rnd[7], rnd[8], qr[0])
        qc.u(rnd[9], rnd[10], rnd[11], qr[1])

        qc.cx(qr[0], qr[1])

        qc.u(rnd[12], rnd[13], rnd[14], qr[0])
        qc.u(rnd[15], rnd[16], rnd[17], qr[1])

        qc.cx(qr[1], qr[0])

        qc.u(rnd[18], rnd[19], rnd[20], qr[0])
        qc.u(rnd[21], rnd[22], rnd[23], qr[1])

        sim = UnitarySimulatorPy()
        unitary = execute(qc, sim).result().get_unitary()
        self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 3)
        self.assertTrue(Operator(two_qubit_cnot_decompose(unitary)).equiv(unitary))
Пример #8
0
 def test_two_qubit_kak_from_paulis(self):
     """Verify decomposing Paulis with KAK
     """
     pauli_xz = Pauli(label='XZ')
     unitary = Unitary(Operator(pauli_xz).data)
     decomp_circuit = two_qubit_kak(unitary)
     result = execute(decomp_circuit, UnitarySimulatorPy()).result()
     decomp_unitary = Unitary(result.get_unitary())
     self.assertAlmostEqual(decomp_unitary, unitary)
Пример #9
0
    def test_cx_equivalence_0cx_random(self, rnd, seed):
        """Check random circuits with  0 cx gates locally equivalent to identity."""
        qr = QuantumRegister(2, name="q")
        qc = QuantumCircuit(qr)

        qc.u(rnd[0], rnd[1], rnd[2], qr[0])
        qc.u(rnd[3], rnd[4], rnd[5], qr[1])

        sim = UnitarySimulatorPy()
        unitary = execute(qc, sim, seed_simulator=seed).result().get_unitary()
        self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 0)
Пример #10
0
 def test_two_qubit_kak_from_paulis(self):
     """Verify decomposing Paulis with KAK
     """
     pauli_xz = Pauli(label='XZ')
     unitary = Operator(pauli_xz)
     decomp_circuit = two_qubit_kak(unitary)
     result = execute(decomp_circuit, UnitarySimulatorPy()).result()
     decomp_unitary = Operator(result.get_unitary())
     equal_up_to_phase = matrix_equal(unitary.data,
                                      decomp_unitary.data,
                                      ignore_phase=True,
                                      atol=1e-7)
     self.assertTrue(equal_up_to_phase)
Пример #11
0
 def test_two_qubit_kak(self):
     """Verify KAK decomposition for random Haar 4x4 unitaries.
     """
     for _ in range(100):
         unitary = random_unitary(4)
         with self.subTest(unitary=unitary):
             decomp_circuit = two_qubit_kak(unitary)
             result = execute(decomp_circuit, UnitarySimulatorPy()).result()
             decomp_unitary = Unitary(result.get_unitary())
             self.assertAlmostEqual(process_fidelity(
                 unitary.representation, decomp_unitary.representation),
                                    1.0,
                                    places=7)
Пример #12
0
 def test_two_qubit_kak(self):
     """Verify KAK decomposition for random Haar 4x4 unitaries.
     """
     for _ in range(100):
         unitary = random_unitary(4)
         with self.subTest(unitary=unitary):
             decomp_circuit = two_qubit_kak(unitary)
             result = execute(decomp_circuit, UnitarySimulatorPy()).result()
             decomp_unitary = Operator(result.get_unitary())
             equal_up_to_phase = matrix_equal(unitary.data,
                                              decomp_unitary.data,
                                              ignore_phase=True,
                                              atol=1e-7)
             self.assertTrue(equal_up_to_phase)
Пример #13
0
 def check_exact_decomposition(self,
                               target_unitary,
                               decomposer,
                               tolerance=1.e-7):
     """Check exact decomposition for a particular target"""
     decomp_circuit = decomposer(target_unitary)
     result = execute(decomp_circuit,
                      UnitarySimulatorPy(),
                      optimization_level=0).result()
     decomp_unitary = result.get_unitary()
     maxdist = np.max(np.abs(target_unitary - decomp_unitary))
     self.assertTrue(
         np.abs(maxdist) < tolerance,
         "Unitary {}: Worst distance {}".format(target_unitary, maxdist))
Пример #14
0
 def check_one_qubit_euler_angles(self, operator, tolerance=1e-14):
     """Check euler_angles_1q works for the given unitary
     """
     with self.subTest(operator=operator):
         target_unitary = operator.data
         angles = euler_angles_1q(target_unitary)
         decomp_circuit = QuantumCircuit(1)
         decomp_circuit.u3(*angles, 0)
         result = execute(decomp_circuit, UnitarySimulatorPy()).result()
         decomp_unitary = result.get_unitary()
         target_unitary *= la.det(target_unitary)**(-0.5)
         decomp_unitary *= la.det(decomp_unitary)**(-0.5)
         maxdist = np.max(np.abs(target_unitary - decomp_unitary))
         if maxdist > 0.1:
             maxdist = np.max(np.abs(target_unitary + decomp_unitary))
         self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist))
Пример #15
0
 def test_one_qubit_euler_angles(self):
     """Verify euler_angles_1q produces correct Euler angles for
     a single-qubit unitary.
     """
     for _ in range(100):
         unitary = random_unitary(2)
         with self.subTest(unitary=unitary):
             angles = euler_angles_1q(unitary.data)
             decomp_circuit = QuantumCircuit(1)
             decomp_circuit.u3(*angles, 0)
             result = execute(decomp_circuit, UnitarySimulatorPy()).result()
             decomp_unitary = Operator(result.get_unitary())
             equal_up_to_phase = matrix_equal(unitary.data,
                                              decomp_unitary.data,
                                              ignore_phase=True,
                                              atol=1e-7)
             self.assertTrue(equal_up_to_phase)
    def test_consolidate_small_block(self):
        """test a small block of gates can be turned into a unitary on same wires"""
        qr = QuantumRegister(2, "qr")
        qc = QuantumCircuit(qr)
        qc.u1(0.5, qr[0])
        qc.u2(0.2, 0.6, qr[1])
        qc.cx(qr[0], qr[1])
        dag = circuit_to_dag(qc)

        pass_ = ConsolidateBlocks(force_consolidate=True)
        pass_.property_set['block_list'] = [list(dag.topological_op_nodes())]
        new_dag = pass_.run(dag)

        sim = UnitarySimulatorPy()
        result = execute(qc, sim).result()
        unitary = UnitaryGate(result.get_unitary())
        self.assertEqual(len(new_dag.op_nodes()), 1)
        fidelity = process_fidelity(new_dag.op_nodes()[0].op.to_matrix(), unitary.to_matrix())
        self.assertAlmostEqual(fidelity, 1.0, places=7)
    def test_3q_blocks(self):
        """blocks of more than 2 qubits work."""
        qr = QuantumRegister(3, "qr")
        qc = QuantumCircuit(qr)
        qc.u1(0.5, qr[0])
        qc.u2(0.2, 0.6, qr[1])
        qc.cx(qr[2], qr[1])
        qc.cx(qr[0], qr[1])
        dag = circuit_to_dag(qc)

        pass_ = ConsolidateBlocks(force_consolidate=True)
        pass_.property_set['block_list'] = [list(dag.topological_op_nodes())]
        new_dag = pass_.run(dag)

        sim = UnitarySimulatorPy()
        result = execute(qc, sim).result()
        unitary = UnitaryGate(result.get_unitary())
        self.assertEqual(len(new_dag.op_nodes()), 1)
        fidelity = process_fidelity(new_dag.op_nodes()[0].op.to_matrix(), unitary.to_matrix())
        self.assertAlmostEqual(fidelity, 1.0, places=7)
    def test_block_spanning_two_regs(self):
        """blocks spanning wires on different quantum registers work."""
        qr0 = QuantumRegister(1, "qr0")
        qr1 = QuantumRegister(1, "qr1")
        qc = QuantumCircuit(qr0, qr1)
        qc.u1(0.5, qr0[0])
        qc.u2(0.2, 0.6, qr1[0])
        qc.cx(qr0[0], qr1[0])
        dag = circuit_to_dag(qc)

        pass_ = ConsolidateBlocks(force_consolidate=True)
        pass_.property_set['block_list'] = [list(dag.topological_op_nodes())]
        new_dag = pass_.run(dag)

        sim = UnitarySimulatorPy()
        result = execute(qc, sim).result()
        unitary = UnitaryGate(result.get_unitary())
        self.assertEqual(len(new_dag.op_nodes()), 1)
        fidelity = process_fidelity(new_dag.op_nodes()[0].op.to_matrix(), unitary.to_matrix())
        self.assertAlmostEqual(fidelity, 1.0, places=7)
Пример #19
0
    def test_cx_equivalence_2cx_random(self, rnd, seed):
        """Check random circuits with 2 cx gates locally equivalent to some circuit with 2 cx.
        """
        qr = QuantumRegister(2, name='q')
        qc = QuantumCircuit(qr)

        qc.u3(rnd[0], rnd[1], rnd[2], qr[0])
        qc.u3(rnd[3], rnd[4], rnd[5], qr[1])

        qc.cx(qr[1], qr[0])

        qc.u3(rnd[6], rnd[7], rnd[8], qr[0])
        qc.u3(rnd[9], rnd[10], rnd[11], qr[1])

        qc.cx(qr[0], qr[1])

        qc.u3(rnd[12], rnd[13], rnd[14], qr[0])
        qc.u3(rnd[15], rnd[16], rnd[17], qr[1])

        sim = UnitarySimulatorPy()
        unitary = execute(qc, sim, seed_simulator=seed).result().get_unitary()
        self.assertEqual(two_qubit_cnot_decompose.num_basis_gates(unitary), 2)
Пример #20
0
    def test_block_spanning_two_regs_different_index(self):
        """blocks spanning wires on different quantum registers work when the wires
        could have conflicting indices. This was raised in #2806 when a CX was applied
        across multiple registers and their indices collided, raising an error."""
        qr0 = QuantumRegister(1, "qr0")
        qr1 = QuantumRegister(2, "qr1")
        qc = QuantumCircuit(qr0, qr1)
        qc.cx(qr0[0], qr1[1])
        dag = circuit_to_dag(qc)

        pass_ = ConsolidateBlocks(force_consolidate=True)
        pass_.property_set['block_list'] = [list(dag.topological_op_nodes())]
        new_dag = pass_.run(dag)

        sim = UnitarySimulatorPy()
        original_result = execute(qc, sim).result()
        original_unitary = UnitaryGate(original_result.get_unitary())

        from qiskit.converters import dag_to_circuit
        new_result = execute(dag_to_circuit(new_dag), sim).result()
        new_unitary = UnitaryGate(new_result.get_unitary())

        self.assertEqual(original_unitary, new_unitary)
Пример #21
0
    def run(self, dag):
        """iterate over each block and replace it with an equivalent Unitary
        on the same wires.
        """
        new_dag = DAGCircuit()
        for qreg in dag.qregs.values():
            new_dag.add_qreg(qreg)
        for creg in dag.cregs.values():
            new_dag.add_creg(creg)

        sim = UnitarySimulatorPy()

        # compute ordered indices for the global circuit wires
        global_index_map = {}
        for wire in dag.wires:
            if not isinstance(wire[0], QuantumRegister):
                continue
            global_qregs = list(dag.qregs.values())
            global_index_map[wire] = global_qregs.index(wire[0]) + wire[1]

        blocks = self.property_set['block_list']
        nodes_seen = set()

        for node in dag.topological_op_nodes():
            # skip already-visited nodes or input/output nodes
            if node in nodes_seen or node.type == 'in' or node.type == 'out':
                continue
            # check if the node belongs to the next block
            if blocks and node in blocks[0]:
                block = blocks[0]
                # find the qubits involved in this block
                block_qargs = set()
                for nd in block:
                    block_qargs |= set(nd.qargs)
                # convert block to a sub-circuit, then simulate unitary and add
                block_width = len(block_qargs)
                q = QuantumRegister(block_width)
                subcirc = QuantumCircuit(q)
                block_index_map = self._block_qargs_to_indices(
                    block_qargs, global_index_map)
                for nd in block:
                    nodes_seen.add(nd)
                    subcirc.append(nd.op,
                                   [q[block_index_map[i]] for i in nd.qargs])
                qobj = assemble_circuits(subcirc)
                unitary_matrix = sim.run(qobj).result().get_unitary()
                unitary = Unitary(unitary_matrix)
                new_dag.apply_operation_back(
                    unitary,
                    sorted(block_qargs, key=lambda x: block_index_map[x]))
                del blocks[0]
            else:
                # the node could belong to some future block, but in that case
                # we simply skip it. It is guaranteed that we will revisit that
                # future block, via its other nodes
                for block in blocks[1:]:
                    if node in block:
                        break
                # freestanding nodes can just be added
                else:
                    nodes_seen.add(node)
                    new_dag.apply_operation_back(node.op, node.qargs,
                                                 node.cargs)

        return new_dag