def test_standard_1Q_one(self):
        """Test standard gate.repeat(1) method.
        """
        qr = QuantumRegister(1, 'qr')
        expected_circ = QuantumCircuit(qr)
        expected_circ.append(SGate(), [qr[0]])
        expected = expected_circ.to_instruction()

        result = SGate().repeat(1)

        self.assertEqual(result.name, 's*1')
        self.assertEqual(result.definition, expected.definition)
        self.assertIsInstance(result, Gate)
Esempio n. 2
0
 def __init__(self):
     # |0> Zp rotation
     prep_zp = QuantumCircuit(1, name="PauliPrepZp")
     # |1> Zm rotation
     prep_zm = QuantumCircuit(1, name="PauliPrepZm")
     prep_zm.append(XGate(), [0])
     # |+> Xp rotation
     prep_xp = QuantumCircuit(1, name="PauliPrepXp")
     prep_xp.append(HGate(), [0])
     # |-> Xm rotation
     prep_xm = QuantumCircuit(1, name="PauliPrepXm")
     prep_xm.append(HGate(), [0])
     prep_xm.append(ZGate(), [0])
     # |+i> Yp rotation
     prep_yp = QuantumCircuit(1, name="PauliPrepYp")
     prep_yp.append(HGate(), [0])
     prep_yp.append(SGate(), [0])
     # |-i> Ym rotation
     prep_ym = QuantumCircuit(1, name="PauliPrepYm")
     prep_ym.append(HGate(), [0])
     prep_ym.append(SdgGate(), [0])
     super().__init__(
         [
             prep_zp,
             prep_zm,
             prep_xp,
             prep_xm,
             prep_yp,
             prep_ym,
         ]
     )
Esempio n. 3
0
    def test_1_qubit_identities(self):
        """Tests identities for 1-qubit gates"""
        # T*X*T = X
        circ1 = QuantumCircuit(1)
        circ1.t(0)
        circ1.x(0)
        circ1.t(0)
        elem1 = CNOTDihedral(circ1)
        elem = CNOTDihedral(XGate())
        self.assertEqual(elem1, elem, "Error: 1-qubit identity does not hold")

        # X*T*X = Tdg
        circ1 = QuantumCircuit(1)
        circ1.x(0)
        circ1.t(0)
        circ1.x(0)
        elem1 = CNOTDihedral(circ1)
        elem = CNOTDihedral(TdgGate())
        self.assertEqual(elem1, elem, "Error: 1-qubit identity does not hold")

        # X*Tdg*X = T
        circ1 = QuantumCircuit(1)
        circ1.x(0)
        circ1.tdg(0)
        circ1.x(0)
        elem1 = CNOTDihedral(circ1)
        elem = CNOTDihedral(TGate())
        self.assertEqual(elem1, elem, "Error: 1-qubit identity does not hold")

        # X*S*X = Sdg
        circ1 = QuantumCircuit(1)
        circ1.x(0)
        circ1.s(0)
        circ1.x(0)
        elem1 = CNOTDihedral(circ1)
        elem = CNOTDihedral(SdgGate())
        self.assertEqual(elem1, elem, "Error: 1-qubit identity does not hold")

        # X*Sdg*X = S
        circ1 = QuantumCircuit(1)
        circ1.x(0)
        circ1.sdg(0)
        circ1.x(0)
        elem1 = CNOTDihedral(circ1)
        elem = CNOTDihedral(SGate())
        self.assertEqual(elem1, elem, "Error: 1-qubit identity does not hold")

        # T*X*Tdg = S*X
        circ1 = QuantumCircuit(1)
        circ1.t(0)
        circ1.x(0)
        circ1.tdg(0)
        circ2 = QuantumCircuit(1)
        circ2.s(0)
        circ2.x(0)
        elem1 = CNOTDihedral(circ1)
        elem2 = CNOTDihedral(circ2)
        self.assertEqual(elem1, elem2, "Error: 1-qubit identity does not hold")
Esempio n. 4
0
def make_oneq_cliffords():
    """Make as list of 1q Cliffords"""
    ixyz_list = [g().to_matrix() for g in (IGate, XGate, YGate, ZGate)]
    ih_list = [g().to_matrix() for g in (IGate, HGate)]
    irs_list = [IGate().to_matrix(),
                SdgGate().to_matrix() @ HGate().to_matrix(),
                HGate().to_matrix() @ SGate().to_matrix()]
    oneq_cliffords = [Operator(ixyz @ ih @ irs) for ixyz in ixyz_list
                      for ih in ih_list
                      for irs in irs_list]
    return oneq_cliffords
Esempio n. 5
0
 def test_from_label(self):
     """Test from_label method"""
     label = 'IXYZHS'
     CI = Clifford(IGate())
     CX = Clifford(XGate())
     CY = Clifford(YGate())
     CZ = Clifford(ZGate())
     CH = Clifford(HGate())
     CS = Clifford(SGate())
     target = CI.tensor(CX).tensor(CY).tensor(CZ).tensor(CH).tensor(CS)
     self.assertEqual(Clifford.from_label(label), target)
    def test_unroller_one(self):
        """Test unrolling gate.repeat(1).
        """
        qr = QuantumRegister(1, 'qr')

        circuit = QuantumCircuit(qr)
        circuit.append(SGate().repeat(1), [qr[0]])
        result = PassManager(Unroller('u3')).run(circuit)

        expected = QuantumCircuit(qr)
        expected.append(U3Gate(0, 0, pi / 2), [qr[0]])

        self.assertEqual(result, expected)
Esempio n. 7
0
 def __init__(self):
     """Initialize Pauli preparation basis"""
     # |0> Zp rotation
     prep_zp = QuantumCircuit(1, name="PauliPrepZp")
     # |1> Zm rotation
     prep_zm = QuantumCircuit(1, name="PauliPrepZm")
     prep_zm.append(XGate(), [0])
     # |+> Xp rotation
     prep_xp = QuantumCircuit(1, name="PauliPrepXp")
     prep_xp.append(HGate(), [0])
     # |+i> Yp rotation
     prep_yp = QuantumCircuit(1, name="PauliPrepYp")
     prep_yp.append(HGate(), [0])
     prep_yp.append(SGate(), [0])
     super().__init__([prep_zp, prep_zm, prep_xp, prep_yp])
Esempio n. 8
0
def random_clifford_circuit(num_qubits, num_gates, gates="all", seed=None):
    """Generate a pseudo random Clifford circuit."""

    if gates == "all":
        if num_qubits == 1:
            gates = ["i", "x", "y", "z", "h", "s", "sdg", "v", "w"]
        else:
            gates = [
                "i", "x", "y", "z", "h", "s", "sdg", "v", "w", "cx", "cz",
                "swap"
            ]

    instructions = {
        "i": (IGate(), 1),
        "x": (XGate(), 1),
        "y": (YGate(), 1),
        "z": (ZGate(), 1),
        "h": (HGate(), 1),
        "s": (SGate(), 1),
        "sdg": (SdgGate(), 1),
        "v": (VGate(), 1),
        "w": (WGate(), 1),
        "cx": (CXGate(), 2),
        "cz": (CZGate(), 2),
        "swap": (SwapGate(), 2),
    }

    if isinstance(seed, np.random.Generator):
        rng = seed
    else:
        rng = np.random.default_rng(seed)

    samples = rng.choice(gates, num_gates)

    circ = QuantumCircuit(num_qubits)

    for name in samples:
        gate, nqargs = instructions[name]
        qargs = rng.choice(range(num_qubits), nqargs, replace=False).tolist()
        circ.append(gate, qargs)

    return circ
Esempio n. 9
0
def random_clifford_circuit(num_qubits, num_gates, gates='all', seed=None):
    """Generate a pseudo random Clifford circuit."""

    if gates == 'all':
        if num_qubits == 1:
            gates = ['i', 'x', 'y', 'z', 'h', 's', 'sdg', 'v', 'w']
        else:
            gates = [
                'i', 'x', 'y', 'z', 'h', 's', 'sdg', 'v', 'w', 'cx', 'cz',
                'swap'
            ]

    instructions = {
        'i': (IGate(), 1),
        'x': (XGate(), 1),
        'y': (YGate(), 1),
        'z': (ZGate(), 1),
        'h': (HGate(), 1),
        's': (SGate(), 1),
        'sdg': (SdgGate(), 1),
        'v': (VGate(), 1),
        'w': (WGate(), 1),
        'cx': (CXGate(), 2),
        'cz': (CZGate(), 2),
        'swap': (SwapGate(), 2)
    }

    if isinstance(seed, np.random.Generator):
        rng = seed
    else:
        rng = np.random.default_rng(seed)

    samples = rng.choice(gates, num_gates)

    circ = QuantumCircuit(num_qubits)

    for name in samples:
        gate, nqargs = instructions[name]
        qargs = rng.choice(range(num_qubits), nqargs, replace=False).tolist()
        circ.append(gate, qargs)

    return circ
