Esempio n. 1
0
 def test_basic_gate_inverse(self):
     """Test that a basic pair of gate inverse can be cancelled."""
     qc = QuantumCircuit(2, 2)
     qc.rx(np.pi / 4, 0)
     qc.rx(-np.pi / 4, 0)
     pass_ = InverseCancellation([(RXGate(np.pi / 4), RXGate(-np.pi / 4))])
     pm = PassManager(pass_)
     new_circ = pm.run(qc)
     gates_after = new_circ.count_ops()
     self.assertNotIn("rx", gates_after)
Esempio n. 2
0
 def test_get_instruction_from_name(self):
     with self.assertRaises(KeyError):
         self.empty_target.operation_from_name("measure")
     self.assertEqual(self.ibm_target.operation_from_name("measure"), Measure())
     self.assertEqual(self.fake_backend_target.operation_from_name("rx_30"), RXGate(math.pi / 6))
     self.assertEqual(
         self.fake_backend_target.operation_from_name("rx"),
         RXGate(self.fake_backend._theta),
     )
     self.assertEqual(self.ideal_sim_target.operation_from_name("ccx"), CCXGate())
Esempio n. 3
0
 def test_non_inverse_do_not_cancel(self):
     """Test that non-inverse gate pairs do not cancel."""
     qc = QuantumCircuit(2, 2)
     qc.rx(np.pi / 4, 0)
     qc.rx(np.pi / 4, 0)
     pass_ = InverseCancellation([(RXGate(np.pi / 4), RXGate(-np.pi / 4))])
     pm = PassManager(pass_)
     new_circ = pm.run(qc)
     gates_after = new_circ.count_ops()
     self.assertIn("rx", gates_after)
     self.assertEqual(gates_after["rx"], 2)
    def test_insert_midmeas_hahn_asap(self):
        """Test a single X gate as Hahn echo can absorb in the upstream circuit.

                               ┌──────────────────┐ ┌────────────────┐┌─────────┐»
        q_0: ────────■─────────┤ U(3π/4,-π/2,π/2) ├─┤ Delay(600[dt]) ├┤ Rx(π/4) ├»
                   ┌─┴─┐       └──────────────────┘┌┴────────────────┤└─────────┘»
        q_1: ──────┤ X ├────────────────■──────────┤ Delay(1000[dt]) ├─────■─────»
             ┌─────┴───┴──────┐       ┌─┴─┐        └───────┬─┬───────┘   ┌─┴─┐   »
        q_2: ┤ Delay(700[dt]) ├───────┤ X ├────────────────┤M├───────────┤ X ├───»
             └────────────────┘       └───┘                └╥┘           └───┘   »
        c: 1/═══════════════════════════════════════════════╩════════════════════»
                                                            0                    »
        «     ┌────────────────┐
        «q_0: ┤ Delay(600[dt]) ├──■──
        «     └────────────────┘┌─┴─┐
        «q_1: ──────────────────┤ X ├
        «     ┌────────────────┐└───┘
        «q_2: ┤ Delay(700[dt]) ├─────
        «     └────────────────┘
        «c: 1/═══════════════════════
        «
        """
        dd_sequence = [RXGate(pi / 4)]
        pm = PassManager([
            ASAPScheduleAnalysis(self.durations),
            PadDynamicalDecoupling(self.durations, dd_sequence),
        ])

        midmeas_dd = pm.run(self.midmeas)

        combined_u = UGate(3 * pi / 4, -pi / 2, pi / 2)

        expected = QuantumCircuit(3, 1)
        expected.cx(0, 1)
        expected.compose(combined_u, [0], inplace=True)
        expected.delay(600, 0)
        expected.rx(pi / 4, 0)
        expected.delay(600, 0)
        expected.delay(700, 2)
        expected.cx(1, 2)
        expected.delay(1000, 1)
        expected.measure(2, 0)
        expected.cx(1, 2)
        expected.cx(0, 1)
        expected.delay(700, 2)

        self.assertEqual(midmeas_dd, expected)
        # check the absorption into U was done correctly
        self.assertTrue(
            Operator(XGate()).equiv(
                Operator(UGate(3 * pi / 4, -pi / 2, pi / 2))
                & Operator(RXGate(pi / 4))))
    def test_for_loop_invalid_params_setter(self):
        """Verify we catch invalid param settings for ForLoopOp."""
        body = QuantumCircuit(3, 1)
        loop_parameter = Parameter("foo")
        indexset = range(0, 10, 2)

        body.rx(loop_parameter, 0)

        op = ForLoopOp(indexset, loop_parameter, body)

        with self.assertWarnsRegex(UserWarning,
                                   r"loop_parameter was not found"):
            op.params = [indexset, Parameter("foo"), body]

        with self.assertRaisesRegex(CircuitError,
                                    r"to be of type QuantumCircuit"):
            op.params = [indexset, loop_parameter, RXGate(loop_parameter)]

        bad_body = QuantumCircuit(2, 1)
        with self.assertRaisesRegex(
                CircuitError,
                r"num_clbits different than that of the ForLoopOp"):
            op.params = [indexset, loop_parameter, bad_body]

        with self.assertRaisesRegex(CircuitError,
                                    r"to be either of type Parameter or None"):
            _ = ForLoopOp(indexset, "foo", body)
Esempio n. 6
0
    def exp_i(self) -> OperatorBase:
        """ Return a ``CircuitOp`` equivalent to e^-iH for this operator H. """
        # if only one qubit is significant, we can perform the evolution
        corrected_x = self.primitive.x[::-1]  # type: ignore
        corrected_z = self.primitive.z[::-1]  # type: ignore
        # pylint: disable=import-outside-toplevel,no-member
        sig_qubits = np.logical_or(corrected_x, corrected_z)
        if np.sum(sig_qubits) == 0:
            # e^I is just a global phase, but we can keep track of it! Should we?
            # For now, just return identity
            return PauliOp(self.primitive)
        if np.sum(sig_qubits) == 1:
            sig_qubit_index = sig_qubits.tolist().index(True)
            coeff = np.real(self.coeff) \
                if not isinstance(self.coeff, ParameterExpression) \
                else self.coeff
            # Y rotation
            if corrected_x[sig_qubit_index] and corrected_z[sig_qubit_index]:
                rot_op = PrimitiveOp(RYGate(coeff))
            # Z rotation
            elif corrected_z[sig_qubit_index]:
                rot_op = PrimitiveOp(RZGate(coeff))
            # X rotation
            elif corrected_x[sig_qubit_index]:
                rot_op = PrimitiveOp(RXGate(coeff))

            from ..operator_globals import I
            left_pad = I.tensorpower(sig_qubit_index)
            right_pad = I.tensorpower(self.num_qubits - sig_qubit_index - 1)
            # Need to use overloaded operators here in case left_pad == I^0
            return left_pad ^ rot_op ^ right_pad
        else:
            from ..evolutions.evolved_op import EvolvedOp
            return EvolvedOp(self)
Esempio n. 7
0
 def test_get_instructions_for_qargs(self):
     with self.assertRaises(KeyError):
         self.empty_target.operations_for_qargs((0, ))
     expected = [RZGate(self.theta), IGate(), SXGate(), XGate(), Measure()]
     res = self.ibm_target.operations_for_qargs((0, ))
     for gate in expected:
         self.assertIn(gate, res)
     expected = [ECRGate()]
     res = self.fake_backend_target.operations_for_qargs((1, 0))
     for gate in expected:
         self.assertIn(gate, res)
     expected = [CXGate()]
     res = self.fake_backend_target.operations_for_qargs((0, 1))
     self.assertEqual(expected, res)
     ideal_sim_expected = [
         UGate(self.theta, self.phi, self.lam),
         RXGate(self.theta),
         RYGate(self.theta),
         RZGate(self.theta),
         CXGate(),
         ECRGate(),
         CCXGate(),
         Measure(),
     ]
     for gate in ideal_sim_expected:
         self.assertIn(gate,
                       self.ideal_sim_target.operations_for_qargs(None))
Esempio n. 8
0
 def test_non_gate_inverse_raise_error(self):
     """Test that non-inverse gate inputs raise an error."""
     qc = QuantumCircuit(2, 2)
     qc.rx(np.pi / 4, 0)
     qc.rx(np.pi / 4, 0)
     with self.assertRaises(TranspilerError):
         InverseCancellation([(RXGate(np.pi / 4))])
    def test_calibrations_basis_gates(self):
        """Check if the calibrations for basis gates provided are added correctly."""
        circ = QuantumCircuit(2)

        with pulse.build() as q0_x180:
            pulse.play(pulse.library.Gaussian(20, 1.0, 3.0),
                       pulse.DriveChannel(0))
        with pulse.build() as q1_y90:
            pulse.play(pulse.library.Gaussian(20, -1.0, 3.0),
                       pulse.DriveChannel(1))

        # Add calibration
        circ.add_calibration(RXGate(3.14), [0], q0_x180)
        circ.add_calibration(RYGate(1.57), [1], q1_y90)

        self.assertEqual(set(circ.calibrations.keys()), {"rx", "ry"})
        self.assertEqual(set(circ.calibrations["rx"].keys()),
                         {((0, ), (3.14, ))})
        self.assertEqual(set(circ.calibrations["ry"].keys()),
                         {((1, ), (1.57, ))})
        self.assertEqual(
            circ.calibrations["rx"][((0, ), (3.14, ))].instructions,
            q0_x180.instructions)
        self.assertEqual(
            circ.calibrations["ry"][((1, ), (1.57, ))].instructions,
            q1_y90.instructions)
Esempio n. 10
0
 def test_operations(self):
     self.assertEqual(self.empty_target.operations, [])
     ibm_expected = [
         RZGate(self.theta),
         IGate(),
         SXGate(),
         XGate(),
         CXGate(),
         Measure()
     ]
     for gate in ibm_expected:
         self.assertIn(gate, self.ibm_target.operations)
     aqt_expected = [
         RZGate(self.theta),
         RXGate(self.theta),
         RYGate(self.theta),
         RGate(self.theta, self.phi),
         RXXGate(self.theta),
     ]
     for gate in aqt_expected:
         self.assertIn(gate, self.aqt_target.operations)
     fake_expected = [
         UGate(self.fake_backend._theta, self.fake_backend._phi,
               self.fake_backend._lam),
         CXGate(),
         Measure(),
         ECRGate(),
         RXGate(math.pi / 6),
         RXGate(self.fake_backend._theta),
     ]
     for gate in fake_expected:
         self.assertIn(gate, self.fake_backend_target.operations)
     ideal_sim_expected = [
         UGate(self.theta, self.phi, self.lam),
         RXGate(self.theta),
         RYGate(self.theta),
         RZGate(self.theta),
         CXGate(),
         ECRGate(),
         CCXGate(),
         Measure(),
     ]
     for gate in ideal_sim_expected:
         self.assertIn(gate, self.ideal_sim_target.operations)
