-
Notifications
You must be signed in to change notification settings - Fork 1
Adding time-dependent Hamiltonian evolution #431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
v-agamshayit
wants to merge
29
commits into
main
Choose a base branch
from
feature/agamshayit/time_evolution
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
cb6f450
docstring
v-agamshayit d020a78
started implementing
v-agamshayit 25774a7
Merge remote-tracking branch 'origin/main' into feature/agamshayit/ti…
v-agamshayit a31336f
Trotter grouping terms by parallelizable layers, fixes pauli strings …
v-agamshayit 6df5b2f
added missing files
v-agamshayit 476bc5f
pre-commit
v-agamshayit 55a0488
implememnting exponentiate_commuting() naively for now
v-agamshayit b55ca4a
added qubit-wise diagonalization when exponentiating disjoint commuti…
v-agamshayit ffe5be0
Revert "added qubit-wise diagonalization when exponentiating disjoint…
v-agamshayit ec87ae3
fixed tests
v-agamshayit 20f25ed
Merge branch 'main' into feature/agamshayit/time_evolution
v-agamshayit bdb435b
updated the evolve_and_measure interface to be compatible with the ne…
v-agamshayit 14495b9
fixing docstring
v-agamshayit 3a24e89
fixing pre-commit
v-agamshayit 0439675
added example notebook
v-agamshayit 522ba7e
added example notebook
v-agamshayit 60c4fda
Apply suggestions from code review
v-agamshayit a8d57c8
combining Pauli product formula containers w/o expanding step_reps
v-agamshayit a2d6432
copilot comments
v-agamshayit 7e2c8bd
pre-commit
v-agamshayit 3e2ce51
more copilot comments
v-agamshayit 1197294
Apply suggestions from code review
v-agamshayit 6d86368
ran pre-commit
v-agamshayit b199a79
added new algorithms to registry
v-agamshayit 6033504
Apply suggestions from code review
v-agamshayit f592b19
more copilot comments, added exact exponentiation to example for refe…
v-agamshayit d4223bc
Merge remote-tracking branch 'origin/feature/agamshayit/time_evolutio…
v-agamshayit 18b5f08
fixed test
v-agamshayit 4b77439
added Trotter docstring
v-agamshayit File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,328 @@ | ||
| { | ||
| "cells": [ | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "694e0a42", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "# Measure time-evolved expectation values in `qdk-chemistry`\n", | ||
| "\n", | ||
| "## This notebook demonstrates the `EvolveAndMeasure` algorithm for Hamiltonian time evolution and observable measurement using `qdk-chemistry`. It shows how to:\n", | ||
| "\n", | ||
| "1. Define a qubit Hamiltonian with time-dependent parameters\n", | ||
| "2. Build a Trotter evolution circuit\n", | ||
| "3. Run the simulation **without noise** using the QDK full-state simulator\n", | ||
| "4. Run the simulation **with noise** using both the QDK and Qiskit Aer backends\n", | ||
| "5. Optionally transpile to a target basis gate set before execution" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "d7052dfd", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "import numpy as np\n", | ||
| "\n", | ||
| "from qdk_chemistry.algorithms import create\n", | ||
| "from qdk_chemistry.algorithms.time_evolution.builder.trotter import Trotter\n", | ||
| "from qdk_chemistry.algorithms.time_evolution.circuit_mapper import PauliSequenceMapper\n", | ||
| "from qdk_chemistry.data import LatticeGraph, QuantumErrorProfile, QubitHamiltonian\n", | ||
| "from qdk_chemistry.utils.model_hamiltonians import create_ising_hamiltonian\n", | ||
| "\n", | ||
| "# Reduce logging output for demo\n", | ||
| "from qdk_chemistry.utils import Logger\n", | ||
| "Logger.set_global_level(Logger.LogLevel.off)" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "974e8334", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "We define two qubit Hamiltonians representing alternating time-evolution steps (e.g., a driven or Floquet-like protocol). The observable is `ZZ`, measured after the full evolution sequence." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "30741065", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "The lists `hamiltonians` and `time_steps` define the discretized time-dependent Hamiltonian $H(t)$ as:\n", | ||
| "\n", | ||
| "$H(t_i) = H_i$, where\n", | ||
| "\n", | ||
| "$H_i \\in $ `hamiltonians` = $\\left[H_1,\\dots,H_n\\right]$,\n", | ||
| "\n", | ||
| "$t_i \\in $`time_steps` = $\\left[t_1,\\dots,t_n\\right]$" | ||
| ] | ||
v-agamshayit marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "c9bdd8b5", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "lattice = LatticeGraph.chain(2)\n", | ||
| "\n", | ||
| "hamiltonian_p = create_ising_hamiltonian(lattice, j=1.0, h=0.5)\n", | ||
| "hamiltonian_m = create_ising_hamiltonian(lattice, j=1.0, h=-0.5)\n", | ||
| "\n", | ||
| "steps = 20\n", | ||
| "hamiltonians = [hamiltonian_p, hamiltonian_m] * (steps // 2)\n", | ||
| "time_steps = [float((t + 1) / 10) for t in range(steps)]\n", | ||
| "\n", | ||
| "observable = QubitHamiltonian([\"ZZ\"], np.array([1.0]))" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "d1affab1", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Exact evolution via matrix exponential\n", | ||
| "\n", | ||
| "Convert the Hamiltonians to sparse matrices and compute the exact time evolution $|\\psi(t)\\rangle = \\prod_i e^{-i H_i \\Delta t_i} |\\psi_0\\rangle$." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "a58bb629", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "from scipy.sparse.linalg import expm_multiply\n", | ||
| "\n", | ||
| "# Convert Hamiltonians to sparse matrices\n", | ||
| "H_p = hamiltonian_p.to_matrix(sparse=True)\n", | ||
| "H_m = hamiltonian_m.to_matrix(sparse=True)\n", | ||
| "\n", | ||
| "num_qubits = H_p.shape[0].bit_length() - 1\n", | ||
| "\n", | ||
| "# Initial state |00...0⟩\n", | ||
| "psi = np.zeros(2**num_qubits, dtype=complex)\n", | ||
| "psi[0] = 1.0\n", | ||
| "\n", | ||
| "# Time-evolve: apply exp(-i H_i dt_i) for each step\n", | ||
| "dt_list = [time_steps[0]] + [time_steps[i] - time_steps[i - 1] for i in range(1, len(time_steps))]\n", | ||
| "\n", | ||
| "for ham, dt in zip(hamiltonians, dt_list):\n", | ||
| " H_sparse = H_p if ham is hamiltonian_p else H_m\n", | ||
| " psi = expm_multiply(-1j * H_sparse * dt, psi)\n", | ||
| "\n", | ||
| "# Compute exact ⟨ZZ⟩\n", | ||
| "Z = np.array([1, -1], dtype=complex)\n", | ||
| "ZZ_diag = np.kron(Z, Z)\n", | ||
| "zz_exact = np.real(np.conj(psi) @ (ZZ_diag * psi))\n", | ||
| "\n", | ||
| "print(f\"Exact ⟨ZZ⟩: {zz_exact:.6f}\")" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "57064b4c", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Noiseless simulation (QDK full-state simulator)\n", | ||
| "Set up the Trotter builder, circuit mapper, energy estimator, and the `measure_simulation` algorithm." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "3ef0a94f", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "evolution_builder = Trotter(num_divisions=2, order=1, optimize_term_ordering=True)\n", | ||
| "mapper = PauliSequenceMapper()\n", | ||
| "energy_estimator = create(\"energy_estimator\", \"qdk\")\n", | ||
| "measure_simulation = create(\"measure_simulation\", \"classical_sampling\")" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "2ca695ec", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "Run the evolution and measure `⟨ZZ⟩` without any noise using the QDK full-state simulator." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "3a876d78", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "circuit_executor_qdk = create(\"circuit_executor\", \"qdk_full_state_simulator\")\n", | ||
| "\n", | ||
| "measurements_noiseless = measure_simulation.run(\n", | ||
| " hamiltonians,\n", | ||
| " times=time_steps,\n", | ||
| " observables=[observable],\n", | ||
| " evolution_builder=evolution_builder,\n", | ||
| " circuit_mapper=mapper,\n", | ||
| " circuit_executor=circuit_executor_qdk,\n", | ||
| " energy_estimator=energy_estimator,\n", | ||
| " shots=10000,\n", | ||
| ")\n", | ||
| "\n", | ||
| "zz_noiseless = measurements_noiseless[0][0].energy_expectation_value\n", | ||
| "print(f\"Noiseless ⟨ZZ⟩: {zz_noiseless:.6f}\")" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "6e70e127", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Define a noise profile\n", | ||
| "\n", | ||
| "`QuantumErrorProfile` provides a backend-agnostic way to specify depolarizing noise on individual gates. This profile can be used with both the QDK and Qiskit Aer simulators.\n", | ||
| "\n", | ||
| "> **Note:** The QDK full-state simulator applies noise at the *native gate level* of the compiled QIR. If the circuit uses high-level Pauli exponentials (e.g. via `PauliSequenceMapper`), those are executed natively without decomposition into `cx`/`rz` gates — so noise on `cx` won't apply. To see noise with the QDK simulator, either use `basis_gates` to force decomposition, or define noise on the native gates (`rzz`, `rx`, etc.)." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "56c5fc06", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "qdk_error_profile = QuantumErrorProfile(\n", | ||
| " name=\"demo_noise\",\n", | ||
| " description=\"Light depolarizing noise on common gates\",\n", | ||
| " errors={\n", | ||
| " \"cx\": {\"type\": \"depolarizing_error\", \"rate\": 0.01, \"num_qubits\": 2},\n", | ||
| " \"cz\": {\"type\": \"depolarizing_error\", \"rate\": 0.01, \"num_qubits\": 2},\n", | ||
| " \"rzz\": {\"type\": \"depolarizing_error\", \"rate\": 0.01, \"num_qubits\": 2},\n", | ||
| " \"h\": {\"type\": \"depolarizing_error\", \"rate\": 0.001, \"num_qubits\": 1},\n", | ||
| " \"rz\": {\"type\": \"depolarizing_error\", \"rate\": 0.001, \"num_qubits\": 1},\n", | ||
| " \"rx\": {\"type\": \"depolarizing_error\", \"rate\": 0.001, \"num_qubits\": 1},\n", | ||
| " \"s\": {\"type\": \"depolarizing_error\", \"rate\": 0.001, \"num_qubits\": 1},\n", | ||
| " \"sdg\": {\"type\": \"depolarizing_error\", \"rate\": 0.001, \"num_qubits\": 1},\n", | ||
| " },\n", | ||
| ")" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "c27af18e", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Noisy simulation — QDK full-state simulator\n", | ||
| "\n", | ||
| "Because `PauliSequenceMapper` produces native Pauli-exponential operations, and our noise profile includes `rzz` (the native two-qubit gate), the QDK simulator **will** apply noise to those operations." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "0742066a", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "measurements_noisy_qdk = measure_simulation.run(\n", | ||
| " hamiltonians,\n", | ||
| " times=time_steps,\n", | ||
| " observables=[observable],\n", | ||
| " evolution_builder=evolution_builder,\n", | ||
| " circuit_mapper=mapper,\n", | ||
| " circuit_executor=circuit_executor_qdk,\n", | ||
| " energy_estimator=energy_estimator,\n", | ||
| " shots=10000,\n", | ||
| " noise=qdk_error_profile,\n", | ||
| ")\n", | ||
| "\n", | ||
| "zz_noisy_qdk = measurements_noisy_qdk[0][0].energy_expectation_value\n", | ||
| "print(f\"Noisy QDK ⟨ZZ⟩: {zz_noisy_qdk:.6f}\")" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "e0518676", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Noisy simulation — Qiskit Aer simulator\n", | ||
| "\n", | ||
| "The Qiskit Aer backend transpiles the circuit to primitive gates (`cx`, `rz`, `h`, …) before execution, so noise on those gates fires naturally." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "cafb9c98", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "circuit_executor_aer = create(\"circuit_executor\", \"qiskit_aer_simulator\")\n", | ||
| "\n", | ||
| "measurements_noisy_aer = measure_simulation.run(\n", | ||
| " hamiltonians,\n", | ||
| " times=time_steps,\n", | ||
| " observables=[observable],\n", | ||
| " evolution_builder=evolution_builder,\n", | ||
| " circuit_mapper=mapper,\n", | ||
| " circuit_executor=circuit_executor_aer,\n", | ||
| " energy_estimator=energy_estimator,\n", | ||
| " shots=10000,\n", | ||
| " noise=qdk_error_profile,\n", | ||
| ")\n", | ||
| "\n", | ||
| "zz_noisy_aer = measurements_noisy_aer[0][0].energy_expectation_value\n", | ||
| "print(f\"Noisy Aer ⟨ZZ⟩: {zz_noisy_aer:.6f}\")" | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "markdown", | ||
| "id": "fdc8f4be", | ||
| "metadata": {}, | ||
| "source": [ | ||
| "## Compare results\n", | ||
| "\n", | ||
| "Side-by-side comparison of the noiseless and noisy expectation values." | ||
| ] | ||
| }, | ||
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "8d7b777c", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "print(\"Simulator ⟨ZZ⟩\")\n", | ||
| "print(\"─\" * 36)\n", | ||
| "print(f\"Exact {zz_exact: .6f}\")\n", | ||
| "print(f\"QDK (noiseless) {zz_noiseless: .6f}\")\n", | ||
| "print(f\"QDK (noisy) {zz_noisy_qdk: .6f}\")\n", | ||
| "print(f\"Aer (noisy) {zz_noisy_aer: .6f}\")" | ||
| ] | ||
| } | ||
| ], | ||
| "metadata": { | ||
| "kernelspec": { | ||
| "display_name": "qdk_chemistry_venv", | ||
| "language": "python", | ||
| "name": "python3" | ||
| }, | ||
| "language_info": { | ||
| "codemirror_mode": { | ||
| "name": "ipython", | ||
| "version": 3 | ||
| }, | ||
| "file_extension": ".py", | ||
| "mimetype": "text/x-python", | ||
| "name": "python", | ||
| "nbconvert_exporter": "python", | ||
| "pygments_lexer": "ipython3", | ||
| "version": "3.12.3" | ||
| } | ||
| }, | ||
| "nbformat": 4, | ||
| "nbformat_minor": 5 | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.