Esempio n. 10
0
    def test_user_style(self):
        """Tests loading a user style"""
        circuit = QuantumCircuit(7)
        circuit.h(0)
        circuit.append(HGate(label="H2"), [1])
        circuit.x(0)
        circuit.cx(0, 1)
        circuit.ccx(0, 1, 2)
        circuit.swap(0, 1)
        circuit.cswap(0, 1, 2)
        circuit.append(SwapGate().control(2), [0, 1, 2, 3])
        circuit.dcx(0, 1)
        circuit.append(DCXGate().control(1), [0, 1, 2])
        circuit.append(DCXGate().control(2), [0, 1, 2, 3])
        circuit.z(4)
        circuit.append(SGate(label="S1"), [4])
        circuit.sdg(4)
        circuit.t(4)
        circuit.tdg(4)
        circuit.p(pi / 2, 4)
        circuit.cz(5, 6)
        circuit.cp(pi / 2, 5, 6)
        circuit.y(5)
        circuit.rx(pi / 3, 5)
        circuit.rzx(pi / 2, 5, 6)
        circuit.u(pi / 2, pi / 2, pi / 2, 5)
        circuit.barrier(5, 6)
        circuit.reset(5)

        self.circuit_drawer(
            circuit,
            style={
                "name": "user_style",
                "displaytext": {
                    "H2": "H_2"
                },
                "displaycolor": {
                    "H2": ("#EEDD00", "#FF0000")
                },
            },
            filename="user_style.png",
        )
Esempio n. 11
0
 def clifford_1_qubit_circuit(self, num):
     """Return the 1-qubit clifford circuit corresponding to `num`
     where `num` is between 0 and 23.
     """
     # pylint: disable=unbalanced-tuple-unpacking
     # This is safe since `_unpack_num` returns list the size of the sig
     (i, j, p) = self._unpack_num(num, self.CLIFFORD_1_QUBIT_SIG)
     qr = QuantumRegister(1)
     qc = QuantumCircuit(qr)
     if i == 1:
         qc.h(0)
     if j == 1:
         qc._append(SXdgGate(), [qr[0]], [])
     if j == 2:
         qc._append(SGate(), [qr[0]], [])
     if p == 1:
         qc.x(0)
     if p == 2:
         qc.y(0)
     if p == 3:
         qc.z(0)
     return qc
