232232# Step 4: Setup localized TFIM from Hamiltonian
233233
234234def estimate_local_parameters (qubit_hamiltonian , n_qubits ):
235- """
236- Estimate (z, J, h) per qubit from Hamiltonian.
237- z: number of ZZ neighbors
238- J: average ZZ coefficient
239- h: average X coefficient
240- """
241235 z = np .zeros (n_qubits , dtype = int )
242236 J = np .zeros (n_qubits )
243237 h = np .zeros (n_qubits )
@@ -247,48 +241,41 @@ def estimate_local_parameters(qubit_hamiltonian, n_qubits):
247241 q , pauli = term [0 ]
248242 if pauli == "X" :
249243 h [q ] += np .abs (coeff )
244+ elif pauli == "Y" :
245+ h [q ] += 0.5 * np .abs (coeff )
250246 elif len (term ) == 2 :
251247 (q1 , p1 ), (q2 , p2 ) = term
252- if {p1 , p2 } = = {"Z" }:
248+ if {p1 , p2 } < = {"Z" }:
253249 J [q1 ] += np .abs (coeff ) / 2
254250 J [q2 ] += np .abs (coeff ) / 2
255251 z [q1 ] += 1
256252 z [q2 ] += 1
253+ else :
254+ h [q1 ] += 0.25 * np .abs (coeff )
255+ h [q2 ] += 0.25 * np .abs (coeff )
257256 return z , J , h
258257
259258def tfim_ground_state_angles (n_qubits , J_vec , h_vec , z_vec , t = 10.0 ):
260- """
261- Generate RY angles based on TFIM magnetization estimates.
262- """
263259 ry_angles = np .zeros (n_qubits )
264260 for i in range (n_qubits ):
265261 m = tfim_magnetization (J = J_vec [i ], h = h_vec [i ], z = z_vec [i ], theta = np .random .rand () * np .pi , t = t , n_qubits = 1 )
266262 p = np .clip ((1.0 - m ) / 2.0 , 1e-6 , 1 - 1e-6 )
267263 ry_angles [i ] = 2.0 * np .arcsin (np .sqrt (p ))
268264 return ry_angles
269265
270- def build_ansatz (angles , wires ):
271- for i , angle in enumerate (angles ):
272- qml .RY (angle , wires = wires [i ])
273- for i in range (len (wires ) - 1 ):
274- qml .CNOT (wires = [wires [i ], wires [i + 1 ]])
275-
276- def tfim_energy_estimate (qubit_hamiltonian , n_qubits , dev = None ):
266+ def hybrid_tfim_vqe (qubit_hamiltonian , n_qubits , dev = None , layers = 1 ):
277267 """
278268 Estimate energy from TFIM-predicted RY angles.
279269 """
280270 z , J , h = estimate_local_parameters (qubit_hamiltonian , n_qubits )
281271 angles = tfim_ground_state_angles (n_qubits , J , h , z )
272+ weights_shape = {"weights" : (layers , n_qubits , 3 )}
282273
283274 if dev is None :
284275 dev = qml .device ("default.qubit" , wires = n_qubits )
285276
286- # Step 4: Extract Qubit Terms for PennyLane
287277 coeffs = []
288278 observables = []
289- n_qubits = molecule .n_qubits # Auto-detect qubit count
290- print (str (n_qubits ) + " qubits..." )
291-
292279 for term , coefficient in qubit_hamiltonian .terms .items ():
293280 pauli_operators = []
294281 for qubit_idx , pauli in term :
@@ -310,14 +297,20 @@ def tfim_energy_estimate(qubit_hamiltonian, n_qubits, dev=None):
310297 hamiltonian = qml .Hamiltonian (coeffs , observables )
311298
312299 @qml .qnode (dev )
313- def circuit ():
314- build_ansatz (angles , wires = range (n_qubits ))
300+ def circuit (weights ):
301+ for i , angle in enumerate (angles ):
302+ qml .RY (angle , wires = i )
303+ qml .StronglyEntanglingLayers (weights , wires = range (n_qubits ))
315304 return qml .expval (hamiltonian )
316305
317- return circuit ()
306+ return circuit , weights_shape
318307
319308# Step 5: Setup Qrack simulator and calculate energy expectation value
320309dev = qml .device ("qrack.simulator" , wires = n_qubits )
321- energy = tfim_energy_estimate (qubit_hamiltonian , n_qubits , dev )
310+ circuit , weights_shape = hybrid_tfim_vqe (qubit_hamiltonian , n_qubits )
311+ weights = np .random .randn (* weights_shape ["weights" ])
322312
323- print (f"Optimized Ground State Energy: { energy } Ha" )
313+ opt = qml .AdamOptimizer (stepsize = 0.1 )
314+ for i in range (100 ):
315+ weights = opt .step (lambda w : circuit (w ), weights )
316+ print (f"Step { i } : Energy = { circuit (weights )} " )
0 commit comments