Skip to main contentIBM Quantum Documentation
Important

IBM Quantum Platform is moving and this version will be sunset on July 1. To get started on the new platform, read the migration guide.

Quimb circuit-based backend

qiskit_addon_mpf.backends.quimb_circuit

A circuit-based time-evolution backend using quimb.

Warning

This backend is only available if the optional dependencies have been installed:

pip install "qiskit-addon-mpf[quimb]"
CircuitEvolverA time-evolution engine based on quantum circuits.
CircuitStateAn 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)
Caution

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.

Was this page helpful?
Report a bug or request content on GitHub.