Esempio n. 12
0
class TestRBUtilities(QiskitExperimentsTestCase):
    """
    A test class for additional functionality provided by the StandardRB
    class.
    """

    instructions = {
        "i": IGate(),
        "x": XGate(),
        "y": YGate(),
        "z": ZGate(),
        "h": HGate(),
        "s": SGate(),
        "sdg": SdgGate(),
        "cx": CXGate(),
        "cz": CZGate(),
        "swap": SwapGate(),
    }
    seed = 42

    @data(
        [1, {((0,), "x"): 3, ((0,), "y"): 2, ((0,), "h"): 1}],
        [5, {((1,), "x"): 3, ((4,), "y"): 2, ((1,), "h"): 1, ((1, 4), "cx"): 7}],
    )
    @unpack
    def test_count_ops(self, num_qubits, expected_counts):
        """Testing the count_ops utility function
        this function receives a circuit and counts the number of gates
        in it, counting gates for different qubits separately"""
        circuit = QuantumCircuit(num_qubits)
        gates_to_add = []
        for gate, count in expected_counts.items():
            gates_to_add += [gate for _ in range(count)]
        rng = np.random.default_rng(self.seed)
        rng.shuffle(gates_to_add)
        for qubits, gate in gates_to_add:
            circuit.append(self.instructions[gate], qubits)
        counts = rb.RBUtils.count_ops(circuit)
        self.assertDictEqual(expected_counts, counts)

    def test_calculate_1q_epg(self):
        """Testing the calculation of 1 qubit error per gate
        The EPG is computed based on the error per clifford determined
        in the RB experiment, the gate counts, and an estimate about the
        relations between the errors of different gate types
        """
        epc_1_qubit = FitVal(0.0037, 0)
        qubits = [0]
        gate_error_ratio = {((0,), "id"): 1, ((0,), "rz"): 0, ((0,), "sx"): 1, ((0,), "x"): 1}
        gates_per_clifford = {((0,), "rz"): 10.5, ((0,), "sx"): 8.15, ((0,), "x"): 0.25}
        epg = rb.RBUtils.calculate_1q_epg(epc_1_qubit, qubits, gate_error_ratio, gates_per_clifford)
        error_dict = {
            ((0,), "rz"): FitVal(0, 0),
            ((0,), "sx"): FitVal(0.0004432101747785104, 0),
            ((0,), "x"): FitVal(0.0004432101747785104, 0),
        }

        for gate in ["x", "sx", "rz"]:
            expected_epg = error_dict[((0,), gate)]
            actual_epg = epg[(0,)][gate]
            self.assertTrue(np.allclose(expected_epg.value, actual_epg.value, atol=0.001))
            self.assertTrue(np.allclose(expected_epg.stderr, actual_epg.stderr, atol=0.001))

    def test_calculate_2q_epg(self):
        """Testing the calculation of 2 qubit error per gate
        The EPG is computed based on the error per clifford determined
        in the RB experiment, the gate counts, and an estimate about the
        relations between the errors of different gate types
        """
        epc_2_qubit = FitVal(0.034184849962675984, 0)
        qubits = [1, 4]
        gate_error_ratio = {
            ((1,), "id"): 1,
            ((4,), "id"): 1,
            ((1,), "rz"): 0,
            ((4,), "rz"): 0,
            ((1,), "sx"): 1,
            ((4,), "sx"): 1,
            ((1,), "x"): 1,
            ((4,), "x"): 1,
            ((4, 1), "cx"): 1,
            ((1, 4), "cx"): 1,
        }
        gates_per_clifford = {
            ((1, 4), "barrier"): 1.032967032967033,
            ((1,), "rz"): 15.932967032967033,
            ((1,), "sx"): 12.382417582417583,
            ((4,), "rz"): 18.681946624803768,
            ((4,), "sx"): 14.522605965463109,
            ((1, 4), "cx"): 1.0246506515936569,
            ((4, 1), "cx"): 0.5212064090480678,
            ((4,), "x"): 0.24237661112857592,
            ((1,), "measure"): 0.01098901098901099,
            ((4,), "measure"): 0.01098901098901099,
            ((1,), "x"): 0.2525918944392083,
        }
        epg_1_qubit = [
            AnalysisResultData("EPG_rz", 0.0, device_components=[1]),
            AnalysisResultData("EPG_rz", 0.0, device_components=[4]),
            AnalysisResultData("EPG_sx", 0.00036207066403884814, device_components=[1]),
            AnalysisResultData("EPG_sx", 0.0005429962529239195, device_components=[4]),
            AnalysisResultData("EPG_x", 0.00036207066403884814, device_components=[1]),
            AnalysisResultData("EPG_x", 0.0005429962529239195, device_components=[4]),
        ]
        epg = rb.RBUtils.calculate_2q_epg(
            epc_2_qubit, qubits, gate_error_ratio, gates_per_clifford, epg_1_qubit
        )

        error_dict = {
            ((1, 4), "cx"): FitVal(0.012438847900902494, 0),
        }

        expected_epg = error_dict[((1, 4), "cx")]
        actual_epg = epg[(1, 4)]["cx"]
        self.assertTrue(np.allclose(expected_epg.value, actual_epg.value, atol=0.001))
        self.assertTrue(np.allclose(expected_epg.stderr, actual_epg.stderr, atol=0.001))

    def test_coherence_limit(self):
        """Test coherence_limit."""
        t1 = 100.0
        t2 = 100.0
        gate_2_qubits = 0.5
        gate_1_qubit = 0.1
        twoq_coherence_err = rb.RBUtils.coherence_limit(2, [t1, t1], [t2, t2], gate_2_qubits)

        oneq_coherence_err = rb.RBUtils.coherence_limit(1, [t1], [t2], gate_1_qubit)

        self.assertAlmostEqual(oneq_coherence_err, 0.00049975, 6, "Error: 1Q Coherence Limit")

        self.assertAlmostEqual(twoq_coherence_err, 0.00597, 5, "Error: 2Q Coherence Limit")

    def test_clifford_1_qubit_generation(self):
        """Verify 1-qubit clifford indeed generates the correct group"""
        clifford_dicts = [
            {"stabilizer": ["+Z"], "destabilizer": ["+X"]},
            {"stabilizer": ["+X"], "destabilizer": ["+Z"]},
            {"stabilizer": ["+Y"], "destabilizer": ["+X"]},
            {"stabilizer": ["+X"], "destabilizer": ["+Y"]},
            {"stabilizer": ["+Z"], "destabilizer": ["+Y"]},
            {"stabilizer": ["+Y"], "destabilizer": ["+Z"]},
            {"stabilizer": ["-Z"], "destabilizer": ["+X"]},
            {"stabilizer": ["+X"], "destabilizer": ["-Z"]},
            {"stabilizer": ["-Y"], "destabilizer": ["+X"]},
            {"stabilizer": ["+X"], "destabilizer": ["-Y"]},
            {"stabilizer": ["-Z"], "destabilizer": ["-Y"]},
            {"stabilizer": ["-Y"], "destabilizer": ["-Z"]},
            {"stabilizer": ["-Z"], "destabilizer": ["-X"]},
            {"stabilizer": ["-X"], "destabilizer": ["-Z"]},
            {"stabilizer": ["+Y"], "destabilizer": ["-X"]},
            {"stabilizer": ["-X"], "destabilizer": ["+Y"]},
            {"stabilizer": ["-Z"], "destabilizer": ["+Y"]},
            {"stabilizer": ["+Y"], "destabilizer": ["-Z"]},
            {"stabilizer": ["+Z"], "destabilizer": ["-X"]},
            {"stabilizer": ["-X"], "destabilizer": ["+Z"]},
            {"stabilizer": ["-Y"], "destabilizer": ["-X"]},
            {"stabilizer": ["-X"], "destabilizer": ["-Y"]},
            {"stabilizer": ["+Z"], "destabilizer": ["-Y"]},
            {"stabilizer": ["-Y"], "destabilizer": ["+Z"]},
        ]
        cliffords = [Clifford.from_dict(i) for i in clifford_dicts]
        utils = rb.CliffordUtils()
        for n in range(24):
            clifford = utils.clifford_1_qubit(n)
            self.assertEqual(clifford, cliffords[n])

    def test_clifford_2_qubit_generation(self):
        """Verify 2-qubit clifford indeed generates the correct group"""
        utils = rb.CliffordUtils()
        pauli_free_elements = [
            0,
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
            9,
            10,
            11,
            12,
            13,
            14,
            15,
            16,
            17,
            18,
            19,
            20,
            21,
            22,
            23,
            24,
            25,
            26,
            27,
            28,
            29,
            30,
            31,
            32,
            33,
            34,
            35,
            576,
            577,
            578,
            579,
            580,
            581,
            582,
            583,
            584,
            585,
            586,
            587,
            588,
            589,
            590,
            591,
            592,
            593,
            594,
            595,
            596,
            597,
            598,
            599,
            600,
            601,
            602,
            603,
            604,
            605,
            606,
            607,
            608,
            609,
            610,
            611,
            612,
            613,
            614,
            615,
            616,
            617,
            618,
            619,
            620,
            621,
            622,
            623,
            624,
            625,
            626,
            627,
            628,
            629,
            630,
            631,
            632,
            633,
            634,
            635,
            636,
            637,
            638,
            639,
            640,
            641,
            642,
            643,
            644,
            645,
            646,
            647,
            648,
            649,
            650,
            651,
            652,
            653,
            654,
            655,
            656,
            657,
            658,
            659,
            660,
            661,
            662,
            663,
            664,
            665,
            666,
            667,
            668,
            669,
            670,
            671,
            672,
            673,
            674,
            675,
            676,
            677,
            678,
            679,
            680,
            681,
            682,
            683,
            684,
            685,
            686,
            687,
            688,
            689,
            690,
            691,
            692,
            693,
            694,
            695,
            696,
            697,
            698,
            699,
            700,
            701,
            702,
            703,
            704,
            705,
            706,
            707,
            708,
            709,
            710,
            711,
            712,
            713,
            714,
            715,
            716,
            717,
            718,
            719,
            720,
            721,
            722,
            723,
            724,
            725,
            726,
            727,
            728,
            729,
            730,
            731,
            732,
            733,
            734,
            735,
            736,
            737,
            738,
            739,
            740,
            741,
            742,
            743,
            744,
            745,
            746,
            747,
            748,
            749,
            750,
            751,
            752,
            753,
            754,
            755,
            756,
            757,
            758,
            759,
            760,
            761,
            762,
            763,
            764,
            765,
            766,
            767,
            768,
            769,
            770,
            771,
            772,
            773,
            774,
            775,
            776,
            777,
            778,
            779,
            780,
            781,
            782,
            783,
            784,
            785,
            786,
            787,
            788,
            789,
            790,
            791,
            792,
            793,
            794,
            795,
            796,
            797,
            798,
            799,
            800,
            801,
            802,
            803,
            804,
            805,
            806,
            807,
            808,
            809,
            810,
            811,
            812,
            813,
            814,
            815,
            816,
            817,
            818,
            819,
            820,
            821,
            822,
            823,
            824,
            825,
            826,
            827,
            828,
            829,
            830,
            831,
            832,
            833,
            834,
            835,
            836,
            837,
            838,
            839,
            840,
            841,
            842,
            843,
            844,
            845,
            846,
            847,
            848,
            849,
            850,
            851,
            852,
            853,
            854,
            855,
            856,
            857,
            858,
            859,
            860,
            861,
            862,
            863,
            864,
            865,
            866,
            867,
            868,
            869,
            870,
            871,
            872,
            873,
            874,
            875,
            876,
            877,
            878,
            879,
            880,
            881,
            882,
            883,
            884,
            885,
            886,
            887,
            888,
            889,
            890,
            891,
            892,
            893,
            894,
            895,
            896,
            897,
            898,
            899,
            5760,
            5761,
            5762,
            5763,
            5764,
            5765,
            5766,
            5767,
            5768,
            5769,
            5770,
            5771,
            5772,
            5773,
            5774,
            5775,
            5776,
            5777,
            5778,
            5779,
            5780,
            5781,
            5782,
            5783,
            5784,
            5785,
            5786,
            5787,
            5788,
            5789,
            5790,
            5791,
            5792,
            5793,
            5794,
            5795,
            5796,
            5797,
            5798,
            5799,
            5800,
            5801,
            5802,
            5803,
            5804,
            5805,
            5806,
            5807,
            5808,
            5809,
            5810,
            5811,
            5812,
            5813,
            5814,
            5815,
            5816,
            5817,
            5818,
            5819,
            5820,
            5821,
            5822,
            5823,
            5824,
            5825,
            5826,
            5827,
            5828,
            5829,
            5830,
            5831,
            5832,
            5833,
            5834,
            5835,
            5836,
            5837,
            5838,
            5839,
            5840,
            5841,
            5842,
            5843,
            5844,
            5845,
            5846,
            5847,
            5848,
            5849,
            5850,
            5851,
            5852,
            5853,
            5854,
            5855,
            5856,
            5857,
            5858,
            5859,
            5860,
            5861,
            5862,
            5863,
            5864,
            5865,
            5866,
            5867,
            5868,
            5869,
            5870,
            5871,
            5872,
            5873,
            5874,
            5875,
            5876,
            5877,
            5878,
            5879,
            5880,
            5881,
            5882,
            5883,
            5884,
            5885,
            5886,
            5887,
            5888,
            5889,
            5890,
            5891,
            5892,
            5893,
            5894,
            5895,
            5896,
            5897,
            5898,
            5899,
            5900,
            5901,
            5902,
            5903,
            5904,
            5905,
            5906,
            5907,
            5908,
            5909,
            5910,
            5911,
            5912,
            5913,
            5914,
            5915,
            5916,
            5917,
            5918,
            5919,
            5920,
            5921,
            5922,
            5923,
            5924,
            5925,
            5926,
            5927,
            5928,
            5929,
            5930,
            5931,
            5932,
            5933,
            5934,
            5935,
            5936,
            5937,
            5938,
            5939,
            5940,
            5941,
            5942,
            5943,
            5944,
            5945,
            5946,
            5947,
            5948,
            5949,
            5950,
            5951,
            5952,
            5953,
            5954,
            5955,
            5956,
            5957,
            5958,
            5959,
            5960,
            5961,
            5962,
            5963,
            5964,
            5965,
            5966,
            5967,
            5968,
            5969,
            5970,
            5971,
            5972,
            5973,
            5974,
            5975,
            5976,
            5977,
            5978,
            5979,
            5980,
            5981,
            5982,
            5983,
            5984,
            5985,
            5986,
            5987,
            5988,
            5989,
            5990,
            5991,
            5992,
            5993,
            5994,
            5995,
            5996,
            5997,
            5998,
            5999,
            6000,
            6001,
            6002,
            6003,
            6004,
            6005,
            6006,
            6007,
            6008,
            6009,
            6010,
            6011,
            6012,
            6013,
            6014,
            6015,
            6016,
            6017,
            6018,
            6019,
            6020,
            6021,
            6022,
            6023,
            6024,
            6025,
            6026,
            6027,
            6028,
            6029,
            6030,
            6031,
            6032,
            6033,
            6034,
            6035,
            6036,
            6037,
            6038,
            6039,
            6040,
            6041,
            6042,
            6043,
            6044,
            6045,
            6046,
            6047,
            6048,
            6049,
            6050,
            6051,
            6052,
            6053,
            6054,
            6055,
            6056,
            6057,
            6058,
            6059,
            6060,
            6061,
            6062,
            6063,
            6064,
            6065,
            6066,
            6067,
            6068,
            6069,
            6070,
            6071,
            6072,
            6073,
            6074,
            6075,
            6076,
            6077,
            6078,
            6079,
            6080,
            6081,
            6082,
            6083,
            10944,
            10945,
            10946,
            10947,
            10948,
            10949,
            10950,
            10951,
            10952,
            10953,
            10954,
            10955,
            10956,
            10957,
            10958,
            10959,
            10960,
            10961,
            10962,
            10963,
            10964,
            10965,
            10966,
            10967,
            10968,
            10969,
            10970,
            10971,
            10972,
            10973,
            10974,
            10975,
            10976,
            10977,
            10978,
            10979,
        ]
        cliffords = []
        for n in pauli_free_elements:
            clifford = utils.clifford_2_qubit(n)
            phase = clifford.table.phase
            for i in range(4):
                self.assertFalse(phase[i])
            for other_clifford in cliffords:
                self.assertNotEqual(clifford, other_clifford)
            cliffords.append(clifford)

        pauli_check_elements_list = [
            [0, 36, 72, 108, 144, 180, 216, 252, 288, 324, 360, 396, 432, 468, 504, 540],
            [
                576,
                900,
                1224,
                1548,
                1872,
                2196,
                2520,
                2844,
                3168,
                3492,
                3816,
                4140,
                4464,
                4788,
                5112,
                5436,
            ],
            [
                5760,
                6084,
                6408,
                6732,
                7056,
                7380,
                7704,
                8028,
                8352,
                8676,
                9000,
                9324,
                9648,
                9972,
                10296,
                10620,
            ],
            [
                10944,
                10980,
                11016,
                11052,
                11088,
                11124,
                11160,
                11196,
                11232,
                11268,
                11304,
                11340,
                11376,
                11412,
                11448,
                11484,
            ],
        ]
        for pauli_check_elements in pauli_check_elements_list:
            phases = []
            table = None
            for n in pauli_check_elements:
                clifford = utils.clifford_2_qubit(n)
                if table is None:
                    table = clifford.table.array
                else:
                    self.assertTrue(np.all(table == clifford.table.array))
                phase = tuple(clifford.table.phase)
                for other_phase in phases:
                    self.assertNotEqual(phase, other_phase)
                phases.append(phase)