Esempio n. 11
0
    def test_multi_circuit_uncommon_calibrations(self):
        """Test that disassembler parses uncommon calibrations (stored at QOBJ experiment-level)."""
        with pulse.build() as sched:
            pulse.play(pulse.library.Drag(50, 0.15, 4, 2), pulse.DriveChannel(0))

        qc_0 = QuantumCircuit(2)
        qc_0.h(0)
        qc_0.append(RXGate(np.pi), [1])
        qc_0.add_calibration("h", [0], sched)
        qc_0.add_calibration(RXGate(np.pi), [1], sched)

        qc_1 = QuantumCircuit(2)
        qc_1.h(0)

        circuits = [qc_0, qc_1]
        qobj = assemble(circuits, FakeOpenPulse2Q())
        output_circuits, _, _ = disassemble(qobj)

        self.assertCircuitCalibrationsEqual(circuits, output_circuits)
Esempio n. 12
0
def rx_matrix(phi: float) -> np.ndarray:
    """
    Computes an RX rotation by the angle of ``phi``.

    Args:
        phi: rotation angle.

    Returns:
        an RX rotation matrix.
    """
    return RXGate(phi).to_matrix()
    def test_multi_controlled_rotation_gate_matrices(self, num_controls,
                                                     base_gate_name,
                                                     use_basis_gates):
        """Test the multi controlled rotation gates without ancillas.

        Based on the test moved here from Aqua:
        https://github.com/Qiskit/qiskit-aqua/blob/769ca8f/test/aqua/test_mcr.py
        """
        q_controls = QuantumRegister(num_controls)
        q_target = QuantumRegister(1)

        # iterate over all possible combinations of control qubits
        for ctrl_state in range(2**num_controls):
            bitstr = bin(ctrl_state)[2:].zfill(num_controls)[::-1]
            theta = 0.871236 * pi
            qc = QuantumCircuit(q_controls, q_target)
            for idx, bit in enumerate(bitstr):
                if bit == '0':
                    qc.x(q_controls[idx])

            # call mcrx/mcry/mcrz
            if base_gate_name == 'y':
                qc.mcry(theta,
                        q_controls,
                        q_target[0],
                        None,
                        mode='noancilla',
                        use_basis_gates=use_basis_gates)
            else:  # case 'x' or 'z' only support the noancilla mode and do not have this keyword
                getattr(qc, 'mcr' + base_gate_name)(
                    theta,
                    q_controls,
                    q_target[0],
                    use_basis_gates=use_basis_gates)

            for idx, bit in enumerate(bitstr):
                if bit == '0':
                    qc.x(q_controls[idx])

            backend = BasicAer.get_backend('unitary_simulator')
            simulated = execute(qc, backend).result().get_unitary(qc)

            if base_gate_name == 'x':
                rot_mat = RXGate(theta).to_matrix()
            elif base_gate_name == 'y':
                rot_mat = RYGate(theta).to_matrix()
            else:  # case 'z'
                rot_mat = U1Gate(theta).to_matrix()

            expected = _compute_control_matrix(rot_mat,
                                               num_controls,
                                               ctrl_state=ctrl_state)
            with self.subTest(msg='control state = {}'.format(ctrl_state)):
                self.assertTrue(matrix_equal(simulated, expected))
 def test_param_gate_instance(self):
     """Verify that the same Parameter gate instance is not being used in
     multiple circuits."""
     a, b = Parameter("a"), Parameter("b")
     rx = RXGate(a)
     qc0, qc1 = QuantumCircuit(1), QuantumCircuit(1)
     qc0.append(rx, [0])
     qc1.append(rx, [0])
     qc0.assign_parameters({a: b}, inplace=True)
     qc0_instance = next(iter(qc0._parameter_table[b]))[0]
     qc1_instance = next(iter(qc1._parameter_table[a]))[0]
     self.assertNotEqual(qc0_instance, qc1_instance)
    def test_hadamard_to_rot_gates(self):
        """Test a transpilation from H to Rx, Ry gates"""
        qr = QuantumRegister(1)
        qc = QuantumCircuit(qr)
        qc.h(0)

        expected = QuantumCircuit(qr, global_phase=np.pi / 2)
        expected.append(RYGate(theta=np.pi / 2), [0])
        expected.append(RXGate(theta=np.pi), [0])

        circuit = transpile(qc, basis_gates=['rx', 'ry'], optimization_level=0)
        self.assertEqual(circuit, expected)
class TestParameterCtrlState(QiskitTestCase):
    """Test gate equality with ctrl_state parameter."""
    @data((RXGate(0.5), CRXGate(0.5)), (RYGate(0.5), CRYGate(0.5)),
          (RZGate(0.5), CRZGate(0.5)), (XGate(), CXGate()),
          (YGate(), CYGate()), (ZGate(), CZGate()),
          (U1Gate(0.5), CU1Gate(0.5)), (SwapGate(), CSwapGate()),
          (HGate(), CHGate()), (U3Gate(0.1, 0.2, 0.3), CU3Gate(0.1, 0.2, 0.3)))
    @unpack
    def test_ctrl_state_one(self, gate, controlled_gate):
        """Test controlled gates with ctrl_state
        See https://github.com/Qiskit/qiskit-terra/pull/4025
        """
        self.assertEqual(gate.control(1, ctrl_state='1'), controlled_gate)
Esempio n. 17
0
 def test_instructions(self):
     self.assertEqual(self.empty_target.instructions, [])
     ibm_expected = [
         (IGate(), (0, )),
         (IGate(), (1, )),
         (IGate(), (2, )),
         (IGate(), (3, )),
         (IGate(), (4, )),
         (RZGate(self.theta), (0, )),
         (RZGate(self.theta), (1, )),
         (RZGate(self.theta), (2, )),
         (RZGate(self.theta), (3, )),
         (RZGate(self.theta), (4, )),
         (SXGate(), (0, )),
         (SXGate(), (1, )),
         (SXGate(), (2, )),
         (SXGate(), (3, )),
         (SXGate(), (4, )),
         (XGate(), (0, )),
         (XGate(), (1, )),
         (XGate(), (2, )),
         (XGate(), (3, )),
         (XGate(), (4, )),
         (CXGate(), (3, 4)),
         (CXGate(), (4, 3)),
         (CXGate(), (3, 1)),
         (CXGate(), (1, 3)),
         (CXGate(), (1, 2)),
         (CXGate(), (2, 1)),
         (CXGate(), (0, 1)),
         (CXGate(), (1, 0)),
         (Measure(), (0, )),
         (Measure(), (1, )),
         (Measure(), (2, )),
         (Measure(), (3, )),
         (Measure(), (4, )),
     ]
     self.assertEqual(ibm_expected, self.ibm_target.instructions)
     ideal_sim_expected = [
         (UGate(self.theta, self.phi, self.lam), None),
         (RXGate(self.theta), None),
         (RYGate(self.theta), None),
         (RZGate(self.theta), None),
         (CXGate(), None),
         (ECRGate(), None),
         (CCXGate(), None),
         (Measure(), None),
     ]
     self.assertEqual(ideal_sim_expected,
                      self.ideal_sim_target.instructions)
    def test_for_loop_invalid_instantiation(self):
        """Verify we catch invalid instantiations of ForLoopOp."""
        body = QuantumCircuit(3, 1)
        loop_parameter = Parameter("foo")
        indexset = range(0, 10, 2)

        body.rx(loop_parameter, 0)

        with self.assertWarnsRegex(UserWarning,
                                   r"loop_parameter was not found"):
            _ = ForLoopOp(indexset, Parameter("foo"), body)

        with self.assertRaisesRegex(CircuitError,
                                    r"to be of type QuantumCircuit"):
            _ = ForLoopOp(indexset, loop_parameter, RXGate(loop_parameter))
Esempio n. 19
0
 def test_instruction_schedule_map_ideal_sim_backend(self):
     ideal_sim_target = Target(num_qubits=3)
     theta = Parameter("theta")
     phi = Parameter("phi")
     lam = Parameter("lambda")
     for inst in [
             UGate(theta, phi, lam),
             RXGate(theta),
             RYGate(theta),
             RZGate(theta),
             CXGate(),
             ECRGate(),
             CCXGate(),
             Measure(),
     ]:
         ideal_sim_target.add_instruction(inst, {None: None})
     inst_map = ideal_sim_target.instruction_schedule_map()
     self.assertEqual(InstructionScheduleMap(), inst_map)
def RXDataset(angle_step=10, probability_step=10, shots=1024, save_dir=None):
    # define constants
    basis_gates = ['u3']
    simulator = QasmSimulator()
    df = pd.DataFrame()

    # generate circuits
    for angle in np.linspace(0, np.pi, angle_step, endpoint=True):
        # define circuit
        circ = QuantumCircuit(1, 1)
        rotate = RXGate(angle)
        circ.append(rotate, [0])
        circ.measure(0, 0)
        new_circ = qiskit.compiler.transpile(circ,
                                             basis_gates=basis_gates,
                                             optimization_level=0)
        print(new_circ)

        # generate noise models:
        for probability in np.linspace(0, 1, probability_step, endpoint=True):
            # add noise
            noise_model = NoiseModel()
            error = depolarizing_error(probability, 1)
            noise_model.add_all_qubit_quantum_error(error,
                                                    ['x', 'u1', 'u2', 'u3'])

            # execution - Noisy
            job = execute(new_circ,
                          simulator,
                          shots=shots,
                          noise_model=noise_model)
            result = job.result()

            # add to Pandas DF
            data = {
                'rx_theta': angle,
                'p': probability,
                'E': result.get_counts(0).get('0', 0) / shots
            }
            df = df.append(data, ignore_index=True)
    df = df[['rx_theta', 'E', 'p']]
    df.to_csv(save_dir + "/dataframe_RX.csv")
    return df
Esempio n. 21
0
    def test_single_circuit_calibrations(self):
        """Test that disassembler parses single circuit QOBJ calibrations (from QOBJ-level)."""
        theta = Parameter("theta")
        qc = QuantumCircuit(2)
        qc.h(0)
        qc.rx(np.pi, 0)
        qc.rx(theta, 1)
        qc = qc.assign_parameters({theta: np.pi})

        with pulse.build() as h_sched:
            pulse.play(pulse.library.Drag(1, 0.15, 4, 2), pulse.DriveChannel(0))

        with pulse.build() as x180:
            pulse.play(pulse.library.Gaussian(1, 0.2, 5), pulse.DriveChannel(0))

        qc.add_calibration("h", [0], h_sched)
        qc.add_calibration(RXGate(np.pi), [0], x180)

        qobj = assemble(qc, FakeOpenPulse2Q())
        output_circuits, _, _ = disassemble(qobj)

        self.assertCircuitCalibrationsEqual([qc], output_circuits)
