99"""Statevector-based QAOA evaluator tests."""
1010
1111from unittest import TestCase
12+ import numpy as np
1213
14+ from qiskit import transpile
15+ from qiskit .circuit .library import qaoa_ansatz
1316from qiskit .quantum_info import SparsePauliOp
1417from ddt import data , ddt , unpack
1518
19+ from qiskit_aer import Aer
20+
1621from qaoa_training_pipeline .evaluation .statevector_evaluator import StatevectorEvaluator
1722from qaoa_training_pipeline .evaluation .pauli_propagation import PPEvaluator
1823from qaoa_training_pipeline .training .scipy_trainer import ScipyTrainer
@@ -35,6 +40,29 @@ def setUp(self):
3540 pp_kwargs = dict (max_weight = 9 , min_abs_coeff = 1e-5 )
3641 self .evaluator = PPEvaluator (pp_kwargs )
3742 self .sv_evaluator = StatevectorEvaluator ()
43+ self .simulator = Aer .get_backend ("aer_simulator_statevector" )
44+
45+ def qiskit_circuit_simulation (self , cost_op , beta , gamma , circ_op = None ):
46+ """This is the baseline simulation based on Qiskit."""
47+ circ_op = circ_op or cost_op
48+
49+ depth_one_qaoa = qaoa_ansatz (
50+ circ_op ,
51+ reps = 1 ,
52+ ).decompose ()
53+
54+ # Printing parameters gives [ParameterVectorElement(β[0]), ParameterVectorElement(γ[0])]
55+ depth_one_qaoa .assign_parameters ([beta , gamma ], inplace = True )
56+ depth_one_qaoa = transpile (depth_one_qaoa , basis_gates = ["cx" , "sx" , "x" , "rz" ])
57+ depth_one_qaoa .save_statevector ()
58+
59+ res = self .simulator .run (depth_one_qaoa ).result ()
60+ state = res .get_statevector ()
61+
62+ cost_mat = np .diag (cost_op .to_matrix ())
63+
64+ nqubits = cost_op .num_qubits
65+ return np .real (sum (state [i ].conj () * cost_mat [i ] * state [i ] for i in range (2 ** nqubits )))
3866
3967 @data (* TEST_CASES )
4068 @unpack
@@ -72,3 +100,22 @@ def test_from_none_config(self):
72100 evaluator = PPEvaluator .from_config (init_kwargs )
73101
74102 self .assertTrue (isinstance (evaluator , PPEvaluator ))
103+
104+ @data ((1 , 1 ), (0.1234 , - 0.56 ), (0.25 , 0.5 ), (0.5 , 0.25 ))
105+ @unpack
106+ def test_sparse_ansatz (self , beta , gamma ):
107+ """Test the case where the ansatz structure does not match the graph."""
108+
109+ cost_op = SparsePauliOp .from_list ([("IIZZ" , 1.0 ), ("ZZII" , 1.0 ), ("ZIIZ" , 1.0 )])
110+ circ_op = SparsePauliOp .from_list ([("IIZZ" , 1.0 ), ("ZZII" , 1.0 )])
111+
112+ baseline = self .qiskit_circuit_simulation (cost_op , beta , gamma , circ_op )
113+
114+ energy = self .evaluator .evaluate (cost_op , [beta , gamma ], ansatz_circuit = circ_op )
115+ energy2 = self .evaluator .evaluate (cost_op , [beta , gamma ])
116+
117+ # Ensure circuit simulation and efficient depth-one match.
118+ self .assertAlmostEqual (energy , baseline , places = 6 )
119+
120+ # Ensure efficient depth-one gives different results if the circuit structure is omitted.
121+ self .assertTrue (abs (energy2 - energy ) > 0.02 )
0 commit comments