Esempio n. 13
0
def make_immutable(obj):
    """ Delete the __setattr__ property to make the object mostly immutable. """

    # TODO figure out how to get correct error message
    # def throw_immutability_exception(self, *args):
    #     raise OpflowError('Operator convenience globals are immutable.')

    obj.__setattr__ = None
    return obj


# 1-Qubit Paulis
X = make_immutable(PauliOp(Pauli('X')))
Y = make_immutable(PauliOp(Pauli('Y')))
Z = make_immutable(PauliOp(Pauli('Z')))
I = make_immutable(PauliOp(Pauli('I')))

# Clifford+T, and some other common non-parameterized gates
CX = make_immutable(CircuitOp(CXGate()))
S = make_immutable(CircuitOp(SGate()))
H = make_immutable(CircuitOp(HGate()))
T = make_immutable(CircuitOp(TGate()))
Swap = make_immutable(CircuitOp(SwapGate()))
CZ = make_immutable(CircuitOp(CZGate()))

# 1-Qubit Paulis
Zero = make_immutable(StateFn('0'))
One = make_immutable(StateFn('1'))
Plus = make_immutable(H.compose(Zero))
Minus = make_immutable(H.compose(X).compose(Zero))
Esempio n. 14
0
    def _gradient_states(
        self,
        state_op: StateFn,
        meas_op: Optional[OperatorBase] = None,
        target_params: Optional[Union[ParameterExpression, ParameterVector,
                                      List[ParameterExpression]]] = None
    ) -> ListOp:
        """Generate the gradient states.

        Args:
            state_op: The operator representing the quantum state for which we compute the gradient.
            meas_op: The operator representing the observable for which we compute the gradient.
            target_params: The parameters we are taking the gradient wrt: ω

        Returns:
            ListOp of StateFns as quantum circuits which are the states w.r.t. which we compute the
            gradient. If a parameter appears multiple times, one circuit is created per
            parameterized gates to compute the product rule.

        Raises:
            AquaError: If one of the circuits could not be constructed.
            TypeError: If the operators is of unsupported type.
        """
        state_qc = deepcopy(state_op.primitive)

        # Define the working qubit to realize the linear combination of unitaries
        qr_work = QuantumRegister(1, 'work_qubit_lin_comb_grad')
        work_q = qr_work[0]

        if not isinstance(target_params, (list, np.ndarray)):
            target_params = [target_params]

        if len(target_params) > 1:
            states = None

        additional_qubits: Tuple[List[Qubit], List[Qubit]] = ([work_q], [])

        for param in target_params:
            if param not in state_qc._parameter_table.get_keys():
                op = ~Zero @ One
            else:
                param_gates = state_qc._parameter_table[param]
                for m, param_occurence in enumerate(param_gates):
                    coeffs, gates = self._gate_gradient_dict(
                        param_occurence[0])[param_occurence[1]]

                    # construct the states
                    for k, gate_to_insert in enumerate(gates):
                        grad_state = QuantumCircuit(*state_qc.qregs, qr_work)
                        grad_state.compose(state_qc, inplace=True)

                        # apply Hadamard on work_q
                        self.insert_gate(grad_state,
                                         param_occurence[0],
                                         HGate(),
                                         qubits=[work_q])

                        # Fix work_q phase
                        coeff_i = coeffs[k]
                        sign = np.sign(coeff_i)
                        is_complex = np.iscomplex(coeff_i)
                        if sign == -1:
                            if is_complex:
                                self.insert_gate(grad_state,
                                                 param_occurence[0],
                                                 SdgGate(),
                                                 qubits=[work_q])
                            else:
                                self.insert_gate(grad_state,
                                                 param_occurence[0],
                                                 ZGate(),
                                                 qubits=[work_q])
                        else:
                            if is_complex:
                                self.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:
                                self.insert_gate(
                                    grad_state, param_occurence[0],
                                    RZGate(param_occurence[0].params[2]))
                                self.insert_gate(grad_state,
                                                 param_occurence[0],
                                                 RXGate(np.pi / 2))
                                self.insert_gate(
                                    grad_state,
                                    param_occurence[0],
                                    gate_to_insert,
                                    additional_qubits=additional_qubits)
                                self.insert_gate(grad_state,
                                                 param_occurence[0],
                                                 RXGate(-np.pi / 2))
                                self.insert_gate(
                                    grad_state, param_occurence[0],
                                    RZGate(-param_occurence[0].params[2]))

                            elif param_occurence[1] == 1:
                                self.insert_gate(
                                    grad_state,
                                    param_occurence[0],
                                    gate_to_insert,
                                    after=True,
                                    additional_qubits=additional_qubits)
                            else:
                                self.insert_gate(
                                    grad_state,
                                    param_occurence[0],
                                    gate_to_insert,
                                    additional_qubits=additional_qubits)
                        else:
                            self.insert_gate(
                                grad_state,
                                param_occurence[0],
                                gate_to_insert,
                                additional_qubits=additional_qubits)
                        grad_state.h(work_q)

                        state = np.sqrt(
                            np.abs(coeff_i)) * state_op.coeff * CircuitStateFn(
                                grad_state)
                        # Chain Rule parameter expressions
                        gate_param = param_occurence[0].params[
                            param_occurence[1]]
                        if meas_op:
                            if gate_param == param:
                                state = meas_op @ state
                            else:
                                if isinstance(gate_param, ParameterExpression):
                                    expr_grad = DerivativeBase.parameter_expression_grad(
                                        gate_param, param)
                                    state = (expr_grad * meas_op) @ state
                                else:
                                    state = ~Zero @ One
                        else:
                            if gate_param == param:
                                state = ListOp([state],
                                               combo_fn=partial(
                                                   self._grad_combo_fn,
                                                   state_op=state_op))
                            else:
                                if isinstance(gate_param, ParameterExpression):
                                    expr_grad = DerivativeBase.parameter_expression_grad(
                                        gate_param, param)
                                    state = expr_grad * ListOp(
                                        [state],
                                        combo_fn=partial(self._grad_combo_fn,
                                                         state_op=state_op))
                                else:
                                    state = ~Zero @ One

                        if m == 0 and k == 0:
                            op = state
                        else:
                            # Product Rule
                            op += state
                if len(target_params) > 1:
                    if not states:
                        states = [op]
                    else:
                        states += [op]
                else:
                    return op
        if len(target_params) > 1:
            return ListOp(states)
        else:
            return op