Esempio n. 22
0
class TestCollect2qBlocks(QiskitTestCase):
    """
    Tests to verify that blocks of 2q interactions are found correctly.
    """
    def test_blocks_in_topological_order(self):
        """the pass returns blocks in correct topological order
                                                    ______
        q0:--[p]-------.----      q0:-------------|      |--
                       |                 ______   |  U2  |
        q1:--[u]--(+)-(+)---   =  q1:---|      |--|______|--
                   |                    |  U1  |
        q2:--------.--------      q2:---|______|------------
        """
        qr = QuantumRegister(3, "qr")
        qc = QuantumCircuit(qr)
        qc.p(0.5, qr[0])
        qc.u(0.0, 0.2, 0.6, qr[1])
        qc.cx(qr[2], qr[1])
        qc.cx(qr[0], qr[1])
        dag = circuit_to_dag(qc)

        topo_ops = list(dag.topological_op_nodes())
        block_1 = [topo_ops[1], topo_ops[2]]
        block_2 = [topo_ops[0], topo_ops[3]]

        pass_ = Collect2qBlocks()
        pass_.run(dag)
        self.assertTrue(pass_.property_set["block_list"], [block_1, block_2])

    def test_block_interrupted_by_gate(self):
        """Test that blocks interrupted by a gate that can't be added
        to the block can be collected correctly

        This was raised in #2775 where a measure in the middle of a block
        stopped the block collection from working properly. This was because
        the pass didn't expect to have measures in the middle of the circuit.

        blocks : [['cx', 'id', 'id', 'id'], ['id', 'cx']]

                ┌───┐┌───┐┌─┐     ┌───┐┌───┐
        q_0: |0>┤ X ├┤ I ├┤M├─────┤ I ├┤ X ├
                └─┬─┘├───┤└╥┘┌───┐└───┘└─┬─┘
        q_1: |0>──■──┤ I ├─╫─┤ I ├───────■──
                     └───┘ ║ └───┘
         c_0: 0 ═══════════╩════════════════

        """
        qc = QuantumCircuit(2, 1)
        qc.cx(1, 0)
        qc.i(0)
        qc.i(1)
        qc.measure(0, 0)
        qc.i(0)
        qc.i(1)
        qc.cx(1, 0)

        dag = circuit_to_dag(qc)
        pass_ = Collect2qBlocks()
        pass_.run(dag)

        # list from Collect2QBlocks of nodes that it should have put into blocks
        good_names = ["cx", "u1", "u2", "u3", "id"]
        dag_nodes = [
            node for node in dag.topological_op_nodes()
            if node.name in good_names
        ]

        # we have to convert them to sets as the ordering can be different
        # but equivalent between python 3.5 and 3.7
        # there is no implied topology in a block, so this isn't an issue
        dag_nodes = [set(dag_nodes[:4]), set(dag_nodes[4:])]
        pass_nodes = [set(bl) for bl in pass_.property_set["block_list"]]

        self.assertEqual(dag_nodes, pass_nodes)

    def test_block_with_classical_register(self):
        """Test that only blocks that share quantum wires are added to the block.
        It was the case that gates which shared a classical wire could be added to
        the same block, despite not sharing the same qubits. This was fixed in #2956.

                                    ┌─────────────────────┐
        q_0: |0>────────────────────┤ U2(0.25*pi,0.25*pi) ├
                     ┌─────────────┐└──────────┬──────────┘
        q_1: |0>──■──┤ U1(0.25*pi) ├───────────┼───────────
                ┌─┴─┐└──────┬──────┘           │
        q_2: |0>┤ X ├───────┼──────────────────┼───────────
                └───┘    ┌──┴──┐            ┌──┴──┐
        c0_0: 0 ═════════╡ = 0 ╞════════════╡ = 0 ╞════════
                         └─────┘            └─────┘

        Previously the blocks collected were : [['cx', 'u1', 'u2']]
        This is now corrected to : [['cx', 'u1']]
        """

        qasmstr = """
        OPENQASM 2.0;
        include "qelib1.inc";
        qreg q[3];
        creg c0[1];

        cx q[1],q[2];
        if(c0==0) u1(0.25*pi) q[1];
        if(c0==0) u2(0.25*pi, 0.25*pi) q[0];
        """
        qc = QuantumCircuit.from_qasm_str(qasmstr)

        pass_manager = PassManager()
        pass_manager.append(Collect2qBlocks())

        pass_manager.run(qc)

        self.assertEqual(
            [["cx"]], [[n.name for n in block]
                       for block in pass_manager.property_set["block_list"]])

    def test_do_not_merge_conditioned_gates(self):
        """Validate that classically conditioned gates are never considered for
        inclusion in a block. Note that there are cases where gates conditioned
        on the same (register, value) pair could be correctly merged, but this is
        not yet implemented.

                 ┌────────┐┌────────┐┌────────┐      ┌───┐
        qr_0: |0>┤ P(0.1) ├┤ P(0.2) ├┤ P(0.3) ├──■───┤ X ├────■───
                 └────────┘└───┬────┘└───┬────┘┌─┴─┐ └─┬─┘  ┌─┴─┐
        qr_1: |0>──────────────┼─────────┼─────┤ X ├───■────┤ X ├─
                               │         │     └───┘   │    └─┬─┘
        qr_2: |0>──────────────┼─────────┼─────────────┼──────┼───
                            ┌──┴──┐   ┌──┴──┐       ┌──┴──┐┌──┴──┐
         cr_0: 0 ═══════════╡     ╞═══╡     ╞═══════╡     ╞╡     ╞
                            │ = 0 │   │ = 0 │       │ = 0 ││ = 1 │
         cr_1: 0 ═══════════╡     ╞═══╡     ╞═══════╡     ╞╡     ╞
                            └─────┘   └─────┘       └─────┘└─────┘

        Previously the blocks collected were : [['p', 'p', 'p', 'cx', 'cx', 'cx']]
        This is now corrected to : [['cx']]
        """
        # ref: https://github.com/Qiskit/qiskit-terra/issues/3215

        qr = QuantumRegister(3, "qr")
        cr = ClassicalRegister(2, "cr")

        qc = QuantumCircuit(qr, cr)
        qc.p(0.1, 0)
        qc.p(0.2, 0).c_if(cr, 0)
        qc.p(0.3, 0).c_if(cr, 0)
        qc.cx(0, 1)
        qc.cx(1, 0).c_if(cr, 0)
        qc.cx(0, 1).c_if(cr, 1)

        pass_manager = PassManager()
        pass_manager.append(Collect2qBlocks())

        pass_manager.run(qc)
        self.assertEqual(
            [["cx"]], [[n.name for n in block]
                       for block in pass_manager.property_set["block_list"]])

    @unpack
    @data(
        (CXGate(), U1Gate(0.1), U2Gate(0.2, 0.3)),
        (RXXGate(pi / 2), RZGate(0.1), RXGate(pi / 2)),
        (
            Gate("custom2qgate", 2, []),
            Gate("custom1qgate1", 1, []),
            Gate("custom1qgate2", 1, []),
        ),
    )
    def test_collect_arbitrary_gates(self, twoQ_gate, oneQ_gate1, oneQ_gate2):
        """Validate we can collect blocks irrespective of gate types in the circuit."""

        qc = QuantumCircuit(3)

        # Block 1 - q[0] and q[1]
        qc.append(oneQ_gate1, [0])
        qc.append(oneQ_gate2, [1])
        qc.append(twoQ_gate, [0, 1])
        qc.append(oneQ_gate1, [0])
        qc.append(oneQ_gate2, [1])

        # Block 2 - q[1] and q[2]
        qc.append(oneQ_gate1, [1])
        qc.append(oneQ_gate2, [2])
        qc.append(twoQ_gate, [1, 2])
        qc.append(oneQ_gate1, [1])
        qc.append(oneQ_gate2, [2])

        # Block 3 - q[0] and q[1]
        qc.append(oneQ_gate1, [0])
        qc.append(oneQ_gate2, [1])
        qc.append(twoQ_gate, [0, 1])
        qc.append(oneQ_gate1, [0])
        qc.append(oneQ_gate2, [1])

        pass_manager = PassManager()
        pass_manager.append(Collect2qBlocks())

        pass_manager.run(qc)
        self.assertEqual(len(pass_manager.property_set["block_list"]), 3)
