Skip to main contentIBM Quantum Documentation

Dynamic MPFs

qiskit_addon_mpf.dynamic

Dynamic MPF coefficients.

This module provides the generator function for the linear system of equations (LSE) for computing dynamic (that is, time-dependent) MPF coefficients.

setup_dynamic_lse

setup_dynamic_lse(trotter_steps, time, identity_factory, exact_evolver_factory, approx_evolver_factory, initial_state)

GitHub

Return the linear system of equations for computing dynamic MPF coefficients.

This function uses the DynamicMPF algorithm to compute the components of the Gram matrix (LSE.A, MM in [1] and [2]) and the overlap vector (LSE.b, LL in [1] and [2]) for the provided time-evolution parameters.

The elements of the Gram matrix, MijM_{ij}, and overlap vector, LiL_i, are defined as

Mij=Tr(ρki(t)ρkj(t)),Li=Tr(ρ(t)ρki(t)),\begin{split}M_{ij} &= \text{Tr}(\rho_{k_i}(t)\rho_{k_j}(t)) \, , \\ L_i &= \text{Tr}(\rho(t)\rho_{k_i}(t)) \, ,\end{split}

where ρ(t)\rho(t) is the exact time-evolution state at time tt and ρki(t)\rho_{k_i}(t) is the time-evolution state approximated using kik_i Trotter steps.

Computing the dynamic (that is, time-dependent) MPF coefficients from MM and LL amounts to finding a solution to the LSE (similarly to how the static MPF coefficients are computed) while enforcing the constraint that all coefficients must sum to 1 (ixi=1\sum_i x_i = 1), which is not enforced as part of this LSE (unlike in the static case). Optimization problems which include this additional constraint are documented in the costs module. The one suggested by [1] and [2] is the setup_frobenius_problem().

Evaluating every element MijM_{ij} and LiL_i requires computing the overlap between two time-evolution states. The DynamicMPF algorithm does so by means of tensor network calculations, provided by one of the optional dependencies. The available backends are listed and explained in more detail in the backends module.

Below, we provide an example using the quimb_tebd backend. We briefly explain each element.

First, we initialize a simple Heisenberg Hamiltonian which we would like to time-evolve. Since we are using a time-evolver based on quimb, we also initialize the Hamiltonian using that library.

>>> from quimb.tensor import ham_1d_heis
>>> num_qubits = 10
>>> hamil = ham_1d_heis(num_qubits, 0.8, 0.3, cyclic=False)

Next, we define the number of Trotter steps to make up our MPF, the target evolution time as well as the initial state (ψin\psi_{in} in [1] and ψ0\psi_0 in [2], resp.) with respect to which we compute the overlap between the time-evolution states. Here, we simply use the Néel state which we also construct using quimb:

>>> trotter_steps = [3, 4]
>>> time = 0.9
>>> from quimb.tensor import MPS_neel_state
>>> initial_state = MPS_neel_state(num_qubits)

Since we must run the full DynamicMPF algorithm for computing every element of MijM_{ij} and LiL_i, we must provide factory methods for initializing the input arguments of the DynamicMPF instances. To this end, we must provide three functions. To construct these, we will use the functools.partial() function.

>>> from functools import partial

First, we need a function to initialize an empty time-evolution state (see also DynamicMPF.evolution_state for more details). This constructor function may not take any positional or keyword arguments and must return a State object.

>>> from qiskit_addon_mpf.backends.quimb_tebd import MPOState
>>> from quimb.tensor import MPO_identity
>>> identity_factory = lambda: MPOState(MPO_identity(num_qubits))

The second and third function must construct the left- and right-hand side time-evolution engines (see also DynamicMPF.lhs and DynamicMPF.rhs for more details). These functions should follow the ExactEvolverFactory and ApproxEvolverFactory protocols, respectively.

The ExactEvolverFactory function should take a State object as its only positional argument and should return a Evolver object, which will be used for computing the LHS of the LiL_i elements (i.e. it should produce the exact time-evolution state, ρ(t)\rho(t)).

Here, we approximate the exact time-evolved state with a fourth-order Suzuki-Trotter formula using a small time step of 0.05. We also specify some quimb-specific truncation options to bound the maximum bond dimension of the underlying tensor network as well as the minimum singular values of the split tensor network bonds.

>>> from qiskit_addon_mpf.backends.quimb_tebd import TEBDEvolver
>>> exact_evolver_factory = partial(
...     TEBDEvolver,
...     H=hamil,
...     dt=0.05,
...     order=4,
...     split_opts={"max_bond": 10, "cutoff": 1e-5},
... )

The ApproxEvolverFactory function should also take a State object as its only positional argument and additionally a keyword argument called dt to specify the time step of the time-evolution. It should also return a Evolver object which produces the approximate time-evolution states, ρki(t)\rho_{k_i}(t), where kik_i is determined by the chosen time step, dt. As such, these instances will be used for computing the RHS of the LiL_i as well as both sides of the MijM_{ij} elements.

Here, we use a second-order Suzuki-Trotter formula with the same truncation settings as before.

>>> approx_evolver_factory = partial(
...     TEBDEvolver,
...     H=hamil,
...     order=2,
...     split_opts={"max_bond": 10, "cutoff": 1e-5},
... )

Finally, we can initialize and run the setup_dynamic_lse() function to obtain the LSE described at the top.