Esempio n. 15
0
    def _hessian_states(
        self,
        state_op: StateFn,
        meas_op: Optional[OperatorBase] = None,
        target_params: Optional[Union[Tuple[ParameterExpression,
                                            ParameterExpression],
                                      List[Tuple[ParameterExpression,
                                                 ParameterExpression]]]] = None
    ) -> OperatorBase:
        """Generate the operator states whose evaluation returns the Hessian (items).

        Args:
            state_op: The operator representing the quantum state for which we compute the Hessian.
            meas_op: The operator representing the observable for which we compute the gradient.
            target_params: The parameters we are computing the Hessian wrt: ω

        Returns:
            Operators which give the Hessian. If a parameter appears multiple times, one circuit is
            created per parameterized gates to compute the product rule.

        Raises:
            AquaError: If one of the circuits could not be constructed.
            TypeError: If ``operator`` is of unsupported type.
        """
        state_qc = deepcopy(state_op.primitive)
        if isinstance(target_params, list) and isinstance(
                target_params[0], tuple):
            tuples_list = deepcopy(target_params)
            target_params = []
            for tuples in tuples_list:
                if all([
                        param in state_qc._parameter_table.get_keys()
                        for param in tuples
                ]):
                    for param in tuples:
                        if param not in target_params:
                            target_params.append(param)
        elif isinstance(target_params, tuple):
            tuples_list = deepcopy([target_params])
            target_params = []
            for tuples in tuples_list:
                if all([
                        param in state_qc._parameter_table.get_keys()
                        for param in tuples
                ]):
                    for param in tuples:
                        if param not in target_params:
                            target_params.append(param)
        else:
            raise TypeError(
                'Please define in the parameters for which the Hessian is evaluated either '
                'as parameter tuple or a list of parameter tuples')

        qr_add0 = QuantumRegister(1, 'work_qubit0')
        work_q0 = qr_add0[0]
        qr_add1 = QuantumRegister(1, 'work_qubit1')
        work_q1 = qr_add1[0]
        # create a copy of the original circuit with an additional working qubit register
        circuit = state_qc.copy()
        circuit.add_register(qr_add0, qr_add1)
        # Get the circuits needed to compute the Hessian
        hessian_ops = None
        for param_a, param_b in tuples_list:

            if param_a not in state_qc._parameter_table.get_keys() or param_b \
                    not in state_qc._parameter_table.get_keys():
                hessian_op = ~Zero @ One
            else:
                param_gates_a = state_qc._parameter_table[param_a]
                param_gates_b = state_qc._parameter_table[param_b]
                for i, param_occurence_a in enumerate(param_gates_a):
                    coeffs_a, gates_a = self._gate_gradient_dict(
                        param_occurence_a[0])[param_occurence_a[1]]
                    # apply Hadamard on working qubit
                    self.insert_gate(circuit,
                                     param_occurence_a[0],
                                     HGate(),
                                     qubits=[work_q0])
                    self.insert_gate(circuit,
                                     param_occurence_a[0],
                                     HGate(),
                                     qubits=[work_q1])
                    for j, gate_to_insert_a in enumerate(gates_a):

                        coeff_a = coeffs_a[j]
                        hessian_circuit_temp = QuantumCircuit(*circuit.qregs)
                        hessian_circuit_temp.data = circuit.data
                        # Fix working qubit 0 phase
                        sign = np.sign(coeff_a)
                        is_complex = np.iscomplex(coeff_a)
                        if sign == -1:
                            if is_complex:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 SdgGate(),
                                                 qubits=[work_q0])
                            else:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 ZGate(),
                                                 qubits=[work_q0])
                        else:
                            if is_complex:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 SGate(),
                                                 qubits=[work_q0])

                        # Insert controlled, intercepting gate - controlled by |1>
                        if isinstance(param_occurence_a[0], UGate):
                            if param_occurence_a[1] == 0:
                                self.insert_gate(
                                    hessian_circuit_temp, param_occurence_a[0],
                                    RZGate(param_occurence_a[0].params[2]))
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 RXGate(np.pi / 2))
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 gate_to_insert_a,
                                                 additional_qubits=([work_q0],
                                                                    []))
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 RXGate(-np.pi / 2))
                                self.insert_gate(
                                    hessian_circuit_temp, param_occurence_a[0],
                                    RZGate(-param_occurence_a[0].params[2]))

                            elif param_occurence_a[1] == 1:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 gate_to_insert_a,
                                                 after=True,
                                                 additional_qubits=([work_q0],
                                                                    []))
                            else:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 gate_to_insert_a,
                                                 additional_qubits=([work_q0],
                                                                    []))
                        else:
                            self.insert_gate(hessian_circuit_temp,
                                             param_occurence_a[0],
                                             gate_to_insert_a,
                                             additional_qubits=([work_q0], []))

                        for m, param_occurence_b in enumerate(param_gates_b):
                            coeffs_b, gates_b = self._gate_gradient_dict(
                                param_occurence_b[0])[param_occurence_b[1]]
                            for n, gate_to_insert_b in enumerate(gates_b):
                                coeff_b = coeffs_b[n]
                                # create a copy of the original circuit with the same registers
                                hessian_circuit = QuantumCircuit(
                                    *hessian_circuit_temp.qregs)
                                hessian_circuit.data = hessian_circuit_temp.data

                                # Fix working qubit 1 phase
                                sign = np.sign(coeff_b)
                                is_complex = np.iscomplex(coeff_b)
                                if sign == -1:
                                    if is_complex:
                                        self.insert_gate(hessian_circuit,
                                                         param_occurence_b[0],
                                                         SdgGate(),
                                                         qubits=[work_q1])
                                    else:
                                        self.insert_gate(hessian_circuit,
                                                         param_occurence_b[0],
                                                         ZGate(),
                                                         qubits=[work_q1])
                                else:
                                    if is_complex:
                                        self.insert_gate(hessian_circuit,
                                                         param_occurence_b[0],
                                                         SGate(),
                                                         qubits=[work_q1])

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

                                if isinstance(param_occurence_b[0], UGate):
                                    if param_occurence_b[1] == 0:
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RZGate(param_occurence_b[0].
                                                   params[2]))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RXGate(np.pi / 2))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            gate_to_insert_b,
                                            additional_qubits=([work_q1], []))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RXGate(-np.pi / 2))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RZGate(-param_occurence_b[0].
                                                   params[2]))

                                    elif param_occurence_b[1] == 1:
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            gate_to_insert_b,
                                            after=True,
                                            additional_qubits=([work_q1], []))
                                    else:
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            gate_to_insert_b,
                                            additional_qubits=([work_q1], []))
                                else:
                                    self.insert_gate(
                                        hessian_circuit,
                                        param_occurence_b[0],
                                        gate_to_insert_b,
                                        additional_qubits=([work_q1], []))

                                hessian_circuit.h(work_q0)
                                hessian_circuit.cz(work_q1, work_q0)
                                hessian_circuit.h(work_q1)

                                term = state_op.coeff * np.sqrt(np.abs(coeff_a) * np.abs(coeff_b)) \
                                                      * CircuitStateFn(hessian_circuit)

                                # Chain Rule Parameter Expression
                                gate_param_a = param_occurence_a[0].params[
                                    param_occurence_a[1]]
                                gate_param_b = param_occurence_b[0].params[
                                    param_occurence_b[1]]

                                if meas_op:
                                    meas = deepcopy(meas_op)
                                    if isinstance(gate_param_a,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        meas *= expr_grad
                                    if isinstance(gate_param_b,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        meas *= expr_grad
                                    term = meas @ term
                                else:
                                    term = ListOp([term],
                                                  combo_fn=partial(
                                                      self._hess_combo_fn,
                                                      state_op=state_op))
                                    if isinstance(gate_param_a,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        term *= expr_grad
                                    if isinstance(gate_param_b,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        term *= expr_grad

                                if i == 0 and j == 0 and m == 0 and n == 0:
                                    hessian_op = term
                                else:
                                    # Product Rule
                                    hessian_op += term
            # Create a list of Hessian elements w.r.t. the given parameter tuples
            if len(tuples_list) == 1:
                return hessian_op
            else:
                if not hessian_ops:
                    hessian_ops = [hessian_op]
                else:
                    hessian_ops += [hessian_op]
        return ListOp(hessian_ops)
Esempio n. 16
0
    def apply_grad_gate(
        circuit,
        gate,
        param_index,
        grad_gate,
        grad_coeff,
        qr_superpos,
        open_ctrl=False,
        trim_after_grad_gate=False,
    ):
        """Util function to apply a gradient gate for the linear combination of unitaries method.
        Replaces the ``gate`` instance in ``circuit`` with ``grad_gate`` using ``qr_superpos`` as
        superposition qubit. Also adds the appropriate sign-fix gates on the superposition qubit.

        Args:
            circuit (QuantumCircuit): The circuit in which to do the replacements.
            gate (Gate): The gate instance to replace.
            param_index (int): The index of the parameter in ``gate``.
            grad_gate (Gate): A controlled gate encoding the gradient of ``gate``.
            grad_coeff (float): A coefficient to the gradient component. Might not be one if the
                gradient contains multiple summed terms.
            qr_superpos (QuantumRegister): A ``QuantumRegister`` of size 1 contained in ``circuit``
                that is used as control for ``grad_gate``.
            open_ctrl (bool): If True use an open control for ``grad_gate`` instead of closed.
            trim_after_grad_gate (bool): If True remove all gates after the ``grad_gate``. Can
                be used to reduce the circuit depth in e.g. computing an overlap of gradients.

        Returns:
            QuantumCircuit: A copy of the original circuit with the gradient gate added.

        Raises:
            RuntimeError: If ``gate`` is not in ``circuit``.
        """
        qr_superpos_qubits = tuple(qr_superpos)
        # copy the input circuit taking the gates by reference
        out = QuantumCircuit(*circuit.qregs)
        out._data = circuit._data.copy()
        out._parameter_table = ParameterTable({
            param: values.copy()
            for param, values in circuit._parameter_table.items()
        })

        # get the data index and qubits of the target gate  TODO use built-in
        gate_idx, gate_qubits = None, None
        for i, instruction in enumerate(out._data):
            if instruction.operation is gate:
                gate_idx, gate_qubits = i, instruction.qubits
                break
        if gate_idx is None:
            raise RuntimeError(
                "The specified gate could not be found in the circuit data.")

        # initialize replacement instructions
        replacement = []

        # insert the phase fix before the target gate better documentation
        sign = np.sign(grad_coeff)
        is_complex = np.iscomplex(grad_coeff)

        if sign < 0 and is_complex:
            replacement.append(
                CircuitInstruction(SdgGate(), qr_superpos_qubits, ()))
        elif sign < 0:
            replacement.append(
                CircuitInstruction(ZGate(), qr_superpos_qubits, ()))
        elif is_complex:
            replacement.append(
                CircuitInstruction(SGate(), qr_superpos_qubits, ()))
        # else no additional gate required

        # open control if specified
        if open_ctrl:
            replacement += [
                CircuitInstruction(XGate(), qr_superpos_qubits, [])
            ]

        # compute the replacement
        if isinstance(gate, UGate) and param_index == 0:
            theta = gate.params[2]
            rz_plus, rz_minus = RZGate(theta), RZGate(-theta)
            replacement += [
                CircuitInstruction(rz_plus, (qubit, ), ())
                for qubit in gate_qubits
            ]
            replacement += [
                CircuitInstruction(RXGate(np.pi / 2), (qubit, ), ())
                for qubit in gate_qubits
            ]
            replacement.append(
                CircuitInstruction(grad_gate, qr_superpos_qubits + gate_qubits,
                                   []))
            replacement += [
                CircuitInstruction(RXGate(-np.pi / 2), (qubit, ), ())
                for qubit in gate_qubits
            ]
            replacement += [
                CircuitInstruction(rz_minus, (qubit, ), ())
                for qubit in gate_qubits
            ]

            # update parametertable if necessary
            if isinstance(theta, ParameterExpression):
                # This dangerously subverts ParameterTable by abusing the fact that binding will
                # mutate the exact instruction instance, and relies on all instances of `rz_plus`
                # that were added before being the same in memory, which QuantumCircuit usually
                # ensures is not the case.  I'm leaving this as close to its previous form as
                # possible, to avoid introducing further complications, but this whole method
                # accesses internal attributes of `QuantumCircuit` and needs rewriting.
                # - Jake Lishman, 2022-03-02.
                out._update_parameter_table(
                    CircuitInstruction(rz_plus, (gate_qubits[0], ), ()))
                out._update_parameter_table(
                    CircuitInstruction(rz_minus, (gate_qubits[0], ), ()))

            if open_ctrl:
                replacement.append(
                    CircuitInstruction(XGate(), qr_superpos_qubits, ()))

            if not trim_after_grad_gate:
                replacement.append(CircuitInstruction(gate, gate_qubits, ()))

        elif isinstance(gate, UGate) and param_index == 1:
            # gradient gate is applied after the original gate in this case
            replacement.append(CircuitInstruction(gate, gate_qubits, ()))
            replacement.append(
                CircuitInstruction(grad_gate, qr_superpos_qubits + gate_qubits,
                                   ()))
            if open_ctrl:
                replacement.append(
                    CircuitInstruction(XGate(), qr_superpos_qubits, ()))

        else:
            replacement.append(
                CircuitInstruction(grad_gate, qr_superpos_qubits + gate_qubits,
                                   ()))
            if open_ctrl:
                replacement.append(
                    CircuitInstruction(XGate(), qr_superpos_qubits, ()))
            if not trim_after_grad_gate:
                replacement.append(CircuitInstruction(gate, gate_qubits, ()))

        # replace the parameter we compute the derivative of with the replacement
        # TODO can this be done more efficiently?
        if trim_after_grad_gate:  # remove everything after the gradient gate
            out._data[gate_idx:] = replacement
            # reset parameter table
            table = ParameterTable()
            for instruction in out._data:
                for idx, param_expression in enumerate(
                        instruction.operation.params):
                    if isinstance(param_expression, ParameterExpression):
                        for param in param_expression.parameters:
                            if param not in table.keys():
                                table[param] = ParameterReferences(
                                    ((instruction.operation, idx), ))
                            else:
                                table[param].add((instruction.operation, idx))

            out._parameter_table = table

        else:
            out._data[gate_idx:gate_idx + 1] = replacement

        return out
Esempio n. 17
0
class TestPauli(QiskitTestCase):
    """Tests for Pauli operator class."""
    @data(*pauli_group_labels(2))
    def test_conjugate(self, label):
        """Test conjugate method."""
        value = Pauli(label).conjugate()
        target = operator_from_label(label).conjugate()
        self.assertEqual(Operator(value), target)

    @data(*pauli_group_labels(2))
    def test_transpose(self, label):
        """Test transpose method."""
        value = Pauli(label).transpose()
        target = operator_from_label(label).transpose()
        self.assertEqual(Operator(value), target)

    @data(*pauli_group_labels(2))
    def test_adjoint(self, label):
        """Test adjoint method."""
        value = Pauli(label).adjoint()
        target = operator_from_label(label).adjoint()
        self.assertEqual(Operator(value), target)

    @data(*pauli_group_labels(2))
    def test_inverse(self, label):
        """Test inverse method."""
        pauli = Pauli(label)
        value = pauli.inverse()
        target = pauli.adjoint()
        self.assertEqual(value, target)

    @data(*it.product(pauli_group_labels(2, full_group=False), repeat=2))
    @unpack
    def test_dot(self, label1, label2):
        """Test dot method."""
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        value = Operator(p1.dot(p2))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.dot(op2)
        self.assertEqual(value, target)

    @data(*pauli_group_labels(1))
    def test_dot_qargs(self, label2):
        """Test dot method with qargs."""
        label1 = "-iXYZ"
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        qargs = [0]
        value = Operator(p1.dot(p2, qargs=qargs))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.dot(op2, qargs=qargs)
        self.assertEqual(value, target)

    @data(*it.product(pauli_group_labels(2, full_group=False), repeat=2))
    @unpack
    def test_compose(self, label1, label2):
        """Test compose method."""
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        value = Operator(p1.compose(p2))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.compose(op2)
        self.assertEqual(value, target)

    @data(*pauli_group_labels(1))
    def test_compose_qargs(self, label2):
        """Test compose method with qargs."""
        label1 = "-XYZ"
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        qargs = [0]
        value = Operator(p1.compose(p2, qargs=qargs))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.compose(op2, qargs=qargs)
        self.assertEqual(value, target)

    @data(*it.product(pauli_group_labels(1, full_group=False), repeat=2))
    @unpack
    def test_tensor(self, label1, label2):
        """Test tensor method."""
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        value = Operator(p1.tensor(p2))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.tensor(op2)
        self.assertEqual(value, target)

    @data(*it.product(pauli_group_labels(1, full_group=False), repeat=2))
    @unpack
    def test_expand(self, label1, label2):
        """Test expand method."""
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        value = Operator(p1.expand(p2))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.expand(op2)
        self.assertEqual(value, target)

    @data("II", "XI", "YX", "ZZ", "YZ")
    def test_power(self, label):
        """Test power method."""
        iden = Pauli("II")
        op = Pauli(label)
        self.assertTrue(op**2, iden)

    @data(1, 1.0, -1, -1.0, 1j, -1j)
    def test_multiply(self, val):
        """Test multiply method."""
        op = val * Pauli(([True, True], [False, False], 0))
        phase = (-1j)**op.phase
        self.assertEqual(phase, val)

    def test_multiply_except(self):
        """Test multiply method raises exceptions."""
        op = Pauli("XYZ")
        self.assertRaises(QiskitError, op._multiply, 2)

    @data(0, 1, 2, 3)
    def test_negate(self, phase):
        """Test negate method"""
        op = Pauli(([False], [True], phase))
        neg = -op
        self.assertTrue(op.equiv(neg))
        self.assertEqual(neg.phase, (op.phase + 2) % 4)

    @data(*it.product(pauli_group_labels(1, False), repeat=2))
    @unpack
    def test_commutes(self, p1, p2):
        """Test commutes method"""
        P1 = Pauli(p1)
        P2 = Pauli(p2)
        self.assertEqual(P1.commutes(P2), P1.dot(P2) == P2.dot(P1))

    @data(*it.product(pauli_group_labels(1, False), repeat=2))
    @unpack
    def test_anticommutes(self, p1, p2):
        """Test anticommutes method"""
        P1 = Pauli(p1)
        P2 = Pauli(p2)
        self.assertEqual(P1.anticommutes(P2), P1.dot(P2) == -P2.dot(P1))

    @data(*it.product(
        (IGate(), XGate(), YGate(), ZGate(), HGate(), SGate(), SdgGate()),
        pauli_group_labels(1, False),
    ))
    @unpack
    def test_evolve_clifford1(self, gate, label):
        """Test evolve method for 1-qubit Clifford gates."""
        op = Operator(gate)
        pauli = Pauli(label)
        value = Operator(pauli.evolve(gate))
        value_h = Operator(pauli.evolve(gate, frame="h"))
        value_s = Operator(pauli.evolve(gate, frame="s"))
        value_inv = Operator(pauli.evolve(gate.inverse()))
        target = op.adjoint().dot(pauli).dot(op)
        self.assertEqual(value, target)
        self.assertEqual(value, value_h)
        self.assertEqual(value_inv, value_s)

    @data(*it.product((CXGate(), CYGate(), CZGate(), SwapGate()),
                      pauli_group_labels(2, False)))
    @unpack
    def test_evolve_clifford2(self, gate, label):
        """Test evolve method for 2-qubit Clifford gates."""
        op = Operator(gate)
        pauli = Pauli(label)
        value = Operator(pauli.evolve(gate))
        value_h = Operator(pauli.evolve(gate, frame="h"))
        value_s = Operator(pauli.evolve(gate, frame="s"))
        value_inv = Operator(pauli.evolve(gate.inverse()))
        target = op.adjoint().dot(pauli).dot(op)
        self.assertEqual(value, target)
        self.assertEqual(value, value_h)
        self.assertEqual(value_inv, value_s)

    def test_evolve_clifford_qargs(self):
        """Test evolve method for random Clifford"""
        cliff = random_clifford(3, seed=10)
        op = Operator(cliff)
        pauli = random_pauli(5, seed=10)
        qargs = [3, 0, 1]
        value = Operator(pauli.evolve(cliff, qargs=qargs))
        value_h = Operator(pauli.evolve(cliff, qargs=qargs, frame="h"))
        value_s = Operator(pauli.evolve(cliff, qargs=qargs, frame="s"))
        value_inv = Operator(pauli.evolve(cliff.adjoint(), qargs=qargs))
        target = Operator(pauli).compose(op.adjoint(),
                                         qargs=qargs).dot(op, qargs=qargs)
        self.assertEqual(value, target)
        self.assertEqual(value, value_h)
        self.assertEqual(value_inv, value_s)

    def test_barrier_delay_sim(self):
        """Test barrier and delay instructions can be simulated"""
        target_circ = QuantumCircuit(2)
        target_circ.x(0)
        target_circ.y(1)
        target = Pauli(target_circ)

        circ = QuantumCircuit(2)
        circ.x(0)
        circ.delay(100, 0)
        circ.barrier([0, 1])
        circ.y(1)
        value = Pauli(circ)
        self.assertEqual(value, target)
    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)
def run_gate_circuits(noise_model, gate_list, n_qubits):
    """Implements a test circuit for each gate in gate_list which is executed
    using the given noise_model

        Parameters
        ----------
        noise_model : NoiseModel    
            the noise model to apply to all test circuits 
        gate_list : List[string]
            list of HAL strings strings corresponding to one gate each
            these are the gates that will be checked for noise
        n_qubits : int
            number of qubits for the test circuit (1 or 2)

        Returns
        -------
        List[bool]
            for each test gate assigns true if there is noise on the test gate, 
            false if there is no noise, i.e. all zeros measured

        Raises
        ------
        ValueError
            No test circuit defined for a given gatestring in gate_list
    """

    # re-define gates with custom labels so that they are executed without noise
    H_perfect = HGate(label='h_perfect')
    S_perfect = SGate(label='s_perfect')

    circuit_errors = []  # list to append results to

    for gate in gate_list:

        q_sim = QiskitQuantumSimulator(register_size=n_qubits,
                                       seed=343,
                                       noise_model=noise_model)

        q_sim.accept_command(command_creator(*["STATE_PREPARATION", 0, 0]))

        if gate in ['H', 'RX', 'RY', 'SX', 'SY', 'X', 'Y']:
            q_sim.accept_command(command_creator(*[gate, 512, 0]))
            q_sim.accept_command(command_creator(*[gate, 512, 0]))

        elif gate in ['Z', 'R', 'RZ']:
            q_sim._circuit.append(H_perfect, [0])
            q_sim.accept_command(command_creator(*[gate, 512, 0]))
            q_sim.accept_command(command_creator(*[gate, 512, 0]))
            q_sim._circuit.append(H_perfect, [0])

        elif gate in ['PIZX']:
            q_sim._circuit.append(H_perfect, [0])
            q_sim.accept_command(command_creator(*[gate, 0, 0]))
            q_sim._circuit.append(S_perfect, [0])
            q_sim._circuit.append(S_perfect, [0])
            q_sim._circuit.append(H_perfect, [0])

        elif gate in ['PIYZ']:
            q_sim._circuit.append(H_perfect, [0])
            q_sim._circuit.append(S_perfect, [0])
            q_sim.accept_command(command_creator(*[gate, 0, 0]))
            q_sim._circuit.append(S_perfect, [0])
            q_sim._circuit.append(H_perfect, [0])

        elif gate in ['PIXY']:
            q_sim._circuit.append(H_perfect, [0])
            q_sim.accept_command(command_creator(*[gate, 0, 0]))
            q_sim._circuit.append(H_perfect, [0])

        elif gate in ['S', 'INVS']:
            q_sim._circuit.append(H_perfect, [0])
            for _ in range(4):
                q_sim.accept_command(command_creator(*[gate, 0, 0]))
            q_sim._circuit.append(H_perfect, [0])

        elif gate in ['SQRT_X']:
            for _ in range(4):
                q_sim.accept_command(command_creator(*[gate, 0, 0]))

        elif gate in ['T']:
            q_sim._circuit.append(H_perfect, [0])
            for _ in range(8):
                q_sim.accept_command(command_creator(*[gate, 0, 0]))
            q_sim._circuit.append(H_perfect, [0])

        elif gate in ['CX']:
            q_sim._circuit.append(H_perfect, [0])
            q_sim.accept_command(command_creator(*['CONTROL', 0, 0]))
            q_sim.accept_command(command_creator(*['X', 0, 1]))
            q_sim.accept_command(command_creator(*['CONTROL', 0, 0]))
            q_sim.accept_command(command_creator(*['X', 0, 1]))
            q_sim._circuit.append(H_perfect, [0])

        elif gate in ['CY']:
            q_sim._circuit.append(H_perfect, [0])
            q_sim.accept_command(command_creator(*['CONTROL', 0, 0]))
            q_sim.accept_command(command_creator(*['Y', 0, 1]))
            q_sim.accept_command(command_creator(*['CONTROL', 0, 0]))
            q_sim.accept_command(command_creator(*['Y', 0, 1]))
            q_sim._circuit.append(H_perfect, [0])

        elif gate in ['CZ']:
            q_sim._circuit.append(H_perfect, [0])
            q_sim._circuit.append(H_perfect, [1])
            q_sim.accept_command(command_creator(*['CONTROL', 0, 0]))
            q_sim.accept_command(command_creator(*['Z', 0, 1]))
            q_sim.accept_command(command_creator(*['CONTROL', 0, 0]))
            q_sim.accept_command(command_creator(*['Z', 0, 1]))
            q_sim._circuit.append(H_perfect, [0])
            q_sim._circuit.append(H_perfect, [1])

        else:
            raise ValueError('test circuit not defined for this gate')

        q_sim._circuit.measure_all()

        job = execute(q_sim._circuit,
                      backend=q_sim._simulator_backend,
                      optimization_level=0,
                      basis_gates=q_sim._noise_model.basis_gates,
                      noise_model=q_sim._noise_model,
                      seed_simulator=243,
                      shots=100)

        result_dict = job.result().get_counts()

        if n_qubits == 1:
            if result_dict['0'] < 100:
                circuit_errors.append(True)
            else:
                circuit_errors.append(False)

        if n_qubits == 2:
            if result_dict['00'] < 100:
                circuit_errors.append(True)
            else:
                circuit_errors.append(False)

    return circuit_errors
Esempio n. 20
0
def make_immutable(obj):
    """ Delete the __setattr__ property to make the object mostly immutable. """

    # TODO figure out how to get correct error message
    # def throw_immutability_exception(self, *args):
    #     raise AquaError('Operator convenience globals are immutable.')

    obj.__setattr__ = None
    return obj


# 1-Qubit Paulis
X = make_immutable(PauliOp(Pauli('X')))
Y = make_immutable(PauliOp(Pauli('Y')))
Z = make_immutable(PauliOp(Pauli('Z')))
I = make_immutable(PauliOp(Pauli('I')))

# Clifford+T, and some other common non-parameterized gates
CX = make_immutable(PrimitiveOp(CXGate()))
S = make_immutable(PrimitiveOp(SGate()))
H = make_immutable(PrimitiveOp(HGate()))
T = make_immutable(PrimitiveOp(TGate()))
Swap = make_immutable(PrimitiveOp(SwapGate()))
CZ = make_immutable(PrimitiveOp(CZGate()))

# 1-Qubit Paulis
Zero = make_immutable(StateFn('0'))
One = make_immutable(StateFn('1'))
Plus = make_immutable(H.compose(Zero))
Minus = make_immutable(H.compose(X).compose(Zero))
Esempio n. 21
0
    def apply_grad_gate(circuit, gate, param_index, grad_gate, grad_coeff, qr_superpos,
                        open_ctrl=False, trim_after_grad_gate=False):
        """Util function to apply a gradient gate for the linear combination of unitaries method.

        Replaces the ``gate`` instance in ``circuit`` with ``grad_gate`` using ``qr_superpos`` as
        superposition qubit. Also adds the appropriate sign-fix gates on the superposition qubit.

        Args:
            circuit (QuantumCircuit): The circuit in which to do the replacements.
            gate (Gate): The gate instance to replace.
            param_index (int): The index of the parameter in ``gate``.
            grad_gate (Gate): A controlled gate encoding the gradient of ``gate``.
            grad_coeff (float): A coefficient to the gradient component. Might not be one if the
                gradient contains multiple summed terms.
            qr_superpos (QuantumRegister): A ``QuantumRegister`` of size 1 contained in ``circuit``
                that is used as control for ``grad_gate``.
            open_ctrl (bool): If True use an open control for ``grad_gate`` instead of closed.
            trim_after_grad_gate (bool): If True remove all gates after the ``grad_gate``. Can
                be used to reduce the circuit depth in e.g. computing an overlap of gradients.

        Returns:
            QuantumCircuit: A copy of the original circuit with the gradient gate added.

        Raises:
            RuntimeError: If ``gate`` is not in ``circuit``.
        """
        # copy the input circuit taking the gates by reference
        out = QuantumCircuit(*circuit.qregs)
        out._data = circuit._data.copy()
        out._parameter_table = ParameterTable({
            param: values.copy() for param, values in circuit._parameter_table.items()
        })

        # get the data index and qubits of the target gate  TODO use built-in
        gate_idx, gate_qubits = None, None
        for i, (op, qarg, _) in enumerate(out._data):
            if op is gate:
                gate_idx, gate_qubits = i, qarg
                break
        if gate_idx is None:
            raise RuntimeError('The specified gate could not be found in the circuit data.')

        # initialize replacement instructions
        replacement = []

        # insert the phase fix before the target gate better documentation
        sign = np.sign(grad_coeff)
        is_complex = np.iscomplex(grad_coeff)

        if sign < 0 and is_complex:
            replacement.append((SdgGate(), qr_superpos[:], []))
        elif sign < 0:
            replacement.append((ZGate(), qr_superpos[:], []))
        elif is_complex:
            replacement.append((SGate(), qr_superpos[:], []))
        # else no additional gate required

        # open control if specified
        if open_ctrl:
            replacement += [(XGate(), qr_superpos[:], [])]

        # compute the replacement
        if isinstance(gate, UGate) and param_index == 0:
            theta = gate.params[2]
            rz_plus, rz_minus = RZGate(theta), RZGate(-theta)
            replacement += [(rz_plus, [qubit], []) for qubit in gate_qubits]
            replacement += [(RXGate(np.pi / 2), [qubit], []) for qubit in gate_qubits]
            replacement.append((grad_gate, qr_superpos[:] + gate_qubits, []))
            replacement += [(RXGate(-np.pi / 2), [qubit], []) for qubit in gate_qubits]
            replacement += [(rz_minus, [qubit], []) for qubit in gate_qubits]

            # update parametertable if necessary
            if isinstance(theta, ParameterExpression):
                out._update_parameter_table(rz_plus)
                out._update_parameter_table(rz_minus)

            if open_ctrl:
                replacement += [(XGate(), qr_superpos[:], [])]

            if not trim_after_grad_gate:
                replacement.append((gate, gate_qubits, []))

        elif isinstance(gate, UGate) and param_index == 1:
            # gradient gate is applied after the original gate in this case
            replacement.append((gate, gate_qubits, []))
            replacement.append((grad_gate, qr_superpos[:] + gate_qubits, []))
            if open_ctrl:
                replacement += [(XGate(), qr_superpos[:], [])]

        else:
            replacement.append((grad_gate, qr_superpos[:] + gate_qubits, []))
            if open_ctrl:
                replacement += [(XGate(), qr_superpos[:], [])]
            if not trim_after_grad_gate:
                replacement.append((gate, gate_qubits, []))

        # replace the parameter we compute the derivative of with the replacement
        # TODO can this be done more efficiently?
        if trim_after_grad_gate:  # remove everything after the gradient gate
            out._data[gate_idx:] = replacement
            # reset parameter table
            table = ParameterTable()
            for op, _, _ in out._data:
                for idx, param_expression in enumerate(op.params):
                    if isinstance(param_expression, ParameterExpression):
                        for param in param_expression.parameters:
                            if param not in table.keys():
                                table[param] = [(op, idx)]
                            else:
                                table[param].append((op, idx))

            out._parameter_table = table

        else:
            out._data[gate_idx:gate_idx + 1] = replacement

        return out
class TestPauli(QiskitTestCase):
    """Tests for Pauli operator class."""
    @data(*pauli_group_labels(2))
    def test_conjugate(self, label):
        """Test conjugate method."""
        value = Pauli(label).conjugate()
        target = operator_from_label(label).conjugate()
        self.assertEqual(Operator(value), target)

    @data(*pauli_group_labels(2))
    def test_transpose(self, label):
        """Test transpose method."""
        value = Pauli(label).transpose()
        target = operator_from_label(label).transpose()
        self.assertEqual(Operator(value), target)

    @data(*pauli_group_labels(2))
    def test_adjoint(self, label):
        """Test adjoint method."""
        value = Pauli(label).adjoint()
        target = operator_from_label(label).adjoint()
        self.assertEqual(Operator(value), target)

    @data(*pauli_group_labels(2))
    def test_inverse(self, label):
        """Test inverse method."""
        pauli = Pauli(label)
        value = pauli.inverse()
        target = pauli.adjoint()
        self.assertEqual(value, target)

    @data(*it.product(pauli_group_labels(2, full_group=False), repeat=2))
    @unpack
    def test_dot(self, label1, label2):
        """Test dot method."""
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        value = Operator(p1.dot(p2))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.dot(op2)
        self.assertEqual(value, target)

    @data(*pauli_group_labels(1))
    def test_dot_qargs(self, label2):
        """Test dot method with qargs."""
        label1 = '-iXYZ'
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        qargs = [0]
        value = Operator(p1.dot(p2, qargs=qargs))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.dot(op2, qargs=qargs)
        self.assertEqual(value, target)

    @data(*it.product(pauli_group_labels(2, full_group=False), repeat=2))
    @unpack
    def test_compose(self, label1, label2):
        """Test compose method."""
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        value = Operator(p1.compose(p2))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.compose(op2)
        self.assertEqual(value, target)

    @data(*pauli_group_labels(1))
    def test_compose_qargs(self, label2):
        """Test compose method with qargs."""
        label1 = '-XYZ'
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        qargs = [0]
        value = Operator(p1.compose(p2, qargs=qargs))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.compose(op2, qargs=qargs)
        self.assertEqual(value, target)

    @data(*it.product(pauli_group_labels(1, full_group=False), repeat=2))
    @unpack
    def test_tensor(self, label1, label2):
        """Test tensor method."""
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        value = Operator(p1.tensor(p2))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.tensor(op2)
        self.assertEqual(value, target)

    @data(*it.product(pauli_group_labels(1, full_group=False), repeat=2))
    @unpack
    def test_expand(self, label1, label2):
        """Test expand method."""
        p1 = Pauli(label1)
        p2 = Pauli(label2)
        value = Operator(p1.expand(p2))
        op1 = operator_from_label(label1)
        op2 = operator_from_label(label2)
        target = op1.expand(op2)
        self.assertEqual(value, target)

    @data('II', 'XI', 'YX', 'ZZ', 'YZ')
    def test_power(self, label):
        """Test power method."""
        iden = Pauli('II')
        op = Pauli(label)
        self.assertTrue(op**2, iden)

    @data(1, 1.0, -1, -1.0, 1j, -1j)
    def test_multiply(self, val):
        """Test multiply method."""
        op = val * Pauli(([True, True], [False, False], 0))
        phase = (-1j)**op.phase
        self.assertEqual(phase, val)

    def test_multiply_except(self):
        """Test multiply method raises exceptions."""
        op = Pauli('XYZ')
        self.assertRaises(QiskitError, op._multiply, 2)

    @data(0, 1, 2, 3)
    def test_negate(self, phase):
        """Test negate method"""
        op = Pauli(([False], [True], phase))
        neg = -op
        self.assertTrue(op.equiv(neg))
        self.assertEqual(neg.phase, (op.phase + 2) % 4)

    @data(*it.product(pauli_group_labels(1, False), repeat=2))
    @unpack
    def test_commutes(self, p1, p2):
        """Test commutes method"""
        P1 = Pauli(p1)
        P2 = Pauli(p2)
        self.assertEqual(P1.commutes(P2), P1.dot(P2) == P2.dot(P1))

    @data(*it.product(pauli_group_labels(1, False), repeat=2))
    @unpack
    def test_anticommutes(self, p1, p2):
        """Test anticommutes method"""
        P1 = Pauli(p1)
        P2 = Pauli(p2)
        self.assertEqual(P1.anticommutes(P2), P1.dot(P2) == -P2.dot(P1))

    @data(*it.product(
        (IGate(), XGate(), YGate(), ZGate(), HGate(), SGate(), SdgGate()),
        pauli_group_labels(1, False)))
    @unpack
    def test_evolve_clifford1(self, gate, label):
        """Test evolve method for 1-qubit Clifford gates."""
        cliff = Clifford(gate)
        op = Operator(gate)
        pauli = Pauli(label)
        value = Operator(pauli.evolve(cliff))
        target = op.adjoint().dot(pauli).dot(op)
        self.assertEqual(value, target)

    @data(*it.product((CXGate(), CYGate(), CZGate(), SwapGate()),
                      pauli_group_labels(2, False)))
    @unpack
    def test_evolve_clifford2(self, gate, label):
        """Test evolve method for 2-qubit Clifford gates."""
        cliff = Clifford(gate)
        op = Operator(gate)
        pauli = Pauli(label)
        value = Operator(pauli.evolve(cliff))
        target = op.adjoint().dot(pauli).dot(op)
        self.assertEqual(value, target)

    def test_evolve_clifford_qargs(self):
        """Test evolve method for random Clifford"""
        cliff = random_clifford(3, seed=10)
        op = Operator(cliff)
        pauli = random_pauli(5, seed=10)
        qargs = [3, 0, 1]
        value = Operator(pauli.evolve(cliff, qargs=qargs))
        target = Operator(pauli).compose(op.adjoint(),
                                         qargs=qargs).dot(op, qargs=qargs)
        self.assertEqual(value, target)
Esempio n. 23
0
from qiskit.circuit.library import HGate, XGate, YGate, ZGate, CXGate, CYGate, CZGate, CHGate
from qiskit.circuit.library import SwapGate, IGate, SGate, TGate, TdgGate, SdgGate, RYGate
from qiskit import QuantumCircuit, Aer, execute, QuantumRegister, ClassicalRegister
import numpy as np

SINGLE_GATE_DICT = {
    'I' : IGate(),
    'H' : HGate(),
    'X' : XGate(),
    'Y' : YGate(),
    'Z' : ZGate(),
    'S' : SGate(),
    'T' : TGate(),
    'T_dg' : TdgGate(),
    'S_dg' : SdgGate(),
    'Ry' : RYGate(np.pi / 4)
}

CONTROLLED_GATE_DICT = {
    'CX0' : CXGate(),
    'CX1' : CXGate(),
    'CY0' : CYGate(),
    'CY1' : CYGate(),
    'CZ0' : CZGate(),
    'CZ1' : CYGate(),
    'CH0' : CHGate(),
    'CH1' : CHGate()
}

def _state_to_gates(state):
Esempio n. 24
0
 def _define(self):
     """W Gate definition."""
     q = QuantumRegister(1, "q")
     qc = QuantumCircuit(q)
     qc.data = [(HGate(), [q[0]], []), (SGate(), [q[0]], [])]
     self.definition = qc
 def test_standard_no_int(self):
     """Test standard Gate.repeat(2/3) method. Raises, since n is not int.
     """
     with self.assertRaises(CircuitError) as context:
         _ = SGate().repeat(2 / 3)
     self.assertIn('strictly positive integer', str(context.exception))
 def test_standard_1Q_minus_one(self):
     """Test standard 2Q gate.repeat(-1) method. Raises, since n<1.
     """
     with self.assertRaises(CircuitError) as context:
         _ = SGate().repeat(-1)
     self.assertIn('strictly positive integer', str(context.exception))