.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "gallery/mbqc_vqe.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_gallery_mbqc_vqe.py: Variational Quantum Eigensolver (VQE) with Measurement-Based Quantum Computing (MBQC) ===================================================================================== In this example, we solve a simple VQE problem using a measurement-based quantum computing (MBQC) approach. The Hamiltonian for the system is given by: .. math:: H = Z_0 Z_1 + X_0 + X_1 where :math:`Z` and :math:`X` are the Pauli-Z and Pauli-X matrices, respectively. This Hamiltonian corresponds to a simple model system often used in quantum computing to demonstrate algorithms like VQE. The goal is to find the ground state energy of this Hamiltonian. We will build a parameterized quantum circuit and optimize its parameters to minimize the expectation value of the Hamiltonian, effectively finding the ground state energy. .. GENERATED FROM PYTHON SOURCE LINES 21-47 .. code-block:: Python from __future__ import annotations import itertools import sys from timeit import timeit from typing import TYPE_CHECKING import numpy as np import numpy.typing as npt from scipy.optimize import minimize from graphix import Circuit from graphix.parameter import Placeholder from graphix.simulator import PatternSimulator if TYPE_CHECKING: from collections.abc import Iterable from graphix.pattern import Pattern from graphix.transpiler import Angle Z = np.array([[1, 0], [0, -1]]) X = np.array([[0, 1], [1, 0]]) .. GENERATED FROM PYTHON SOURCE LINES 48-49 Define the Hamiltonian for the VQE problem (Example: H = Z0Z1 + X0 + X1) .. GENERATED FROM PYTHON SOURCE LINES 49-66 .. code-block:: Python def create_hamiltonian() -> npt.NDArray[np.complex128]: return np.kron(Z, Z) + np.kron(X, np.eye(2)) + np.kron(np.eye(2), X) if sys.version_info >= (3, 12): batched = itertools.batched else: # From https://docs.python.org/3/library/itertools.html#itertools.batched def batched(iterable, n): # batched('ABCDEFG', 3) → ABC DEF G if n < 1: raise ValueError("n must be at least one") iterator = iter(iterable) while batch := tuple(itertools.islice(iterator, n)): yield batch .. GENERATED FROM PYTHON SOURCE LINES 67-68 Function to build the VQE circuit .. GENERATED FROM PYTHON SOURCE LINES 68-79 .. code-block:: Python def build_vqe_circuit(n_qubits: int, params: Iterable[Angle]) -> Circuit: circuit = Circuit(n_qubits) for i, (x, y, z) in enumerate(batched(params, n=3)): circuit.rx(i, x) circuit.ry(i, y) circuit.rz(i, z) for i in range(n_qubits - 1): circuit.cnot(i, i + 1) return circuit .. GENERATED FROM PYTHON SOURCE LINES 80-128 .. code-block:: Python class MBQCVQE: def __init__(self, n_qubits: int, hamiltonian: npt.NDArray): self.n_qubits = n_qubits self.hamiltonian = hamiltonian # %% # Function to build the MBQC pattern def build_mbqc_pattern(self, params: Iterable[Angle]) -> Pattern: circuit = build_vqe_circuit(self.n_qubits, params) pattern = circuit.transpile().pattern pattern.standardize() pattern.shift_signals() pattern.perform_pauli_measurements() # Perform Pauli measurements return pattern # %% # Function to simulate the MBQC circuit def simulate_mbqc(self, params: Iterable[float], backend="tensornetwork"): pattern = self.build_mbqc_pattern(params) simulator = PatternSimulator(pattern, backend=backend) if backend == "tensornetwork": simulator.run() # Simulate the MBQC circuit using tensor network tn = simulator.backend.state tn.default_output_nodes = pattern.output_nodes # Set the default_output_nodes attribute if tn.default_output_nodes is None: raise ValueError("Output nodes are not set for tensor network simulation.") return tn return simulator.run() # Simulate the MBQC circuit using other backends # %% # Function to compute the energy def compute_energy(self, params: Iterable[float]): # Simulate the MBQC circuit using tensor network backend tn = self.simulate_mbqc(params, backend="tensornetwork") # Compute the expectation value using MBQCTensornet.expectation_value return tn.expectation_value(self.hamiltonian, qubit_indices=range(self.n_qubits)) class MBQCVQEWithPlaceholders(MBQCVQE): def __init__(self, n_qubits: int, hamiltonian) -> None: super().__init__(n_qubits, hamiltonian) self.placeholders = tuple(Placeholder(f"{r}[{q}]") for q in range(n_qubits) for r in ("X", "Y", "Z")) self.pattern = super().build_mbqc_pattern(self.placeholders) def build_mbqc_pattern(self, params): return self.pattern.xreplace(dict(zip(self.placeholders, params))) .. GENERATED FROM PYTHON SOURCE LINES 129-130 Set parameters for VQE .. GENERATED FROM PYTHON SOURCE LINES 130-133 .. code-block:: Python n_qubits = 2 hamiltonian = create_hamiltonian() .. GENERATED FROM PYTHON SOURCE LINES 134-135 Instantiate the MBQCVQE class .. GENERATED FROM PYTHON SOURCE LINES 135-138 .. code-block:: Python mbqc_vqe = MBQCVQEWithPlaceholders(n_qubits, hamiltonian) .. GENERATED FROM PYTHON SOURCE LINES 139-140 Define the cost function .. GENERATED FROM PYTHON SOURCE LINES 140-144 .. code-block:: Python def cost_function(params): return mbqc_vqe.compute_energy(params) .. GENERATED FROM PYTHON SOURCE LINES 145-146 Random initial parameters .. GENERATED FROM PYTHON SOURCE LINES 146-150 .. code-block:: Python rng = np.random.default_rng() initial_params = rng.random(n_qubits * 3) .. GENERATED FROM PYTHON SOURCE LINES 151-152 Perform the optimization using COBYLA .. GENERATED FROM PYTHON SOURCE LINES 152-161 .. code-block:: Python def compute(): return minimize(cost_function, initial_params, method="COBYLA", options={"maxiter": 100}) result = compute() print(f"Optimized parameters: {result.x}") print(f"Optimized energy: {result.fun}") .. rst-class:: sphx-glr-script-out .. code-block:: none Optimized parameters: [ 6.55292040e-01 3.14166163e+00 3.14158332e+00 1.30709479e+00 2.67796523e+00 -3.40283156e-05] Optimized energy: -2.236067973841869 .. GENERATED FROM PYTHON SOURCE LINES 162-163 Compare with the analytical solution .. GENERATED FROM PYTHON SOURCE LINES 163-166 .. code-block:: Python analytical_solution = -np.sqrt(2) - 1 print(f"Analytical solution: {analytical_solution}") .. rst-class:: sphx-glr-script-out .. code-block:: none Analytical solution: -2.414213562373095 .. GENERATED FROM PYTHON SOURCE LINES 167-168 Compare performances between using parameterized circuits (with placeholders) or not .. GENERATED FROM PYTHON SOURCE LINES 168-176 .. code-block:: Python mbqc_vqe = MBQCVQEWithPlaceholders(n_qubits, hamiltonian) time_with_placeholders = timeit(compute, number=2) print(f"Time with placeholders: {time_with_placeholders}") mbqc_vqe = MBQCVQE(n_qubits, hamiltonian) time_without_placeholders = timeit(compute, number=2) print(f"Time without placeholders: {time_without_placeholders}") .. rst-class:: sphx-glr-script-out .. code-block:: none Time with placeholders: 1.4693784179980867 Time without placeholders: 1.9249759779995657 .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 6.352 seconds) .. _sphx_glr_download_gallery_mbqc_vqe.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: mbqc_vqe.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: mbqc_vqe.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: mbqc_vqe.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_