Esempio n. 23
0
class TestTwoLocal(QiskitTestCase):
    """Tests for the TwoLocal circuit."""

    def assertCircuitEqual(self, qc1, qc2, visual=False, transpiled=True):
        """An equality test specialized to circuits."""
        if transpiled:
            basis_gates = ['id', 'u1', 'u3', 'cx']
            qc1_transpiled = transpile(qc1, basis_gates=basis_gates, optimization_level=0)
            qc2_transpiled = transpile(qc2, basis_gates=basis_gates, optimization_level=0)
            qc1, qc2 = qc1_transpiled, qc2_transpiled

        if visual:
            self.assertEqual(qc1.draw(), qc2.draw())
        else:
            self.assertEqual(qc1, qc2)

    def test_skip_final_rotation_layer(self):
        """Test skipping the final rotation layer works."""
        two = TwoLocal(3, ['ry', 'h'], ['cz', 'cx'], reps=2, skip_final_rotation_layer=True)
        self.assertEqual(two.num_parameters, 6)  # would be 9 with a final rotation layer

    @data((5, 'rx', 'cx', 'full', 2, 15),
          (3, 'x', 'z', 'linear', 1, 0),
          (3, ['rx', 'ry'], ['cry', 'cx'], 'circular', 2, 24),
          )
    @unpack
    def test_num_parameters(self, num_qubits, rot, ent, ent_mode, reps, expected):
        """Test the number of parameters."""
        two = TwoLocal(num_qubits, rotation_blocks=rot, entanglement_blocks=ent,
                       entanglement=ent_mode, reps=reps)

        with self.subTest(msg='num_parameters_settable'):
            self.assertEqual(two.num_parameters_settable, expected)

        with self.subTest(msg='num_parameters'):
            self.assertEqual(two.num_parameters, expected)

    def test_empty_two_local(self):
        """Test the setup of an empty two-local circuit."""
        two = TwoLocal()

        with self.subTest(msg='0 qubits'):
            self.assertEqual(two.num_qubits, 0)

        with self.subTest(msg='no blocks are set'):
            self.assertListEqual(two.rotation_blocks, [])
            self.assertListEqual(two.entanglement_blocks, [])

        with self.subTest(msg='equal to empty circuit'):
            self.assertEqual(two, QuantumCircuit())

    @data('rx', RXGate(Parameter('p')), RXGate, 'circuit')
    def test_various_block_types(self, rot):
        """Test setting the rotation blocks to various type and assert the output type is RX."""
        if rot == 'circuit':
            rot = QuantumCircuit(1)
            rot.rx(Parameter('angle'), 0)

        two = TwoLocal(3, rot, 'cz', reps=1)
        self.assertEqual(len(two.rotation_blocks), 1)
        rotation = two.rotation_blocks[0]

        # decompose
        self.assertIsInstance(rotation.data[0][0], RXGate)

    def test_parameter_setters(self):
        """Test different possibilities to set parameters."""
        two = TwoLocal(3, rotation_blocks='rx', entanglement='cz', reps=2)
        params = [0, 1, 2, Parameter('x'), Parameter('y'), Parameter('z'), 6, 7, 0]
        params_set = set(param for param in params if isinstance(param, Parameter))

        with self.subTest(msg='dict assign and copy'):
            ordered = two.ordered_parameters
            bound = two.assign_parameters(dict(zip(ordered, params)), inplace=False)
            self.assertEqual(bound.parameters, params_set)
            self.assertEqual(two.num_parameters, 9)

        with self.subTest(msg='list assign and copy'):
            ordered = two.ordered_parameters
            bound = two.assign_parameters(params, inplace=False)
            self.assertEqual(bound.parameters, params_set)
            self.assertEqual(two.num_parameters, 9)

        with self.subTest(msg='list assign inplace'):
            ordered = two.ordered_parameters
            two.assign_parameters(params, inplace=True)
            self.assertEqual(two.parameters, params_set)
            self.assertEqual(two.num_parameters, 3)
            self.assertEqual(two.num_parameters_settable, 9)

    def test_parameters_settable_is_constant(self):
        """Test the attribute num_parameters_settable does not change on parameter change."""
        two = TwoLocal(3, rotation_blocks='rx', entanglement='cz', reps=2)
        ordered_params = two.ordered_parameters

        x = Parameter('x')
        two.assign_parameters(dict(zip(ordered_params, [x] * two.num_parameters)), inplace=True)

        with self.subTest(msg='num_parameters collapsed to 1'):
            self.assertEqual(two.num_parameters, 1)

        with self.subTest(msg='num_parameters_settable remained constant'):
            self.assertEqual(two.num_parameters_settable, len(ordered_params))

    def test_compose_inplace_to_circuit(self):
        """Test adding a two-local to an existing circuit."""
        two = TwoLocal(3, ['ry', 'rz'], 'cz', 'full', reps=1, insert_barriers=True)
        circuit = QuantumCircuit(3)
        circuit.compose(two, inplace=True)

        reference = QuantumCircuit(3)
        param_iter = iter(two.ordered_parameters)
        for i in range(3):
            reference.ry(next(param_iter), i)
        for i in range(3):
            reference.rz(next(param_iter), i)
        reference.barrier()
        reference.cz(0, 1)
        reference.cz(0, 2)
        reference.cz(1, 2)
        reference.barrier()
        for i in range(3):
            reference.ry(next(param_iter), i)
        for i in range(3):
            reference.rz(next(param_iter), i)

        self.assertCircuitEqual(circuit, reference)

    def test_composing_two(self):
        """Test adding two two-local circuits."""
        entangler_map = [[0, 3], [0, 2]]
        two = TwoLocal(4, [], 'cry', entangler_map, reps=1)
        circuit = two.compose(two)

        reference = QuantumCircuit(4)
        params = two.ordered_parameters
        for _ in range(2):
            reference.cry(params[0], 0, 3)
            reference.cry(params[1], 0, 2)

        self.assertCircuitEqual(reference, circuit)

    def test_ry_blocks(self):
        """Test that the RealAmplitudes circuit is instantiated correctly."""
        two = RealAmplitudes(4)
        with self.subTest(msg='test rotation gate'):
            self.assertEqual(len(two.rotation_blocks), 1)
            self.assertIsInstance(two.rotation_blocks[0].data[0][0], RYGate)

        with self.subTest(msg='test parameter bounds'):
            expected = [(-np.pi, np.pi)] * two.num_parameters
            np.testing.assert_almost_equal(two.parameter_bounds, expected)

    def test_ry_circuit(self):
        """Test an RealAmplitudes circuit."""
        num_qubits = 3
        reps = 2
        entanglement = 'full'
        parameters = ParameterVector('theta', num_qubits * (reps + 1))
        param_iter = iter(parameters)

        expected = QuantumCircuit(3)
        for _ in range(reps):
            for i in range(num_qubits):
                expected.ry(next(param_iter), i)
            expected.cx(0, 1)
            expected.cx(0, 2)
            expected.cx(1, 2)
        for i in range(num_qubits):
            expected.ry(next(param_iter), i)

        library = RealAmplitudes(num_qubits, reps=reps,
                                 entanglement=entanglement).assign_parameters(parameters)

        self.assertCircuitEqual(library, expected)

    def test_ryrz_blocks(self):
        """Test that the EfficientSU2 circuit is instantiated correctly."""
        two = EfficientSU2(3)
        with self.subTest(msg='test rotation gate'):
            self.assertEqual(len(two.rotation_blocks), 2)
            self.assertIsInstance(two.rotation_blocks[0].data[0][0], RYGate)
            self.assertIsInstance(two.rotation_blocks[1].data[0][0], RZGate)

        with self.subTest(msg='test parameter bounds'):
            expected = [(-np.pi, np.pi)] * two.num_parameters
            np.testing.assert_almost_equal(two.parameter_bounds, expected)

    def test_ryrz_circuit(self):
        """Test an EfficientSU2 circuit."""
        num_qubits = 3
        reps = 2
        entanglement = 'circular'
        parameters = ParameterVector('theta', 2 * num_qubits * (reps + 1))
        param_iter = iter(parameters)

        expected = QuantumCircuit(3)
        for _ in range(reps):
            for i in range(num_qubits):
                expected.ry(next(param_iter), i)
            for i in range(num_qubits):
                expected.rz(next(param_iter), i)
            expected.cx(2, 0)
            expected.cx(0, 1)
            expected.cx(1, 2)
        for i in range(num_qubits):
            expected.ry(next(param_iter), i)
        for i in range(num_qubits):
            expected.rz(next(param_iter), i)

        library = EfficientSU2(num_qubits, reps=reps, entanglement=entanglement).assign_parameters(
            parameters
        )

        self.assertCircuitEqual(library, expected)

    def test_swaprz_blocks(self):
        """Test that the ExcitationPreserving circuit is instantiated correctly."""
        two = ExcitationPreserving(5)
        with self.subTest(msg='test rotation gate'):
            self.assertEqual(len(two.rotation_blocks), 1)
            self.assertIsInstance(two.rotation_blocks[0].data[0][0], RZGate)

        with self.subTest(msg='test entanglement gate'):
            self.assertEqual(len(two.entanglement_blocks), 1)
            block = two.entanglement_blocks[0]
            self.assertEqual(len(block.data), 2)
            self.assertIsInstance(block.data[0][0], RXXGate)
            self.assertIsInstance(block.data[1][0], RYYGate)

        with self.subTest(msg='test parameter bounds'):
            expected = [(-np.pi, np.pi)] * two.num_parameters
            np.testing.assert_almost_equal(two.parameter_bounds, expected)

    def test_swaprz_circuit(self):
        """Test a ExcitationPreserving circuit in iswap mode."""
        num_qubits = 3
        reps = 2
        entanglement = 'linear'
        parameters = ParameterVector('theta', num_qubits * (reps + 1) + reps * (num_qubits - 1))
        param_iter = iter(parameters)

        expected = QuantumCircuit(3)
        for _ in range(reps):
            for i in range(num_qubits):
                expected.rz(next(param_iter), i)
            shared_param = next(param_iter)
            expected.rxx(shared_param, 0, 1)
            expected.ryy(shared_param, 0, 1)
            shared_param = next(param_iter)
            expected.rxx(shared_param, 1, 2)
            expected.ryy(shared_param, 1, 2)
        for i in range(num_qubits):
            expected.rz(next(param_iter), i)

        library = ExcitationPreserving(num_qubits, reps=reps,
                                       entanglement=entanglement).assign_parameters(parameters)

        self.assertCircuitEqual(library, expected)

    def test_fsim_circuit(self):
        """Test a ExcitationPreserving circuit in fsim mode."""
        num_qubits = 3
        reps = 2
        entanglement = 'linear'
        # need the parameters in the entanglement blocks to be the same because the order
        # can get mixed up in ExcitationPreserving (since parameters are not ordered in circuits)
        parameters = [1] * (num_qubits * (reps + 1) + reps * (1 + num_qubits))
        param_iter = iter(parameters)

        expected = QuantumCircuit(3)
        for _ in range(reps):
            for i in range(num_qubits):
                expected.rz(next(param_iter), i)
            shared_param = next(param_iter)
            expected.rxx(shared_param, 0, 1)
            expected.ryy(shared_param, 0, 1)
            expected.cp(next(param_iter), 0, 1)
            shared_param = next(param_iter)
            expected.rxx(shared_param, 1, 2)
            expected.ryy(shared_param, 1, 2)
            expected.cp(next(param_iter), 1, 2)
        for i in range(num_qubits):
            expected.rz(next(param_iter), i)

        library = ExcitationPreserving(num_qubits, reps=reps, mode='fsim',
                                       entanglement=entanglement).assign_parameters(parameters)

        self.assertCircuitEqual(library, expected)

    def test_circular_on_same_block_and_circuit_size(self):
        """Test circular entanglement works correctly if the circuit and block sizes match."""

        two = TwoLocal(2, 'ry', 'cx', entanglement='circular', reps=1)
        parameters = np.arange(two.num_parameters)

        ref = QuantumCircuit(2)
        ref.ry(parameters[0], 0)
        ref.ry(parameters[1], 1)
        ref.cx(0, 1)
        ref.ry(parameters[2], 0)
        ref.ry(parameters[3], 1)

        self.assertCircuitEqual(two.assign_parameters(parameters), ref)