>>> from qiskit_addon_mpf.dynamic import setup_dynamic_lse
>>> lse = setup_dynamic_lse(
...     trotter_steps,
...     time,
...     identity_factory,
...     exact_evolver_factory,
...     approx_evolver_factory,
...     initial_state,
... )
>>> print(lse.A)  
[[1.         0.99998513]
 [0.99998513 1.        ]]
>>> print(lse.b)  
[1.00001585 0.99998955]

Parameters

  • trotter_steps (list[int]) – the sequence of trotter steps to be used.
  • time (float) – the total target evolution time.
  • identity_factory (IdentityStateFactory) – a function to generate an empty State object.
  • exact_evolver_factory (ExactEvolverFactory) – a function to initialize the Evolver instance which produces the exact time-evolution state, ρ(t)\rho(t).
  • approx_evolver_factory (ApproxEvolverFactory) – a function to initialize the Evolver instance which produces the approximate time-evolution state, ρki(t)\rho_{k_i}(t), for different values of kik_i depending on the provided time step, dt.
  • initial_state (Any) – the initial state (ψin\psi_{in} or ψ0\psi_0) with respect to which to compute the elements MijM_{ij} of LSE.A and LiL_i of LSE.b. The type of this object must match the tensor network backend chosen for the previous arguments.

Returns

The LSE to find the dynamic MPF coefficients as described above.

Return type

LSE

References

[1]: S. Zhuk et al., Phys. Rev. Research 6, 033309 (2024).

https://journals.aps.org/prresearch/abstract/10.1103/PhysRevResearch.6.033309

[2]: N. Robertson et al., arXiv:2407.17405v2 (2024).

https://arxiv.org/abs/2407.17405v2


Factory Protocols

The following protocols define the function signatures for the various object factory arguments.

IdentityStateFactory

class IdentityStateFactory(*args, **kwargs)

GitHub

Bases: Protocol

The factory function protocol for constructing an identity State instance.

As explained in more detail in setup_dynamic_lse(), this factory function is called to initialize the DynamicMPF.evolution_state with an identity or empty state. This function should not take any arguments and return a State instance.

ExactEvolverFactory

class ExactEvolverFactory(*args, **kwargs)

GitHub

Bases: Protocol

The factory function protocol for constructing an exact Evolver instance.

As explained in more detail in setup_dynamic_lse(), this factory function is called to initialize the DynamicMPF.lhs instances of Evolver which produce the exact time-evolution state, ρ(t)\rho(t), when computing the elements LiL_i.

ApproxEvolverFactory

class ApproxEvolverFactory(*args, **kwargs)

GitHub

Bases: Protocol

The factory function protocol for constructing an approximate Evolver instance.

As explained in more detail in setup_dynamic_lse(), this factory function is called to initialize either the DynamicMPF.rhs instances of Evolver when computing the elements LiL_i or both sides (DynamicMPF.lhs and DynamicMPF.rhs) when computing elements MijM_{ij}. Since these approximate time evolution states depend on the Trotter step (ρki(t)\rho_{k_i}(t)), this function requires the time step of the time evolution to be provided as a keyword argument called dt.


Core algorithm

DynamicMPF

class DynamicMPF(evolution_state, lhs, rhs)

GitHub

Bases: object

The dynamic MPF algorithm.

Instantiated with a LHS and RHS Evolver this algorithm will evolve() a shared State up to a target evolution time. Afterwards, the DynamicMPF.overlap() of the time-evolved State with some initial state can be computed. See setup_dynamic_lse() for a more detailed explanation on how this is used to compute the elements MijM_{ij} and LiL_i making up the LSE of the dynamic MPF coefficients.

References

[1]: S. Zhuk et al., Phys. Rev. Research 6, 033309 (2024).

https://journals.aps.org/prresearch/abstract/10.1103/PhysRevResearch.6.033309

[2]: N. Robertson et al., arXiv:2407.17405 (2024).

https://arxiv.org/abs/2407.17405

Construct a DynamicMPF instance.

Parameters

  • evolution_state (State) – the state to be shared by the LHS and RHS time-evolution engines.
  • lhs (Evolver) – the LHS time-evolution engine.
  • rhs (Evolver) – the RHS time-evolution engine.

evolution_state

The state shared between the LHS and RHS time-evolution engines.

evolve

evolve(time)

GitHub

Evolve the dynamic MPF algorithm up to the provided time.

This actually runs the dynamic MPF algorithm by time-evolving DynamicMPF.evolution_state up to the specified time using the LHS and RHS Evolver instances.

Parameters

time (float) – the total target evolution time.

Raises

RuntimeError – if the LHS and RHS evolved times are not equal at the end.

Return type

None

lhs

The LHS time-evolution engine.

overlap

overlap(initial_state)

GitHub

Compute the overlap of DynamicMPF.evolution_state with the provided state.

Warning

The type of the provided initial_state will depend on the chosen backend used for the State and Evolver instances provided to this DynamicMPF instance. In other words, a backend may only support a specific type of initial_state objects for this overlap computation. See also the explanations of the initial_state argument to the setup_dynamic_lse() for more details.

Parameters

initial_state (Any) – the initial state with which to compute the overlap.

Raises

TypeError – if the provided initial state has an incompatible type.

Returns

The overlap of DynamicMPF.evolution_state with the provided one.

Return type

complex

rhs

The RHS time-evolution engine.

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