Quimb circuit-based backend
qiskit_addon_mpf.backends.quimb_circuit
A circuit-based time-evolution backend using quimb
.
This backend is only available if the optional dependencies have been installed:
pip install "qiskit-addon-mpf[quimb]"
CircuitEvolver | A time-evolution engine based on quantum circuits. |
CircuitState | An MPO-like representation of a time-evolution state based on quantum circuits. |
Underlying method
Quimb boasts direct support for the simulation of quantum circuits in the form of its tensor-network based quimb.tensor.Circuit
representation. We can leverage this, to bypass any explicit time-evolution algorithm and instead directly encode the time-evolution in a QuantumCircuit
and use quimb
to compute the overlap between two such circuits. For more information, check out their guide on Quantum Circuits.
Code example
This section shows a simple example to get you started with using this backend. The example shows how to create the three factory functions required for the setup_dynamic_lse()
.
The IdentityStateFactory
protocol is already fulfilled by the CircuitState
constructor, rendering the identity_factory
argument trivial:
>>> from qiskit_addon_mpf.backends.quimb_circuit import CircuitState
>>> identity_factory = CircuitState
The setup of the CircuitEvolver
is slightly more involved. It requires a parameterized QuantumCircuit
object as its input where the Parameter
should take the place of the Trotter methods time step (dt
).
To show how such a parameterized Trotter circuit template is constructed, we reuse the same Hamiltonian and second-order Suzuki-Trotter formula as in quimb_layers
.
>>> from qiskit.quantum_info import SparsePauliOp
>>> hamil = SparsePauliOp.from_sparse_list(
... [("ZZ", (i, i+1), 1.0) for i in range(0, 9, 2)] +
... [("Z", (i,), 0.5) for i in range(10)] +
... [("ZZ", (i, i+1), 1.0) for i in range(1, 9, 2)] +
... [("X", (i,), 0.25) for i in range(10)],
... num_qubits=10,
... )
But this time, we specify a Parameter
as the time
argument when constructing the actual circuits.
>>> from functools import partial
>>> from qiskit.circuit import Parameter
>>> from qiskit.synthesis import SuzukiTrotter
>>> from qiskit_addon_mpf.backends.quimb_circuit import CircuitEvolver
>>> from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit
>>> dt = Parameter("dt")
>>> suzuki_2 = generate_time_evolution_circuit(hamil, time=dt, synthesis=SuzukiTrotter(order=2))
>>> approx_evolver_factory = partial(CircuitEvolver, circuit=suzuki_2)
It is necessary that the name of the Parameter
is dt
!
We can choose a higher order Trotter formula for the exact_evolver_factory
. But note, that we must once again use a parameterized circuit, even if we immediately bind its parameter when constructing the partial
function.
>>> suzuki_4 = generate_time_evolution_circuit(hamil, time=dt, synthesis=SuzukiTrotter(order=4))
>>> exact_evolver_factory = partial(CircuitEvolver, circuit=suzuki_4, dt=0.05)
These factory functions may now be used to run the setup_dynamic_lse()
. Refer to its documentation for more details on that.