Esempio n. 24
0
class TestTwoLocal(QiskitTestCase):
    """Tests for the TwoLocal circuit."""
    def assertCircuitEqual(self, qc1, qc2, visual=False, transpiled=True):
        """An equality test specialized to circuits."""
        if transpiled:
            basis_gates = ["id", "u1", "u3", "cx"]
            qc1_transpiled = transpile(qc1,
                                       basis_gates=basis_gates,
                                       optimization_level=0)
            qc2_transpiled = transpile(qc2,
                                       basis_gates=basis_gates,
                                       optimization_level=0)
            qc1, qc2 = qc1_transpiled, qc2_transpiled

        if visual:
            self.assertEqual(qc1.draw(), qc2.draw())
        else:
            self.assertEqual(qc1, qc2)

    def test_skip_final_rotation_layer(self):
        """Test skipping the final rotation layer works."""
        two = TwoLocal(3, ["ry", "h"], ["cz", "cx"],
                       reps=2,
                       skip_final_rotation_layer=True)
        self.assertEqual(two.num_parameters,
                         6)  # would be 9 with a final rotation layer

    @data(
        (5, "rx", "cx", "full", 2, 15),
        (3, "x", "z", "linear", 1, 0),
        (3, "rx", "cz", "linear", 0, 3),
        (3, ["rx", "ry"], ["cry", "cx"], "circular", 2, 24),
    )
    @unpack
    def test_num_parameters(self, num_qubits, rot, ent, ent_mode, reps,
                            expected):
        """Test the number of parameters."""
        two = TwoLocal(
            num_qubits,
            rotation_blocks=rot,
            entanglement_blocks=ent,
            entanglement=ent_mode,
            reps=reps,
        )

        with self.subTest(msg="num_parameters_settable"):
            self.assertEqual(two.num_parameters_settable, expected)

        with self.subTest(msg="num_parameters"):
            self.assertEqual(two.num_parameters, expected)

    def test_empty_two_local(self):
        """Test the setup of an empty two-local circuit."""
        two = TwoLocal()

        with self.subTest(msg="0 qubits"):
            self.assertEqual(two.num_qubits, 0)

        with self.subTest(msg="no blocks are set"):
            self.assertListEqual(two.rotation_blocks, [])
            self.assertListEqual(two.entanglement_blocks, [])

        with self.subTest(msg="equal to empty circuit"):
            self.assertEqual(two, QuantumCircuit())

    @data("rx", RXGate(Parameter("p")), RXGate, "circuit")
    def test_various_block_types(self, rot):
        """Test setting the rotation blocks to various type and assert the output type is RX."""
        if rot == "circuit":
            rot = QuantumCircuit(1)
            rot.rx(Parameter("angle"), 0)

        two = TwoLocal(3, rot, reps=0)
        self.assertEqual(len(two.rotation_blocks), 1)
        rotation = two.rotation_blocks[0]

        # decompose
        self.assertIsInstance(rotation.data[0].operation, RXGate)

    def test_parameter_setters(self):
        """Test different possibilities to set parameters."""
        two = TwoLocal(3, rotation_blocks="rx", entanglement="cz", reps=2)
        params = [
            0, 1, 2,
            Parameter("x"),
            Parameter("y"),
            Parameter("z"), 6, 7, 0
        ]
        params_set = {
            param
            for param in params if isinstance(param, Parameter)
        }

        with self.subTest(msg="dict assign and copy"):
            ordered = two.ordered_parameters
            bound = two.assign_parameters(dict(zip(ordered, params)),
                                          inplace=False)
            self.assertEqual(bound.parameters, params_set)
            self.assertEqual(two.num_parameters, 9)

        with self.subTest(msg="list assign and copy"):
            ordered = two.ordered_parameters
            bound = two.assign_parameters(params, inplace=False)
            self.assertEqual(bound.parameters, params_set)
            self.assertEqual(two.num_parameters, 9)

        with self.subTest(msg="list assign inplace"):
            ordered = two.ordered_parameters
            two.assign_parameters(params, inplace=True)
            self.assertEqual(two.parameters, params_set)
            self.assertEqual(two.num_parameters, 3)
            self.assertEqual(two.num_parameters_settable, 9)

    def test_parameters_settable_is_constant(self):
        """Test the attribute num_parameters_settable does not change on parameter change."""
        two = TwoLocal(3, rotation_blocks="rx", entanglement="cz", reps=2)
        ordered_params = two.ordered_parameters

        x = Parameter("x")
        two.assign_parameters(dict(
            zip(ordered_params, [x] * two.num_parameters)),
                              inplace=True)

        with self.subTest(msg="num_parameters collapsed to 1"):
            self.assertEqual(two.num_parameters, 1)

        with self.subTest(msg="num_parameters_settable remained constant"):
            self.assertEqual(two.num_parameters_settable, len(ordered_params))

    def test_compose_inplace_to_circuit(self):
        """Test adding a two-local to an existing circuit."""
        two = TwoLocal(3, ["ry", "rz"],
                       "cz",
                       "full",
                       reps=1,
                       insert_barriers=True)
        circuit = QuantumCircuit(3)
        circuit.compose(two, inplace=True)

        #      ┌──────────┐┌──────────┐ ░           ░ ┌──────────┐ ┌──────────┐
        # q_0: ┤ Ry(θ[0]) ├┤ Rz(θ[3]) ├─░──■──■─────░─┤ Ry(θ[6]) ├─┤ Rz(θ[9]) ├
        #      ├──────────┤├──────────┤ ░  │  │     ░ ├──────────┤┌┴──────────┤
        # q_1: ┤ Ry(θ[1]) ├┤ Rz(θ[4]) ├─░──■──┼──■──░─┤ Ry(θ[7]) ├┤ Rz(θ[10]) ├
        #      ├──────────┤├──────────┤ ░     │  │  ░ ├──────────┤├───────────┤
        # q_2: ┤ Ry(θ[2]) ├┤ Rz(θ[5]) ├─░─────■──■──░─┤ Ry(θ[8]) ├┤ Rz(θ[11]) ├
        #      └──────────┘└──────────┘ ░           ░ └──────────┘└───────────┘
        reference = QuantumCircuit(3)
        param_iter = iter(two.ordered_parameters)
        for i in range(3):
            reference.ry(next(param_iter), i)
        for i in range(3):
            reference.rz(next(param_iter), i)
        reference.barrier()
        reference.cz(0, 1)
        reference.cz(0, 2)
        reference.cz(1, 2)
        reference.barrier()
        for i in range(3):
            reference.ry(next(param_iter), i)
        for i in range(3):
            reference.rz(next(param_iter), i)

        self.assertCircuitEqual(circuit.decompose(), reference)

    def test_composing_two(self):
        """Test adding two two-local circuits."""
        entangler_map = [[0, 3], [0, 2]]
        two = TwoLocal(4, [], "cry", entangler_map, reps=1)
        circuit = two.compose(two)

        reference = QuantumCircuit(4)
        params = two.ordered_parameters
        for _ in range(2):
            reference.cry(params[0], 0, 3)
            reference.cry(params[1], 0, 2)

        self.assertCircuitEqual(reference, circuit)

    def test_ry_blocks(self):
        """Test that the RealAmplitudes circuit is instantiated correctly."""
        two = RealAmplitudes(4)
        with self.subTest(msg="test rotation gate"):
            self.assertEqual(len(two.rotation_blocks), 1)
            self.assertIsInstance(two.rotation_blocks[0].data[0].operation,
                                  RYGate)

        with self.subTest(msg="test parameter bounds"):
            expected = [(-np.pi, np.pi)] * two.num_parameters
            np.testing.assert_almost_equal(two.parameter_bounds, expected)

    def test_ry_circuit_reverse_linear(self):
        """Test a RealAmplitudes circuit with entanglement = "reverse_linear"."""
        num_qubits = 3
        reps = 2
        entanglement = "reverse_linear"
        parameters = ParameterVector("theta", num_qubits * (reps + 1))
        param_iter = iter(parameters)

        expected = QuantumCircuit(3)
        for _ in range(reps):
            for i in range(num_qubits):
                expected.ry(next(param_iter), i)
            expected.cx(1, 2)
            expected.cx(0, 1)
        for i in range(num_qubits):
            expected.ry(next(param_iter), i)

        library = RealAmplitudes(
            num_qubits, reps=reps,
            entanglement=entanglement).assign_parameters(parameters)
        self.assertCircuitEqual(library, expected)

    def test_ry_circuit_full(self):
        """Test a RealAmplitudes circuit with entanglement = "full"."""
        num_qubits = 3
        reps = 2
        entanglement = "full"
        parameters = ParameterVector("theta", num_qubits * (reps + 1))
        param_iter = iter(parameters)

        #      ┌──────────┐          ┌──────────┐                      ┌──────────┐
        # q_0: ┤ Ry(θ[0]) ├──■────■──┤ Ry(θ[3]) ├──────────────■────■──┤ Ry(θ[6]) ├────────────
        #      ├──────────┤┌─┴─┐  │  └──────────┘┌──────────┐┌─┴─┐  │  └──────────┘┌──────────┐
        # q_1: ┤ Ry(θ[1]) ├┤ X ├──┼─────────■────┤ Ry(θ[4]) ├┤ X ├──┼─────────■────┤ Ry(θ[7]) ├
        #      ├──────────┤└───┘┌─┴─┐     ┌─┴─┐  ├──────────┤└───┘┌─┴─┐     ┌─┴─┐  ├──────────┤
        # q_2: ┤ Ry(θ[2]) ├─────┤ X ├─────┤ X ├──┤ Ry(θ[5]) ├─────┤ X ├─────┤ X ├──┤ Ry(θ[8]) ├
        #      └──────────┘     └───┘     └───┘  └──────────┘     └───┘     └───┘  └──────────┘
        expected = QuantumCircuit(3)
        for _ in range(reps):
            for i in range(num_qubits):
                expected.ry(next(param_iter), i)
            expected.cx(0, 1)
            expected.cx(0, 2)
            expected.cx(1, 2)
        for i in range(num_qubits):
            expected.ry(next(param_iter), i)

        library = RealAmplitudes(
            num_qubits, reps=reps,
            entanglement=entanglement).assign_parameters(parameters)
        self.assertCircuitEqual(library, expected)

    def test_ryrz_blocks(self):
        """Test that the EfficientSU2 circuit is instantiated correctly."""
        two = EfficientSU2(3)
        with self.subTest(msg="test rotation gate"):
            self.assertEqual(len(two.rotation_blocks), 2)
            self.assertIsInstance(two.rotation_blocks[0].data[0].operation,
                                  RYGate)
            self.assertIsInstance(two.rotation_blocks[1].data[0].operation,
                                  RZGate)

        with self.subTest(msg="test parameter bounds"):
            expected = [(-np.pi, np.pi)] * two.num_parameters
            np.testing.assert_almost_equal(two.parameter_bounds, expected)

    def test_ryrz_circuit(self):
        """Test an EfficientSU2 circuit."""
        num_qubits = 3
        reps = 2
        entanglement = "circular"
        parameters = ParameterVector("theta", 2 * num_qubits * (reps + 1))
        param_iter = iter(parameters)

        #      ┌──────────┐┌──────────┐┌───┐     ┌──────────┐┌──────────┐             »
        # q_0: ┤ Ry(θ[0]) ├┤ Rz(θ[3]) ├┤ X ├──■──┤ Ry(θ[6]) ├┤ Rz(θ[9]) ├─────────────»
        #      ├──────────┤├──────────┤└─┬─┘┌─┴─┐└──────────┘├──────────┤┌───────────┐»
        # q_1: ┤ Ry(θ[1]) ├┤ Rz(θ[4]) ├──┼──┤ X ├─────■──────┤ Ry(θ[7]) ├┤ Rz(θ[10]) ├»
        #      ├──────────┤├──────────┤  │  └───┘   ┌─┴─┐    ├──────────┤├───────────┤»
        # q_2: ┤ Ry(θ[2]) ├┤ Rz(θ[5]) ├──■──────────┤ X ├────┤ Ry(θ[8]) ├┤ Rz(θ[11]) ├»
        #      └──────────┘└──────────┘             └───┘    └──────────┘└───────────┘»
        # «     ┌───┐     ┌───────────┐┌───────────┐
        # «q_0: ┤ X ├──■──┤ Ry(θ[12]) ├┤ Rz(θ[15]) ├─────────────
        # «     └─┬─┘┌─┴─┐└───────────┘├───────────┤┌───────────┐
        # «q_1: ──┼──┤ X ├──────■──────┤ Ry(θ[13]) ├┤ Rz(θ[16]) ├
        # «       │  └───┘    ┌─┴─┐    ├───────────┤├───────────┤
        # «q_2: ──■───────────┤ X ├────┤ Ry(θ[14]) ├┤ Rz(θ[17]) ├
        # «                   └───┘    └───────────┘└───────────┘
        expected = QuantumCircuit(3)
        for _ in range(reps):
            for i in range(num_qubits):
                expected.ry(next(param_iter), i)
            for i in range(num_qubits):
                expected.rz(next(param_iter), i)
            expected.cx(2, 0)
            expected.cx(0, 1)
            expected.cx(1, 2)
        for i in range(num_qubits):
            expected.ry(next(param_iter), i)
        for i in range(num_qubits):
            expected.rz(next(param_iter), i)

        library = EfficientSU2(
            num_qubits, reps=reps,
            entanglement=entanglement).assign_parameters(parameters)

        self.assertCircuitEqual(library, expected)

    def test_swaprz_blocks(self):
        """Test that the ExcitationPreserving circuit is instantiated correctly."""
        two = ExcitationPreserving(5)
        with self.subTest(msg="test rotation gate"):
            self.assertEqual(len(two.rotation_blocks), 1)
            self.assertIsInstance(two.rotation_blocks[0].data[0].operation,
                                  RZGate)

        with self.subTest(msg="test entanglement gate"):
            self.assertEqual(len(two.entanglement_blocks), 1)
            block = two.entanglement_blocks[0]
            self.assertEqual(len(block.data), 2)
            self.assertIsInstance(block.data[0].operation, RXXGate)
            self.assertIsInstance(block.data[1].operation, RYYGate)

        with self.subTest(msg="test parameter bounds"):
            expected = [(-np.pi, np.pi)] * two.num_parameters
            np.testing.assert_almost_equal(two.parameter_bounds, expected)

    def test_swaprz_circuit(self):
        """Test a ExcitationPreserving circuit in iswap mode."""
        num_qubits = 3
        reps = 2
        entanglement = "linear"
        parameters = ParameterVector(
            "theta",
            num_qubits * (reps + 1) + reps * (num_qubits - 1))
        param_iter = iter(parameters)

        #      ┌──────────┐┌────────────┐┌────────────┐ ┌──────────┐               »
        # q_0: ┤ Rz(θ[0]) ├┤0           ├┤0           ├─┤ Rz(θ[5]) ├───────────────»
        #      ├──────────┤│  Rxx(θ[3]) ││  Ryy(θ[3]) │┌┴──────────┴┐┌────────────┐»
        # q_1: ┤ Rz(θ[1]) ├┤1           ├┤1           ├┤0           ├┤0           ├»
        #      ├──────────┤└────────────┘└────────────┘│  Rxx(θ[4]) ││  Ryy(θ[4]) │»
        # q_2: ┤ Rz(θ[2]) ├────────────────────────────┤1           ├┤1           ├»
        #      └──────────┘                            └────────────┘└────────────┘»
        # «                 ┌────────────┐┌────────────┐┌───────────┐               »
        # «q_0: ────────────┤0           ├┤0           ├┤ Rz(θ[10]) ├───────────────»
        # «     ┌──────────┐│  Rxx(θ[8]) ││  Ryy(θ[8]) │├───────────┴┐┌────────────┐»
        # «q_1: ┤ Rz(θ[6]) ├┤1           ├┤1           ├┤0           ├┤0           ├»
        # «     ├──────────┤└────────────┘└────────────┘│  Rxx(θ[9]) ││  Ryy(θ[9]) │»
        # «q_2: ┤ Rz(θ[7]) ├────────────────────────────┤1           ├┤1           ├»
        # «     └──────────┘                            └────────────┘└────────────┘»
        # «
        # «q_0: ─────────────
        # «     ┌───────────┐
        # «q_1: ┤ Rz(θ[11]) ├
        # «     ├───────────┤
        # «q_2: ┤ Rz(θ[12]) ├
        # «     └───────────┘
        expected = QuantumCircuit(3)
        for _ in range(reps):
            for i in range(num_qubits):
                expected.rz(next(param_iter), i)
            shared_param = next(param_iter)
            expected.rxx(shared_param, 0, 1)
            expected.ryy(shared_param, 0, 1)
            shared_param = next(param_iter)
            expected.rxx(shared_param, 1, 2)
            expected.ryy(shared_param, 1, 2)
        for i in range(num_qubits):
            expected.rz(next(param_iter), i)

        library = ExcitationPreserving(
            num_qubits, reps=reps,
            entanglement=entanglement).assign_parameters(parameters)

        self.assertCircuitEqual(library, expected)

    def test_fsim_circuit(self):
        """Test a ExcitationPreserving circuit in fsim mode."""
        num_qubits = 3
        reps = 2
        entanglement = "linear"
        # need the parameters in the entanglement blocks to be the same because the order
        # can get mixed up in ExcitationPreserving (since parameters are not ordered in circuits)
        parameters = [1] * (num_qubits * (reps + 1) + reps * (1 + num_qubits))
        param_iter = iter(parameters)

        #      ┌───────┐┌─────────┐┌─────────┐        ┌───────┐                   »
        # q_0: ┤ Rz(1) ├┤0        ├┤0        ├─■──────┤ Rz(1) ├───────────────────»
        #      ├───────┤│  Rxx(1) ││  Ryy(1) │ │P(1) ┌┴───────┴┐┌─────────┐       »
        # q_1: ┤ Rz(1) ├┤1        ├┤1        ├─■─────┤0        ├┤0        ├─■─────»
        #      ├───────┤└─────────┘└─────────┘       │  Rxx(1) ││  Ryy(1) │ │P(1) »
        # q_2: ┤ Rz(1) ├─────────────────────────────┤1        ├┤1        ├─■─────»
        #      └───────┘                             └─────────┘└─────────┘       »
        # «              ┌─────────┐┌─────────┐        ┌───────┐                   »
        # «q_0: ─────────┤0        ├┤0        ├─■──────┤ Rz(1) ├───────────────────»
        # «     ┌───────┐│  Rxx(1) ││  Ryy(1) │ │P(1) ┌┴───────┴┐┌─────────┐       »
        # «q_1: ┤ Rz(1) ├┤1        ├┤1        ├─■─────┤0        ├┤0        ├─■─────»
        # «     ├───────┤└─────────┘└─────────┘       │  Rxx(1) ││  Ryy(1) │ │P(1) »
        # «q_2: ┤ Rz(1) ├─────────────────────────────┤1        ├┤1        ├─■─────»
        # «     └───────┘                             └─────────┘└─────────┘       »
        # «
        # «q_0: ─────────
        # «     ┌───────┐
        # «q_1: ┤ Rz(1) ├
        # «     ├───────┤
        # «q_2: ┤ Rz(1) ├
        # «     └───────┘
        expected = QuantumCircuit(3)
        for _ in range(reps):
            for i in range(num_qubits):
                expected.rz(next(param_iter), i)
            shared_param = next(param_iter)
            expected.rxx(shared_param, 0, 1)
            expected.ryy(shared_param, 0, 1)
            expected.cp(next(param_iter), 0, 1)
            shared_param = next(param_iter)
            expected.rxx(shared_param, 1, 2)
            expected.ryy(shared_param, 1, 2)
            expected.cp(next(param_iter), 1, 2)
        for i in range(num_qubits):
            expected.rz(next(param_iter), i)

        library = ExcitationPreserving(
            num_qubits, reps=reps, mode="fsim",
            entanglement=entanglement).assign_parameters(parameters)

        self.assertCircuitEqual(library, expected)

    def test_circular_on_same_block_and_circuit_size(self):
        """Test circular entanglement works correctly if the circuit and block sizes match."""

        two = TwoLocal(2, "ry", "cx", entanglement="circular", reps=1)
        parameters = np.arange(two.num_parameters)

        #      ┌───────┐     ┌───────┐
        # q_0: ┤ Ry(0) ├──■──┤ Ry(2) ├
        #      ├───────┤┌─┴─┐├───────┤
        # q_1: ┤ Ry(1) ├┤ X ├┤ Ry(3) ├
        #      └───────┘└───┘└───────┘
        ref = QuantumCircuit(2)
        ref.ry(parameters[0], 0)
        ref.ry(parameters[1], 1)
        ref.cx(0, 1)
        ref.ry(parameters[2], 0)
        ref.ry(parameters[3], 1)

        self.assertCircuitEqual(two.assign_parameters(parameters), ref)

    def test_circuit_with_numpy_integers(self):
        """Test if TwoLocal can be made from numpy integers"""
        num_qubits = 6
        reps = 3
        expected_np32 = [(i, j) for i in np.arange(num_qubits, dtype=np.int32)
                         for j in np.arange(num_qubits, dtype=np.int32)
                         if i < j]
        expected_np64 = [(i, j) for i in np.arange(num_qubits, dtype=np.int64)
                         for j in np.arange(num_qubits, dtype=np.int64)
                         if i < j]

        two_np32 = TwoLocal(num_qubits,
                            "ry",
                            "cx",
                            entanglement=expected_np32,
                            reps=reps)
        two_np64 = TwoLocal(num_qubits,
                            "ry",
                            "cx",
                            entanglement=expected_np64,
                            reps=reps)

        expected_cx = reps * num_qubits * (num_qubits - 1) / 2

        self.assertEqual(two_np32.decompose().count_ops()["cx"], expected_cx)
        self.assertEqual(two_np64.decompose().count_ops()["cx"], expected_cx)

    @combine(num_qubits=[4, 5])
    def test_full_vs_reverse_linear(self, num_qubits):
        """Test that 'full' and 'reverse_linear' provide the same unitary element."""
        reps = 2
        full = RealAmplitudes(num_qubits=num_qubits,
                              entanglement="full",
                              reps=reps)
        num_params = (reps + 1) * num_qubits
        np.random.seed(num_qubits)
        params = np.random.rand(num_params)
        reverse = RealAmplitudes(num_qubits=num_qubits,
                                 entanglement="reverse_linear",
                                 reps=reps)
        full.assign_parameters(params, inplace=True)
        reverse.assign_parameters(params, inplace=True)
        assert Operator(full) == Operator(reverse)
