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_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 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_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_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 __init__( self, ansatz: QuantumCircuit, initial_parameters: np.ndarray, expectation: ExpectationBase, optimizer: Optional[Union[Optimizer, Minimizer]] = None, num_timesteps: Optional[int] = None, evolution: Optional[EvolutionSynthesis] = None, use_parameter_shift: bool = True, initial_guess: Optional[np.ndarray] = None, quantum_instance: Optional[Union[Backend, QuantumInstance]] = None, ) -> None: """ Args: ansatz: A parameterized circuit preparing the variational ansatz to model the time evolved quantum state. initial_parameters: The initial parameters for the ansatz. Together with the ansatz, these define the initial state of the time evolution. expectation: The expectation converter to evaluate expectation values. optimizer: The classical optimizers used to minimize the overlap between Trotterization and ansatz. Can be either a :class:`.Optimizer` or a callable using the :class:`.Minimizer` protocol. This argument is optional since it is not required for :meth:`get_loss`, but it has to be set before :meth:`evolve` is called. num_timestep: The number of time steps. If ``None`` it will be set such that the timestep is close to 0.01. evolution: The evolution synthesis to use for the construction of the Trotter step. Defaults to first-order Lie-Trotter decomposition, see also :mod:`~qiskit.synthesis.evolution` for different options. use_parameter_shift: If True, use the parameter shift rule to compute gradients. If False, the optimizer will not be passed a gradient callable. In that case, Qiskit optimizers will use a finite difference rule to approximate the gradients. initial_guess: The initial guess for the first VQE optimization. Afterwards the previous iteration result is used as initial guess. If None, this is set to a random vector with elements in the interval :math:`[-0.01, 0.01]`. quantum_instance: The backend or quantum instance used to evaluate the circuits. """ if evolution is None: evolution = LieTrotter() self.ansatz = ansatz self.initial_parameters = initial_parameters self.num_timesteps = num_timesteps self.optimizer = optimizer self.initial_guess = initial_guess self.expectation = expectation self.evolution = evolution self.use_parameter_shift = use_parameter_shift self._sampler = None self.quantum_instance = quantum_instance
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[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_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_param_expr_time(self): """Test loading a circuit with an evolution gate that has a parameter for time.""" synthesis = LieTrotter(reps=2) time = Parameter("t") evo = PauliEvolutionGate((Z ^ I) + (I ^ Z), time=time * time, 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)
def __init__( self, operator, time: Union[int, float, ParameterExpression] = 1.0, label: Optional[str] = None, synthesis: Optional[EvolutionSynthesis] = None, ) -> None: """ Args: operator (Pauli | PauliOp | SparsePauliOp | PauliSumOp | list): The operator to evolve. Can also be provided as list of non-commuting operators where the elements are sums of commuting operators. For example: ``[XY + YX, ZZ + ZI + IZ, YY]``. time: The evolution time. label: A label for the gate to display in visualizations. Per default, the label is set to ``exp(-it <operators>)`` where ``<operators>`` is the sum of the Paulis. Note that the label does not include any coefficients of the Paulis. See the class docstring for an example. synthesis: A synthesis strategy. If None, the default synthesis is the Lie-Trotter product formula with a single repetition. """ if isinstance(operator, list): operator = [_to_sparse_pauli_op(op) for op in operator] else: operator = _to_sparse_pauli_op(operator) if synthesis is None: synthesis = LieTrotter() if label is None: label = _get_default_label(operator) num_qubits = operator[0].num_qubits if isinstance( operator, list) else operator.num_qubits super().__init__(name="PauliEvolution", num_qubits=num_qubits, params=[time], label=label) self.operator = operator self.synthesis = synthesis
def __init__( self, product_formula: Optional[ProductFormula] = None, expectation: Optional[ExpectationBase] = None, quantum_instance: Optional[Union[QuantumInstance, Backend]] = None, ) -> None: """ Args: product_formula: A Lie-Trotter-Suzuki product formula. The default is the Lie-Trotter first order product formula with a single repetition. expectation: An instance of ExpectationBase which defines a method for calculating expectation values of EvolutionProblem.aux_operators. quantum_instance: A quantum instance used for calculating expectation values of EvolutionProblem.aux_operators. """ if product_formula is None: product_formula = LieTrotter() self._product_formula = product_formula self._quantum_instance = None self._circuit_sampler = None if quantum_instance is not None: self.quantum_instance = quantum_instance self._expectation = expectation
def __init__( self, operator, time: Union[int, float, ParameterExpression] = 1.0, label: Optional[str] = None, synthesis: Optional[EvolutionSynthesis] = None, ) -> None: """ Args: operator (Pauli | PauliOp | SparsePauliOp | PauliSumOp | list): The operator to evolve. Can also be provided as list of non-commuting operators where the elements are sums of commuting operators. For example: ``[XY + YX, ZZ + ZI + IZ, YY]``. time: The evolution time. label: A label for the gate to display in visualizations. synthesis: A synthesis strategy. If None, the default synthesis is the Lie-Trotter product formula with a single repetition. """ if isinstance(operator, list): operator = [_to_sparse_pauli_op(op) for op in operator] name = f"exp(-i {[' + '.join(op.paulis.to_labels()) for op in operator]})" else: operator = _to_sparse_pauli_op(operator) name = f"exp(-i {' + '.join(operator.paulis.to_labels())})" if synthesis is None: synthesis = LieTrotter() num_qubits = operator[0].num_qubits if isinstance( operator, list) else operator.num_qubits super().__init__(name=name, num_qubits=num_qubits, params=[time], label=label) self.operator = operator self.synthesis = synthesis
def test_pauliop_coefficients_respected(self): """Test that global ``PauliOp`` coefficients are being taken care of.""" evo = PauliEvolutionGate(5 * (Z ^ I), time=1, synthesis=LieTrotter()) circuit = evo.definition.decompose() rz_angle = circuit.data[0][0].params[0] self.assertEqual(rz_angle, 10)
def _get_evolution_synthesis(self): """Return the ``EvolutionSynthesis`` corresponding to this Trotterization.""" if self.trotter.order == 1: return LieTrotter(reps=self.trotter.reps) return SuzukiTrotter(reps=self.trotter.reps, order=self.trotter.order)