class TestExpectationFactory(QiskitOpflowTestCase): """Tests for the expectation factory.""" @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_aer_simulator_pauli_sum(self): """Test expectation selection with Aer's qasm_simulator.""" backend = Aer.get_backend("aer_simulator") op = 0.2 * (X ^ X) + 0.1 * (Z ^ I) with self.subTest("Defaults"): expectation = ExpectationFactory.build(op, backend, include_custom=False) self.assertIsInstance(expectation, PauliExpectation) with self.subTest("Include custom"): expectation = ExpectationFactory.build(op, backend, include_custom=True) self.assertIsInstance(expectation, AerPauliExpectation)
class TestBlockOperation(BaseTestBlock): """Test fundamental operation on schedule block. Because ScheduleBlock adapts to the lazy scheduling, no uniitest for overlap constraints is necessary. Test scheme becomes simpler than the schedule. Some tests have dependency on schedule conversion. This operation should be tested in `test.python.pulse.test_block.TestTransformation`. """ def setUp(self): super().setUp() self.test_blocks = [ pulse.Play(self.test_waveform0, self.d0), pulse.Play(self.test_waveform1, self.d1), pulse.Delay(50, self.d0), pulse.Play(self.test_waveform1, self.d0), ] def test_append_an_instruction_to_empty_block(self): """Test append instructions to an empty block.""" block = pulse.ScheduleBlock() block = block.append(pulse.Play(self.test_waveform0, self.d0)) self.assertEqual(block.blocks[0], pulse.Play(self.test_waveform0, self.d0)) def test_append_an_instruction_to_empty_block_sugar(self): """Test append instructions to an empty block with syntax sugar.""" block = pulse.ScheduleBlock() block += pulse.Play(self.test_waveform0, self.d0) self.assertEqual(block.blocks[0], pulse.Play(self.test_waveform0, self.d0)) def test_append_an_instruction_to_empty_block_inplace(self): """Test append instructions to an empty block with inplace.""" block = pulse.ScheduleBlock() block.append(pulse.Play(self.test_waveform0, self.d0), inplace=True) self.assertEqual(block.blocks[0], pulse.Play(self.test_waveform0, self.d0)) def test_append_a_block_to_empty_block(self): """Test append another ScheduleBlock to empty block.""" block = pulse.ScheduleBlock() block.append(pulse.Play(self.test_waveform0, self.d0), inplace=True) block_main = pulse.ScheduleBlock() block_main = block_main.append(block) self.assertEqual(block_main.blocks[0], block) def test_append_an_instruction_to_block(self): """Test append instructions to a non-empty block.""" block = pulse.ScheduleBlock() block = block.append(pulse.Delay(100, self.d0)) block = block.append(pulse.Delay(100, self.d0)) self.assertEqual(len(block.blocks), 2) def test_append_an_instruction_to_block_inplace(self): """Test append instructions to a non-empty block with inplace.""" block = pulse.ScheduleBlock() block = block.append(pulse.Delay(100, self.d0)) block.append(pulse.Delay(100, self.d0), inplace=True) self.assertEqual(len(block.blocks), 2) def test_duration(self): """Test if correct duration is returned with implicit scheduling.""" block = pulse.ScheduleBlock() for inst in self.test_blocks: block.append(inst) self.assertEqual(block.duration, 350) def test_channels(self): """Test if all channels are returned.""" block = pulse.ScheduleBlock() for inst in self.test_blocks: block.append(inst) self.assertEqual(len(block.channels), 2) def test_instructions(self): """Test if all instructions are returned.""" block = pulse.ScheduleBlock() for inst in self.test_blocks: block.append(inst) self.assertEqual(block.blocks, tuple(self.test_blocks)) def test_channel_duraction(self): """Test if correct durations is calculated for each channel.""" block = pulse.ScheduleBlock() for inst in self.test_blocks: block.append(inst) self.assertEqual(block.ch_duration(self.d0), 350) self.assertEqual(block.ch_duration(self.d1), 200) def test_cannot_append_schedule(self): """Test schedule cannot be appended. Schedule should be input as Call instruction.""" block = pulse.ScheduleBlock() sched = pulse.Schedule() sched += pulse.Delay(10, self.d0) with self.assertRaises(PulseError): block.append(sched) def test_replace(self): """Test replacing specific instruction.""" block = pulse.ScheduleBlock() for inst in self.test_blocks: block.append(inst) replaced = pulse.Play(pulse.Constant(300, 0.1), self.d1) target = pulse.Delay(50, self.d0) block_replaced = block.replace(target, replaced, inplace=False) # original schedule is not destroyed self.assertListEqual(list(block.blocks), self.test_blocks) ref_sched = pulse.Schedule() ref_sched = ref_sched.insert(0, pulse.Play(self.test_waveform0, self.d0)) ref_sched = ref_sched.insert(0, pulse.Play(self.test_waveform1, self.d1)) ref_sched = ref_sched.insert(200, replaced) ref_sched = ref_sched.insert(100, pulse.Play(self.test_waveform1, self.d0)) self.assertScheduleEqual(block_replaced, ref_sched) def test_replace_inplace(self): """Test replacing specific instruction with inplace.""" block = pulse.ScheduleBlock() for inst in self.test_blocks: block.append(inst) replaced = pulse.Play(pulse.Constant(300, 0.1), self.d1) target = pulse.Delay(50, self.d0) block.replace(target, replaced, inplace=True) ref_sched = pulse.Schedule() ref_sched = ref_sched.insert(0, pulse.Play(self.test_waveform0, self.d0)) ref_sched = ref_sched.insert(0, pulse.Play(self.test_waveform1, self.d1)) ref_sched = ref_sched.insert(200, replaced) ref_sched = ref_sched.insert(100, pulse.Play(self.test_waveform1, self.d0)) self.assertScheduleEqual(block, ref_sched) def test_replace_block_by_instruction(self): """Test replacing block with instruction.""" sub_block1 = pulse.ScheduleBlock() sub_block1 = sub_block1.append(pulse.Delay(50, self.d0)) sub_block1 = sub_block1.append(pulse.Play(self.test_waveform0, self.d0)) sub_block2 = pulse.ScheduleBlock() sub_block2 = sub_block2.append(pulse.Delay(50, self.d0)) sub_block2 = sub_block2.append(pulse.Play(self.test_waveform1, self.d1)) main_block = pulse.ScheduleBlock() main_block = main_block.append(pulse.Delay(50, self.d0)) main_block = main_block.append(pulse.Play(self.test_waveform0, self.d0)) main_block = main_block.append(sub_block1) main_block = main_block.append(sub_block2) main_block = main_block.append(pulse.Play(self.test_waveform0, self.d1)) replaced = main_block.replace(sub_block1, pulse.Delay(100, self.d0)) ref_blocks = [ pulse.Delay(50, self.d0), pulse.Play(self.test_waveform0, self.d0), pulse.Delay(100, self.d0), sub_block2, pulse.Play(self.test_waveform0, self.d1), ] self.assertListEqual(list(replaced.blocks), ref_blocks) def test_replace_instruction_by_block(self): """Test replacing instruction with block.""" sub_block1 = pulse.ScheduleBlock() sub_block1 = sub_block1.append(pulse.Delay(50, self.d0)) sub_block1 = sub_block1.append(pulse.Play(self.test_waveform0, self.d0)) sub_block2 = pulse.ScheduleBlock() sub_block2 = sub_block2.append(pulse.Delay(50, self.d0)) sub_block2 = sub_block2.append(pulse.Play(self.test_waveform1, self.d1)) main_block = pulse.ScheduleBlock() main_block = main_block.append(pulse.Delay(50, self.d0)) main_block = main_block.append(pulse.Play(self.test_waveform0, self.d0)) main_block = main_block.append(pulse.Delay(100, self.d0)) main_block = main_block.append(sub_block2) main_block = main_block.append(pulse.Play(self.test_waveform0, self.d1)) replaced = main_block.replace(pulse.Delay(100, self.d0), sub_block1) ref_blocks = [ pulse.Delay(50, self.d0), pulse.Play(self.test_waveform0, self.d0), sub_block1, sub_block2, pulse.Play(self.test_waveform0, self.d1), ] self.assertListEqual(list(replaced.blocks), ref_blocks) def test_len(self): """Test __len__ method""" block = pulse.ScheduleBlock() self.assertEqual(len(block), 0) for j in range(1, 10): block = block.append(pulse.Delay(10, self.d0)) self.assertEqual(len(block), j) def test_inherit_from(self): """Test creating schedule with another schedule.""" ref_metadata = {"test": "value"} ref_name = "test" base_sched = pulse.ScheduleBlock(name=ref_name, metadata=ref_metadata) new_sched = pulse.ScheduleBlock.initialize_from(base_sched) self.assertEqual(new_sched.name, ref_name) self.assertDictEqual(new_sched.metadata, ref_metadata) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_execute_block(self): """Test executing a ScheduleBlock on a Pulse backend""" with pulse.build(name="test_block") as sched_block: pulse.play(pulse.Constant(160, 1.0), pulse.DriveChannel(0)) pulse.acquire(50, pulse.MeasureChannel(0), pulse.MemorySlot(0)) backend = FakeArmonk() test_result = backend.run(sched_block).result() self.assertDictEqual(test_result.get_counts(), {"0": 1024})
class TestVQE(QiskitAlgorithmsTestCase): """Test VQE""" def setUp(self): super().setUp() self.seed = 50 algorithm_globals.random_seed = self.seed self.h2_op = (-1.052373245772859 * (I ^ I) + 0.39793742484318045 * (I ^ Z) - 0.39793742484318045 * (Z ^ I) - 0.01128010425623538 * (Z ^ Z) + 0.18093119978423156 * (X ^ X)) self.h2_energy = -1.85727503 self.ryrz_wavefunction = TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz") self.ry_wavefunction = TwoLocal(rotation_blocks="ry", entanglement_blocks="cz") self.qasm_simulator = QuantumInstance( BasicAer.get_backend("qasm_simulator"), shots=1024, seed_simulator=self.seed, seed_transpiler=self.seed, ) self.statevector_simulator = QuantumInstance( BasicAer.get_backend("statevector_simulator"), shots=1, seed_simulator=self.seed, seed_transpiler=self.seed, ) def test_basic_aer_statevector(self): """Test the VQE on BasicAer's statevector simulator.""" wavefunction = self.ryrz_wavefunction vqe = VQE( ansatz=wavefunction, optimizer=L_BFGS_B(), quantum_instance=QuantumInstance( BasicAer.get_backend("statevector_simulator"), basis_gates=["u1", "u2", "u3", "cx", "id"], coupling_map=[[0, 1]], seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ), ) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) with self.subTest(msg="test eigenvalue"): self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy) with self.subTest(msg="test dimension of optimal point"): self.assertEqual(len(result.optimal_point), 16) with self.subTest(msg="assert cost_function_evals is set"): self.assertIsNotNone(result.cost_function_evals) with self.subTest(msg="assert optimizer_time is set"): self.assertIsNotNone(result.optimizer_time) def test_circuit_input(self): """Test running the VQE on a plain QuantumCircuit object.""" wavefunction = QuantumCircuit(2).compose(EfficientSU2(2)) optimizer = SLSQP(maxiter=50) vqe = VQE(ansatz=wavefunction, optimizer=optimizer, quantum_instance=self.statevector_simulator) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=5) @data( (MatrixExpectation(), 1), (AerPauliExpectation(), 1), (PauliExpectation(), 2), ) @unpack def test_construct_circuit(self, expectation, num_circuits): """Test construct circuits returns QuantumCircuits and the right number of them.""" try: wavefunction = EfficientSU2(2, reps=1) vqe = VQE(ansatz=wavefunction, expectation=expectation) params = [0] * wavefunction.num_parameters circuits = vqe.construct_circuit(parameter=params, operator=self.h2_op) self.assertEqual(len(circuits), num_circuits) for circuit in circuits: self.assertIsInstance(circuit, QuantumCircuit) except MissingOptionalLibraryError as ex: self.skipTest(str(ex)) return def test_missing_varform_params(self): """Test specifying a variational form with no parameters raises an error.""" circuit = QuantumCircuit(self.h2_op.num_qubits) vqe = VQE( ansatz=circuit, quantum_instance=BasicAer.get_backend("statevector_simulator")) with self.assertRaises(RuntimeError): vqe.compute_minimum_eigenvalue(operator=self.h2_op) @data( (SLSQP(maxiter=50), 5, 4), (SPSA(maxiter=150), 2, 2), # max_evals_grouped=n or =2 if n>2 ) @unpack def test_max_evals_grouped(self, optimizer, places, max_evals_grouped): """VQE Optimizers test""" vqe = VQE( ansatz=self.ryrz_wavefunction, optimizer=optimizer, max_evals_grouped=max_evals_grouped, quantum_instance=self.statevector_simulator, ) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=places) def test_basic_aer_qasm(self): """Test the VQE on BasicAer's QASM simulator.""" optimizer = SPSA(maxiter=300, last_avg=5) wavefunction = self.ry_wavefunction vqe = VQE( ansatz=wavefunction, optimizer=optimizer, max_evals_grouped=1, quantum_instance=self.qasm_simulator, ) # TODO benchmark this later. result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, -1.86823, places=2) def test_qasm_eigenvector_normalized(self): """Test VQE with qasm_simulator returns normalized eigenvector.""" wavefunction = self.ry_wavefunction vqe = VQE(ansatz=wavefunction, quantum_instance=self.qasm_simulator) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) amplitudes = list(result.eigenstate.values()) self.assertAlmostEqual(np.linalg.norm(amplitudes), 1.0, places=4) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_with_aer_statevector(self): """Test VQE with Aer's statevector_simulator.""" backend = Aer.get_backend("aer_simulator_statevector") wavefunction = self.ry_wavefunction optimizer = L_BFGS_B() quantum_instance = QuantumInstance( backend, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ) vqe = VQE( ansatz=wavefunction, optimizer=optimizer, max_evals_grouped=1, quantum_instance=quantum_instance, ) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_with_aer_qasm(self): """Test VQE with Aer's qasm_simulator.""" backend = Aer.get_backend("aer_simulator") optimizer = SPSA(maxiter=200, last_avg=5) wavefunction = self.ry_wavefunction quantum_instance = QuantumInstance( backend, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ) vqe = VQE( ansatz=wavefunction, optimizer=optimizer, expectation=PauliExpectation(), quantum_instance=quantum_instance, ) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, -1.86305, places=2) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_with_aer_qasm_snapshot_mode(self): """Test the VQE using Aer's qasm_simulator snapshot mode.""" backend = Aer.get_backend("aer_simulator") optimizer = L_BFGS_B() wavefunction = self.ry_wavefunction quantum_instance = QuantumInstance( backend, shots=1, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ) vqe = VQE( ansatz=wavefunction, optimizer=optimizer, expectation=AerPauliExpectation(), quantum_instance=quantum_instance, ) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") @data( CG(maxiter=1), L_BFGS_B(maxfun=1), P_BFGS(maxfun=1, max_processes=0), SLSQP(maxiter=1), TNC(maxiter=1), ) def test_with_gradient(self, optimizer): """Test VQE using Gradient().""" quantum_instance = QuantumInstance( backend=Aer.get_backend("qasm_simulator"), shots=1, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ) vqe = VQE( ansatz=self.ry_wavefunction, optimizer=optimizer, gradient=Gradient(), expectation=AerPauliExpectation(), quantum_instance=quantum_instance, max_evals_grouped=1000, ) vqe.compute_minimum_eigenvalue(operator=self.h2_op) def test_with_two_qubit_reduction(self): """Test the VQE using TwoQubitReduction.""" qubit_op = PauliSumOp.from_list([ ("IIII", -0.8105479805373266), ("IIIZ", 0.17218393261915552), ("IIZZ", -0.22575349222402472), ("IZZI", 0.1721839326191556), ("ZZII", -0.22575349222402466), ("IIZI", 0.1209126326177663), ("IZZZ", 0.16892753870087912), ("IXZX", -0.045232799946057854), ("ZXIX", 0.045232799946057854), ("IXIX", 0.045232799946057854), ("ZXZX", -0.045232799946057854), ("ZZIZ", 0.16614543256382414), ("IZIZ", 0.16614543256382414), ("ZZZZ", 0.17464343068300453), ("ZIZI", 0.1209126326177663), ]) tapered_qubit_op = TwoQubitReduction(num_particles=2).convert(qubit_op) for simulator in [self.qasm_simulator, self.statevector_simulator]: with self.subTest(f"Test for {simulator}."): vqe = VQE( self.ry_wavefunction, SPSA(maxiter=300, last_avg=5), quantum_instance=simulator, ) result = vqe.compute_minimum_eigenvalue(tapered_qubit_op) energy = -1.868 if simulator == self.qasm_simulator else self.h2_energy self.assertAlmostEqual(result.eigenvalue.real, energy, places=2) def test_callback(self): """Test the callback on VQE.""" history = {"eval_count": [], "parameters": [], "mean": [], "std": []} def store_intermediate_result(eval_count, parameters, mean, std): history["eval_count"].append(eval_count) history["parameters"].append(parameters) history["mean"].append(mean) history["std"].append(std) optimizer = COBYLA(maxiter=3) wavefunction = self.ry_wavefunction vqe = VQE( ansatz=wavefunction, optimizer=optimizer, callback=store_intermediate_result, quantum_instance=self.qasm_simulator, ) vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertTrue( all(isinstance(count, int) for count in history["eval_count"])) self.assertTrue( all(isinstance(mean, float) for mean in history["mean"])) self.assertTrue(all(isinstance(std, float) for std in history["std"])) for params in history["parameters"]: self.assertTrue(all(isinstance(param, float) for param in params)) def test_reuse(self): """Test re-using a VQE algorithm instance.""" vqe = VQE() with self.subTest(msg="assert running empty raises AlgorithmError"): with self.assertRaises(AlgorithmError): _ = vqe.compute_minimum_eigenvalue(operator=self.h2_op) ansatz = TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz") vqe.ansatz = ansatz with self.subTest(msg="assert missing operator raises AlgorithmError"): with self.assertRaises(AlgorithmError): _ = vqe.compute_minimum_eigenvalue(operator=self.h2_op) vqe.expectation = MatrixExpectation() vqe.quantum_instance = self.statevector_simulator with self.subTest(msg="assert VQE works once all info is available"): result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=5) operator = PrimitiveOp( np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, 2, 0], [0, 0, 0, 3]])) with self.subTest(msg="assert minimum eigensolver interface works"): result = vqe.compute_minimum_eigenvalue(operator=operator) self.assertAlmostEqual(result.eigenvalue.real, -1.0, places=5) def test_vqe_optimizer(self): """Test running same VQE twice to re-use optimizer, then switch optimizer""" vqe = VQE( optimizer=SLSQP(), quantum_instance=QuantumInstance( BasicAer.get_backend("statevector_simulator")), ) def run_check(): result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, -1.85727503, places=5) run_check() with self.subTest("Optimizer re-use"): run_check() with self.subTest("Optimizer replace"): vqe.optimizer = L_BFGS_B() run_check() @data(MatrixExpectation(), None) def test_backend_change(self, user_expectation): """Test that VQE works when backend changes.""" vqe = VQE( ansatz=TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz"), optimizer=SLSQP(maxiter=2), expectation=user_expectation, quantum_instance=BasicAer.get_backend("statevector_simulator"), ) result0 = vqe.compute_minimum_eigenvalue(operator=self.h2_op) if user_expectation is not None: with self.subTest("User expectation kept."): self.assertEqual(vqe.expectation, user_expectation) vqe.quantum_instance = BasicAer.get_backend("qasm_simulator") # works also if no expectation is set, since it will be determined automatically result1 = vqe.compute_minimum_eigenvalue(operator=self.h2_op) if user_expectation is not None: with self.subTest( "Change backend with user expectation, it is kept."): self.assertEqual(vqe.expectation, user_expectation) with self.subTest("Check results."): self.assertEqual(len(result0.optimal_point), len(result1.optimal_point)) def test_batch_evaluate_with_qnspsa(self): """Test batch evaluating with QNSPSA works.""" ansatz = TwoLocal(2, rotation_blocks=["ry", "rz"], entanglement_blocks="cz") wrapped_backend = BasicAer.get_backend("qasm_simulator") inner_backend = BasicAer.get_backend("statevector_simulator") callcount = {"count": 0} def wrapped_run(circuits, **kwargs): kwargs["callcount"]["count"] += 1 return inner_backend.run(circuits) wrapped_backend.run = partial(wrapped_run, callcount=callcount) fidelity = QNSPSA.get_fidelity(ansatz, backend=wrapped_backend) qnspsa = QNSPSA(fidelity, maxiter=5) vqe = VQE( ansatz=ansatz, optimizer=qnspsa, max_evals_grouped=100, quantum_instance=wrapped_backend, ) _ = vqe.compute_minimum_eigenvalue(Z ^ Z) # 1 calibration + 1 stddev estimation + 1 initial blocking # + 5 (1 loss + 1 fidelity + 1 blocking) + 1 return loss + 1 VQE eval expected = 1 + 1 + 1 + 5 * 3 + 1 + 1 self.assertEqual(callcount["count"], expected) def test_set_ansatz_to_none(self): """Tests that setting the ansatz to None results in the default behavior""" vqe = VQE( ansatz=self.ryrz_wavefunction, optimizer=L_BFGS_B(), quantum_instance=self.statevector_simulator, ) vqe.ansatz = None self.assertIsInstance(vqe.ansatz, RealAmplitudes) def test_set_optimizer_to_none(self): """Tests that setting the optimizer to None results in the default behavior""" vqe = VQE( ansatz=self.ryrz_wavefunction, optimizer=L_BFGS_B(), quantum_instance=self.statevector_simulator, ) vqe.optimizer = None self.assertIsInstance(vqe.optimizer, SLSQP) def test_optimizer_scipy_callable(self): """Test passing a SciPy optimizer directly as callable.""" vqe = VQE( optimizer=partial(scipy_minimize, method="L-BFGS-B", options={"maxiter": 2}), quantum_instance=self.statevector_simulator, ) result = vqe.compute_minimum_eigenvalue(Z) self.assertEqual(result.cost_function_evals, 20) def test_optimizer_callable(self): """Test passing a optimizer directly as callable.""" ansatz = RealAmplitudes(1, reps=1) vqe = VQE(ansatz=ansatz, optimizer=_mock_optimizer, quantum_instance=self.statevector_simulator) result = vqe.compute_minimum_eigenvalue(Z) self.assertTrue( np.all(result.optimal_point == np.zeros(ansatz.num_parameters))) def test_aux_operators_list(self): """Test list-based aux_operators.""" wavefunction = self.ry_wavefunction vqe = VQE(ansatz=wavefunction, quantum_instance=self.statevector_simulator) # Start with an empty list result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=[]) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) self.assertIsNone(result.aux_operator_eigenvalues) # Go again with two auxiliary operators aux_op1 = PauliSumOp.from_list([("II", 2.0)]) aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)]) aux_ops = [aux_op1, aux_op2] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) self.assertEqual(len(result.aux_operator_eigenvalues), 2) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0, places=6) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0) # Go again with additional None and zero operators extra_ops = [*aux_ops, None, 0] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=extra_ops) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) self.assertEqual(len(result.aux_operator_eigenvalues), 4) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0, places=6) self.assertEqual(result.aux_operator_eigenvalues[2][0], 0.0) self.assertEqual(result.aux_operator_eigenvalues[3][0], 0.0) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[2][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[3][1], 0.0) def test_aux_operators_dict(self): """Test dictionary compatibility of aux_operators""" wavefunction = self.ry_wavefunction vqe = VQE(ansatz=wavefunction, quantum_instance=self.statevector_simulator) # Start with an empty dictionary result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators={}) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) self.assertIsNone(result.aux_operator_eigenvalues) # Go again with two auxiliary operators aux_op1 = PauliSumOp.from_list([("II", 2.0)]) aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)]) aux_ops = {"aux_op1": aux_op1, "aux_op2": aux_op2} result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) self.assertEqual(len(result.aux_operator_eigenvalues), 2) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][0], 2, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][0], 0, places=6) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][1], 0.0) # Go again with additional None and zero operators extra_ops = {**aux_ops, "None_operator": None, "zero_operator": 0} result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=extra_ops) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) self.assertEqual(len(result.aux_operator_eigenvalues), 3) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][0], 2, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][0], 0, places=6) self.assertEqual(result.aux_operator_eigenvalues["zero_operator"][0], 0.0) self.assertTrue( "None_operator" not in result.aux_operator_eigenvalues.keys()) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op1"][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues["aux_op2"][1], 0.0) self.assertAlmostEqual( result.aux_operator_eigenvalues["zero_operator"][1], 0.0) def test_aux_operator_std_dev_pauli(self): """Test non-zero standard deviations of aux operators with PauliExpectation.""" wavefunction = self.ry_wavefunction vqe = VQE( ansatz=wavefunction, expectation=PauliExpectation(), optimizer=COBYLA(maxiter=0), quantum_instance=self.qasm_simulator, ) # Go again with two auxiliary operators aux_op1 = PauliSumOp.from_list([("II", 2.0)]) aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)]) aux_ops = [aux_op1, aux_op2] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) self.assertEqual(len(result.aux_operator_eigenvalues), 2) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2.0, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0.6796875, places=6) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.02534712219145965, places=6) # Go again with additional None and zero operators aux_ops = [*aux_ops, None, 0] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) self.assertEqual(len(result.aux_operator_eigenvalues), 4) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2.0, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0.57421875, places=6) self.assertEqual(result.aux_operator_eigenvalues[2][0], 0.0) self.assertEqual(result.aux_operator_eigenvalues[3][0], 0.0) # # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.026562146577166837, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues[2][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[3][1], 0.0) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_aux_operator_std_dev_aer_pauli(self): """Test non-zero standard deviations of aux operators with AerPauliExpectation.""" wavefunction = self.ry_wavefunction vqe = VQE( ansatz=wavefunction, expectation=AerPauliExpectation(), optimizer=COBYLA(maxiter=0), quantum_instance=QuantumInstance( backend=Aer.get_backend("qasm_simulator"), shots=1, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ), ) # Go again with two auxiliary operators aux_op1 = PauliSumOp.from_list([("II", 2.0)]) aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)]) aux_ops = [aux_op1, aux_op2] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) self.assertEqual(len(result.aux_operator_eigenvalues), 2) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2.0, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0.6698863565455391, places=6) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0, places=6) # Go again with additional None and zero operators aux_ops = [*aux_ops, None, 0] result = vqe.compute_minimum_eigenvalue(self.h2_op, aux_operators=aux_ops) self.assertEqual(len(result.aux_operator_eigenvalues), 4) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0], 2.0, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][0], 0.6036400943063891, places=6) self.assertEqual(result.aux_operator_eigenvalues[2][0], 0.0) self.assertEqual(result.aux_operator_eigenvalues[3][0], 0.0) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[1][1], 0.0, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues[2][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[3][1], 0.0) def test_2step_transpile(self): """Test the two-step transpiler pass.""" # count how often the pass for parameterized circuits is called pre_counter = LogPass("pre_passmanager") pre_pass = PassManager(pre_counter) config = PassManagerConfig(basis_gates=["u3", "cx"]) pre_pass += level_1_pass_manager(config) # ... and the pass for bound circuits bound_counter = LogPass("bound_pass_manager") bound_pass = PassManager(bound_counter) quantum_instance = QuantumInstance( backend=BasicAer.get_backend("statevector_simulator"), basis_gates=["u3", "cx"], pass_manager=pre_pass, bound_pass_manager=bound_pass, ) optimizer = SPSA(maxiter=5, learning_rate=0.01, perturbation=0.01) vqe = VQE(optimizer=optimizer, quantum_instance=quantum_instance) _ = vqe.compute_minimum_eigenvalue(Z) with self.assertLogs(logger, level="INFO") as cm: _ = vqe.compute_minimum_eigenvalue(Z) expected = [ "pre_passmanager", "bound_pass_manager", "bound_pass_manager", "bound_pass_manager", "bound_pass_manager", "bound_pass_manager", "bound_pass_manager", "bound_pass_manager", "bound_pass_manager", "bound_pass_manager", "bound_pass_manager", "bound_pass_manager", "pre_passmanager", "bound_pass_manager", ] self.assertEqual([record.message for record in cm.records], expected) def test_construct_eigenstate_from_optpoint(self): """Test constructing the eigenstate from the optimal point, if the default ansatz is used.""" # use Hamiltonian yielding more than 11 parameters in the default ansatz hamiltonian = Z ^ Z ^ Z optimizer = SPSA(maxiter=1, learning_rate=0.01, perturbation=0.01) quantum_instance = QuantumInstance( backend=BasicAer.get_backend("statevector_simulator"), basis_gates=["u3", "cx"]) vqe = VQE(optimizer=optimizer, quantum_instance=quantum_instance) result = vqe.compute_minimum_eigenvalue(hamiltonian) optimal_circuit = vqe.ansatz.bind_parameters(result.optimal_point) self.assertTrue(Statevector(result.eigenstate).equiv(optimal_circuit))
Gradient, I, MatrixExpectation, PauliExpectation, PauliSumOp, PrimitiveOp, TwoQubitReduction, X, Z, ) from qiskit.quantum_info import Statevector from qiskit.transpiler import PassManager, PassManagerConfig from qiskit.transpiler.preset_passmanagers import level_1_pass_manager from qiskit.utils import QuantumInstance, algorithm_globals, has_aer if has_aer(): from qiskit import Aer logger = "LocalLogger" class LogPass(DummyAP): """A dummy analysis pass that logs when executed""" def __init__(self, message): super().__init__() self.message = message def run(self, dag): logging.getLogger(logger).info(self.message)
class TestVQE(QiskitAlgorithmsTestCase): """Test VQE""" def setUp(self): super().setUp() self.seed = 50 algorithm_globals.random_seed = self.seed self.h2_op = (-1.052373245772859 * (I ^ I) + 0.39793742484318045 * (I ^ Z) - 0.39793742484318045 * (Z ^ I) - 0.01128010425623538 * (Z ^ Z) + 0.18093119978423156 * (X ^ X)) self.h2_energy = -1.85727503 self.ryrz_wavefunction = TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz") self.ry_wavefunction = TwoLocal(rotation_blocks="ry", entanglement_blocks="cz") self.qasm_simulator = QuantumInstance( BasicAer.get_backend("qasm_simulator"), shots=1024, seed_simulator=self.seed, seed_transpiler=self.seed, ) self.statevector_simulator = QuantumInstance( BasicAer.get_backend("statevector_simulator"), shots=1, seed_simulator=self.seed, seed_transpiler=self.seed, ) def test_basic_aer_statevector(self): """Test the VQE on BasicAer's statevector simulator.""" wavefunction = self.ryrz_wavefunction vqe = VQE( ansatz=wavefunction, optimizer=L_BFGS_B(), quantum_instance=QuantumInstance( BasicAer.get_backend("statevector_simulator"), basis_gates=["u1", "u2", "u3", "cx", "id"], coupling_map=[[0, 1]], seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ), ) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) with self.subTest(msg="test eigenvalue"): self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy) with self.subTest(msg="test dimension of optimal point"): self.assertEqual(len(result.optimal_point), 16) with self.subTest(msg="assert cost_function_evals is set"): self.assertIsNotNone(result.cost_function_evals) with self.subTest(msg="assert optimizer_time is set"): self.assertIsNotNone(result.optimizer_time) def test_circuit_input(self): """Test running the VQE on a plain QuantumCircuit object.""" wavefunction = QuantumCircuit(2).compose(EfficientSU2(2)) optimizer = SLSQP(maxiter=50) vqe = VQE(ansatz=wavefunction, optimizer=optimizer, quantum_instance=self.statevector_simulator) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=5) @data( (MatrixExpectation(), 1), (AerPauliExpectation(), 1), (PauliExpectation(), 2), ) @unpack def test_construct_circuit(self, expectation, num_circuits): """Test construct circuits returns QuantumCircuits and the right number of them.""" try: wavefunction = EfficientSU2(2, reps=1) vqe = VQE(ansatz=wavefunction, expectation=expectation) params = [0] * wavefunction.num_parameters circuits = vqe.construct_circuit(parameter=params, operator=self.h2_op) self.assertEqual(len(circuits), num_circuits) for circuit in circuits: self.assertIsInstance(circuit, QuantumCircuit) except MissingOptionalLibraryError as ex: self.skipTest(str(ex)) return def test_missing_varform_params(self): """Test specifying a variational form with no parameters raises an error.""" circuit = QuantumCircuit(self.h2_op.num_qubits) vqe = VQE( ansatz=circuit, quantum_instance=BasicAer.get_backend("statevector_simulator")) with self.assertRaises(RuntimeError): vqe.compute_minimum_eigenvalue(operator=self.h2_op) @data( (SLSQP(maxiter=50), 5, 4), (SPSA(maxiter=150), 3, 2), # max_evals_grouped=n or =2 if n>2 ) @unpack def test_max_evals_grouped(self, optimizer, places, max_evals_grouped): """VQE Optimizers test""" with self.assertWarns(DeprecationWarning): vqe = VQE( ansatz=self.ryrz_wavefunction, optimizer=optimizer, max_evals_grouped=max_evals_grouped, quantum_instance=self.statevector_simulator, sort_parameters_by_name=True, ) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=places) def test_basic_aer_qasm(self): """Test the VQE on BasicAer's QASM simulator.""" optimizer = SPSA(maxiter=300, last_avg=5) wavefunction = self.ry_wavefunction vqe = VQE( ansatz=wavefunction, optimizer=optimizer, max_evals_grouped=1, quantum_instance=self.qasm_simulator, ) # TODO benchmark this later. result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, -1.86823, places=2) def test_qasm_aux_operators_normalized(self): """Test VQE with qasm_simulator returns normalized aux_operator eigenvalues.""" wavefunction = self.ry_wavefunction vqe = VQE(ansatz=wavefunction, quantum_instance=self.qasm_simulator) _ = vqe.compute_minimum_eigenvalue(operator=self.h2_op) opt_params = [ 3.50437328, 3.87415376, 0.93684363, 5.92219622, -1.53527887, 1.87941418, -4.5708326, 0.70187027, ] vqe._ret.optimal_point = opt_params vqe._ret.optimal_parameters = dict( zip(sorted(wavefunction.parameters, key=lambda p: p.name), opt_params)) with self.assertWarns(DeprecationWarning): optimal_vector = vqe.get_optimal_vector() self.assertAlmostEqual(sum(v**2 for v in optimal_vector.values()), 1.0, places=4) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_with_aer_statevector(self): """Test VQE with Aer's statevector_simulator.""" backend = Aer.get_backend("aer_simulator_statevector") wavefunction = self.ry_wavefunction optimizer = L_BFGS_B() quantum_instance = QuantumInstance( backend, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ) vqe = VQE( ansatz=wavefunction, optimizer=optimizer, max_evals_grouped=1, quantum_instance=quantum_instance, ) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_with_aer_qasm(self): """Test VQE with Aer's qasm_simulator.""" backend = Aer.get_backend("aer_simulator") optimizer = SPSA(maxiter=200, last_avg=5) wavefunction = self.ry_wavefunction quantum_instance = QuantumInstance( backend, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ) vqe = VQE( ansatz=wavefunction, optimizer=optimizer, expectation=PauliExpectation(), quantum_instance=quantum_instance, ) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, -1.86305, places=2) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_with_aer_qasm_snapshot_mode(self): """Test the VQE using Aer's qasm_simulator snapshot mode.""" backend = Aer.get_backend("aer_simulator") optimizer = L_BFGS_B() wavefunction = self.ry_wavefunction quantum_instance = QuantumInstance( backend, shots=1, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ) vqe = VQE( ansatz=wavefunction, optimizer=optimizer, expectation=AerPauliExpectation(), quantum_instance=quantum_instance, ) result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=6) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") @data( CG(maxiter=1), L_BFGS_B(maxfun=1), P_BFGS(maxfun=1, max_processes=0), SLSQP(maxiter=1), TNC(maxiter=1), ) def test_with_gradient(self, optimizer): """Test VQE using Gradient().""" quantum_instance = QuantumInstance( backend=Aer.get_backend("qasm_simulator"), shots=1, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ) vqe = VQE( ansatz=self.ry_wavefunction, optimizer=optimizer, gradient=Gradient(), expectation=AerPauliExpectation(), quantum_instance=quantum_instance, max_evals_grouped=1000, ) vqe.compute_minimum_eigenvalue(operator=self.h2_op) def test_with_two_qubit_reduction(self): """Test the VQE using TwoQubitReduction.""" qubit_op = PauliSumOp.from_list([ ("IIII", -0.8105479805373266), ("IIIZ", 0.17218393261915552), ("IIZZ", -0.22575349222402472), ("IZZI", 0.1721839326191556), ("ZZII", -0.22575349222402466), ("IIZI", 0.1209126326177663), ("IZZZ", 0.16892753870087912), ("IXZX", -0.045232799946057854), ("ZXIX", 0.045232799946057854), ("IXIX", 0.045232799946057854), ("ZXZX", -0.045232799946057854), ("ZZIZ", 0.16614543256382414), ("IZIZ", 0.16614543256382414), ("ZZZZ", 0.17464343068300453), ("ZIZI", 0.1209126326177663), ]) tapered_qubit_op = TwoQubitReduction(num_particles=2).convert(qubit_op) for simulator in [self.qasm_simulator, self.statevector_simulator]: with self.subTest(f"Test for {simulator}."): vqe = VQE( self.ry_wavefunction, SPSA(maxiter=300, last_avg=5), quantum_instance=simulator, ) result = vqe.compute_minimum_eigenvalue(tapered_qubit_op) energy = -1.868 if simulator == self.qasm_simulator else self.h2_energy self.assertAlmostEqual(result.eigenvalue.real, energy, places=2) def test_callback(self): """Test the callback on VQE.""" history = {"eval_count": [], "parameters": [], "mean": [], "std": []} def store_intermediate_result(eval_count, parameters, mean, std): history["eval_count"].append(eval_count) history["parameters"].append(parameters) history["mean"].append(mean) history["std"].append(std) optimizer = COBYLA(maxiter=3) wavefunction = self.ry_wavefunction vqe = VQE( ansatz=wavefunction, optimizer=optimizer, callback=store_intermediate_result, quantum_instance=self.qasm_simulator, ) vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertTrue( all(isinstance(count, int) for count in history["eval_count"])) self.assertTrue( all(isinstance(mean, float) for mean in history["mean"])) self.assertTrue(all(isinstance(std, float) for std in history["std"])) for params in history["parameters"]: self.assertTrue(all(isinstance(param, float) for param in params)) def test_reuse(self): """Test re-using a VQE algorithm instance.""" vqe = VQE() with self.subTest(msg="assert running empty raises AlgorithmError"): with self.assertRaises(AlgorithmError): _ = vqe.compute_minimum_eigenvalue(operator=self.h2_op) ansatz = TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz") vqe.ansatz = ansatz with self.subTest(msg="assert missing operator raises AlgorithmError"): with self.assertRaises(AlgorithmError): _ = vqe.compute_minimum_eigenvalue(operator=self.h2_op) vqe.expectation = MatrixExpectation() vqe.quantum_instance = self.statevector_simulator with self.subTest(msg="assert VQE works once all info is available"): result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, self.h2_energy, places=5) operator = PrimitiveOp( np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, 2, 0], [0, 0, 0, 3]])) with self.subTest(msg="assert minimum eigensolver interface works"): result = vqe.compute_minimum_eigenvalue(operator=operator) self.assertAlmostEqual(result.eigenvalue.real, -1.0, places=5) def test_vqe_optimizer(self): """Test running same VQE twice to re-use optimizer, then switch optimizer""" vqe = VQE( optimizer=SLSQP(), quantum_instance=QuantumInstance( BasicAer.get_backend("statevector_simulator")), ) def run_check(): result = vqe.compute_minimum_eigenvalue(operator=self.h2_op) self.assertAlmostEqual(result.eigenvalue.real, -1.85727503, places=5) run_check() with self.subTest("Optimizer re-use"): run_check() with self.subTest("Optimizer replace"): vqe.optimizer = L_BFGS_B() run_check() @data(MatrixExpectation(), None) def test_backend_change(self, user_expectation): """Test that VQE works when backend changes.""" vqe = VQE( ansatz=TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz"), optimizer=SLSQP(maxiter=2), expectation=user_expectation, quantum_instance=BasicAer.get_backend("statevector_simulator"), ) result0 = vqe.compute_minimum_eigenvalue(operator=self.h2_op) if user_expectation is not None: with self.subTest("User expectation kept."): self.assertEqual(vqe.expectation, user_expectation) vqe.quantum_instance = BasicAer.get_backend("qasm_simulator") # works also if no expectation is set, since it will be determined automatically result1 = vqe.compute_minimum_eigenvalue(operator=self.h2_op) if user_expectation is not None: with self.subTest( "Change backend with user expectation, it is kept."): self.assertEqual(vqe.expectation, user_expectation) with self.subTest("Check results."): self.assertEqual(len(result0.optimal_point), len(result1.optimal_point)) def test_batch_evaluate_with_qnspsa(self): """Test batch evaluating with QNSPSA works.""" ansatz = TwoLocal(2, rotation_blocks=["ry", "rz"], entanglement_blocks="cz") wrapped_backend = BasicAer.get_backend("qasm_simulator") inner_backend = BasicAer.get_backend("statevector_simulator") callcount = {"count": 0} def wrapped_run(circuits, **kwargs): kwargs["callcount"]["count"] += 1 return inner_backend.run(circuits) wrapped_backend.run = partial(wrapped_run, callcount=callcount) fidelity = QNSPSA.get_fidelity(ansatz, backend=wrapped_backend) qnspsa = QNSPSA(fidelity, maxiter=5) vqe = VQE( ansatz=ansatz, optimizer=qnspsa, max_evals_grouped=100, quantum_instance=wrapped_backend, ) _ = vqe.compute_minimum_eigenvalue(Z ^ Z) # 1 calibration + 1 stddev estimation + 1 initial blocking # + 5 (1 loss + 1 fidelity + 1 blocking) + 1 return loss + 1 VQE eval expected = 1 + 1 + 1 + 5 * 3 + 1 + 1 self.assertEqual(callcount["count"], expected)
class TestVQD(QiskitAlgorithmsTestCase): """Test VQD""" def setUp(self): super().setUp() self.seed = 50 algorithm_globals.random_seed = self.seed self.h2_op = (-1.052373245772859 * (I ^ I) + 0.39793742484318045 * (I ^ Z) - 0.39793742484318045 * (Z ^ I) - 0.01128010425623538 * (Z ^ Z) + 0.18093119978423156 * (X ^ X)) self.h2_energy = -1.85727503 self.h2_energy_excited = [-1.85727503, -1.24458455] self.test_op = MatrixOp(np.diagflat([3, 5, -1, 0.8, 0.2, 2, 1, -3])).to_pauli_op() self.test_results = [-3, -1] self.ryrz_wavefunction = TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz", reps=1) self.ry_wavefunction = TwoLocal(rotation_blocks="ry", entanglement_blocks="cz") self.qasm_simulator = QuantumInstance( BasicAer.get_backend("qasm_simulator"), shots=2048, seed_simulator=self.seed, seed_transpiler=self.seed, ) self.statevector_simulator = QuantumInstance( BasicAer.get_backend("statevector_simulator"), shots=1, seed_simulator=self.seed, seed_transpiler=self.seed, ) def test_basic_aer_statevector(self): """Test the VQD on BasicAer's statevector simulator.""" wavefunction = self.ryrz_wavefunction vqd = VQD( k=2, ansatz=wavefunction, optimizer=COBYLA(), quantum_instance=QuantumInstance( BasicAer.get_backend("statevector_simulator"), basis_gates=["u1", "u2", "u3", "cx", "id"], coupling_map=[[0, 1]], seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ), ) result = vqd.compute_eigenvalues(operator=self.h2_op) with self.subTest(msg="test eigenvalue"): np.testing.assert_array_almost_equal(result.eigenvalues.real, self.h2_energy_excited, decimal=1) with self.subTest(msg="test dimension of optimal point"): self.assertEqual(len(result.optimal_point[-1]), 8) with self.subTest(msg="assert cost_function_evals is set"): self.assertIsNotNone(result.cost_function_evals) with self.subTest(msg="assert optimizer_time is set"): self.assertIsNotNone(result.optimizer_time) def test_mismatching_num_qubits(self): """Ensuring circuit and operator mismatch is caught""" wavefunction = QuantumCircuit(1) optimizer = SLSQP(maxiter=50) vqd = VQD( k=1, ansatz=wavefunction, optimizer=optimizer, quantum_instance=self.statevector_simulator, ) with self.assertRaises(AlgorithmError): _ = vqd.compute_eigenvalues(operator=self.h2_op) @data( (MatrixExpectation(), 1), (AerPauliExpectation(), 1), (PauliExpectation(), 2), ) @unpack def test_construct_circuit(self, expectation, num_circuits): """Test construct circuits returns QuantumCircuits and the right number of them.""" try: wavefunction = EfficientSU2(2, reps=1) vqd = VQD(k=2, ansatz=wavefunction, expectation=expectation) params = [0] * wavefunction.num_parameters circuits = vqd.construct_circuit(parameter=params, operator=self.h2_op) self.assertEqual(len(circuits), num_circuits) for circuit in circuits: self.assertIsInstance(circuit, QuantumCircuit) except MissingOptionalLibraryError as ex: self.skipTest(str(ex)) return def test_missing_varform_params(self): """Test specifying a variational form with no parameters raises an error.""" circuit = QuantumCircuit(self.h2_op.num_qubits) vqd = VQD( k=1, ansatz=circuit, quantum_instance=BasicAer.get_backend("statevector_simulator")) with self.assertRaises(RuntimeError): vqd.compute_eigenvalues(operator=self.h2_op) def test_basic_aer_qasm(self): """Test the VQD on BasicAer's QASM simulator.""" optimizer = COBYLA(maxiter=1000) wavefunction = self.ry_wavefunction vqd = VQD( ansatz=wavefunction, optimizer=optimizer, max_evals_grouped=1, quantum_instance=self.qasm_simulator, ) # TODO benchmark this later. result = vqd.compute_eigenvalues(operator=self.h2_op) np.testing.assert_array_almost_equal(result.eigenvalues.real, self.h2_energy_excited, decimal=1) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_with_aer_statevector(self): """Test VQD with Aer's statevector_simulator.""" backend = Aer.get_backend("aer_simulator_statevector") wavefunction = self.ry_wavefunction optimizer = L_BFGS_B() quantum_instance = QuantumInstance( backend, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ) vqd = VQD( k=2, ansatz=wavefunction, optimizer=optimizer, max_evals_grouped=1, quantum_instance=quantum_instance, ) result = vqd.compute_eigenvalues(operator=self.h2_op) np.testing.assert_array_almost_equal(result.eigenvalues.real, self.h2_energy_excited, decimal=2) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_with_aer_qasm(self): """Test VQD with Aer's qasm_simulator.""" backend = Aer.get_backend("aer_simulator") optimizer = COBYLA(maxiter=1000) wavefunction = self.ry_wavefunction quantum_instance = QuantumInstance( backend, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ) vqd = VQD( k=2, ansatz=wavefunction, optimizer=optimizer, expectation=PauliExpectation(), quantum_instance=quantum_instance, ) result = vqd.compute_eigenvalues(operator=self.h2_op) np.testing.assert_array_almost_equal(result.eigenvalues.real, self.h2_energy_excited, decimal=1) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_with_aer_qasm_snapshot_mode(self): """Test the VQD using Aer's qasm_simulator snapshot mode.""" backend = Aer.get_backend("aer_simulator") optimizer = COBYLA(maxiter=400) wavefunction = self.ryrz_wavefunction quantum_instance = QuantumInstance( backend, shots=100, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ) vqd = VQD( k=2, ansatz=wavefunction, optimizer=optimizer, expectation=AerPauliExpectation(), quantum_instance=quantum_instance, ) result = vqd.compute_eigenvalues(operator=self.test_op) np.testing.assert_array_almost_equal(result.eigenvalues.real, self.test_results, decimal=1) def test_callback(self): """Test the callback on VQD.""" history = {"eval_count": [], "parameters": [], "mean": [], "std": []} def store_intermediate_result(eval_count, parameters, mean, std): history["eval_count"].append(eval_count) history["parameters"].append(parameters) history["mean"].append(mean) history["std"].append(std) optimizer = COBYLA(maxiter=3) wavefunction = self.ry_wavefunction vqd = VQD( ansatz=wavefunction, optimizer=optimizer, callback=store_intermediate_result, quantum_instance=self.qasm_simulator, ) vqd.compute_eigenvalues(operator=self.h2_op) self.assertTrue( all(isinstance(count, int) for count in history["eval_count"])) self.assertTrue( all(isinstance(mean, float) for mean in history["mean"])) self.assertTrue(all(isinstance(std, float) for std in history["std"])) for params in history["parameters"]: self.assertTrue(all(isinstance(param, float) for param in params)) def test_reuse(self): """Test re-using a VQD algorithm instance.""" vqd = VQD(k=1) with self.subTest(msg="assert running empty raises AlgorithmError"): with self.assertRaises(AlgorithmError): _ = vqd.compute_eigenvalues(operator=self.h2_op) ansatz = TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz") vqd.ansatz = ansatz with self.subTest(msg="assert missing operator raises AlgorithmError"): with self.assertRaises(AlgorithmError): _ = vqd.compute_eigenvalues(operator=self.h2_op) vqd.expectation = MatrixExpectation() vqd.quantum_instance = self.statevector_simulator with self.subTest(msg="assert VQE works once all info is available"): result = vqd.compute_eigenvalues(operator=self.h2_op) np.testing.assert_array_almost_equal(result.eigenvalues.real, self.h2_energy, decimal=2) operator = PrimitiveOp( np.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, 2, 0], [0, 0, 0, 3]])) with self.subTest(msg="assert minimum eigensolver interface works"): result = vqd.compute_eigenvalues(operator=operator) self.assertAlmostEqual(result.eigenvalues.real[0], -1.0, places=5) def test_vqd_optimizer(self): """Test running same VQD twice to re-use optimizer, then switch optimizer""" vqd = VQD( k=2, optimizer=SLSQP(), quantum_instance=QuantumInstance( BasicAer.get_backend("statevector_simulator")), ) def run_check(): result = vqd.compute_eigenvalues(operator=self.h2_op) np.testing.assert_array_almost_equal(result.eigenvalues.real, self.h2_energy_excited, decimal=3) run_check() with self.subTest("Optimizer re-use"): run_check() with self.subTest("Optimizer replace"): vqd.optimizer = L_BFGS_B() run_check() @data(MatrixExpectation(), None) def test_backend_change(self, user_expectation): """Test that VQE works when backend changes.""" vqd = VQD( k=1, ansatz=TwoLocal(rotation_blocks=["ry", "rz"], entanglement_blocks="cz"), optimizer=SLSQP(maxiter=2), expectation=user_expectation, quantum_instance=BasicAer.get_backend("statevector_simulator"), ) result0 = vqd.compute_eigenvalues(operator=self.h2_op) if user_expectation is not None: with self.subTest("User expectation kept."): self.assertEqual(vqd.expectation, user_expectation) vqd.quantum_instance = BasicAer.get_backend("qasm_simulator") # works also if no expectation is set, since it will be determined automatically result1 = vqd.compute_eigenvalues(operator=self.h2_op) if user_expectation is not None: with self.subTest( "Change backend with user expectation, it is kept."): self.assertEqual(vqd.expectation, user_expectation) with self.subTest("Check results."): self.assertEqual(len(result0.optimal_point), len(result1.optimal_point)) def test_set_ansatz_to_none(self): """Tests that setting the ansatz to None results in the default behavior""" vqd = VQD( k=1, ansatz=self.ryrz_wavefunction, optimizer=L_BFGS_B(), quantum_instance=self.statevector_simulator, ) vqd.ansatz = None self.assertIsInstance(vqd.ansatz, RealAmplitudes) def test_set_optimizer_to_none(self): """Tests that setting the optimizer to None results in the default behavior""" vqd = VQD( k=1, ansatz=self.ryrz_wavefunction, optimizer=L_BFGS_B(), quantum_instance=self.statevector_simulator, ) vqd.optimizer = None self.assertIsInstance(vqd.optimizer, SLSQP) def test_aux_operators_list(self): """Test list-based aux_operators.""" wavefunction = self.ry_wavefunction vqd = VQD(k=2, ansatz=wavefunction, quantum_instance=self.statevector_simulator) # Start with an empty list result = vqd.compute_eigenvalues(self.h2_op, aux_operators=[]) np.testing.assert_array_almost_equal(result.eigenvalues.real, self.h2_energy_excited, decimal=2) self.assertIsNone(result.aux_operator_eigenvalues) # Go again with two auxiliary operators aux_op1 = PauliSumOp.from_list([("II", 2.0)]) aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)]) aux_ops = [aux_op1, aux_op2] result = vqd.compute_eigenvalues(self.h2_op, aux_operators=aux_ops) np.testing.assert_array_almost_equal(result.eigenvalues.real, self.h2_energy_excited, decimal=2) self.assertEqual(len(result.aux_operator_eigenvalues), 2) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][0], 2, places=2) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][0], 0, places=2) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][1], 0.0) # Go again with additional None and zero operators extra_ops = [*aux_ops, None, 0] result = vqd.compute_eigenvalues(self.h2_op, aux_operators=extra_ops) np.testing.assert_array_almost_equal(result.eigenvalues.real, self.h2_energy_excited, decimal=2) self.assertEqual(len(result.aux_operator_eigenvalues), 2) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][0], 2, places=2) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][0], 0, places=2) self.assertEqual(result.aux_operator_eigenvalues[0][2][0], 0.0) self.assertEqual(result.aux_operator_eigenvalues[0][3][0], 0.0) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][1], 0.0) self.assertEqual(result.aux_operator_eigenvalues[0][3][1], 0.0) def test_aux_operators_dict(self): """Test dictionary compatibility of aux_operators""" wavefunction = self.ry_wavefunction vqd = VQD(ansatz=wavefunction, quantum_instance=self.statevector_simulator) # Start with an empty dictionary result = vqd.compute_eigenvalues(self.h2_op, aux_operators={}) np.testing.assert_array_almost_equal(result.eigenvalues.real, self.h2_energy_excited, decimal=2) self.assertIsNone(result.aux_operator_eigenvalues) # Go again with two auxiliary operators aux_op1 = PauliSumOp.from_list([("II", 2.0)]) aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)]) aux_ops = {"aux_op1": aux_op1, "aux_op2": aux_op2} result = vqd.compute_eigenvalues(self.h2_op, aux_operators=aux_ops) self.assertEqual(len(result.eigenvalues), 2) self.assertEqual(len(result.eigenstates), 2) self.assertEqual(result.eigenvalues.dtype, np.complex128) self.assertAlmostEqual(result.eigenvalues[0], -1.85727503) self.assertEqual(len(result.aux_operator_eigenvalues), 2) self.assertEqual(len(result.aux_operator_eigenvalues[0]), 2) # expectation values self.assertAlmostEqual( result.aux_operator_eigenvalues[0]["aux_op1"][0], 2, places=6) self.assertAlmostEqual( result.aux_operator_eigenvalues[0]["aux_op2"][0], 0, places=1) # standard deviations self.assertAlmostEqual( result.aux_operator_eigenvalues[0]["aux_op1"][1], 0.0) self.assertAlmostEqual( result.aux_operator_eigenvalues[0]["aux_op2"][1], 0.0) # Go again with additional None and zero operators extra_ops = {**aux_ops, "None_operator": None, "zero_operator": 0} result = vqd.compute_eigenvalues(self.h2_op, aux_operators=extra_ops) self.assertEqual(len(result.eigenvalues), 2) self.assertEqual(len(result.eigenstates), 2) self.assertEqual(result.eigenvalues.dtype, np.complex128) self.assertAlmostEqual(result.eigenvalues[0], -1.85727503) self.assertEqual(len(result.aux_operator_eigenvalues), 2) self.assertEqual(len(result.aux_operator_eigenvalues[0]), 3) # expectation values self.assertAlmostEqual( result.aux_operator_eigenvalues[0]["aux_op1"][0], 2, places=6) self.assertAlmostEqual( result.aux_operator_eigenvalues[0]["aux_op2"][0], 0, places=6) self.assertEqual( result.aux_operator_eigenvalues[0]["zero_operator"][0], 0.0) self.assertTrue( "None_operator" not in result.aux_operator_eigenvalues[0].keys()) # standard deviations self.assertAlmostEqual( result.aux_operator_eigenvalues[0]["aux_op1"][1], 0.0) self.assertAlmostEqual( result.aux_operator_eigenvalues[0]["aux_op2"][1], 0.0) self.assertAlmostEqual( result.aux_operator_eigenvalues[0]["zero_operator"][1], 0.0) def test_aux_operator_std_dev_pauli(self): """Test non-zero standard deviations of aux operators with PauliExpectation.""" wavefunction = self.ry_wavefunction vqd = VQD( ansatz=wavefunction, expectation=PauliExpectation(), initial_point=[ 1.70256666, -5.34843975, -0.39542903, 5.99477786, -2.74374986, -4.85284669, 0.2442925, -1.51638917, ], optimizer=COBYLA(maxiter=0), quantum_instance=self.qasm_simulator, ) # Go again with two auxiliary operators aux_op1 = PauliSumOp.from_list([("II", 2.0)]) aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)]) aux_ops = [aux_op1, aux_op2] result = vqd.compute_eigenvalues(self.h2_op, aux_operators=aux_ops) self.assertEqual(len(result.aux_operator_eigenvalues), 2) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][0], 2.0, places=1) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][0], 0.0019531249999999445, places=1) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][1], 0.015183867579396111, places=1) # Go again with additional None and zero operators aux_ops = [*aux_ops, None, 0] result = vqd.compute_eigenvalues(self.h2_op, aux_operators=aux_ops) self.assertEqual(len(result.aux_operator_eigenvalues[0]), 4) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][0], 2.0, places=1) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][0], 0.0019531249999999445, places=1) self.assertEqual(result.aux_operator_eigenvalues[0][2][0], 0.0) self.assertEqual(result.aux_operator_eigenvalues[0][3][0], 0.0) # # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][1], 0.01548658094658011, places=1) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][2][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][3][1], 0.0) @unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.") def test_aux_operator_std_dev_aer_pauli(self): """Test non-zero standard deviations of aux operators with AerPauliExpectation.""" wavefunction = self.ry_wavefunction vqd = VQD( ansatz=wavefunction, expectation=AerPauliExpectation(), optimizer=COBYLA(maxiter=0), quantum_instance=QuantumInstance( backend=Aer.get_backend("qasm_simulator"), shots=1, seed_simulator=algorithm_globals.random_seed, seed_transpiler=algorithm_globals.random_seed, ), ) # Go again with two auxiliary operators aux_op1 = PauliSumOp.from_list([("II", 2.0)]) aux_op2 = PauliSumOp.from_list([("II", 0.5), ("ZZ", 0.5), ("YY", 0.5), ("XX", -0.5)]) aux_ops = [aux_op1, aux_op2] result = vqd.compute_eigenvalues(self.h2_op, aux_operators=aux_ops) self.assertEqual(len(result.aux_operator_eigenvalues), 2) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][0], 2.0, places=1) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][0], 0.6698863565455391, places=1) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][1], 0.0, places=6) # Go again with additional None and zero operators aux_ops = [*aux_ops, None, 0] result = vqd.compute_eigenvalues(self.h2_op, aux_operators=aux_ops) self.assertEqual(len(result.aux_operator_eigenvalues[-1]), 4) # expectation values self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][0], 2.0, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][0], 0.6036400943063891, places=6) self.assertEqual(result.aux_operator_eigenvalues[0][2][0], 0.0) self.assertEqual(result.aux_operator_eigenvalues[0][3][0], 0.0) # standard deviations self.assertAlmostEqual(result.aux_operator_eigenvalues[0][0][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][1][1], 0.0, places=6) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][2][1], 0.0) self.assertAlmostEqual(result.aux_operator_eigenvalues[0][3][1], 0.0)