|
| 1 | + |
| 2 | +Variational Quantum Eigensolver (VQE) Implementation (3 Qubits) |
| 3 | + |
| 4 | + |
| 5 | +The Variational Quantum Eigensolver (VQE) is a hybrid quantum-classical algorithm that approximates the ground-state energy of a Hamiltonian by preparing a parameterized quantum state (ansatz) and minimizing the expectation value ⟨ψ(θ)|H|ψ(θ)⟩ . We represent a system of 3 qubits as an 8-dimensional complex statevector (since n qubits span a 2^n-dimensional Hilbert space ). In code we build a random 8×8 Hermitian matrix H = (A + A†)/2 (so that its eigenvalues are real) and use the initial state |000⟩ = [1,0,…,0]. |
| 6 | + |
| 7 | + |
| 8 | +Variational Ansatz (RY + CNOT) |
| 9 | + |
| 10 | + |
| 11 | +We manually construct a variational ansatz with layers of single-qubit Ry rotations and CNOT entangling gates. Single-qubit rotations plus CNOT form a universal gate set , meaning any state can in principle be prepared with such gates. Concretely, we use two layers of Ry(θ) on each qubit, with CNOTs connecting qubit 0→1 and qubit 1→2 between layers. In simulation, each gate is represented by a matrix acting on the statevector . For example, the Ry(θ) gate has matrix |
| 12 | +Ry(θ) = [[cos(θ/2), -sin(θ/2)], |
| 13 | + [sin(θ/2), cos(θ/2)]] |
| 14 | +and the CNOT flips the target qubit when the control is |1⟩. We apply these gates by constructing the appropriate multi-qubit operator (via tensor products or index manipulation) and multiplying it with the statevector . The ansatz thus has 6 parameters (three angles per layer). |
| 15 | + |
| 16 | + |
| 17 | +Energy Expectation and Optimization |
| 18 | + |
| 19 | + |
| 20 | +For a given parameter vector θ, we prepare the state ψ(θ) by applying the ansatz gates to |000⟩. We compute the energy expectation as |
| 21 | +E(θ) = ⟨ψ(θ)| H |ψ(θ)⟩ = ψ(θ)† · (H ψ(θ)) |
| 22 | +(which returns a real number since H is Hermitian). We then use SciPy’s COBYLA optimizer to minimize E over the parameters . A callback function records the energy at each iteration, so we can track convergence. COBYLA is a suitable choice here (as in many VQE examples ), though any gradient-free optimizer could be used. |
| 23 | + |
| 24 | + |
| 25 | +Results and Convergence |
| 26 | + |
| 27 | + |
| 28 | +The optimization yields an estimate of the ground-state energy. We record the energy at each iteration and plot it to check convergence. For illustration, a typical VQE convergence curve (energy vs. iteration) is shown below: |
| 29 | + |
| 30 | +Figure: Example VQE energy convergence (energy expectation ⟨ψ|H|ψ⟩ vs. iteration) during optimization. |
| 31 | + |
| 32 | +Finally, a text summary of the ansatz circuit is printed. For example: |
| 33 | +Ansatz circuit (text form): |
| 34 | + Layer 1: RY(θ0) on qubit 0, RY(θ1) on qubit 1, RY(θ2) on qubit 2 |
| 35 | + CNOT(0→1), CNOT(1→2) |
| 36 | + Layer 2: RY(θ3) on qubit 0, RY(θ4) on qubit 1, RY(θ5) on qubit 2 |
| 37 | + CNOT(0→1), CNOT(1→2) |
| 38 | +Below is a complete Python implementation. It is modular and documented with comments for clarity. |
| 39 | +import numpy as np |
| 40 | +from scipy.optimize import minimize |
| 41 | + |
| 42 | +# --- Generate a random Hermitian Hamiltonian (8x8) --- |
| 43 | +np.random.seed(0) |
| 44 | +A = np.random.randn(8,8) + 1j*np.random.randn(8,8) |
| 45 | +H = (A + A.conj().T) / 2 # Hermitian Hamiltonian |
| 46 | + |
| 47 | +# --- Define single-qubit and two-qubit gates --- |
| 48 | +def ry(theta): |
| 49 | + """2x2 rotation around Y by angle theta.""" |
| 50 | + return np.array([[np.cos(theta/2), -np.sin(theta/2)], |
| 51 | + [np.sin(theta/2), np.cos(theta/2)]], dtype=complex) |
| 52 | + |
| 53 | +def apply_single_qubit_gate(state, gate, target, n_qubits=3): |
| 54 | + """Apply a single-qubit gate to 'target' qubit of the statevector.""" |
| 55 | + # Build full operator as tensor product of identities and the gate |
| 56 | + op = 1 |
| 57 | + for q in range(n_qubits): |
| 58 | + op = np.kron(op, gate if q==target else np.eye(2)) |
| 59 | + return op.dot(state) |
| 60 | + |
| 61 | +def apply_cnot(state, control, target, n_qubits=3): |
| 62 | + """Apply a CNOT gate with given control and target on the statevector.""" |
| 63 | + new_state = np.zeros_like(state) |
| 64 | + for idx, amp in enumerate(state): |
| 65 | + bits = list(map(int, format(idx, f'0{n_qubits}b'))) |
| 66 | + # If control qubit is |1>, flip the target bit |
| 67 | + if bits[control] == 1: |
| 68 | + bits[target] ^= 1 |
| 69 | + new_idx = int("".join(str(b) for b in bits), 2) |
| 70 | + new_state[new_idx] += amp |
| 71 | + return new_state |
| 72 | + |
| 73 | +# --- Ansatz state preparation --- |
| 74 | +def prepare_state(params): |
| 75 | + """ |
| 76 | + Prepare the 3-qubit statevector from parameters. |
| 77 | + Ansatz: 2 layers of Ry + chain of CNOTs. |
| 78 | + params: list or array of length 6 [θ0,...,θ5]. |
| 79 | + """ |
| 80 | + # Start in |000> |
| 81 | + state = np.zeros(8, dtype=complex) |
| 82 | + state[0] = 1.0 |
| 83 | + |
| 84 | + # Layer 1: RY on each qubit 0,1,2 |
| 85 | + for q in range(3): |
| 86 | + state = apply_single_qubit_gate(state, ry(params[q]), q) |
| 87 | + # Entangling CNOTs |
| 88 | + state = apply_cnot(state, control=0, target=1) |
| 89 | + state = apply_cnot(state, control=1, target=2) |
| 90 | + |
| 91 | + # Layer 2: another RY on each qubit |
| 92 | + for q in range(3): |
| 93 | + state = apply_single_qubit_gate(state, ry(params[3+q]), q) |
| 94 | + # Another round of CNOTs |
| 95 | + state = apply_cnot(state, control=0, target=1) |
| 96 | + state = apply_cnot(state, control=1, target=2) |
| 97 | + |
| 98 | + return state |
| 99 | + |
| 100 | +# --- Energy expectation function --- |
| 101 | +def energy_expectation(params): |
| 102 | + """ |
| 103 | + Return the expectation value <psi(θ)|H|psi(θ)> for the ansatz state. |
| 104 | + """ |
| 105 | + psi = prepare_state(params) |
| 106 | + # ⟨psi|H|psi⟩ = psi.conj().T @ H @ psi |
| 107 | + return np.real(np.vdot(psi, H.dot(psi))) |
| 108 | + |
| 109 | +# --- Optimization with COBYLA and convergence tracking --- |
| 110 | +energy_history = [] # to record energy at each iteration |
| 111 | + |
| 112 | +def callback(params): |
| 113 | + """Callback to store energy at each iteration.""" |
| 114 | + energy_history.append(energy_expectation(params)) |
| 115 | + |
| 116 | +# Random initial parameters (e.g., in [0,2π]) |
| 117 | +init_params = np.random.rand(6) * 2*np.pi |
| 118 | +energy_history.append(energy_expectation(init_params)) # record initial energy |
| 119 | + |
| 120 | +res = minimize(energy_expectation, init_params, method='COBYLA', |
| 121 | + callback=callback, options={'maxiter': 200, 'tol': 1e-6}) |
| 122 | + |
| 123 | +print("Optimization success:", res.success) |
| 124 | +print("Minimum energy found:", res.fun) |
| 125 | +print("Ground-state eigenvalue (True):", np.min(np.linalg.eigvalsh(H))) |
| 126 | + |
| 127 | +# --- Display convergence curve (matplotlib can be used here) --- |
| 128 | +import matplotlib.pyplot as plt |
| 129 | + |
| 130 | +plt.plot(energy_history, marker='o') |
| 131 | +plt.title("VQE Convergence (Energy vs Iteration)") |
| 132 | +plt.xlabel("Iteration") |
| 133 | +plt.ylabel("Energy ⟨ψ|H|ψ⟩") |
| 134 | +plt.grid(True) |
| 135 | +plt.show() |
| 136 | + |
| 137 | +# --- Print ansatz structure (text) --- |
| 138 | +print("\nAnsatz circuit (text form):") |
| 139 | +print(" Layer 1: RY(θ0) on qubit 0, RY(θ1) on qubit 1, RY(θ2) on qubit 2") |
| 140 | +print(" CNOT(0→1), CNOT(1→2)") |
| 141 | +print(" Layer 2: RY(θ3) on qubit 0, RY(θ4) on qubit 1, RY(θ5) on qubit 2") |
| 142 | +print(" CNOT(0→1), CNOT(1→2)") |
| 143 | +Explanation of key steps: We generate a random Hermitian H and start in |000⟩. The ansatz state is built by applying two layers of Ry rotations and CNOTs (as described above) using NumPy arrays and kron/indexing. The energy ⟨ψ|H|ψ⟩ is computed by a vector-matrix-vector multiplication. We minimize this energy using scipy.optimize.minimize(method='COBYLA') , storing the energy after each step. Finally, we plot the recorded energy vs. iteration (as shown) and print a textual description of the ansatz circuit. This fully implements VQE without relying on Qiskit or PennyLane. |
| 144 | + |
| 145 | +Sources: The VQE method and energy-minimization principle are discussed in standard references . Quantum states are vectors and gates are matrices in simulation , and using single-qubit Ry rotations with CNOTs is a universal ansatz . We use the COBYLA optimizer from SciPy as recommended for VQE tasks . |
0 commit comments