def test_basic_zz(self): """Test to decompose a ZZ-based evolution op. The expected circuit is: ..parsed-literal:: ┌────────────────┐ q_0: ───────────────────X──────────────────────┤0 ├ ┌────────────────┐ │ ┌────────────────┐ │ exp(-i ZZ)(3) │ q_1: ┤0 ├─X─┤0 ├─X─┤1 ├ │ exp(-i ZZ)(1) │ │ exp(-i ZZ)(2) │ │ └────────────────┘ q_2: ┤1 ├─X─┤1 ├─X─────────────────── └────────────────┘ │ └────────────────┘ q_3: ───────────────────X──────────────────────────────────────── """ op = PauliSumOp.from_list([("IZZI", 1), ("ZIIZ", 2), ("ZIZI", 3)]) circ = QuantumCircuit(4) circ.append(PauliEvolutionGate(op, 1), range(4)) swapped = self.pm_.run(circ) expected = QuantumCircuit(4) expected.append(PauliEvolutionGate(Pauli("ZZ"), 1), (1, 2)) expected.swap(0, 1) expected.swap(2, 3) expected.append(PauliEvolutionGate(Pauli("ZZ"), 2), (1, 2)) expected.swap(1, 2) expected.append(PauliEvolutionGate(Pauli("ZZ"), 3), (0, 1)) self.assertEqual(swapped, expected)
def test_inverse(self, synth_cls): """Test calculating the inverse is correct.""" evo = PauliEvolutionGate(X + Y, time=0.12, synthesis=synth_cls()) circuit = QuantumCircuit(1) circuit.append(evo, circuit.qubits) circuit.append(evo.inverse(), circuit.qubits) self.assertTrue( Operator(circuit).equiv(np.identity(2**circuit.num_qubits)))
def test_ccx(self): """Test that extra multi-qubit operations are properly adjusted. Here, we test that the circuit .. parsed-literal:: ┌──────────────────────────┐ q_0: ┤0 ├──■── │ │┌─┴─┐ q_1: ┤1 exp(-it (IZZ + ZIZ))(1) ├┤ X ├ │ │└─┬─┘ q_2: ┤2 ├──■── └──────────────────────────┘ q_3: ───────────────────────────────── becomes .. parsed-literal:: ┌─────────────────┐ ┌───┐ q_0: ┤0 ├─X────────────────────┤ X ├ │ exp(-it ZZ)(1) │ │ ┌─────────────────┐└─┬─┘ q_1: ┤1 ├─X─┤0 ├──■── └─────────────────┘ │ exp(-it ZZ)(2) │ │ q_2: ──────────────────────┤1 ├──■── └─────────────────┘ q_3: ────────────────────────────────────────────── as expected. I.e. the Toffoli is properly adjusted at the end. """ cmap = CouplingMap(couplinglist=[(0, 1), (1, 2)]) swap_strat = SwapStrategy(cmap, swap_layers=(((0, 1), ), )) pm_ = PassManager([ FindCommutingPauliEvolutions(), Commuting2qGateRouter(swap_strat), ]) op = PauliSumOp.from_list([("IZZ", 1), ("ZIZ", 2)]) circ = QuantumCircuit(4) circ.append(PauliEvolutionGate(op, 1), range(3)) circ.ccx(0, 2, 1) swapped = pm_.run(circ) expected = QuantumCircuit(4) expected.append(PauliEvolutionGate(Pauli("ZZ"), 1), (0, 1)) expected.swap(0, 1) expected.append(PauliEvolutionGate(Pauli("ZZ"), 2), (1, 2)) expected.ccx(1, 2, 0) self.assertEqual(swapped, expected)
def test_different_input_types(self, op): """Test all different supported input types and that they yield the same.""" expected = QuantumCircuit(2) expected.rx(4, 1) with self.subTest(msg="plain"): evo = PauliEvolutionGate(op, time=2, synthesis=LieTrotter()) self.assertEqual(evo.definition, expected) with self.subTest(msg="wrapped in list"): evo = PauliEvolutionGate([op], time=2, synthesis=LieTrotter()) self.assertEqual(evo.definition, expected)
def test_basic_xx_with_measure(self): """Test to route an XX-based evolution op with measures. The op is :code:`[("XXII", -1), ("IIXX", 1), ("XIIX", -2), ("IXIX", 2)]`. The expected circuit is: ..parsed-literal:: ┌────────────────┐ ░ ┌─┐ q_0: ─┤0 ├─X──────────────────────────────────────────░────┤M├────── │ exp(-i XX)(3) │ │ ┌─────────────────┐ ░ └╥┘ ┌─┐ q_1: ─┤1 ├─X─┤0 ├─X────────────────────░─────╫────┤M├ ┌┴────────────────┤ │ exp(-i XX)(-6) │ │ ┌────────────────┐ ░ ┌─┐ ║ └╥┘ q_2: ┤0 ├─X─┤1 ├─X─┤0 ├─░─┤M├─╫─────╫─ │ exp(-i XX)(-3) │ │ └─────────────────┘ │ exp(-i XX)(6) │ ░ └╥┘ ║ ┌─┐ ║ q_3: ┤1 ├─X───────────────────────┤1 ├─░──╫──╫─┤M├─╫─ └─────────────────┘ └────────────────┘ ░ ║ ║ └╥┘ ║ meas: 4/══════════════════════════════════════════════════════════════════╩══╩══╩══╩═ 0 1 2 3 """ op = PauliSumOp.from_list([("XXII", -1), ("IIXX", 1), ("XIIX", -2), ("IXIX", 2)]) circ = QuantumCircuit(4, 4) circ.append(PauliEvolutionGate(op, 3), range(4)) circ.barrier() for idx in range(4): circ.measure(idx, idx) swapped = self.pm_.run(circ) expected = QuantumCircuit(4, 4) expected.append(PauliEvolutionGate(Pauli("XX"), 3), (0, 1)) expected.append(PauliEvolutionGate(Pauli("XX"), -3), (2, 3)) expected.swap(0, 1) expected.swap(2, 3) expected.append(PauliEvolutionGate(Pauli("XX"), -6), (1, 2)) expected.swap(1, 2) expected.append(PauliEvolutionGate(Pauli("XX"), 6), (2, 3)) expected.barrier() expected.measure(2, 0) expected.measure(0, 1) expected.measure(3, 2) expected.measure(1, 3) self.assertEqual(swapped, expected)
def _recursive_convert(self, operator: OperatorBase) -> OperatorBase: if isinstance(operator, EvolvedOp): if isinstance(operator.primitive, (PauliOp, PauliSumOp)): pauli = operator.primitive.primitive time = operator.coeff * operator.primitive.coeff evo = PauliEvolutionGate( pauli, time=time, synthesis=self._get_evolution_synthesis()) return CircuitOp(evo.definition) # operator = EvolvedOp(operator.primitive.to_pauli_op(), coeff=operator.coeff) if not {"Pauli"} == operator.primitive_strings(): logger.warning( "Evolved Hamiltonian is not composed of only Paulis, converting to " "Pauli representation, which can be expensive.") # Setting massive=False because this conversion is implicit. User can perform this # action on the Hamiltonian with massive=True explicitly if they so choose. # TODO explore performance to see whether we should avoid doing this repeatedly pauli_ham = operator.primitive.to_pauli_op(massive=False) operator = EvolvedOp(pauli_ham, coeff=operator.coeff) if isinstance(operator.primitive, SummedOp): # TODO uncomment when we implement Abelian grouped evolution. # if operator.primitive.abelian: # return self.evolution_for_abelian_paulisum(operator.primitive) # else: # Collect terms that are not the identity. oplist = [ x for x in operator.primitive if not isinstance(x, PauliOp) or sum(x.primitive.x + x.primitive.z) != 0 ] # Collect the coefficients of any identity terms, # which become global phases when exponentiated. identity_phases = [ x.coeff for x in operator.primitive if isinstance(x, PauliOp) and sum(x.primitive.x + x.primitive.z) == 0 ] # Construct sum without the identity operators. new_primitive = SummedOp(oplist, coeff=operator.primitive.coeff) trotterized = self.trotter.convert(new_primitive) circuit_no_identities = self._recursive_convert(trotterized) # Set the global phase of the QuantumCircuit to account for removed identity terms. global_phase = -sum(identity_phases) * operator.primitive.coeff circuit_no_identities.primitive.global_phase = global_phase return circuit_no_identities # Covers ListOp, ComposedOp, TensoredOp elif isinstance(operator.primitive, ListOp): converted_ops = [ self._recursive_convert(op) for op in operator.primitive.oplist ] return operator.primitive.__class__(converted_ops, coeff=operator.coeff) elif isinstance(operator, ListOp): return operator.traverse(self.convert).reduce() return operator
def test_cnot_chain_options(self, option): """Test selecting different kinds of CNOT chains.""" op = Z ^ Z ^ Z synthesis = LieTrotter(reps=1, cx_structure=option) evo = PauliEvolutionGate(op, synthesis=synthesis) expected = QuantumCircuit(3) if option == "chain": expected.cx(2, 1) expected.cx(1, 0) else: expected.cx(1, 0) expected.cx(2, 0) expected.rz(2, 0) if option == "chain": expected.cx(1, 0) expected.cx(2, 1) else: expected.cx(2, 0) expected.cx(1, 0) self.assertEqual(expected, evo.definition)
def _decompose_to_2q(self, dag: DAGCircuit, op: PauliEvolutionGate) -> DAGCircuit: """Decompose the PauliSumOp into two-qubit. Args: dag: The dag needed to get access to qubits. op: The operator with all the Pauli terms we need to apply. Returns: A dag made of two-qubit :class:`.PauliEvolutionGate`. """ sub_dag = dag.copy_empty_like() required_paulis = { self._pauli_to_edge(pauli): (pauli, coeff) for pauli, coeff in zip(op.operator.paulis, op.operator.coeffs) } for edge, (pauli, coeff) in required_paulis.items(): qubits = [dag.qubits[edge[0]], dag.qubits[edge[1]]] simple_pauli = Pauli(pauli.to_label().replace("I", "")) pauli_2q = PauliEvolutionGate(simple_pauli, op.time * np.real(coeff)) sub_dag.apply_operation_back(pauli_2q, qubits) return sub_dag
def test_suzuki_trotter_manual(self): """Test the evolution circuit of Suzuki Trotter against a manually constructed circuit.""" op = X + Y time = 0.1 reps = 1 evo_gate = PauliEvolutionGate(op, time, synthesis=SuzukiTrotter(order=4, reps=reps)) # manually construct expected evolution expected = QuantumCircuit(1) p_4 = 1 / (4 - 4**(1 / 3) ) # coefficient for reduced time from Suzuki paper for _ in range(2): # factor of 1/2 already included with factor 1/2 in rotation gate expected.rx(p_4 * time, 0) expected.ry(2 * p_4 * time, 0) expected.rx(p_4 * time, 0) expected.rx((1 - 4 * p_4) * time, 0) expected.ry(2 * (1 - 4 * p_4) * time, 0) expected.rx((1 - 4 * p_4) * time, 0) for _ in range(2): expected.rx(p_4 * time, 0) expected.ry(2 * p_4 * time, 0) expected.rx(p_4 * time, 0) self.assertEqual(evo_gate.definition.decompose(), expected)
def test_lie_trotter(self): """Test constructing the circuit with Lie Trotter decomposition.""" op = (X ^ 3) + (Y ^ 3) + (Z ^ 3) time = 0.123 reps = 4 evo_gate = PauliEvolutionGate(op, time, synthesis=LieTrotter(reps=reps)) decomposed = evo_gate.definition.decompose() self.assertEqual(decomposed.count_ops()["cx"], reps * 3 * 4)
def test_passing_grouped_paulis(self): """Test passing a list of already grouped Paulis.""" grouped_ops = [(X ^ Y) + (Y ^ X), (Z ^ I) + (Z ^ Z) + (I ^ Z), (X ^ X)] evo_gate = PauliEvolutionGate(grouped_ops, time=0.12, synthesis=LieTrotter()) decomposed = evo_gate.definition.decompose() self.assertEqual(decomposed.count_ops()["rz"], 4) self.assertEqual(decomposed.count_ops()["rzz"], 1) self.assertEqual(decomposed.count_ops()["rxx"], 1)
def test_single_qubit_circuit(self): """Test that a circuit with only single qubit gates is left unchanged.""" op = PauliSumOp.from_list([("IIIX", 1), ("IIXI", 2), ("IZII", 3), ("XIII", 4)]) circ = QuantumCircuit(4) circ.append(PauliEvolutionGate(op, 1), range(4)) self.assertEqual(circ, self.pm_.run(circ))
def test_paulisumop_coefficients_respected(self): """Test that global ``PauliSumOp`` coefficients are being taken care of.""" evo = PauliEvolutionGate(5 * (2 * X + 3 * Y - Z), time=1, synthesis=LieTrotter()) circuit = evo.definition.decompose() rz_angles = [ circuit.data[0][0].params[0], # X circuit.data[1][0].params[0], # Y circuit.data[2][0].params[0], # Z ] self.assertListEqual(rz_angles, [20, 30, -10])
def test_labels_and_name(self): """Test the name and labels are correct.""" operators = [X, (X + Y), ((I ^ Z) + (Z ^ I) - 0.2 * (X ^ X))] # note: the labels do not show coefficients! expected_labels = ["X", "(X + Y)", "(IZ + ZI + XX)"] for op, label in zip(operators, expected_labels): with self.subTest(op=op, label=label): evo = PauliEvolutionGate(op) self.assertEqual(evo.name, "PauliEvolution") self.assertEqual(evo.label, f"exp(-it {label})")
def test_qdrift_evolution(self): """Test QDrift on an example.""" op = 0.1 * (Z ^ Z) + (X ^ I) + (I ^ X) + 0.2 * (X ^ X) reps = 20 qdrift = PauliEvolutionGate(op, time=0.5 / reps, synthesis=QDrift(reps=reps)).definition exact = scipy.linalg.expm(-0.5j * op.to_matrix()).dot(np.eye(4)[0, :]) def energy(evo): return Statevector(evo).expectation_value(op.to_matrix()) self.assertAlmostEqual(energy(exact), energy(qdrift), places=2)
def test_matrix_decomposition(self): """Test the default decomposition.""" op = (X ^ 3) + (Y ^ 3) + (Z ^ 3) time = 0.123 matrix = op.to_matrix() evolved = scipy.linalg.expm(-1j * time * matrix) evo_gate = PauliEvolutionGate(op, time, synthesis=MatrixExponential()) self.assertTrue(Operator(evo_gate).equiv(evolved))
def generate_evolution_gate(): """Generate a circuit with a pauli evolution gate.""" # Runtime import since this only exists in terra 0.19.0 from qiskit.circuit.library import PauliEvolutionGate from qiskit.synthesis import SuzukiTrotter synthesis = SuzukiTrotter() evo = PauliEvolutionGate([(Z ^ I) + (I ^ Z)] * 5, time=2.0, synthesis=synthesis) qc = QuantumCircuit(2) qc.append(evo, range(2)) return qc
def test_idle_qubit(self): """Test to route on an op that has an idle qubit. The op is :code:`[("IIXX", 1), ("IXIX", 2)]`. The expected circuit is: ..parsed-literal:: ┌─────────────────┐ q_0: ┤0 ├─X──────────────────── │ exp(-it XX)(3) │ │ ┌─────────────────┐ q_1: ┤1 ├─X─┤0 ├ └─────────────────┘ │ exp(-it XX)(6) │ q_2: ──────────────────────┤1 ├ └─────────────────┘ q_3: ───────────────────────────────────────── """ op = PauliSumOp.from_list([("IIXX", 1), ("IXIX", 2)]) cmap = CouplingMap(couplinglist=[(0, 1), (1, 2), (2, 3)]) swap_strat = SwapStrategy(cmap, swap_layers=(((0, 1), ), )) pm_ = PassManager([ FindCommutingPauliEvolutions(), Commuting2qGateRouter(swap_strat) ]) circ = QuantumCircuit(4) circ.append(PauliEvolutionGate(op, 3), range(4)) swapped = pm_.run(circ) expected = QuantumCircuit(4) expected.append(PauliEvolutionGate(Pauli("XX"), 3), (0, 1)) expected.swap(0, 1) expected.append(PauliEvolutionGate(Pauli("XX"), 6), (1, 2)) self.assertEqual(swapped, expected)
def test_enlarge_with_ancilla(self): """This pass tests that idle qubits after an embedding are left idle.""" # Create a four qubit problem. op = PauliSumOp.from_list([("IZZI", 1), ("ZIIZ", 2), ("ZIZI", 3)]) circ = QuantumCircuit(4) circ.append(PauliEvolutionGate(op, 1), range(4)) # Create a four qubit quantum circuit. backend_cmap = CouplingMap(couplinglist=[(0, 1), (1, 2), (1, 3), (3, 4)]) swap_cmap = CouplingMap(couplinglist=[(0, 1), (1, 2), (2, 3)]) swap_strat = SwapStrategy(swap_cmap, swap_layers=(((0, 1), (2, 3)), ((1, 2), ))) initial_layout = Layout.from_intlist([0, 1, 3, 4], *circ.qregs) pm_pre = PassManager([ FindCommutingPauliEvolutions(), Commuting2qGateRouter(swap_strat), SetLayout(initial_layout), FullAncillaAllocation(backend_cmap), EnlargeWithAncilla(), ApplyLayout(), ]) embedded = pm_pre.run(circ) expected = QuantumCircuit(5) expected.append(PauliEvolutionGate(Pauli("ZZ"), 1), (1, 3)) expected.swap(0, 1) expected.swap(3, 4) expected.append(PauliEvolutionGate(Pauli("ZZ"), 2), (1, 3)) expected.swap(1, 3) expected.append(PauliEvolutionGate(Pauli("ZZ"), 3), (0, 1)) self.assertEqual(embedded, expected)
def test_lie_trotter_two_qubit_correct_order(self): """Test that evolutions on two qubit operators are in the right order. Regression test of Qiskit/qiskit-terra#7544. """ operator = I ^ Z ^ Z time = 0.5 exact = scipy.linalg.expm(-1j * time * operator.to_matrix()) lie_trotter = PauliEvolutionGate(operator, time, synthesis=LieTrotter()) self.assertTrue(Operator(lie_trotter).equiv(exact))
def test_basic_xx(self): """Test to route an XX-based evolution op. The op is :code:`[("XXII", -1), ("IIXX", 1), ("XIIX", -2), ("IXIX", 2)]`. The expected circuit is: ..parsed-literal:: ┌────────────────┐ q_0: ─┤0 ├─X───────────────────────────────────────── │ exp(-i XX)(3) │ │ ┌─────────────────┐ q_1: ─┤1 ├─X─┤0 ├─X─────────────────── ┌┴────────────────┤ │ exp(-i XX)(-6) │ │ ┌────────────────┐ q_2: ┤0 ├─X─┤1 ├─X─┤0 ├ │ exp(-i XX)(-3) │ │ └─────────────────┘ │ exp(-i XX)(6) │ q_3: ┤1 ├─X───────────────────────┤1 ├ └─────────────────┘ └────────────────┘ """ op = PauliSumOp.from_list([("XXII", -1), ("IIXX", 1), ("XIIX", -2), ("IXIX", 2)]) circ = QuantumCircuit(4) circ.append(PauliEvolutionGate(op, 3), range(4)) swapped = self.pm_.run(circ) expected = QuantumCircuit(4) expected.append(PauliEvolutionGate(Pauli("XX"), 3), (0, 1)) expected.append(PauliEvolutionGate(Pauli("XX"), -3), (2, 3)) expected.swap(0, 1) expected.swap(2, 3) expected.append(PauliEvolutionGate(Pauli("XX"), -6), (1, 2)) expected.swap(1, 2) expected.append(PauliEvolutionGate(Pauli("XX"), 6), (2, 3)) self.assertEqual(swapped, expected)
def test_rzx_order(self): """Test ZX is mapped onto the correct qubits.""" evo_gate = PauliEvolutionGate(X ^ Z) decomposed = evo_gate.definition.decompose() ref = QuantumCircuit(2) ref.h(1) ref.cx(1, 0) ref.rz(2.0, 0) ref.cx(1, 0) ref.h(1) # don't use circuit equality since RZX here decomposes with RZ on the bottom self.assertTrue(Operator(decomposed).equiv(ref))
def test_qdrift_manual(self, op, time, reps, sampled_ops): """Test the evolution circuit of Suzuki Trotter against a manually constructed circuit.""" qdrift = QDrift(reps=reps) evo_gate = PauliEvolutionGate(op, time, synthesis=qdrift) evo_gate.definition.decompose() # manually construct expected evolution expected = QuantumCircuit(1) for pauli in sampled_ops: if pauli[0].to_label() == "X": expected.rx(2 * pauli[1], 0) elif pauli[0].to_label() == "Y": expected.ry(2 * pauli[1], 0) self.assertTrue(Operator(evo_gate.definition).equiv(expected))
def setUp(self): """Setup useful variables.""" super().setUp() # A fully connected problem. op = PauliSumOp.from_list([("IIZZ", 1), ("IZIZ", 1), ("ZIIZ", 1), ("IZZI", 1), ("ZIZI", 1), ("ZZII", 1)]) self.circ = QuantumCircuit(4) self.circ.append(PauliEvolutionGate(op, 1), range(4)) self.swap_cmap = CouplingMap(couplinglist=[(0, 1), (1, 2), (2, 3)]) # This swap strategy does not reach full connectivity. self.swap_strat = SwapStrategy(self.swap_cmap, swap_layers=(((0, 1), (2, 3)), ))
def test_op_list_evolutiongate(self): """Test loading a circuit with evolution gate works.""" evo = PauliEvolutionGate([(Z ^ I) + (I ^ Z)] * 5, time=0.2, synthesis=None) qc = QuantumCircuit(2) qc.append(evo, range(2)) qpy_file = io.BytesIO() dump(qc, qpy_file) qpy_file.seek(0) new_circ = load(qpy_file)[0] self.assertEqual(qc, new_circ) self.assertEqual([x[0].label for x in qc.data], [x[0].label for x in new_circ.data]) new_evo = new_circ.data[0][0] self.assertIsInstance(new_evo, PauliEvolutionGate)
def test_op_evolution_gate_suzuki_trotter(self): """Test qpy path with a suzuki trotter synthesis method on an evolution gate.""" synthesis = SuzukiTrotter() evo = PauliEvolutionGate((Z ^ I) + (I ^ Z), time=0.2, synthesis=synthesis) qc = QuantumCircuit(2) qc.append(evo, range(2)) qpy_file = io.BytesIO() dump(qc, qpy_file) qpy_file.seek(0) new_circ = load(qpy_file)[0] self.assertEqual(qc, new_circ) self.assertEqual([x[0].label for x in qc.data], [x[0].label for x in new_circ.data]) new_evo = new_circ.data[0][0] self.assertIsInstance(new_evo, PauliEvolutionGate)
def test_dag_conversion(self): """Test constructing a circuit with evolutions yields a DAG with evolution blocks.""" time = Parameter("t") evo = PauliEvolutionGate((Z ^ 2) + (X ^ 2), time=time) circuit = QuantumCircuit(2) circuit.h(circuit.qubits) circuit.append(evo, circuit.qubits) circuit.cx(0, 1) dag = circuit_to_dag(circuit) expected_ops = {"HGate", "CXGate", "PauliEvolutionGate"} ops = set(node.op.__class__.__name__ for node in dag.op_nodes()) self.assertEqual(ops, expected_ops)
def test_evolutiongate_param_vec_time(self): """Test loading a an evolution gate that has a param vector element for time.""" synthesis = LieTrotter(reps=2) time = ParameterVector("TimeVec", 1) evo = PauliEvolutionGate((Z ^ I) + (I ^ Z), time=time[0], synthesis=synthesis) qc = QuantumCircuit(2) qc.append(evo, range(2)) qpy_file = io.BytesIO() dump(qc, qpy_file) qpy_file.seek(0) new_circ = load(qpy_file)[0] self.assertEqual(qc, new_circ) self.assertEqual([x[0].label for x in qc.data], [x[0].label for x in new_circ.data]) new_evo = new_circ.data[0][0] self.assertIsInstance(new_evo, PauliEvolutionGate)
def test_list_from_grouped_paulis(self): """Test getting a string representation from grouped Paulis.""" grouped_ops = [(X ^ Y) + (Y ^ X), (Z ^ I) + (Z ^ Z) + (I ^ Z), (X ^ X)] evo_gate = PauliEvolutionGate(grouped_ops, time=0.12, synthesis=LieTrotter()) pauli_strings = [] for op in evo_gate.operator: if isinstance(op, SparsePauliOp): pauli_strings.append(op.to_list()) else: pauli_strings.append([(str(op), 1 + 0j)]) expected = [ [("XY", 1 + 0j), ("YX", 1 + 0j)], [("ZI", 1 + 0j), ("ZZ", 1 + 0j), ("IZ", 1 + 0j)], [("XX", 1 + 0j)], ] self.assertListEqual(pauli_strings, expected)
def test_evolutiongate(self): """Test loading a circuit with evolution gate works.""" synthesis = LieTrotter(reps=2) evo = PauliEvolutionGate((Z ^ I) + (I ^ Z), time=2, synthesis=synthesis) qc = QuantumCircuit(2) qc.append(evo, range(2)) qpy_file = io.BytesIO() dump(qc, qpy_file) qpy_file.seek(0) new_circ = load(qpy_file)[0] self.assertEqual(qc, new_circ) self.assertEqual([x.operation.label for x in qc.data], [x.operation.label for x in new_circ.data]) new_evo = new_circ.data[0].operation self.assertIsInstance(new_evo, PauliEvolutionGate)