Adding time-dependent Hamiltonian evolution#431
Conversation
📊 Coverage Summary
Detailed Coverage ReportsC++ Coverage DetailsPython Coverage DetailsPybind11 Coverage Details |
… commuting pauli strings" This reverts commit b55ca4a.
…w energy_estimator
There was a problem hiding this comment.
Pull request overview
This PR adds an end-to-end workflow for time-dependent Hamiltonian evolution: building a (Trotterized) time-evolution unitary, mapping it to a Q#/QIR-backed circuit, and measuring observables via the existing EnergyEstimator infrastructure.
Changes:
- Introduces an
EvolveAndMeasuremeasure-simulation algorithm that composes optional state preparation with time evolution and measures observables. - Adds a
PauliSequenceMapperplus new Q# utilities (PauliExp,CircuitComposition) to generate executable evolution circuits. - Extends the Trotter builder with
optimize_term_orderingterm grouping/merging and adds tests around ordering + merging behavior.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| python/src/qdk_chemistry/algorithms/time_evolution/measure_simulation/base.py | New base abstractions/utilities for evolve-and-measure workflows (circuit composition, transpile helper, observable measurement helper). |
| python/src/qdk_chemistry/algorithms/time_evolution/measure_simulation/evolve_and_measure.py | New concrete evolve+measure implementation that chains piecewise evolution segments and runs measurement(s). |
| python/src/qdk_chemistry/algorithms/time_evolution/measure_simulation/init.py | Exports measure-simulation algorithms/factories. |
| python/src/qdk_chemistry/algorithms/time_evolution/circuit_mapper/base.py | New evolution-circuit-mapper algorithm base + factory. |
| python/src/qdk_chemistry/algorithms/time_evolution/circuit_mapper/pauli_sequence_mapper.py | New mapper that converts Pauli-product-formula evolution into a Q# Exp-based circuit/QIR. |
| python/src/qdk_chemistry/algorithms/time_evolution/circuit_mapper/init.py | Exports evolution circuit mapper factory + implementations. |
| python/src/qdk_chemistry/utils/qsharp/PauliExp.qs | Adds non-controlled Pauli exponential Q# helpers (single + repeated evolution) used by the mapper. |
| python/src/qdk_chemistry/utils/qsharp/CircuitComposition.qs | Adds Q# helpers for sequentially composing two Qubit[] => Unit operations into a single circuit/op. |
| python/src/qdk_chemistry/utils/qsharp/init.py | Registers the new Q# utility files for lazy-loading via QSHARP_UTILS. |
| python/src/qdk_chemistry/data/time_evolution/containers/pauli_product_formula.py | Adds combine() to concatenate evolutions and fuse adjacent identical Pauli terms. |
| python/src/qdk_chemistry/algorithms/time_evolution/builder/trotter.py | Adds optimize_term_ordering setting and implements commuting/parallelizable grouping and duplicate merging. |
| python/tests/test_time_evolution_trotter.py | Adds tests for duplicate-term merging and optimized term ordering behavior. |
| python/tests/test_time_evolution_circuit_mapper_noncontrolled.py | Adds tests validating the non-controlled PauliSequenceMapper produces a Q# circuit of expected width. |
| python/tests/test_evolve_and_measure.py | Adds tests for state-prep composition and an example evolve+measure workflow. |
| python/pyproject.toml | Adds paulimer dependency. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 17 out of 17 changed files in this pull request and generated 11 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…backend' into feature/agamshayit/transpile_to_backend
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…gamshayit/time_evolution
…backend' into feature/agamshayit/time_evolution
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 29 out of 29 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| evolution = self._create_time_evolution(qubit_hamiltonians[0], times[0], evolution_builder) | ||
|
|
||
| for i in range(1, len(qubit_hamiltonians)): | ||
| delta_t = times[i] - times[i - 1] | ||
| evolution = TimeEvolutionUnitary( | ||
| evolution.get_container().combine( | ||
| self._create_time_evolution(qubit_hamiltonians[i], delta_t, evolution_builder).get_container(), | ||
| ) | ||
| ) | ||
|
|
There was a problem hiding this comment.
_build_evolution_circuit() repeatedly calls container.combine(...) inside a loop. Since combine() rebuilds a new merged list starting from the beginning each time, constructing an evolution from N time-slices becomes O(N^2) in the number of emitted Pauli terms. Prefer accumulating terms in a single pass (e.g., maintain a running list and only merge the boundary term when appending the next slice) or add a container-level combine_many API and use it here.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if device_backend_name is not None: | ||
| if not qiskit_plugin.QDK_CHEMISTRY_HAS_QISKIT_IBM_RUNTIME: | ||
| raise ImportError( | ||
| "The fake_provider module from qiskit_ibm_runtime is required for device backend simulation. " | ||
| "Install it with: pip install qiskit-ibm-runtime" | ||
| ) | ||
|
|
||
| provider = qiskit_ibm_runtime.fake_provider.FakeProviderForBackendV2() | ||
| try: | ||
| device_backend = provider.backend(device_backend_name) | ||
| except QiskitBackendNotFoundError: |
There was a problem hiding this comment.
qiskit_ibm_runtime is imported only at module import time when QDK_CHEMISTRY_HAS_QISKIT_IBM_RUNTIME is already true. If a caller imports this module before plugin loading sets that flag, then later enables IBM runtime and passes device_backend_name, this branch will raise NameError when referencing qiskit_ibm_runtime. Import qiskit_ibm_runtime.fake_provider inside the device_backend_name branch (or via importlib) to make this robust regardless of import order.
| if key == "equivalent_gate_set" and isinstance(value, list): | ||
| value = list({*value, "id"}) | ||
| Logger.trace_entering() | ||
| super().set(key, value) |
There was a problem hiding this comment.
equivalent_gate_set is normalized via list({*value, "id"}), which does not preserve order and can be non-deterministic across processes (hash randomization). If these settings are serialized, displayed, or compared, this can cause flakiness. Consider preserving input order while ensuring uniqueness (e.g., append "id" if missing, then de-dup with an order-preserving approach).
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 28 out of 28 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if qiskit_plugin.QDK_CHEMISTRY_HAS_QISKIT_IBM_RUNTIME: | ||
| import qiskit_ibm_runtime.fake_provider |
There was a problem hiding this comment.
qiskit_ibm_runtime is only imported at module import time when QDK_CHEMISTRY_HAS_QISKIT_IBM_RUNTIME is true. If this module is imported before qiskit_plugin.load() sets that flag, device_backend_name can later take the runtime branch and hit a NameError when referencing qiskit_ibm_runtime. Consider doing a local import inside the device_backend_name branch (or importing unconditionally with a try/except) so the name is always defined when needed.
| if qiskit_plugin.QDK_CHEMISTRY_HAS_QISKIT_IBM_RUNTIME: | |
| import qiskit_ibm_runtime.fake_provider | |
| try: | |
| import qiskit_ibm_runtime.fake_provider | |
| except ImportError: | |
| qiskit_ibm_runtime = None |
This PR adds the ability to run time evolution experiments by mapping a time-dependent Hamiltonian (represented by a list of Hamiltonians and corresponding time coordinates) into a Trotterized unitary. The time evolution unitaryis then converted to a circuit and observables are measured using the native EnergyEstimator.
This includes the optimization of the Trotter decomposition into commuting layers. Commuting layers are then decomposed into parallelizable sublayers to minimize circuit depth.
Added a notebook with periodically-kicked Ising model example