Esempio n. 25
0
import qiskit
from qiskit import QuantumCircuit
from qiskit.circuit.library import RXGate
import numpy as np

basis_gates = ['u3']
circ = QuantumCircuit(1, 1)
RX = RXGate(0)
# circ.append(RX, [0])
circ.h(0)
circ.measure(0, 0)
print("Before Transpiling:")
print(circ)
new_circ = qiskit.compiler.transpile(circ,
                                     basis_gates=basis_gates,
                                     optimization_level=0)
print("After Transpiling:")
print(new_circ)
Esempio n. 26
0
    def setUp(self):
        super().setUp()
        self.fake_backend = FakeBackendV2()
        self.fake_backend_target = self.fake_backend.target
        self.theta = Parameter("theta")
        self.phi = Parameter("phi")
        self.ibm_target = Target()
        i_props = {
            (0, ): InstructionProperties(duration=35.5e-9, error=0.000413),
            (1, ): InstructionProperties(duration=35.5e-9, error=0.000502),
            (2, ): InstructionProperties(duration=35.5e-9, error=0.0004003),
            (3, ): InstructionProperties(duration=35.5e-9, error=0.000614),
            (4, ): InstructionProperties(duration=35.5e-9, error=0.006149),
        }
        self.ibm_target.add_instruction(IGate(), i_props)
        rz_props = {
            (0, ): InstructionProperties(duration=0, error=0),
            (1, ): InstructionProperties(duration=0, error=0),
            (2, ): InstructionProperties(duration=0, error=0),
            (3, ): InstructionProperties(duration=0, error=0),
            (4, ): InstructionProperties(duration=0, error=0),
        }
        self.ibm_target.add_instruction(RZGate(self.theta), rz_props)
        sx_props = {
            (0, ): InstructionProperties(duration=35.5e-9, error=0.000413),
            (1, ): InstructionProperties(duration=35.5e-9, error=0.000502),
            (2, ): InstructionProperties(duration=35.5e-9, error=0.0004003),
            (3, ): InstructionProperties(duration=35.5e-9, error=0.000614),
            (4, ): InstructionProperties(duration=35.5e-9, error=0.006149),
        }
        self.ibm_target.add_instruction(SXGate(), sx_props)
        x_props = {
            (0, ): InstructionProperties(duration=35.5e-9, error=0.000413),
            (1, ): InstructionProperties(duration=35.5e-9, error=0.000502),
            (2, ): InstructionProperties(duration=35.5e-9, error=0.0004003),
            (3, ): InstructionProperties(duration=35.5e-9, error=0.000614),
            (4, ): InstructionProperties(duration=35.5e-9, error=0.006149),
        }
        self.ibm_target.add_instruction(XGate(), x_props)
        cx_props = {
            (3, 4): InstructionProperties(duration=270.22e-9, error=0.00713),
            (4, 3): InstructionProperties(duration=305.77e-9, error=0.00713),
            (3, 1): InstructionProperties(duration=462.22e-9, error=0.00929),
            (1, 3): InstructionProperties(duration=497.77e-9, error=0.00929),
            (1, 2): InstructionProperties(duration=227.55e-9, error=0.00659),
            (2, 1): InstructionProperties(duration=263.11e-9, error=0.00659),
            (0, 1): InstructionProperties(duration=519.11e-9, error=0.01201),
            (1, 0): InstructionProperties(duration=554.66e-9, error=0.01201),
        }
        self.ibm_target.add_instruction(CXGate(), cx_props)
        measure_props = {
            (0, ): InstructionProperties(duration=5.813e-6, error=0.0751),
            (1, ): InstructionProperties(duration=5.813e-6, error=0.0225),
            (2, ): InstructionProperties(duration=5.813e-6, error=0.0146),
            (3, ): InstructionProperties(duration=5.813e-6, error=0.0215),
            (4, ): InstructionProperties(duration=5.813e-6, error=0.0333),
        }
        self.ibm_target.add_instruction(Measure(), measure_props)

        self.aqt_target = Target(description="AQT Target")
        rx_props = {
            (0, ): None,
            (1, ): None,
            (2, ): None,
            (3, ): None,
            (4, ): None,
        }
        self.aqt_target.add_instruction(RXGate(self.theta), rx_props)
        ry_props = {
            (0, ): None,
            (1, ): None,
            (2, ): None,
            (3, ): None,
            (4, ): None,
        }
        self.aqt_target.add_instruction(RYGate(self.theta), ry_props)
        rz_props = {
            (0, ): None,
            (1, ): None,
            (2, ): None,
            (3, ): None,
            (4, ): None,
        }
        self.aqt_target.add_instruction(RZGate(self.theta), rz_props)
        r_props = {
            (0, ): None,
            (1, ): None,
            (2, ): None,
            (3, ): None,
            (4, ): None,
        }
        self.aqt_target.add_instruction(RGate(self.theta, self.phi), r_props)
        rxx_props = {
            (0, 1): None,
            (0, 2): None,
            (0, 3): None,
            (0, 4): None,
            (1, 0): None,
            (2, 0): None,
            (3, 0): None,
            (4, 0): None,
            (1, 2): None,
            (1, 3): None,
            (1, 4): None,
            (2, 1): None,
            (3, 1): None,
            (4, 1): None,
            (2, 3): None,
            (2, 4): None,
            (3, 2): None,
            (4, 2): None,
            (3, 4): None,
            (4, 3): None,
        }
        self.aqt_target.add_instruction(RXXGate(self.theta), rxx_props)
        measure_props = {
            (0, ): None,
            (1, ): None,
            (2, ): None,
            (3, ): None,
            (4, ): None,
        }
        self.aqt_target.add_instruction(Measure(), measure_props)
        self.empty_target = Target()
        self.ideal_sim_target = Target(num_qubits=3,
                                       description="Ideal Simulator")
        self.lam = Parameter("lam")
        for inst in [
                UGate(self.theta, self.phi, self.lam),
                RXGate(self.theta),
                RYGate(self.theta),
                RZGate(self.theta),
                CXGate(),
                ECRGate(),
                CCXGate(),
                Measure(),
        ]:
            self.ideal_sim_target.add_instruction(inst, {None: None})
 def test_controlled_rx(self):
     """Test the creation of a controlled RX gate."""
     theta = 0.5
     self.assertEqual(RXGate(theta).control(), CRXGate(theta))
    def convert(
        self,
        operator: CircuitStateFn,
        params: Optional[Union[ParameterExpression, ParameterVector,
                               List[ParameterExpression]]] = None,
    ) -> ListOp:
        r"""
        Args:
            operator: The operator corresponding to the quantum state :math:`|\psi(\omega)\rangle`
                for which we compute the QFI.
            params: The parameters :math:`\omega` with respect to which we are computing the QFI.

        Returns:
            A ``ListOp[ListOp]`` where the operator at position ``[k][l]`` corresponds to the matrix
            element :math:`k, l` of the QFI.

        Raises:
            AquaError: If one of the circuits could not be constructed.
            TypeError: If ``operator`` is an unsupported type.
        """

        # QFI & phase fix observable
        qfi_observable = ~StateFn(4 * Z ^ (I ^ operator.num_qubits))
        phase_fix_observable = ~StateFn((X + 1j * Y)
                                        ^ (I ^ operator.num_qubits))
        # see https://arxiv.org/pdf/quant-ph/0108146.pdf

        # Check if the given operator corresponds to a quantum state given as a circuit.
        if not isinstance(operator, CircuitStateFn):
            raise TypeError(
                'LinCombFull is only compatible with states that are given as CircuitStateFn'
            )

        # If a single parameter is given wrap it into a list.
        if not isinstance(params, (list, np.ndarray)):
            params = [params]
        state_qc = operator.primitive

        # First, the operators are computed which can compensate for a potential phase-mismatch
        # between target and trained state, i.e.〈ψ|∂lψ〉
        phase_fix_states = None
        # Add working qubit
        qr_work = QuantumRegister(1, 'work_qubit')
        work_q = qr_work[0]
        additional_qubits: Tuple[List[Qubit], List[Qubit]] = ([work_q], [])
        for param in params:
            # Get the gates of the given quantum state which are parameterized by param
            param_gates = state_qc._parameter_table[param]
            # Loop through the occurrences of param in the quantum state
            for m, param_occurence in enumerate(param_gates):
                # Get the coefficients and gates for the linear combination gradient for each
                # occurrence, see e.g. https://arxiv.org/abs/2006.06004
                coeffs_i, gates_i = LinComb._gate_gradient_dict(
                    param_occurence[0])[param_occurence[1]]
                # Construct the quantum states which are then evaluated for the respective QFI
                # element.
                for k, gate_to_insert_i in enumerate(gates_i):
                    grad_state = state_qc.copy()
                    grad_state.add_register(qr_work)

                    # apply Hadamard on work_q
                    LinComb.insert_gate(grad_state,
                                        param_occurence[0],
                                        HGate(),
                                        qubits=[work_q])
                    # Fix work_q phase such that the gradient is correct.
                    coeff_i = coeffs_i[k]
                    sign = np.sign(coeff_i)
                    is_complex = np.iscomplex(coeff_i)
                    if sign == -1:
                        if is_complex:
                            LinComb.insert_gate(grad_state,
                                                param_occurence[0],
                                                SdgGate(),
                                                qubits=[work_q])
                        else:
                            LinComb.insert_gate(grad_state,
                                                param_occurence[0],
                                                ZGate(),
                                                qubits=[work_q])
                    else:
                        if is_complex:
                            LinComb.insert_gate(grad_state,
                                                param_occurence[0],
                                                SGate(),
                                                qubits=[work_q])

                    # Insert controlled, intercepting gate - controlled by |0>

                    if isinstance(param_occurence[0], UGate):
                        if param_occurence[1] == 0:
                            LinComb.insert_gate(
                                grad_state, param_occurence[0],
                                RZGate(param_occurence[0].params[2]))
                            LinComb.insert_gate(grad_state, param_occurence[0],
                                                RXGate(np.pi / 2))
                            LinComb.insert_gate(
                                grad_state,
                                param_occurence[0],
                                gate_to_insert_i,
                                additional_qubits=additional_qubits)
                            LinComb.insert_gate(grad_state, param_occurence[0],
                                                RXGate(-np.pi / 2))
                            LinComb.insert_gate(
                                grad_state, param_occurence[0],
                                RZGate(-param_occurence[0].params[2]))

                        elif param_occurence[1] == 1:
                            LinComb.insert_gate(
                                grad_state,
                                param_occurence[0],
                                gate_to_insert_i,
                                after=True,
                                additional_qubits=additional_qubits)
                        else:
                            LinComb.insert_gate(
                                grad_state,
                                param_occurence[0],
                                gate_to_insert_i,
                                additional_qubits=additional_qubits)
                    else:
                        LinComb.insert_gate(
                            grad_state,
                            param_occurence[0],
                            gate_to_insert_i,
                            additional_qubits=additional_qubits)

                    # Remove unnecessary gates.
                    grad_state = self.trim_circuit(grad_state,
                                                   param_occurence[0])
                    # Apply the final Hadamard on the working qubit.
                    grad_state.h(work_q)
                    # Add the coefficient needed for the gradient as well as the original
                    # coefficient of the given quantum state.
                    state = np.sqrt(np.abs(
                        coeff_i)) * operator.coeff * CircuitStateFn(grad_state)

                    # Check if the gate parameter corresponding to param is a parameter expression
                    gate_param = param_occurence[0].params[param_occurence[1]]
                    if gate_param == param:
                        state = phase_fix_observable @ state
                    else:
                        # If the gate parameter is a parameter expressions the chain rule needs
                        # to be taken into account.
                        if isinstance(gate_param, ParameterExpression):
                            expr_grad = DerivativeBase.parameter_expression_grad(
                                gate_param, param)
                            state = (expr_grad * phase_fix_observable) @ state
                        else:
                            state *= 0

                    if m == 0 and k == 0:
                        phase_fix_state = state
                    else:
                        # Take the product rule into account
                        phase_fix_state += state
            # Create a list for the phase fix states
            if not phase_fix_states:
                phase_fix_states = [phase_fix_state]
            else:
                phase_fix_states += [phase_fix_state]

        # Get  4 * Re[〈∂kψ|∂lψ]
        qfi_operators = []
        # Add a working qubit
        qr_work_qubit = QuantumRegister(1, 'work_qubit')
        work_qubit = qr_work_qubit[0]
        additional_qubits = ([work_qubit], [])
        # create a copy of the original circuit with an additional work_qubit register
        circuit = state_qc.copy()
        circuit.add_register(qr_work_qubit)
        # Apply a Hadamard on the working qubit
        LinComb.insert_gate(circuit,
                            state_qc._parameter_table[params[0]][0][0],
                            HGate(),
                            qubits=[work_qubit])

        # Get the circuits needed to compute〈∂iψ|∂jψ〉
        for i, param_i in enumerate(params):  # loop over parameters
            qfi_ops = None
            for j, param_j in enumerate(params):
                # Get the gates of the quantum state which are parameterized by param_i
                param_gates_i = state_qc._parameter_table[param_i]
                for m_i, param_occurence_i in enumerate(param_gates_i):
                    coeffs_i, gates_i = LinComb._gate_gradient_dict(
                        param_occurence_i[0])[param_occurence_i[1]]

                    for k_i, gate_to_insert_i in enumerate(gates_i):
                        coeff_i = coeffs_i[k_i]
                        # Get the gates of the quantum state which are parameterized by param_j
                        param_gates_j = state_qc._parameter_table[param_j]
                        for m_j, param_occurence_j in enumerate(param_gates_j):
                            coeffs_j, gates_j = \
                                LinComb._gate_gradient_dict(param_occurence_j[0])[
                                    param_occurence_j[1]]
                            for k_j, gate_to_insert_j in enumerate(gates_j):
                                coeff_j = coeffs_j[k_j]

                                # create a copy of the original circuit with the same registers
                                qfi_circuit = QuantumCircuit(*circuit.qregs)
                                qfi_circuit.data = circuit.data

                                # Correct the phase of the working qubit according to coefficient i
                                # and coefficient j
                                sign = np.sign(np.conj(coeff_i) * coeff_j)
                                is_complex = np.iscomplex(
                                    np.conj(coeff_i) * coeff_j)
                                if sign == -1:
                                    if is_complex:
                                        LinComb.insert_gate(
                                            qfi_circuit,
                                            param_occurence_i[0],
                                            SdgGate(),
                                            qubits=[work_qubit])
                                    else:
                                        LinComb.insert_gate(
                                            qfi_circuit,
                                            param_occurence_i[0],
                                            ZGate(),
                                            qubits=[work_qubit])
                                else:
                                    if is_complex:
                                        LinComb.insert_gate(
                                            qfi_circuit,
                                            param_occurence_i[0],
                                            SGate(),
                                            qubits=[work_qubit])

                                LinComb.insert_gate(qfi_circuit,
                                                    param_occurence_i[0],
                                                    XGate(),
                                                    qubits=[work_qubit])

                                # Insert controlled, intercepting gate i - controlled by |1>
                                if isinstance(param_occurence_i[0], UGate):
                                    if param_occurence_i[1] == 0:
                                        LinComb.insert_gate(
                                            qfi_circuit, param_occurence_i[0],
                                            RZGate(param_occurence_i[0].
                                                   params[2]))
                                        LinComb.insert_gate(
                                            qfi_circuit, param_occurence_i[0],
                                            RXGate(np.pi / 2))
                                        LinComb.insert_gate(
                                            qfi_circuit,
                                            param_occurence_i[0],
                                            gate_to_insert_i,
                                            additional_qubits=additional_qubits
                                        )
                                        LinComb.insert_gate(
                                            qfi_circuit, param_occurence_i[0],
                                            RXGate(-np.pi / 2))
                                        LinComb.insert_gate(
                                            qfi_circuit, param_occurence_i[0],
                                            RZGate(-param_occurence_i[0].
                                                   params[2]))

                                    elif param_occurence_i[1] == 1:
                                        LinComb.insert_gate(
                                            qfi_circuit,
                                            param_occurence_i[0],
                                            gate_to_insert_i,
                                            after=True,
                                            additional_qubits=additional_qubits
                                        )
                                    else:
                                        LinComb.insert_gate(
                                            qfi_circuit,
                                            param_occurence_i[0],
                                            gate_to_insert_i,
                                            additional_qubits=additional_qubits
                                        )
                                else:
                                    LinComb.insert_gate(
                                        qfi_circuit,
                                        param_occurence_i[0],
                                        gate_to_insert_i,
                                        additional_qubits=additional_qubits)

                                LinComb.insert_gate(qfi_circuit,
                                                    gate_to_insert_i,
                                                    XGate(),
                                                    qubits=[work_qubit],
                                                    after=True)

                                # Insert controlled, intercepting gate j - controlled by |0>
                                if isinstance(param_occurence_j[0], UGate):
                                    if param_occurence_j[1] == 0:
                                        LinComb.insert_gate(
                                            qfi_circuit, param_occurence_j[0],
                                            RZGate(param_occurence_j[0].
                                                   params[2]))
                                        LinComb.insert_gate(
                                            qfi_circuit, param_occurence_j[0],
                                            RXGate(np.pi / 2))
                                        LinComb.insert_gate(
                                            qfi_circuit,
                                            param_occurence_j[0],
                                            gate_to_insert_j,
                                            additional_qubits=additional_qubits
                                        )
                                        LinComb.insert_gate(
                                            qfi_circuit, param_occurence_j[0],
                                            RXGate(-np.pi / 2))
                                        LinComb.insert_gate(
                                            qfi_circuit, param_occurence_j[0],
                                            RZGate(-param_occurence_j[0].
                                                   params[2]))

                                    elif param_occurence_j[1] == 1:
                                        LinComb.insert_gate(
                                            qfi_circuit,
                                            param_occurence_j[0],
                                            gate_to_insert_j,
                                            after=True,
                                            additional_qubits=additional_qubits
                                        )
                                    else:
                                        LinComb.insert_gate(
                                            qfi_circuit,
                                            param_occurence_j[0],
                                            gate_to_insert_j,
                                            additional_qubits=additional_qubits
                                        )
                                else:
                                    LinComb.insert_gate(
                                        qfi_circuit,
                                        param_occurence_j[0],
                                        gate_to_insert_j,
                                        additional_qubits=additional_qubits)

                                # Remove redundant gates

                                if j <= i:
                                    qfi_circuit = self.trim_circuit(
                                        qfi_circuit, param_occurence_i[0])
                                else:
                                    qfi_circuit = self.trim_circuit(
                                        qfi_circuit, param_occurence_j[0])
                                # Apply final Hadamard gate
                                qfi_circuit.h(work_qubit)
                                # Convert the quantum circuit into a CircuitStateFn and add the
                                # coefficients i, j and the original operator coefficient
                                term = np.sqrt(
                                    np.abs(coeff_i) *
                                    np.abs(coeff_j)) * operator.coeff
                                term = term * CircuitStateFn(qfi_circuit)

                                # Check if the gate parameters i and j are parameter expressions
                                gate_param_i = param_occurence_i[0].params[
                                    param_occurence_i[1]]
                                gate_param_j = param_occurence_j[0].params[
                                    param_occurence_j[1]]

                                meas = deepcopy(qfi_observable)
                                # If the gate parameter i is a parameter expression use the chain
                                # rule.
                                if isinstance(gate_param_i,
                                              ParameterExpression):
                                    expr_grad = DerivativeBase.parameter_expression_grad(
                                        gate_param_i, param_i)
                                    meas *= expr_grad
                                # If the gate parameter j is a parameter expression use the chain
                                # rule.
                                if isinstance(gate_param_j,
                                              ParameterExpression):
                                    expr_grad = DerivativeBase.parameter_expression_grad(
                                        gate_param_j, param_j)
                                    meas *= expr_grad
                                term = meas @ term

                                if m_i == 0 and k_i == 0 and m_j == 0 and k_j == 0:
                                    qfi_op = term
                                else:
                                    # Product Rule
                                    qfi_op += term

                # Compute −4 * Re(〈∂kψ|ψ〉〈ψ|∂lψ〉)
                def phase_fix_combo_fn(x):
                    return 4 * (-0.5) * (x[0] * np.conjugate(x[1]) +
                                         x[1] * np.conjugate(x[0]))

                phase_fix = ListOp([phase_fix_states[i], phase_fix_states[j]],
                                   combo_fn=phase_fix_combo_fn)
                # Add the phase fix quantities to the entries of the QFI
                # Get 4 * Re[〈∂kψ|∂lψ〉−〈∂kψ|ψ〉〈ψ|∂lψ〉]
                if not qfi_ops:
                    qfi_ops = [qfi_op + phase_fix]
                else:
                    qfi_ops += [qfi_op + phase_fix]
            qfi_operators.append(ListOp(qfi_ops))
        # Return the full QFI
        return ListOp(qfi_operators)