From 35b69c316479a6c93436f794db514777c999c2f9 Mon Sep 17 00:00:00 2001 From: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:59:26 -0500 Subject: [PATCH] [do not merge] demo new mpf docs --- docs/api/qiskit-addon-mpf/_toc.json | 101 +++++++ ...backends-quimb-circuit-circuit-evolver.mdx | 66 ++++ .../backends-quimb-circuit-circuit-state.mdx | 62 ++++ .../backends-quimb-circuit.mdx | 87 ++++++ .../backends-quimb-layers-layer-model.mdx | 88 ++++++ ...ackends-quimb-layers-layerwise-evolver.mdx | 51 ++++ .../backends-quimb-layers.mdx | 155 ++++++++++ .../backends-quimb-tebd-mpo-state.mdx | 114 +++++++ .../backends-quimb-tebd-tebd-evolver.mdx | 102 +++++++ .../qiskit-addon-mpf/backends-quimb-tebd.mdx | 101 +++++++ .../backends-tenpy-layers-layer-model.mdx | 108 +++++++ ...ackends-tenpy-layers-layerwise-evolver.mdx | 128 ++++++++ .../backends-tenpy-layers.mdx | 166 ++++++++++ .../backends-tenpy-tebd-mpo-state.mdx | 68 +++++ .../backends-tenpy-tebd-mps-neel-state.mdx | 30 ++ .../backends-tenpy-tebd-tebd-evolver.mdx | 87 ++++++ .../qiskit-addon-mpf/backends-tenpy-tebd.mdx | 123 ++++++++ docs/api/qiskit-addon-mpf/backends.mdx | 148 +++++++++ docs/api/qiskit-addon-mpf/costs.mdx | 283 ++++++++++++++++++ docs/api/qiskit-addon-mpf/dynamic.mdx | 281 +++++++++++++++++ docs/api/qiskit-addon-mpf/index.mdx | 3 + docs/api/qiskit-addon-mpf/release-notes.mdx | 25 ++ docs/api/qiskit-addon-mpf/static.mdx | 206 ++----------- public/api/qiskit-addon-mpf/objects.inv | Bin 1568 -> 4403 bytes ...skit_addon_mpf-backends-quimb_layers-2.png | Bin 0 -> 32884 bytes ...skit_addon_mpf-backends-quimb_layers-3.png | Bin 0 -> 43085 bytes ...skit_addon_mpf-backends-tenpy_layers-2.png | Bin 0 -> 32884 bytes ...skit_addon_mpf-backends-tenpy_layers-3.png | Bin 0 -> 43085 bytes 28 files changed, 2394 insertions(+), 189 deletions(-) create mode 100644 docs/api/qiskit-addon-mpf/backends-quimb-circuit-circuit-evolver.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-quimb-circuit-circuit-state.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-quimb-circuit.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-quimb-layers-layer-model.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-quimb-layers-layerwise-evolver.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-quimb-layers.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-quimb-tebd-mpo-state.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-quimb-tebd-tebd-evolver.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-quimb-tebd.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-tenpy-layers-layer-model.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-tenpy-layers-layerwise-evolver.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-tenpy-layers.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-tenpy-tebd-mpo-state.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-tenpy-tebd-mps-neel-state.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-tenpy-tebd-tebd-evolver.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends-tenpy-tebd.mdx create mode 100644 docs/api/qiskit-addon-mpf/backends.mdx create mode 100644 docs/api/qiskit-addon-mpf/costs.mdx create mode 100644 docs/api/qiskit-addon-mpf/dynamic.mdx create mode 100644 public/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-quimb_layers-2.png create mode 100644 public/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-quimb_layers-3.png create mode 100644 public/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-tenpy_layers-2.png create mode 100644 public/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-tenpy_layers-3.png diff --git a/docs/api/qiskit-addon-mpf/_toc.json b/docs/api/qiskit-addon-mpf/_toc.json index 1e496abefe0..d3bc32eb5a3 100644 --- a/docs/api/qiskit-addon-mpf/_toc.json +++ b/docs/api/qiskit-addon-mpf/_toc.json @@ -5,6 +5,107 @@ "title": "API index", "url": "/api/qiskit-addon-mpf" }, + { + "title": "qiskit_addon_mpf.backends", + "url": "/api/qiskit-addon-mpf/backends" + }, + { + "title": "qiskit_addon_mpf.backends.quimb_circuit", + "children": [ + { + "title": "Module overview", + "url": "/api/qiskit-addon-mpf/backends-quimb-circuit" + }, + { + "title": "CircuitEvolver", + "url": "/api/qiskit-addon-mpf/backends-quimb-circuit-circuit-evolver" + }, + { + "title": "CircuitState", + "url": "/api/qiskit-addon-mpf/backends-quimb-circuit-circuit-state" + } + ] + }, + { + "title": "qiskit_addon_mpf.backends.quimb_layers", + "children": [ + { + "title": "Module overview", + "url": "/api/qiskit-addon-mpf/backends-quimb-layers" + }, + { + "title": "LayerModel", + "url": "/api/qiskit-addon-mpf/backends-quimb-layers-layer-model" + }, + { + "title": "LayerwiseEvolver", + "url": "/api/qiskit-addon-mpf/backends-quimb-layers-layerwise-evolver" + } + ] + }, + { + "title": "qiskit_addon_mpf.backends.quimb_tebd", + "children": [ + { + "title": "Module overview", + "url": "/api/qiskit-addon-mpf/backends-quimb-tebd" + }, + { + "title": "MPOState", + "url": "/api/qiskit-addon-mpf/backends-quimb-tebd-mpo-state" + }, + { + "title": "TEBDEvolver", + "url": "/api/qiskit-addon-mpf/backends-quimb-tebd-tebd-evolver" + } + ] + }, + { + "title": "qiskit_addon_mpf.backends.tenpy_layers", + "children": [ + { + "title": "Module overview", + "url": "/api/qiskit-addon-mpf/backends-tenpy-layers" + }, + { + "title": "LayerModel", + "url": "/api/qiskit-addon-mpf/backends-tenpy-layers-layer-model" + }, + { + "title": "LayerwiseEvolver", + "url": "/api/qiskit-addon-mpf/backends-tenpy-layers-layerwise-evolver" + } + ] + }, + { + "title": "qiskit_addon_mpf.backends.tenpy_tebd", + "children": [ + { + "title": "Module overview", + "url": "/api/qiskit-addon-mpf/backends-tenpy-tebd" + }, + { + "title": "MPOState", + "url": "/api/qiskit-addon-mpf/backends-tenpy-tebd-mpo-state" + }, + { + "title": "MPS_neel_state", + "url": "/api/qiskit-addon-mpf/backends-tenpy-tebd-mps-neel-state" + }, + { + "title": "TEBDEvolver", + "url": "/api/qiskit-addon-mpf/backends-tenpy-tebd-tebd-evolver" + } + ] + }, + { + "title": "qiskit_addon_mpf.costs", + "url": "/api/qiskit-addon-mpf/costs" + }, + { + "title": "qiskit_addon_mpf.dynamic", + "url": "/api/qiskit-addon-mpf/dynamic" + }, { "title": "qiskit_addon_mpf.static", "url": "/api/qiskit-addon-mpf/static" diff --git a/docs/api/qiskit-addon-mpf/backends-quimb-circuit-circuit-evolver.mdx b/docs/api/qiskit-addon-mpf/backends-quimb-circuit-circuit-evolver.mdx new file mode 100644 index 00000000000..6180c28fec0 --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-quimb-circuit-circuit-evolver.mdx @@ -0,0 +1,66 @@ +--- +title: CircuitEvolver (latest version) +description: API reference for qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 1 +python_api_type: class +python_api_name: qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver +--- + +# CircuitEvolver + + + Bases: [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.interface.Evolver") + + A time-evolution engine based on quantum circuits. + + This algorithm performs time-evolution by means of successively applying a quantum circuit corresponding to a single Trotter step to its internal state. More specifically, it builds out a tensor network in the [`CircuitState`](backends-quimb-circuit-circuit-state "qiskit_addon_mpf.backends.quimb_circuit.CircuitState"). As required by the [`DynamicMPF`](dynamic#dynamicmpf "qiskit_addon_mpf.dynamic.DynamicMPF") algorithm, it tracks a left- and right-hand side of the time-evolution for computing the overlap of two circuits. Depending on [`conjugate`](#qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver.conjugate "qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver.conjugate"), an instance of this engine will apply the quantum gates of its template circuit to the corresponding side (see [`quimb_circuit`](backends-quimb-circuit#module-qiskit_addon_mpf.backends.quimb_circuit "qiskit_addon_mpf.backends.quimb_circuit") for more details). + + Initialize a [`CircuitEvolver`](#qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver "qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver") instance. + + **Parameters** + + * **evolution\_state** ([*CircuitState*](backends-quimb-circuit-circuit-state "qiskit_addon_mpf.backends.quimb_circuit.CircuitState")) – a reference to the time-evolution state. + * **circuit** (*QuantumCircuit*) – the template circuit encoding the time-evolution of a single Trotter step. This circuit **must** be parametrized (see [`Parameter`](/api/qiskit/qiskit.circuit.Parameter "(in Qiskit v1.2)") in place of the Trotter methods time step. This parameter must be named `dt`. + * **dt** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – the time step that will be used and later bound to the [`Parameter`](/api/qiskit/qiskit.circuit.Parameter "(in Qiskit v1.2)") of the `circuit` object. + + ## Attributes + + ### conjugate + + + Returns whether this time-evolver instance acts on the right-hand side. + + + ### evolved\_time + + + Returns the current evolution time. + + + ### evolution\_state + + + The time-evolution state (see also [`DynamicMPF.evolution_state`](dynamic#evolution_state "qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state")). + + + ### circuit + + + The parameterized [`QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit "(in Qiskit v1.2)") describing the Trotter step. + + + ## Methods + + ### step + + + Perform a single time step of TEBD. + + This will apply the gates of the [`circuit`](#qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver.circuit "qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver.circuit") to the [`evolution_state`](#qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver.evolution_state "qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver.evolution_state"). If [`conjugate`](#qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver.conjugate "qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver.conjugate") is `True`, it applies to [`CircuitState.lhs`](backends-quimb-circuit-circuit-state#lhs "qiskit_addon_mpf.backends.quimb_circuit.CircuitState.lhs"), otherwise to [`CircuitState.rhs`](backends-quimb-circuit-circuit-state#rhs "qiskit_addon_mpf.backends.quimb_circuit.CircuitState.rhs"). + + **Return type** + + None + + + diff --git a/docs/api/qiskit-addon-mpf/backends-quimb-circuit-circuit-state.mdx b/docs/api/qiskit-addon-mpf/backends-quimb-circuit-circuit-state.mdx new file mode 100644 index 00000000000..e281bfc87c0 --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-quimb-circuit-circuit-state.mdx @@ -0,0 +1,62 @@ +--- +title: CircuitState (latest version) +description: API reference for qiskit_addon_mpf.backends.quimb_circuit.CircuitState in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 1 +python_api_type: class +python_api_name: qiskit_addon_mpf.backends.quimb_circuit.CircuitState +--- + +# CircuitState + + + Bases: [`State`](backends#state "qiskit_addon_mpf.backends.interface.State") + + An MPO-like representation of a time-evolution state based on quantum circuits. + + This time-evolution state can be evolved on its left- and right-hand side as required by the [`DynamicMPF`](dynamic#dynamicmpf "qiskit_addon_mpf.dynamic.DynamicMPF") algorithm. + + Initialize a [`CircuitState`](#qiskit_addon_mpf.backends.quimb_circuit.CircuitState "qiskit_addon_mpf.backends.quimb_circuit.CircuitState") instance. + + ## Attributes + + ### lhs + + + The left-hand side circuit in form of a tensor network. + + + ### rhs + + + The right-hand side circuit in form of a tensor network. + + + ## Methods + + ### overlap + + + Compute the overlap of this state with the provided initial state. + + + This implementation only supports instances of [`qiskit.circuit.QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit "(in Qiskit v1.2)") for `initial_state`. + + + **Parameters** + + **initial\_state** ([*Any*](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")) – the initial state with which to compute the overlap. + + **Raises** + + [**TypeError**](https://docs.python.org/3/library/exceptions.html#TypeError "(in Python v3.13)") – if the provided initial state has an incompatible type. + + **Returns** + + The overlap of this state with the provided one. + + **Return type** + + [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)") + + + diff --git a/docs/api/qiskit-addon-mpf/backends-quimb-circuit.mdx b/docs/api/qiskit-addon-mpf/backends-quimb-circuit.mdx new file mode 100644 index 00000000000..725412498a3 --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-quimb-circuit.mdx @@ -0,0 +1,87 @@ +--- +title: quimb_circuit (latest version) +description: API reference for qiskit_addon_mpf.backends.quimb_circuit in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_mpf.backends.quimb_circuit +--- + + + + + +# Quimb circuit-based backend + +`qiskit_addon_mpf.backends.quimb_circuit` + +A circuit-based time-evolution backend using [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)"). + + + This backend is only available if the optional dependencies have been installed: + + ```python + pip install "qiskit-addon-mpf[quimb]" + ``` + + +| | | +| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | +| [`CircuitEvolver`](backends-quimb-circuit-circuit-evolver "qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver") | A time-evolution engine based on quantum circuits. | +| [`CircuitState`](backends-quimb-circuit-circuit-state "qiskit_addon_mpf.backends.quimb_circuit.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`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.Circuit "(in quimb v1.8)") representation. We can leverage this, to bypass any explicit time-evolution algorithm and instead directly encode the time-evolution in a [`QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit "(in Qiskit v1.2)") and use [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)") to compute the overlap between two such circuits. For more information, check out their guide on [Quantum Circuits](https://quimb.readthedocs.io/en/latest/tensor-circuit.html "(in quimb v1.8)"). + +## 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()`](dynamic#setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse"). + +The [`IdentityStateFactory`](dynamic#identitystatefactory "qiskit_addon_mpf.dynamic.IdentityStateFactory") protocol is already fulfilled by the [`CircuitState`](backends-quimb-circuit-circuit-state "qiskit_addon_mpf.backends.quimb_circuit.CircuitState") constructor, rendering the `identity_factory` argument trivial: + +```python +>>> from qiskit_addon_mpf.backends.quimb_circuit import CircuitState +>>> identity_factory = CircuitState +``` + +The setup of the [`CircuitEvolver`](backends-quimb-circuit-circuit-evolver "qiskit_addon_mpf.backends.quimb_circuit.CircuitEvolver") is slightly more involved. It requires a **parametrized** [`QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit "(in Qiskit v1.2)") object as its input where the [`Parameter`](/api/qiskit/qiskit.circuit.Parameter "(in Qiskit v1.2)") should take the place of the Trotter methods time step (`dt`). + +To show how such a parametrized Trotter circuit template is constructed, we reuse the same Hamiltonian and second-order Suzuki-Trotter formula as in [`quimb_layers`](backends-quimb-layers#module-qiskit_addon_mpf.backends.quimb_layers "qiskit_addon_mpf.backends.quimb_layers"). + +```python +>>> 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`](/api/qiskit/qiskit.circuit.Parameter "(in Qiskit v1.2)") as the `time` argument when constructing the actual circuits. + +```python +>>> 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`](/api/qiskit/qiskit.circuit.Parameter "(in Qiskit v1.2)") is `dt`! + + +We can choose a higher order Trotter formula for the `exact_evolver_factory`. But note, that we must once again use a parametrized circuit, even if we immediately bind its parameter when constructing the `partial` function. + +```python +>>> 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()`](dynamic#setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse"). Refer to its documentation for more details on that. + diff --git a/docs/api/qiskit-addon-mpf/backends-quimb-layers-layer-model.mdx b/docs/api/qiskit-addon-mpf/backends-quimb-layers-layer-model.mdx new file mode 100644 index 00000000000..58c0edef1ad --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-quimb-layers-layer-model.mdx @@ -0,0 +1,88 @@ +--- +title: LayerModel (latest version) +description: API reference for qiskit_addon_mpf.backends.quimb_layers.LayerModel in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 1 +python_api_type: class +python_api_name: qiskit_addon_mpf.backends.quimb_layers.LayerModel +--- + +# LayerModel + + + Bases: [`LocalHam1D`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/tensor_1d_tebd/index.html#quimb.tensor.tensor_1d_tebd.LocalHam1D "(in quimb v1.8)") + + A model for representing a layer of time-evolution interactions. + + Essentially, this class is a simple wrapper of [`quimb.tensor.LocalHam1D`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.LocalHam1D "(in quimb v1.8)"). Its main purpose is to provide a simple interface for constructing a Quimb-compatible Hamiltonian from Qiskit objects. + + Initialize a [`LayerModel`](#qiskit_addon_mpf.backends.quimb_layers.LayerModel "qiskit_addon_mpf.backends.quimb_layers.LayerModel") instance. + + Most of the arguments below are simply forwarded to [`quimb.tensor.LocalHam1D`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.LocalHam1D "(in quimb v1.8)") so check out its documentation for more details. + + **Parameters** + + * **L** – the number of qubits. + * **H2** – the two-site interactions. + * **H1** – the optional on-site interactions. + * **cyclic** – whether to apply periodic boundary conditions. + * **keep\_only\_odd** – whether to keep only odd bond interactions. For more details see [`keep_only_odd`](#qiskit_addon_mpf.backends.quimb_layers.LayerModel.keep_only_odd "qiskit_addon_mpf.backends.quimb_layers.LayerModel.keep_only_odd"). + + ## Attributes + + ### keep\_only\_odd + + + Whether to keep only interactions on bonds with odd indices. + + + ## Methods + + ### from\_quantum\_circuit + + + Construct a [`LayerModel`](#qiskit_addon_mpf.backends.quimb_layers.LayerModel "qiskit_addon_mpf.backends.quimb_layers.LayerModel") from a [`QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit "(in Qiskit v1.2)"). + + You can see an example of this function in action in the docs of `quimb_layers`. + + **Parameters** + + * **circuit** ([*QuantumCircuit*](/api/qiskit/qiskit.circuit.QuantumCircuit "(in Qiskit v1.2)")) – the quantum circuit to parse. + * **scaling\_factor** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – a factor with which to scale the term strengths. This can be used to apply (for example) a time step scaling factor. It may also be used (e.g.) to split onsite terms into two layers (even and odd) with \$0.5\$ of the strength, each. + * **keep\_only\_odd** ([*bool*](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)") *| None*) – the value to use for [`keep_only_odd`](#qiskit_addon_mpf.backends.quimb_layers.LayerModel.keep_only_odd "qiskit_addon_mpf.backends.quimb_layers.LayerModel.keep_only_odd"). + * **kwargs** – any additional keyword arguments to pass to the [`LayerModel`](#qiskit_addon_mpf.backends.quimb_layers.LayerModel "qiskit_addon_mpf.backends.quimb_layers.LayerModel") constructor. + + **Returns** + + A new LayerModel instance. + + **Raises** + + [**NotImplementedError**](https://docs.python.org/3/library/exceptions.html#NotImplementedError "(in Python v3.13)") – if an unsupported quantum gate is encountered. + + **Return type** + + [*LayerModel*](#qiskit_addon_mpf.backends.quimb_layers.LayerModel "qiskit_addon_mpf.backends.quimb_layers.model.LayerModel") + + + ### get\_gate\_expm + + + Get the local term at the sites `where`, matrix exponentiated by `x`. + + If `where` applies to an even bond index and [`keep_only_odd`](#qiskit_addon_mpf.backends.quimb_layers.LayerModel.keep_only_odd "qiskit_addon_mpf.backends.quimb_layers.LayerModel.keep_only_odd") is `True`, this method will return `None`. + + **Parameters** + + * **where** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")*\[*[*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")*,* [*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")*]*) – the pair of site indices of the local term to get. This identifies the bond index. + * **x** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – the value with which to matrix exponentiate the interaction term. + + **Returns** + + The interaction in terms of an array or `None` depending on [`keep_only_odd`](#qiskit_addon_mpf.backends.quimb_layers.LayerModel.keep_only_odd "qiskit_addon_mpf.backends.quimb_layers.LayerModel.keep_only_odd") (see above). + + **Return type** + + [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray "(in NumPy v2.1)") | None + + + diff --git a/docs/api/qiskit-addon-mpf/backends-quimb-layers-layerwise-evolver.mdx b/docs/api/qiskit-addon-mpf/backends-quimb-layers-layerwise-evolver.mdx new file mode 100644 index 00000000000..1e1efce3dd5 --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-quimb-layers-layerwise-evolver.mdx @@ -0,0 +1,51 @@ +--- +title: LayerwiseEvolver (latest version) +description: API reference for qiskit_addon_mpf.backends.quimb_layers.LayerwiseEvolver in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 1 +python_api_type: class +python_api_name: qiskit_addon_mpf.backends.quimb_layers.LayerwiseEvolver +--- + +# LayerwiseEvolver + + + Bases: [`TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.evolver.TEBDEvolver") + + A special case of the [`TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver") based on layer-wise evolution models. + + As also explained in [`quimb_layers`](backends-quimb-layers#module-qiskit_addon_mpf.backends.quimb_layers "qiskit_addon_mpf.backends.quimb_layers"), this implementation extracts the alternating even/odd bond updates implemented inside of the original [`quimb.tensor.TEBD`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD "(in quimb v1.8)") to become the end users responsibility. It does so, by replacing the single Hamiltonian provided to the [`TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver") instance with a sequence of [`LayerModel`](backends-quimb-layers-layer-model "qiskit_addon_mpf.backends.quimb_layers.LayerModel") instances. Every single instance of these encodes a single **layer** of interactions. These should enforce the alternating updates of even and odd bonds of the underlying tensor network. + + The motivation for this more complicated interface is that is provides a lot more flexbility and enables users to define custom Trotter product formulas rather than being limited to the ones implemented by Quimb directly. + + Initialize a [`LayerwiseEvolver`](#qiskit_addon_mpf.backends.quimb_layers.LayerwiseEvolver "qiskit_addon_mpf.backends.quimb_layers.LayerwiseEvolver") instance. + + **Parameters** + + * **evolution\_state** ([*quimb\_tebd.MPOState*](backends-quimb-tebd-mpo-state "qiskit_addon_mpf.backends.quimb_tebd.MPOState")) – forwarded to [`TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver"). Please refer to its documentation for more details. + * **layers** ([*list*](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")*\[*[*LayerModel*](backends-quimb-layers-layer-model "qiskit_addon_mpf.backends.quimb_layers.LayerModel")*]*) – the list of models describing single layers of interactions. See above as well as the explanations provided in [`quimb_layers`](backends-quimb-layers#module-qiskit_addon_mpf.backends.quimb_layers "qiskit_addon_mpf.backends.quimb_layers"). + * **args** – any further positional arguments will be forwarded to the [`TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver") constructor. + * **kwargs** – any further keyword arguments will be forwarded to the [`TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver") constructor. + + ## Attributes + + ### layers + + + The layers of interactions used to implement the time-evolution. + + + ## Methods + + ### step + + + Perform a single time step of TEBD. + + This will iterate over the [`layers`](#qiskit_addon_mpf.backends.quimb_layers.LayerwiseEvolver.layers "qiskit_addon_mpf.backends.quimb_layers.LayerwiseEvolver.layers") and apply their interaction to the internal state. + + **Return type** + + None + + + diff --git a/docs/api/qiskit-addon-mpf/backends-quimb-layers.mdx b/docs/api/qiskit-addon-mpf/backends-quimb-layers.mdx new file mode 100644 index 00000000000..81179a47c6d --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-quimb-layers.mdx @@ -0,0 +1,155 @@ +--- +title: quimb_layers (latest version) +description: API reference for qiskit_addon_mpf.backends.quimb_layers in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_mpf.backends.quimb_layers +--- + + + + + +# Quimb layer-based backend + +`qiskit_addon_mpf.backends.quimb_layers` + +A layer-wise time-evolution backend using [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)"). + + + This backend is only available if the optional dependencies have been installed: + + ```python + pip install "qiskit-addon-mpf[quimb]" + ``` + + +| | | +| ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`LayerwiseEvolver`](backends-quimb-layers-layerwise-evolver "qiskit_addon_mpf.backends.quimb_layers.LayerwiseEvolver") | A special case of the [`TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver") based on layer-wise evolution models. | +| [`LayerModel`](backends-quimb-layers-layer-model "qiskit_addon_mpf.backends.quimb_layers.LayerModel") | A model for representing a layer of time-evolution interactions. | + +## Underlying method + +This module provides a time-evolution backend similar to the TEBD-based one provided by the [`quimb_tebd`](backends-quimb-tebd#module-qiskit_addon_mpf.backends.quimb_tebd "qiskit_addon_mpf.backends.quimb_tebd") module. The main difference is that this module gives the user full flexibility for defining their product formulas, thereby not limiting them to the options built into the [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)") library. + +At its core, the algorithm provided by this module is still a TEBD \[1] algorithm. However, rather than enforcing the alternating updates to the even and odd bonds of the time-evolution state (see also [`quimb_tebd.TEBDEvolver.sweep()`](backends-quimb-tebd-tebd-evolver#sweep "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver.sweep")) this implementation outsources the responsibility of updating bonds in alternating fashion to the definition of multiple time-evolution **layers**. + +This is best explained with an example. Let us assume, we have some generic Hamiltonian acting on a 1-dimensional chain of sites. + + + Below we are very deliberate about the order of the Hamiltonian’s Pauli terms because this directly impacts the structure of the time-evolution circuit later on. + + +```python +>>> from qiskit.quantum_info import SparsePauliOp +>>> hamil = SparsePauliOp.from_sparse_list( +... [("ZZ", (i, i+1), 1.0) for i in range(1, 9, 2)] + +... [("Z", (i,), 0.5) for i in range(10)] + +... [("ZZ", (i, i+1), 1.0) for i in range(0, 9, 2)], +... num_qubits=10, +... ) +``` + +Let us now inspect the time-evolution circuit of this Hamiltonian using a second-order Suzuki-Trotter formula. + +```python +>>> from qiskit.synthesis import SuzukiTrotter +>>> from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit +>>> circuit = generate_time_evolution_circuit(hamil, time=1.0, synthesis=SuzukiTrotter(order=2)) +>>> circuit.draw("mpl") +
+``` + +![../\_images/qiskit\_addon\_mpf-backends-quimb\_layers-2.png](/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-quimb_layers-2.png) + +In the circuit above, we can clearly identify its layer-wise structure. We can emphasize this further, by splitting the circuit into multiple layers as shown below (we recombine the `layers` into a single circuit with barriers between them to ease the visualization). + +```python +>>> from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types +>>> layers = slice_by_gate_types(circuit) +>>> combine_slices(layers, include_barriers=True).draw("mpl") +
+``` + +![../\_images/qiskit\_addon\_mpf-backends-quimb\_layers-3.png](/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-quimb_layers-3.png) + + + The asymmetry of the central layers is a result of the implementation of Qiskit’s [`SuzukiTrotter`](/api/qiskit/qiskit.synthesis.SuzukiTrotter "(in Qiskit v1.2)") formula. In its second-order form, it combines the two half-time evolutions of the final term in the Hamiltonian into a single one of twice the length. We could transpile this circuit to collapse all such subequent gates in the central two layers (just like the last one), but for the sake of simplicity of this example, we will not do that here. + + +It is not possible to instruct Quimb’s TEBD algorithm to simulate the exact structure of the circuit shown above. The reason for that is a limitation in its interface, as it only accepts the full Hamiltonian to be provided which is then time-evolved using pre-defined Trotter formulas. However, in doing so it does not treat the order of the Pauli terms in a Hamiltonian with any significance (like we do here). + +If one wants to compute the dynamic MPF coefficients of a time-evolution employing a product formula structure other than the ones implemented in quimb (like the example above), then one can use the time-evolution algorithm provided by this module. Rather than taking a single monolithic Hamiltonian whose time-evolution is to be modeled, the [`LayerwiseEvolver`](backends-quimb-layers-layerwise-evolver "qiskit_addon_mpf.backends.quimb_layers.LayerwiseEvolver") accepts a list of [`LayerModel`](backends-quimb-layers-layer-model "qiskit_addon_mpf.backends.quimb_layers.LayerModel") objects, each one describing an individual layer of the product formula. This gives the user full flexibility in defining the Trotter decomposition down to the most granular level. + +However, caution must be applied to ensure that the property of TEBD to update even and odd bonds in an alternating manner is still guaranteed. Luckily, for quantum circuits consisting of at most two-qubit gates, this property is satisfied by construction. + +## Code example + +In this section, we build up on the example above and show how to take a custom Trotter formula and use it to construct a [`LayerwiseEvolver`](backends-quimb-layers-layerwise-evolver "qiskit_addon_mpf.backends.quimb_layers.LayerwiseEvolver") which can be used to replace the [`quimb_tebd.TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver") in the workflow described in [`quimb_tebd`](backends-quimb-tebd#module-qiskit_addon_mpf.backends.quimb_tebd "qiskit_addon_mpf.backends.quimb_tebd"). + + + The overall workflow of using this module is the same as of the [`quimb_tebd`](backends-quimb-tebd#module-qiskit_addon_mpf.backends.quimb_tebd "qiskit_addon_mpf.backends.quimb_tebd") module, so be sure to read those instructions as well. + + +Simply put, we must convert each one of the circuit `layers` (see above) into a [`LayerModel`](backends-quimb-layers-layer-model "qiskit_addon_mpf.backends.quimb_layers.LayerModel") instance. For this purpose, we can use its [`from_quantum_circuit()`](backends-quimb-layers-layer-model#from_quantum_circuit "qiskit_addon_mpf.backends.quimb_layers.LayerModel.from_quantum_circuit") method. + +```python +>>> from qiskit_addon_mpf.backends.quimb_layers import LayerModel +>>> model0 = LayerModel.from_quantum_circuit(layers[0]) +>>> layer_models = [model0] +``` + +In the code above you can see how simple the conversion is for layers which contain only two-qubit gates acting on mutually exclusive qubits (which layers of depth 1 guarantee). + +However, we must be more careful with layers including single-qubit gates. The reason for that is that the TEBD algorithm underlying the [`LayerwiseEvolver`](backends-quimb-layers-layerwise-evolver "qiskit_addon_mpf.backends.quimb_layers.LayerwiseEvolver") must update even and odd bonds in an alternating manner. And because single-qubit gates are not applied on a site, but instead are split in half and applied to the bonds on either side, a layer of single-qubit gates acting on all qubits would break this assumption. + +To circumvent this problem, we can take any layer consisting of only single-qubit gates, and apply twice (once on the even and once on the odd bonds) while scaling each one with a factor of `0.5`. + +```python +>>> model1a = LayerModel.from_quantum_circuit(layers[1], keep_only_odd=True, scaling_factor=0.5) +>>> model1b = LayerModel.from_quantum_circuit(layers[1], keep_only_odd=False, scaling_factor=0.5) +>>> layer_models.extend([model1a, model1b]) +``` + +Now that we know how to treat layers consisting of two-qubit and single-qubit gates, we can transform the remaining layers. + +```python +>>> for layer in layers[2:]: +... num_qubits = len(layer.data[0].qubits) +... if num_qubits == 2: +... layer_models.append(LayerModel.from_quantum_circuit(layer)) +... else: +... layer_models.append( +... LayerModel.from_quantum_circuit(layer, keep_only_odd=True, scaling_factor=0.5) +... ) +... layer_models.append( +... LayerModel.from_quantum_circuit(layer, keep_only_odd=False, scaling_factor=0.5) +... ) +>>> assert len(layer_models) == 8 +``` + +In the end, we have 8 [`LayerModel`](backends-quimb-layers-layer-model "qiskit_addon_mpf.backends.quimb_layers.LayerModel")’s, one for each of the 4 two-qubit layers, and two for each of the 2 single-qubit layers. + +Finally, we can define our [`ApproxEvolverFactory`](dynamic#approxevolverfactory "qiskit_addon_mpf.dynamic.ApproxEvolverFactory") protocol to be used within the [`setup_dynamic_lse()`](dynamic#setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse") function. + +```python +>>> from functools import partial +>>> from qiskit_addon_mpf.backends.quimb_layers import LayerwiseEvolver +>>> approx_evolver_factory = partial( +... LayerwiseEvolver, +... layers=layer_models, +... split_opts={"max_bond": 10, "cutoff": 1e-5}, +... ) +``` + + + It should be noted, that in this workflow we have not yet fixed the time step used by the Trotter formula. We have also only set up a single repetition of the Trotter formula as the rest will be done by the internal [`DynamicMPF`](dynamic#dynamicmpf "qiskit_addon_mpf.dynamic.DynamicMPF") algorithm, executed during [`setup_dynamic_lse()`](dynamic#setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse"). + + +Of course, you could also use this to specify a [`ExactEvolverFactory`](dynamic#exactevolverfactory "qiskit_addon_mpf.dynamic.ExactEvolverFactory"). But you can also mix-and-match a [`quimb_layers.LayerwiseEvolver`](backends-quimb-layers-layerwise-evolver "qiskit_addon_mpf.backends.quimb_layers.LayerwiseEvolver") with a [`quimb_tebd.TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver"). + +## Resources + +\[1]: [https://en.wikipedia.org/wiki/Time-evolving\_block\_decimation](https://en.wikipedia.org/wiki/Time-evolving_block_decimation) + diff --git a/docs/api/qiskit-addon-mpf/backends-quimb-tebd-mpo-state.mdx b/docs/api/qiskit-addon-mpf/backends-quimb-tebd-mpo-state.mdx new file mode 100644 index 00000000000..bda4b9e0cdf --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-quimb-tebd-mpo-state.mdx @@ -0,0 +1,114 @@ +--- +title: MPOState (latest version) +description: API reference for qiskit_addon_mpf.backends.quimb_tebd.MPOState in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 1 +python_api_type: class +python_api_name: qiskit_addon_mpf.backends.quimb_tebd.MPOState +--- + +# MPOState + + + Bases: [`MatrixProductOperator`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/tensor_1d/index.html#quimb.tensor.tensor_1d.MatrixProductOperator "(in quimb v1.8)"), [`State`](backends#state "qiskit_addon_mpf.backends.interface.State") + + An MPO enforcing the Vidal gauge. + + This specialization of quimb’s existing [`quimb.tensor.MatrixProductOperator`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.MatrixProductOperator "(in quimb v1.8)") enforces the Vidal gauge throughout its existence. This ensures a stable behavior of the [`DynamicMPF`](dynamic#dynamicmpf "qiskit_addon_mpf.dynamic.DynamicMPF") algorithm when using the [`TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver"). + + Initialize a [`MPOState`](#qiskit_addon_mpf.backends.quimb_tebd.MPOState "qiskit_addon_mpf.backends.quimb_tebd.MPOState") instance. + + + All arguments (positional and keyword) are simply forwarded to the [`quimb.tensor.MatrixProductOperator`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.MatrixProductOperator "(in quimb v1.8)") constructor. Additionally, the [`vidal_singular_values`](#qiskit_addon_mpf.backends.quimb_tebd.MPOState.vidal_singular_values "qiskit_addon_mpf.backends.quimb_tebd.MPOState.vidal_singular_values") attribute gets initialized to a list of empty lists of length equal to the number of sites in this MPO. + + + **Parameters** + + * **args** – all positional arguments will be forwarded to the [`quimb.tensor.MatrixProductState`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.MatrixProductState "(in quimb v1.8)") constructor. + * **kwargs** – all keyword arguments will be forwarded to the [`quimb.tensor.MatrixProductState`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.MatrixProductState "(in quimb v1.8)") constructor. + + ## Attributes + + ### vidal\_singular\_values + + + A nested list of singular values. The outer list is of equal length as this MPO itself ([`quimb.tensor.TensorNetwork1D.L`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TensorNetwork1D.L "(in quimb v1.8)")). Every item is another list of all the singular values for determining the Vidal gauge at that site. + + + ## Methods + + ### gate\_split + + + Apply a two-site gate and contract it back into the MPO. + + The basic principle of this method is the same as that of [`quimb.tensor.MatrixProductState.gate_split()`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.MatrixProductState.gate_split "(in quimb v1.8)"). However, the implementation ensures that the Vidal gauge is conserved. + + **Parameters** + + * **gate** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray "(in NumPy v2.1)")) – the gate to be applied to the MPO. Its shape should be either `(d**2, d**2)` for a physical dimension of `d`, or a reshaped version thereof. + + * **where** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")*\[*[*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")*,* [*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")*]*) – the indices of the sites where the gate should be applied. + + * **inplace** ([*bool*](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")) – whether to perform the gate application in-place or return a new [`MPOState`](#qiskit_addon_mpf.backends.quimb_tebd.MPOState "qiskit_addon_mpf.backends.quimb_tebd.MPOState") with the gate applied to it. + + * **conj** ([*bool*](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")) – + + whether the gate should be applied to the lower (`conj=False`, the default, [`lower_ind()`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/tensor_arbgeom/index.html#quimb.tensor.tensor_arbgeom.TensorNetworkGenOperator.lower_ind "(in quimb v1.8)")) or upper (`conj=True`, [`upper_ind()`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/tensor_arbgeom/index.html#quimb.tensor.tensor_arbgeom.TensorNetworkGenOperator.upper_ind "(in quimb v1.8)")) indices of the underlying MPO. + + + This is essentially how the LHS and RHS of the [`DynamicMPF`](dynamic#dynamicmpf "qiskit_addon_mpf.dynamic.DynamicMPF") are differentiated, by passing their [`Evolver.conjugate`](backends#conjugate "qiskit_addon_mpf.backends.Evolver.conjugate") property to this argument. + + + * **split\_opts** – additional keyword arguments that will be forwarded to the [`quimb.tensor.tensor_split()`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.tensor_split "(in quimb v1.8)") function. These can be used to affect the truncation of the tensor before it gets contracted back into the MPO. + + **Returns** + + The [`MPOState`](#qiskit_addon_mpf.backends.quimb_tebd.MPOState "qiskit_addon_mpf.backends.quimb_tebd.MPOState") with the `gate` applied and contracted. + + **Return type** + + [*MPOState*](#qiskit_addon_mpf.backends.quimb_tebd.MPOState "qiskit_addon_mpf.backends.quimb_tebd.state.MPOState") + + + ### gate\_split\_ + + + **Parameters** + + * **gate** (*np.ndarray*) + * **where** ([*tuple*](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")*\[*[*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")*,* [*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")*]*) + * **inplace** ([*bool*](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")) + * **conj** ([*bool*](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")) + + **Return type** + + [MPOState](#qiskit_addon_mpf.backends.quimb_tebd.MPOState "qiskit_addon_mpf.backends.quimb_tebd.MPOState") + + + ### overlap + + + Compute the overlap of this state with the provided initial state. + + + This implementation only supports instances of [`quimb.tensor.MatrixProductState`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.MatrixProductState "(in quimb v1.8)") for `initial_state`. + + + **Parameters** + + **initial\_state** ([*Any*](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")) – the initial state with which to compute the overlap. + + **Raises** + + [**TypeError**](https://docs.python.org/3/library/exceptions.html#TypeError "(in Python v3.13)") – if the provided initial state has an incompatible type. + + **Returns** + + The overlap of this state with the provided one. + + **Return type** + + [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)") + + + diff --git a/docs/api/qiskit-addon-mpf/backends-quimb-tebd-tebd-evolver.mdx b/docs/api/qiskit-addon-mpf/backends-quimb-tebd-tebd-evolver.mdx new file mode 100644 index 00000000000..5c7f124c482 --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-quimb-tebd-tebd-evolver.mdx @@ -0,0 +1,102 @@ +--- +title: TEBDEvolver (latest version) +description: API reference for qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 1 +python_api_type: class +python_api_name: qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver +--- + +# TEBDEvolver + + + Bases: [`TEBD`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/tensor_1d_tebd/index.html#quimb.tensor.tensor_1d_tebd.TEBD "(in quimb v1.8)"), [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.interface.Evolver") + + A TEBD algorithm for evolving an internal MPO. + + As discussed in more detail in [`quimb_tebd`](backends-quimb-tebd#module-qiskit_addon_mpf.backends.quimb_tebd "qiskit_addon_mpf.backends.quimb_tebd"), this extension of quimb’s existing [`quimb.tensor.TEBD`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD "(in quimb v1.8)") implementation time-evolves an internal matrix product operator (MPO) rather than the conventional matrix product state (MPS). + + More concretely, the internal object is expected to be an [`MPOState`](backends-quimb-tebd-mpo-state "qiskit_addon_mpf.backends.quimb_tebd.MPOState"). + + + The API of this class is actually much larger than shown here, because it inherits additional methods from the [`quimb.tensor.TEBD`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD "(in quimb v1.8)") base class. However, we do not duplicate that API here. + + + Initialize a [`TEBDEvolver`](#qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver") instance. + + **Parameters** + + * **evolution\_state** ([*MPOState*](backends-quimb-tebd-mpo-state "qiskit_addon_mpf.backends.quimb_tebd.MPOState")) – + + a reference to the time-evolution state. This overwrites the `p0` argument of the underlying [`quimb.tensor.TEBD`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD "(in quimb v1.8)") class. + + + In contrast to the default behavior, this state will **NOT** be canonicalized. Instead, it is taken as is and is kept **by reference** (i.e. no copy is created). This ensures that the same object can be shared between two instances of this class, as required by the [`DynamicMPF`](dynamic#dynamicmpf "qiskit_addon_mpf.dynamic.DynamicMPF") algorithm. + + + * **args** – any further positional arguments will be forwarded to the [`quimb.tensor.TEBD`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD "(in quimb v1.8)") constructor. + + * **order** ([*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")) – the order of the builtin Suzuki-Trotter formula to use during time evolution. This will be the value forwarded to the [`quimb.tensor.TEBD.step()`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD.step "(in quimb v1.8)") method. + + * **kwargs** – any further keyword arguments will be forwarded to the [`quimb.tensor.TEBD`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD "(in quimb v1.8)") constructor. + + ## Attributes + + ### conjugate + + + Returns whether this time-evolver instance acts on the right-hand side. + + + ### evolved\_time + + + Returns the current evolution time. + + + ## Methods + + ### step + + + Perform a single time step of TEBD. + + This essentially calls [`quimb.tensor.TEBD.step()`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD.step "(in quimb v1.8)") and forwards the value of the `order` attribute that was provided upon construction. + + **Return type** + + None + + + ### sweep + + + Perform a single sweep of the TEBD algorithm \[1]. + + The TEBD algorithm updates the even and odd bonds of the underlying tensor network in alternating fashion. In the implementation of the [`quimb.tensor.TEBD`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD "(in quimb v1.8)") base class, this is realized in the form of alternating “sweeps” in left and right directions over the internal state. + + We are overwriting the behavior of this method in this subclass, in order to call the specialized [`gate_split()`](backends-quimb-tebd-mpo-state#gate_split "qiskit_addon_mpf.backends.quimb_tebd.MPOState.gate_split") method. + + **Parameters** + + * **direction** ([*Literal*](https://docs.python.org/3/library/typing.html#typing.Literal "(in Python v3.13)")*\['left', 'right']*) – the direction of the sweep. This must be either of the literal strings, `"left"` or `"right"`. + * **dt\_frac** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – what fraction of the internal time step (`dt`) to time-evolve for. This is how any builtin Suzuki-Trotter formula specifies its splitting. + * **dt** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)") *| None*) – an optional value to overwrite the internal time step. + * **queue** ([*bool*](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")) – setting this to `True` will raise a [`NotImplementedError`](https://docs.python.org/3/library/exceptions.html#NotImplementedError "(in Python v3.13)"). + + **Raises** + + * [**NotImplementedError**](https://docs.python.org/3/library/exceptions.html#NotImplementedError "(in Python v3.13)") – if `queue=True`. + * [**NotImplementedError**](https://docs.python.org/3/library/exceptions.html#NotImplementedError "(in Python v3.13)") – if [`cyclic`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD.cyclic "(in quimb v1.8)") is `True`. + * [**NotImplementedError**](https://docs.python.org/3/library/exceptions.html#NotImplementedError "(in Python v3.13)") – if [`imag`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD.imag "(in quimb v1.8)") is `True`. + * [**RuntimeError**](https://docs.python.org/3/library/exceptions.html#RuntimeError "(in Python v3.13)") – if an invalid `direction` is provided. + + **Return type** + + None + + **References** + + \[1]: [https://en.wikipedia.org/wiki/Time-evolving\_block\_decimation](https://en.wikipedia.org/wiki/Time-evolving_block_decimation) + + + diff --git a/docs/api/qiskit-addon-mpf/backends-quimb-tebd.mdx b/docs/api/qiskit-addon-mpf/backends-quimb-tebd.mdx new file mode 100644 index 00000000000..ebfb7bbe35f --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-quimb-tebd.mdx @@ -0,0 +1,101 @@ +--- +title: quimb_tebd (latest version) +description: API reference for qiskit_addon_mpf.backends.quimb_tebd in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_mpf.backends.quimb_tebd +--- + + + + + +# Quimb TEBD backend + +`qiskit_addon_mpf.backends.quimb_tebd` + +A [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)")-based TEBD backend. + + + This backend is only available if the optional dependencies have been installed: + + ```python + pip install "qiskit-addon-mpf[quimb]" + ``` + + +| | | +| ---------------------------------------------------------------------------------------------------- | ---------------------------------------------- | +| [`TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver") | A TEBD algorithm for evolving an internal MPO. | +| [`MPOState`](backends-quimb-tebd-mpo-state "qiskit_addon_mpf.backends.quimb_tebd.MPOState") | An MPO enforcing the Vidal gauge. | + +## Underlying method + +This module provides a time-evolution backend for computing dynamic MPF coefficients based on the time-evolving block decimation (TEBD) algorithm \[1] implemented in the [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)") tensor network library. + +The classes provided by this module serve two purposes: + +1. Connecting [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)")’s implementation to the interface set out by [`qiskit_addon_mpf.backends`](backends#module-qiskit_addon_mpf.backends "qiskit_addon_mpf.backends"). +2. Extending [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)")’s TEBD implementation to handle an internal MPO (rather than MPS) state (see also [`State`](backends#state "qiskit_addon_mpf.backends.State") for more details). + +In the simplest sense, this module provides a straight-forward extension of the TEBD algorithm to evolve an internal MPO state. As such, if you wish to use this backend for your dynamic MPF algorithm, you must encode the Hamiltonian that you wish to time-evolve, in a [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)")-native form. To be more concrete, the [`TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver") class (which is a subclass of [`quimb.tensor.TEBD`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD "(in quimb v1.8)")) works with a Hamiltonian in the form of a [`quimb.tensor.LocalHam1D`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.LocalHam1D "(in quimb v1.8)"). Quimb provides a number of convenience methods for constructing such Hamiltonians in its [`quimb.tensor.tensor_builder`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/tensor_builder/index.html#module-quimb.tensor.tensor_builder "(in quimb v1.8)") module. If none of those fulfill your needs, you can consider using the [`LayerModel`](backends-quimb-layers-layer-model "qiskit_addon_mpf.backends.quimb_layers.LayerModel") class which implements some conversion methods from Qiskit-native objects. + +## 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()`](dynamic#setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse"). + +First, we create the `identity_factory` which has to match the [`IdentityStateFactory`](dynamic#identitystatefactory "qiskit_addon_mpf.dynamic.IdentityStateFactory") protocol. We do so simply by using the [`quimb.tensor.MPO_identity()`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.MPO_identity "(in quimb v1.8)") function and wrapping the resulting [`quimb.tensor.MatrixProductOperator`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.MatrixProductOperator "(in quimb v1.8)") with our custom [`MPOState`](backends-quimb-tebd-mpo-state "qiskit_addon_mpf.backends.quimb_tebd.MPOState") interface. + +```python +>>> from qiskit_addon_mpf.backends.quimb_tebd import MPOState +>>> from quimb.tensor import MPO_identity +>>> num_qubits = 10 +>>> identity_factory = lambda: MPOState(MPO_identity(num_qubits)) +``` + +Next, before being able to define the [`ExactEvolverFactory`](dynamic#exactevolverfactory "qiskit_addon_mpf.dynamic.ExactEvolverFactory") and [`ApproxEvolverFactory`](dynamic#approxevolverfactory "qiskit_addon_mpf.dynamic.ApproxEvolverFactory") protocols, we must define the Hamiltonian which we would like to time-evolve. Here, we simply choose one of [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)")’s convenience methods. + +```python +>>> from quimb.tensor import ham_1d_heis +>>> hamil = ham_1d_heis(num_qubits, 0.8, 0.3, cyclic=False) +``` + +We can now construct the exact and approximate time-evolution instance factories. To do so, we can simply use [`functools.partial()`](https://docs.python.org/3/library/functools.html#functools.partial "(in Python v3.13)") to bind the pre-defined values of the [`TEBDEvolver`](backends-quimb-tebd-tebd-evolver "qiskit_addon_mpf.backends.quimb_tebd.TEBDEvolver") initializer, reducing it to the correct interface as expected by the [`ExactEvolverFactory`](dynamic#exactevolverfactory "qiskit_addon_mpf.dynamic.ExactEvolverFactory") and [`ApproxEvolverFactory`](dynamic#approxevolverfactory "qiskit_addon_mpf.dynamic.ApproxEvolverFactory") protocols, respectively. + +```python +>>> from functools import partial +>>> from qiskit_addon_mpf.backends.quimb_tebd import TEBDEvolver +>>> exact_evolver_factory = partial( +... TEBDEvolver, +... H=hamil, +... dt=0.05, +... order=4, +... ) +``` + +Notice, how we have fixed the `dt` value to a small time step and have used a higher-order Suzuki-Trotter decomposition to mimic the exact time evolution above. + +Below, we do not fix the `dt` value and use only a second-order Suzuki-Trotter formula for the approximate time evolution. Additionally, we also specify some truncation settings. + +```python +>>> approx_evolver_factory = partial( +... TEBDEvolver, +... H=hamil, +... order=2, +... split_opts={"max_bond": 10, "cutoff": 1e-5}, +... ) +``` + +Of course, you are not limited to the examples shown here, and we encourage you to play around with the other settings provided by the [`quimb.tensor.TEBD`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/index.html#quimb.tensor.TEBD "(in quimb v1.8)") implementation. + +## Limitations + +Finally, we point out a few known limitations on what kind of Hamiltonians can be treated by this backend: + +* all interactions must be 1-dimensional +* the interactions must be acylic + +## Resources + +\[1]: [https://en.wikipedia.org/wiki/Time-evolving\_block\_decimation](https://en.wikipedia.org/wiki/Time-evolving_block_decimation) + diff --git a/docs/api/qiskit-addon-mpf/backends-tenpy-layers-layer-model.mdx b/docs/api/qiskit-addon-mpf/backends-tenpy-layers-layer-model.mdx new file mode 100644 index 00000000000..f10c3b2b65d --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-tenpy-layers-layer-model.mdx @@ -0,0 +1,108 @@ +--- +title: LayerModel (latest version) +description: API reference for qiskit_addon_mpf.backends.tenpy_layers.LayerModel in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 1 +python_api_type: class +python_api_name: qiskit_addon_mpf.backends.tenpy_layers.LayerModel +--- + +# LayerModel + + + Bases: [`CouplingMPOModel`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.models.model.CouplingMPOModel.html#tenpy.models.model.CouplingMPOModel "(in TeNPy v1.0.4)"), [`NearestNeighborModel`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.models.model.NearestNeighborModel.html#tenpy.models.model.NearestNeighborModel "(in TeNPy v1.0.4)") + + A model for representing a layer of time-evolution interactions. + + Essentially, this class is a simple wrapper of [`tenpy.models.model.CouplingMPOModel`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.models.model.CouplingMPOModel.html#tenpy.models.model.CouplingMPOModel "(in TeNPy v1.0.4)") and [`tenpy.models.model.NearestNeighborModel`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.models.model.NearestNeighborModel.html#tenpy.models.model.NearestNeighborModel "(in TeNPy v1.0.4)"). Its main purpose is to provide a simple interface for constructing a TeNPy-compatible Hamiltonian from Qiskit objects. + + ## Attributes + + ## Methods + + ### calc\_H\_bond + + + Calculate the interaction Hamiltonian based on the coupling and onsite terms. + + Essentially, this class overwrites [`calc_H_bond()`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.models.model.CouplingModel.html#tenpy.models.model.CouplingModel.calc_H_bond "(in TeNPy v1.0.4)") and takes care of removing even or odd bond interaction Hamiltonians depending on the value of `keep_only_odd` (see [`tenpy_layers`](backends-tenpy-layers#module-qiskit_addon_mpf.backends.tenpy_layers "qiskit_addon_mpf.backends.tenpy_layers") for more details). + + **Parameters** + + **tol\_zero** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – the threshold for values considered to be zero. + + **Returns** + + The list of interaction Hamiltonians for all bonds. + + **Return type** + + [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)") + + + ### from\_quantum\_circuit + + + Construct a [`LayerModel`](#qiskit_addon_mpf.backends.tenpy_layers.LayerModel "qiskit_addon_mpf.backends.tenpy_layers.LayerModel") from a [`QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit "(in Qiskit v1.2)"). + + You can see an example of this function in action in the docs of `tenpy_layers`. + + **Parameters** + + * **circuit** ([*QuantumCircuit*](/api/qiskit/qiskit.circuit.QuantumCircuit "(in Qiskit v1.2)")) – the quantum circuit to parse. + * **scaling\_factor** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – a factor with which to scale the term strengths. This can be used to apply (for example) a time step scaling factor. It may also be used (e.g.) to split onsite terms into two layers (even and odd) with \$0.5\$ of the strength, each. + * **kwargs** – any additional keyword arguments to pass to the [`LayerModel`](#qiskit_addon_mpf.backends.tenpy_layers.LayerModel "qiskit_addon_mpf.backends.tenpy_layers.LayerModel") constructor. + + **Returns** + + A new LayerModel instance. + + **Raises** + + [**NotImplementedError**](https://docs.python.org/3/library/exceptions.html#NotImplementedError "(in Python v3.13)") – if an unsupported quantum gate is encountered. + + **Return type** + + [*LayerModel*](#qiskit_addon_mpf.backends.tenpy_layers.LayerModel "qiskit_addon_mpf.backends.tenpy_layers.model.LayerModel") + + + ### init\_sites + + + Initializes the sites of this Hamiltonian. + + See [`init_sites()`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.models.model.CouplingMPOModel.html#tenpy.models.model.CouplingMPOModel.init_sites "(in TeNPy v1.0.4)") for more details. + + + Currently, this enforces `Sz` conservation on all sites. + + + **Parameters** + + **model\_params** ([*Config*](https://tenpy.readthedocs.io/en/latest/reference/tenpy.tools.params.Config.html#tenpy.tools.params.Config "(in TeNPy v1.0.4)")) – the model parameters. + + **Returns** + + The site to be used internally. + + **Return type** + + [*Site*](https://tenpy.readthedocs.io/en/latest/reference/tenpy.networks.site.Site.html#tenpy.networks.site.Site "(in TeNPy v1.0.4)") + + + ### init\_terms + + + Initializes the terms of this Hamiltonian. + + See [`init_terms()`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.models.model.CouplingMPOModel.html#tenpy.models.model.CouplingMPOModel.init_terms "(in TeNPy v1.0.4)") for more details. + + **Parameters** + + **model\_params** ([*Config*](https://tenpy.readthedocs.io/en/latest/reference/tenpy.tools.params.Config.html#tenpy.tools.params.Config "(in TeNPy v1.0.4)")) – the model parameters. + + **Return type** + + None + + + diff --git a/docs/api/qiskit-addon-mpf/backends-tenpy-layers-layerwise-evolver.mdx b/docs/api/qiskit-addon-mpf/backends-tenpy-layers-layerwise-evolver.mdx new file mode 100644 index 00000000000..b357de96af0 --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-tenpy-layers-layerwise-evolver.mdx @@ -0,0 +1,128 @@ +--- +title: LayerwiseEvolver (latest version) +description: API reference for qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 1 +python_api_type: class +python_api_name: qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver +--- + +# LayerwiseEvolver + + + Bases: [`TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.evolver.TEBDEvolver") + + A special case of the [`TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver") based on layer-wise evolution models. + + As also explained in [`tenpy_layers`](backends-tenpy-layers#module-qiskit_addon_mpf.backends.tenpy_layers "qiskit_addon_mpf.backends.tenpy_layers"), this implementation extracts the alternating even/odd bond updates implemented inside of the original [`TEBDEngine`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine "(in TeNPy v1.0.4)") to become the end users responsibility. It does so, by replacing the single Hamiltonian provided to the [`TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver") instance with a sequence of [`LayerModel`](backends-tenpy-layers-layer-model "qiskit_addon_mpf.backends.tenpy_layers.LayerModel") instances. Every single instance of these encodes a single **layer** of interactions. These should enforce the alternating updates of even and odd bonds of the underlying tensor network. + + The motivation for this more complicated interface is that is provides a lot more flexbility and enables users to define custom Trotter product formulas rather than being limited to the ones implemented by TeNPy directly. + + Initialize a [`LayerwiseEvolver`](#qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver "qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver") instance. + + **Parameters** + + * **evolution\_state** ([*tenpy\_tebd.MPOState*](backends-tenpy-tebd-mpo-state "qiskit_addon_mpf.backends.tenpy_tebd.MPOState")) – forwarded to [`TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver"). Please refer to its documentation for more details. + * **layers** ([*list*](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")*\[*[*LayerModel*](backends-tenpy-layers-layer-model "qiskit_addon_mpf.backends.tenpy_layers.LayerModel")*]*) – the list of models describing single layers of interactions. See above as well as the explanations provided in [`tenpy_layers`](backends-tenpy-layers#module-qiskit_addon_mpf.backends.tenpy_layers "qiskit_addon_mpf.backends.tenpy_layers"). + * **args** – any further positional arguments will be forwarded to the [`TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver") constructor. + * **kwargs** – any further keyword arguments will be forwarded to the [`TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver") constructor. + + ## Attributes + + ### layers + + + The layers of interactions used to implement the time-evolution. + + + ### dt + + + The time step to be used by this time-evolution instance. + + + ## Methods + + ### calc\_U + + + Calculates the local bond updates. + + This adapts [`calc_U()`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine.calc_U "(in TeNPy v1.0.4)") to work with the layer-wise implementation. + + **Parameters** + + * **order** ([*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")) – this is being ignored. + * **delta\_t** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – the time-step to use. + * **type\_evo** ([*str*](https://docs.python.org/3/library/stdtypes.html#str "(in Python v3.13)")) – the type of time-evolution. Imaginary time-evolution is not supported at this time. + * **E\_offset** ([*list*](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")*\[*[*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")*] | None*) – a constant energy offset to be applied. + + **Return type** + + None + + + ### evolve + + + Perform a single time step of TEBD. + + **Parameters** + + * **N\_steps** ([*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")) – should always be `1` in this case. See [`TEBDEngine`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine "(in TeNPy v1.0.4)") for more details. + * **dt** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – the time-step to use. + + **Returns** + + The truncation error. + + **Return type** + + [*TruncationError*](https://tenpy.readthedocs.io/en/latest/reference/tenpy.linalg.truncation.TruncationError.html#tenpy.linalg.truncation.TruncationError "(in TeNPy v1.0.4)") + + + ### suzuki\_trotter\_decomposition + + + Returns an empty list. + + + This method is undefined for this subclass but we cannot raise an error upon calling it because of the internal algorithm flow. Instead, the Trotter decomposition in this class is encoded directly into the [`layers`](#qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver.layers "qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver.layers"). + + + **Parameters** + + * **order** ([*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")) – is being ignored. + * **N\_steps** ([*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")) – is being ignored. + + **Returns** + + An empty list. + + **Return type** + + [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\[[tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\[[int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)"), [int](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")]] + + + ### suzuki\_trotter\_time\_steps + + + Returns an empty list. + + + This method is undefined for this subclass but we cannot raise an error upon calling it because of the internal algorithm flow. Instead, the Trotter decomposition in this class is encoded directly into the [`layers`](#qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver.layers "qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver.layers"). + + + **Parameters** + + **order** ([*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")) – is being ignored. + + **Returns** + + An empty list. + + **Return type** + + [list](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")\[[float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")] + + + diff --git a/docs/api/qiskit-addon-mpf/backends-tenpy-layers.mdx b/docs/api/qiskit-addon-mpf/backends-tenpy-layers.mdx new file mode 100644 index 00000000000..33c35d9dcf4 --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-tenpy-layers.mdx @@ -0,0 +1,166 @@ +--- +title: tenpy_layers (latest version) +description: API reference for qiskit_addon_mpf.backends.tenpy_layers in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_mpf.backends.tenpy_layers +--- + + + + + +# TeNPy layer-based backend + +`qiskit_addon_mpf.backends.tenpy_layers` + +A layer-wise time-evolution backend using [`tenpy`](https://tenpy.readthedocs.io/en/latest/main.html#module-tenpy "(in TeNPy v1.0.4)"). + + + The optional dependency [TeNPy](https://github.com/tenpy/tenpy) was previously offered under a GPLv3 license. As of the release of [v1.0.4](https://github.com/tenpy/tenpy/releases/tag/v1.0.4) on October 2nd, 2024, it has been offered under the Apache v2 license. The license of this package is only compatible with Apache-licensed versions of TeNPy. + + + + This backend is only available if the optional dependencies have been installed: + + ```python + pip install "qiskit-addon-mpf[tenpy]" + ``` + + +| | | +| ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`LayerwiseEvolver`](backends-tenpy-layers-layerwise-evolver "qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver") | A special case of the [`TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver") based on layer-wise evolution models. | +| [`LayerModel`](backends-tenpy-layers-layer-model "qiskit_addon_mpf.backends.tenpy_layers.LayerModel") | A model for representing a layer of time-evolution interactions. | + +## Underlying method + +This module provides a time-evolution backend similar to the TEBD-based one provided by the [`tenpy_tebd`](backends-tenpy-tebd#module-qiskit_addon_mpf.backends.tenpy_tebd "qiskit_addon_mpf.backends.tenpy_tebd") module. The main difference is that this module gives the user full flexibility for defining their product formulas, thereby not limiting them to the options built into the [`tenpy`](https://tenpy.readthedocs.io/en/latest/main.html#module-tenpy "(in TeNPy v1.0.4)") library. + +At its core, the algorithm provided by this module is still a TEBD \[1] algorithm. However, rather than enforcing the alternating updates to the even and odd bonds of the time-evolution state (see also [`evolve_step()`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine.evolve_step "(in TeNPy v1.0.4)")) this implementation outsources the responsibility of updating bonds in alternating fashion to the definition of multiple time-evolution **layers**. + +This is best explained with an example. Let us assume, we have some generic Hamiltonian acting on a 1-dimensional chain of sites. + + + Below we are very deliberate about the order of the Hamiltonian’s Pauli terms because this directly impacts the structure of the time-evolution circuit later on. + + +```python +>>> from qiskit.quantum_info import SparsePauliOp +>>> hamil = SparsePauliOp.from_sparse_list( +... [("ZZ", (i, i+1), 1.0) for i in range(1, 9, 2)] + +... [("Z", (i,), 0.5) for i in range(10)] + +... [("ZZ", (i, i+1), 1.0) for i in range(0, 9, 2)], +... num_qubits=10, +... ) +``` + +Let us now inspect the time-evolution circuit of this Hamiltonian using a second-order Suzuki-Trotter formula. + +```python +>>> from qiskit.synthesis import SuzukiTrotter +>>> from qiskit_addon_utils.problem_generators import generate_time_evolution_circuit +>>> circuit = generate_time_evolution_circuit(hamil, time=1.0, synthesis=SuzukiTrotter(order=2)) +>>> circuit.draw("mpl") +
+``` + +![../\_images/qiskit\_addon\_mpf-backends-tenpy\_layers-2.png](/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-tenpy_layers-2.png) + +In the circuit above, we can clearly identify its layer-wise structure. We can emphasize this further, by splitting the circuit into multiple layers as shown below (we recombine the `layers` into a single circuit with barriers between them to ease the visualization). + +```python +>>> from qiskit_addon_utils.slicing import combine_slices, slice_by_gate_types +>>> layers = slice_by_gate_types(circuit) +>>> combine_slices(layers, include_barriers=True).draw("mpl") +
+``` + +![../\_images/qiskit\_addon\_mpf-backends-tenpy\_layers-3.png](/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-tenpy_layers-3.png) + + + The asymmetry of the central layers is a result of the implementation of Qiskit’s [`SuzukiTrotter`](/api/qiskit/qiskit.synthesis.SuzukiTrotter "(in Qiskit v1.2)") formula. In its second-order form, it combines the two half-time evolutions of the final term in the Hamiltonian into a single one of twice the length. We could transpile this circuit to collapse all such subequent gates in the central two layers (just like the last one), but for the sake of simplicity of this example, we will not do that here. + + +It is not possible to instruct TeNPy’s TEBD algorithm to simulate the exact structure of the circuit shown above. The reason for that is a limitation in its interface, as it only accepts the full Hamiltonian to be provided which is then time-evolved using pre-defined Trotter formulas. However, in doing so it does not treat the order of the Pauli terms in a Hamiltonian with any significance (like we do here). + +If one wants to compute the dynamic MPF coefficients of a time-evolution employing a product formula structure other than the ones implemented in TeNPy (like the example above), then one can use the time-evolution algorithm provided by this module. Rather than taking a single monolithic Hamiltonian whose time-evolution is to be modeled, the [`LayerwiseEvolver`](backends-tenpy-layers-layerwise-evolver "qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver") accepts a list of [`LayerModel`](backends-tenpy-layers-layer-model "qiskit_addon_mpf.backends.tenpy_layers.LayerModel") objects, each one describing an individual layer of the product formula. This gives the user full flexibility in defining the Trotter decomposition down to the most granular level. + +However, caution must be applied to ensure that the property of TEBD to update even and odd bonds in an alternating manner is still guaranteed. Luckily, for quantum circuits consisting of at most two-qubit gates, this property is satisfied by construction. + +## Code example + +In this section, we build up on the example above and show how to take a custom Trotter formula and use it to construct a [`LayerwiseEvolver`](backends-tenpy-layers-layerwise-evolver "qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver") which can be used to replace the [`tenpy_tebd.TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver") in the workflow described in [`tenpy_tebd`](backends-tenpy-tebd#module-qiskit_addon_mpf.backends.tenpy_tebd "qiskit_addon_mpf.backends.tenpy_tebd"). + + + The overall workflow of using this module is the same as of the [`tenpy_tebd`](backends-tenpy-tebd#module-qiskit_addon_mpf.backends.tenpy_tebd "qiskit_addon_mpf.backends.tenpy_tebd") module, so be sure to read those instructions as well. + + +Simply put, we must convert each one of the circuit `layers` (see above) into a [`LayerModel`](backends-tenpy-layers-layer-model "qiskit_addon_mpf.backends.tenpy_layers.LayerModel") instance. For this purpose, we can use its [`from_quantum_circuit()`](backends-tenpy-layers-layer-model#from_quantum_circuit "qiskit_addon_mpf.backends.tenpy_layers.LayerModel.from_quantum_circuit") method. + +```python +>>> from qiskit_addon_mpf.backends.tenpy_layers import LayerModel +>>> model0 = LayerModel.from_quantum_circuit(layers[0]) +>>> layer_models = [model0] +``` + +In the code above you can see how simple the conversion is for layers which contain only two-qubit gates acting on mutually exclusive qubits (which layers of depth 1 guarantee). + +However, we must be more careful with layers including single-qubit gates. The reason for that is that the TEBD algorithm underlying the [`LayerwiseEvolver`](backends-tenpy-layers-layerwise-evolver "qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver") must update even and odd bonds in an alternating manner. And because single-qubit gates are not applied on a site, but instead are split in half and applied to the bonds on either side, a layer of single-qubit gates acting on all qubits would break this assumption. + +To circumvent this problem, we can take any layer consisting of only single-qubit gates, and apply it twice (once on the even and once on the odd bonds) while scaling each one with a factor of `0.5`. + +```python +>>> model1a = LayerModel.from_quantum_circuit(layers[1], keep_only_odd=True, scaling_factor=0.5) +>>> model1b = LayerModel.from_quantum_circuit(layers[1], keep_only_odd=False, scaling_factor=0.5) +>>> layer_models.extend([model1a, model1b]) +``` + +Now that we know how to treat layers consisting of two-qubit and single-qubit gates, we can transform the remaining layers. + +```python +>>> for layer in layers[2:]: +... num_qubits = len(layer.data[0].qubits) +... if num_qubits == 2: +... layer_models.append(LayerModel.from_quantum_circuit(layer)) +... else: +... layer_models.append( +... LayerModel.from_quantum_circuit(layer, keep_only_odd=True, scaling_factor=0.5) +... ) +... layer_models.append( +... LayerModel.from_quantum_circuit(layer, keep_only_odd=False, scaling_factor=0.5) +... ) +>>> assert len(layer_models) == 8 +``` + +In the end, we have 8 [`LayerModel`](backends-tenpy-layers-layer-model "qiskit_addon_mpf.backends.tenpy_layers.LayerModel")’s, one for each of the 4 two-qubit layers, and two for each of the 2 single-qubit layers. + +Finally, we can define our [`ApproxEvolverFactory`](dynamic#approxevolverfactory "qiskit_addon_mpf.dynamic.ApproxEvolverFactory") protocol to be used within the [`setup_dynamic_lse()`](dynamic#setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse") function. + +```python +>>> from functools import partial +>>> from qiskit_addon_mpf.backends.tenpy_layers import LayerwiseEvolver +>>> approx_evolver_factory = partial( +... LayerwiseEvolver, +... layers=layer_models, +... options={ +... "preserve_norm": False, +... "trunc_params": { +... "chi_max": 10, +... "svd_min": 1e-5, +... "trunc_cut": None, +... }, +... }, +... ) +``` + + + It should be noted, that in this workflow we have not yet fixed the time step used by the Trotter formula. We have also only set up a single repetition of the Trotter formula as the rest will be done by the internal [`DynamicMPF`](dynamic#dynamicmpf "qiskit_addon_mpf.dynamic.DynamicMPF") algorithm, executed during [`setup_dynamic_lse()`](dynamic#setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse"). + + +Of course, you could also use this to specify a [`ExactEvolverFactory`](dynamic#exactevolverfactory "qiskit_addon_mpf.dynamic.ExactEvolverFactory"). But you can also mix-and-match a [`tenpy_layers.LayerwiseEvolver`](backends-tenpy-layers-layerwise-evolver "qiskit_addon_mpf.backends.tenpy_layers.LayerwiseEvolver") with a [`tenpy_tebd.TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver"). + +## Resources + +\[1]: [https://en.wikipedia.org/wiki/Time-evolving\_block\_decimation](https://en.wikipedia.org/wiki/Time-evolving_block_decimation) + diff --git a/docs/api/qiskit-addon-mpf/backends-tenpy-tebd-mpo-state.mdx b/docs/api/qiskit-addon-mpf/backends-tenpy-tebd-mpo-state.mdx new file mode 100644 index 00000000000..1867bd805be --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-tenpy-tebd-mpo-state.mdx @@ -0,0 +1,68 @@ +--- +title: MPOState (latest version) +description: API reference for qiskit_addon_mpf.backends.tenpy_tebd.MPOState in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 1 +python_api_type: class +python_api_name: qiskit_addon_mpf.backends.tenpy_tebd.MPOState +--- + +# MPOState + + + Bases: [`MPO`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.networks.mpo.MPO.html#tenpy.networks.mpo.MPO "(in TeNPy v1.0.4)"), [`State`](backends#state "qiskit_addon_mpf.backends.interface.State") + + A mediator class to make TeNPy’s MPO match the [`State`](backends#state "qiskit_addon_mpf.backends.State") interface. + + This class simply ensures that a [`tenpy.networks.mpo.MPO`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.networks.mpo.MPO.html#tenpy.networks.mpo.MPO "(in TeNPy v1.0.4)") object can work as a [`State`](backends#state "qiskit_addon_mpf.backends.State") instance. + + ## Attributes + + ## Methods + + ### initialize\_from\_lattice + + + Construct an identity [`MPOState`](#qiskit_addon_mpf.backends.tenpy_tebd.MPOState "qiskit_addon_mpf.backends.tenpy_tebd.MPOState") instance matching the provided lattice shape. + + Given a lattice, this method constructs a new MPO identity matching the shape of the lattice. + + **Parameters** + + **lat** ([*Lattice*](https://tenpy.readthedocs.io/en/latest/reference/tenpy.models.lattice.Lattice.html#tenpy.models.lattice.Lattice "(in TeNPy v1.0.4)")) – the lattice describing the MPO sites. + + **Returns** + + An identity MPO. + + **Return type** + + [*MPOState*](#qiskit_addon_mpf.backends.tenpy_tebd.MPOState "qiskit_addon_mpf.backends.tenpy_tebd.state.MPOState") + + + ### overlap + + + Compute the overlap of this state with the provided initial state. + + + This implementation only supports instances of [`tenpy.networks.mps.MPS`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.networks.mps.MPS.html#tenpy.networks.mps.MPS "(in TeNPy v1.0.4)") for `initial_state`. + + + **Parameters** + + **initial\_state** ([*Any*](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")) – the initial state with which to compute the overlap. + + **Raises** + + [**TypeError**](https://docs.python.org/3/library/exceptions.html#TypeError "(in Python v3.13)") – if the provided initial state has an incompatible type. + + **Returns** + + The overlap of this state with the provided one. + + **Return type** + + [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)") + + + diff --git a/docs/api/qiskit-addon-mpf/backends-tenpy-tebd-mps-neel-state.mdx b/docs/api/qiskit-addon-mpf/backends-tenpy-tebd-mps-neel-state.mdx new file mode 100644 index 00000000000..11bca83fa8b --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-tenpy-tebd-mps-neel-state.mdx @@ -0,0 +1,30 @@ +--- +title: MPS_neel_state (latest version) +description: API reference for qiskit_addon_mpf.backends.tenpy_tebd.MPS_neel_state in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 1 +python_api_type: class +python_api_name: qiskit_addon_mpf.backends.tenpy_tebd.MPS_neel_state +--- + + + +# MPS\_neel\_state + + + Bases: + + Constructs the Néel state as an MPS. + + **Parameters** + + **lat** ([*Lattice*](https://tenpy.readthedocs.io/en/latest/reference/tenpy.models.lattice.Lattice.html#tenpy.models.lattice.Lattice "(in TeNPy v1.0.4)")) – the lattice describing the MPS sites. + + **Returns** + + A Néel state as an MPS. + + **Return type** + + [*MPS*](https://tenpy.readthedocs.io/en/latest/reference/tenpy.networks.mps.MPS.html#tenpy.networks.mps.MPS "(in TeNPy v1.0.4)") + + diff --git a/docs/api/qiskit-addon-mpf/backends-tenpy-tebd-tebd-evolver.mdx b/docs/api/qiskit-addon-mpf/backends-tenpy-tebd-tebd-evolver.mdx new file mode 100644 index 00000000000..792bbb3aa8b --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-tenpy-tebd-tebd-evolver.mdx @@ -0,0 +1,87 @@ +--- +title: TEBDEvolver (latest version) +description: API reference for qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 1 +python_api_type: class +python_api_name: qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver +--- + +# TEBDEvolver + + + Bases: [`TEBDEngine`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine "(in TeNPy v1.0.4)"), [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.interface.Evolver") + + A TEBD algorithm for evolving an internal MPO. + + As discussed in more detail in [`tenpy_tebd`](backends-tenpy-tebd#module-qiskit_addon_mpf.backends.tenpy_tebd "qiskit_addon_mpf.backends.tenpy_tebd"), this extension of TeNPy’s existing [`TEBDEngine`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine "(in TeNPy v1.0.4)") implementation time-evolves an internal matrix product operator (MPO) rather than the conventional matrix product state (MPS). + + More concretely, the internal object is expected to be an [`MPOState`](backends-tenpy-tebd-mpo-state "qiskit_addon_mpf.backends.tenpy_tebd.MPOState"). + + + The API of this class is actually much larger than shown here, because it inherits additional methods from the [`TEBDEngine`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine "(in TeNPy v1.0.4)") base class. However, we do not duplicate that API here. + + + Initialize a [`TEBDEvolver`](#qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver") instance. + + **Parameters** + + * **args** – any positional arguments will be forwarded to the [`TEBDEngine`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine "(in TeNPy v1.0.4)") constructor. + * **dt** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – the time step to be used by this time-evolution instance. + * **kwargs** – any further keyword arguments will be forwarded to the [`TEBDEngine`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine "(in TeNPy v1.0.4)") constructor. + + ## Attributes + + ### conjugate + + + Returns whether this time-evolver instance acts on the right-hand side. + + + ### evolved\_time + + + Returns the current evolution time. + + + ### dt + + + The time step to be used by this time-evolution instance. + + + ## Methods + + ### step + + + Perform a single time step of TEBD. + + This essentially calls [`run_evolution()`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine.run_evolution "(in TeNPy v1.0.4)") and forwards the value of [`dt`](#qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver.dt "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver.dt") that was provided upon construction. + + **Return type** + + None + + + ### update\_bond + + + Update the specified bond. + + Overwrites the original (MPS-based) implementation to support an MPO as the shared state. + + **Parameters** + + * **i** ([*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")) – the bond index. + * **U\_bond** ([*Array*](https://tenpy.readthedocs.io/en/latest/reference/tenpy.linalg.np_conserved.Array.html#tenpy.linalg.np_conserved.Array "(in TeNPy v1.0.4)")) – the bond to update. + + **Returns** + + The truncation error. + + **Return type** + + [float](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)") + + + diff --git a/docs/api/qiskit-addon-mpf/backends-tenpy-tebd.mdx b/docs/api/qiskit-addon-mpf/backends-tenpy-tebd.mdx new file mode 100644 index 00000000000..7967557c225 --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends-tenpy-tebd.mdx @@ -0,0 +1,123 @@ +--- +title: tenpy_tebd (latest version) +description: API reference for qiskit_addon_mpf.backends.tenpy_tebd in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_mpf.backends.tenpy_tebd +--- + + + + + +# TeNPy TEBD backend + +`qiskit_addon_mpf.backends.tenpy_tebd` + +A [`tenpy`](https://tenpy.readthedocs.io/en/latest/main.html#module-tenpy "(in TeNPy v1.0.4)")-based TEBD backend. + + + The optional dependency [TeNPy](https://github.com/tenpy/tenpy) was previously offered under a GPLv3 license. As of the release of [v1.0.4](https://github.com/tenpy/tenpy/releases/tag/v1.0.4) on October 2nd, 2024, it has been offered under the Apache v2 license. The license of this package is only compatible with Apache-licensed versions of TeNPy. + + + + This backend is only available if the optional dependencies have been installed: + + ```python + pip install "qiskit-addon-mpf[tenpy]" + ``` + + +| | | +| ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | +| [`TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver") | A TEBD algorithm for evolving an internal MPO. | +| [`MPOState`](backends-tenpy-tebd-mpo-state "qiskit_addon_mpf.backends.tenpy_tebd.MPOState") | A mediator class to make TeNPy's MPO match the [`State`](backends#state "qiskit_addon_mpf.backends.State") interface. | +| [`MPS_neel_state`](backends-tenpy-tebd-mps-neel-state "qiskit_addon_mpf.backends.tenpy_tebd.MPS_neel_state") | Constructs the Néel state as an MPS. | + +## Underlying method + +This module provides a time-evolution backend for computing dynamic MPF coefficients based on the time-evolving block decimation (TEBD) algorithm \[1] implemented in the [`tenpy`](https://tenpy.readthedocs.io/en/latest/main.html#module-tenpy "(in TeNPy v1.0.4)") tensor network library. + +The classes provided by this module serve two purposes: + +1. Connecting [`tenpy`](https://tenpy.readthedocs.io/en/latest/main.html#module-tenpy "(in TeNPy v1.0.4)")’s implementation to the interface set out by [`qiskit_addon_mpf.backends`](backends#module-qiskit_addon_mpf.backends "qiskit_addon_mpf.backends"). +2. Extending [`tenpy`](https://tenpy.readthedocs.io/en/latest/main.html#module-tenpy "(in TeNPy v1.0.4)")’s TEBD implementation to handle an internal MPO (rather than MPS) state (see also [`State`](backends#state "qiskit_addon_mpf.backends.State") for more details). + +In the simplest sense, this module provides a straight-forward extension of the TEBD algorithm to evolve an internal MPO state. As such, if you wish to use this backend for your dynamic MPF algorithm, you must encode the Hamiltonian that you wish to time-evolve, in a [`tenpy`](https://tenpy.readthedocs.io/en/latest/main.html#module-tenpy "(in TeNPy v1.0.4)")-native form. To be more concrete, the [`TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver") class (which is a subclass of [`tenpy.algorithms.tebd.TEBDEngine`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine "(in TeNPy v1.0.4)")) works with a Hamiltonian in the form of a [`Model`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.models.model.Model.html#tenpy.models.model.Model "(in TeNPy v1.0.4)"). TeNPy provides a number of convenience methods for constructing such Hamiltonians in its [`tenpy.models`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.models.html#module-tenpy.models "(in TeNPy v1.0.4)") module. If none of those fulfill your needs, you can consider using the [`LayerModel`](backends-tenpy-layers-layer-model "qiskit_addon_mpf.backends.tenpy_layers.LayerModel") class which implements some conversion methods from Qiskit-native objects. + +## 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()`](dynamic#setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse"). + +First of all, we define the Hamiltonian which we would like to time-evolve. Here, we simply choose one of [`tenpy`](https://tenpy.readthedocs.io/en/latest/main.html#module-tenpy "(in TeNPy v1.0.4)")’s convenience methods. + +```python +>>> from tenpy.models import XXZChain2 +>>> hamil = XXZChain2( +... { +... "L": 10, +... "Jz": 0.8, +... "Jxx": 0.7, +... "hz": 0.3, +... "bc_MPS": "finite", +... "sort_charge": False, +... } +... ) +``` + +Next, we can create the `identity_factory` which has to match the [`IdentityStateFactory`](dynamic#identitystatefactory "qiskit_addon_mpf.dynamic.IdentityStateFactory") protocol. We do so by using the `initialize_from_lattice()` convenience method which takes the lattice underlying the Hamiltonian which we just defined as its only input. + +```python +>>> from functools import partial +>>> from qiskit_addon_mpf.backends.tenpy_tebd import MPOState +>>> identity_factory = partial(MPOState.initialize_from_lattice, hamil.lat), +``` + +We can now construct the [`ExactEvolverFactory`](dynamic#exactevolverfactory "qiskit_addon_mpf.dynamic.ExactEvolverFactory") and [`ApproxEvolverFactory`](dynamic#approxevolverfactory "qiskit_addon_mpf.dynamic.ApproxEvolverFactory") time-evolution instance factories. To do so, we can simply bind the pre-defined values of the [`TEBDEvolver`](backends-tenpy-tebd-tebd-evolver "qiskit_addon_mpf.backends.tenpy_tebd.TEBDEvolver") initializer, reducing it to the correct interface as expected by the respective function protocols. + +```python +>>> from qiskit_addon_mpf.backends.tenpy_tebd import TEBDEvolver +>>> exact_evolver_factory = partial( +... TEBDEvolver, +... model=hamil, +... dt=0.05, +... options={ +... "order": 4, +... "preserve_norm": False, +... }, +... ) +``` + +Notice, how we have fixed the `dt` value to a small time step and have used a higher-order Suzuki-Trotter decomposition to mimic the exact time-evolution above. + +Below, we do not fix the `dt` value and use only a second-order Suzuki-Trotter formula for the approximate time-evolution. Additionally, we also specify some truncation settings. + +```python +>>> approx_evolver_factory = partial( +... TEBDEvolver, +... model=hamil, +... options={ +... "order": 2, +... "preserve_norm": False, +... "trunc_params": { +... "chi_max": 10, +... "svd_min": 1e-5, +... "trunc_cut": None, +... }, +... }, +... ) +``` + +Of course, you are not limited to the examples shown here, and we encourage you to play around with the other settings provided by TeNPy’s [`TEBDEngine`](https://tenpy.readthedocs.io/en/latest/reference/tenpy.algorithms.tebd.TEBDEngine.html#tenpy.algorithms.tebd.TEBDEngine "(in TeNPy v1.0.4)") implementation. + +## Limitations + +Finally, we point out a few known limitations on what kind of Hamiltonians can be treated by this backend: + +* all interactions must be 1-dimensional +* the interactions must use finite boundary conditions + +## Resources + +\[1]: [https://en.wikipedia.org/wiki/Time-evolving\_block\_decimation](https://en.wikipedia.org/wiki/Time-evolving_block_decimation) + diff --git a/docs/api/qiskit-addon-mpf/backends.mdx b/docs/api/qiskit-addon-mpf/backends.mdx new file mode 100644 index 00000000000..22cb4c9f7fa --- /dev/null +++ b/docs/api/qiskit-addon-mpf/backends.mdx @@ -0,0 +1,148 @@ +--- +title: backends (latest version) +description: API reference for qiskit_addon_mpf.backends in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_mpf.backends +--- + + + + + +# Backends + +`qiskit_addon_mpf.backends` + +Optional backends for the [`DynamicMPF`](dynamic#dynamicmpf "qiskit_addon_mpf.dynamic.DynamicMPF") algorithm. + +## Availability + +Whether a certain backend can be used depends on the availability of the underlying tensor network library. This can easily be asserted at runtime using the following indicators: + + + Indicates whether the optional [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)") dependency is installed. + + +### HAS\_TENPY + + + Indicates whether the optional [`tenpy`](https://tenpy.readthedocs.io/en/latest/main.html#module-tenpy "(in TeNPy v1.0.4)") dependency is installed. + + +## Backends + +Depending on the availability (see above), the following backends are available: + +| | | +| ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`quimb_tebd`](backends-quimb-tebd#module-qiskit_addon_mpf.backends.quimb_tebd "qiskit_addon_mpf.backends.quimb_tebd") | A [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)")-based TEBD backend. | +| [`quimb_layers`](backends-quimb-layers#module-qiskit_addon_mpf.backends.quimb_layers "qiskit_addon_mpf.backends.quimb_layers") | A layer-wise time-evolution backend using [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)"). | +| [`quimb_circuit`](backends-quimb-circuit#module-qiskit_addon_mpf.backends.quimb_circuit "qiskit_addon_mpf.backends.quimb_circuit") | A circuit-based time-evolution backend using [`quimb`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)"). | +| [`tenpy_tebd`](backends-tenpy-tebd#module-qiskit_addon_mpf.backends.tenpy_tebd "qiskit_addon_mpf.backends.tenpy_tebd") | A [`tenpy`](https://tenpy.readthedocs.io/en/latest/main.html#module-tenpy "(in TeNPy v1.0.4)")-based TEBD backend. | +| [`tenpy_layers`](backends-tenpy-layers#module-qiskit_addon_mpf.backends.tenpy_layers "qiskit_addon_mpf.backends.tenpy_layers") | A layer-wise time-evolution backend using [`tenpy`](https://tenpy.readthedocs.io/en/latest/main.html#module-tenpy "(in TeNPy v1.0.4)"). | + +## Interface + +The interface implemented by any one of these optional backends is made up of the following classes: + +### Evolver + + + Bases: [`ABC`](https://docs.python.org/3/library/abc.html#abc.ABC "(in Python v3.13)") + + The interface for the time-evolution algorithms used within [`DynamicMPF`](dynamic#dynamicmpf "qiskit_addon_mpf.dynamic.DynamicMPF"). + + This time-evolution interface is used by the [`DynamicMPF.lhs`](dynamic#lhs "qiskit_addon_mpf.dynamic.DynamicMPF.lhs") and [`DynamicMPF.rhs`](dynamic#rhs "qiskit_addon_mpf.dynamic.DynamicMPF.rhs") and should time-evolve a [`State`](#qiskit_addon_mpf.backends.State "qiskit_addon_mpf.backends.State") object under its hood. The exact mechanism of the algorithm is described in more detail in [`DynamicMPF`](dynamic#dynamicmpf "qiskit_addon_mpf.dynamic.DynamicMPF"), [`State`](#qiskit_addon_mpf.backends.State "qiskit_addon_mpf.backends.State"), and [`setup_dynamic_lse()`](dynamic#setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse"). + + #### abstract property conjugate + + + Returns whether this time-evolver instance acts on the right-hand side. + + + #### abstract property evolved\_time + + + Returns the current evolution time. + + + #### step + + + Perform a single time step of this time-evolution algorithm. + + This should act on the internally referenced [`State`](#qiskit_addon_mpf.backends.State "qiskit_addon_mpf.backends.State") object (for which no name is prescribed by this interface). Whether this time-evolution algorithm instance should evolve the [`State`](#qiskit_addon_mpf.backends.State "qiskit_addon_mpf.backends.State") from the left- or right-hand side, depends on the value of [`conjugate`](#qiskit_addon_mpf.backends.Evolver.conjugate "qiskit_addon_mpf.backends.Evolver.conjugate"). + + **Return type** + + None + + + +### State + + + Bases: [`ABC`](https://docs.python.org/3/library/abc.html#abc.ABC "(in Python v3.13)") + + The interface for the [`DynamicMPF.evolution_state`](dynamic#evolution_state "qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state"). + + This time-evolution state is shared between the LHS and RHS [`Evolver`](#qiskit_addon_mpf.backends.Evolver "qiskit_addon_mpf.backends.Evolver") instances of the [`DynamicMPF`](dynamic#dynamicmpf "qiskit_addon_mpf.dynamic.DynamicMPF") instance. In most cases where a concrete backend implementing this interface is based on tensor networks, this state will be a matrix product operator (MPO). This is because most time-evolution algorithms would normally evolve a matrix product state (MPS) as shown pictorially below, where time evolution blocks (`U#`) are successively applied to a 1-dimensional MPS (`S#`). Here, the tensor network grows towards the right as time goes on. + + ```python + MPS Evolution + + S0┄┄┲━━━━┱┄┄┄┄┄┄┄┄┲━━━━┱┄ + │ ┃ U1 ┃ ┃ U5 ┃ + S1┄┄┺━━━━┹┄┲━━━━┱┄┺━━━━┹┄ + │ ┃ U3 ┃ + S2┄┄┲━━━━┱┄┺━━━━┹┄┲━━━━┱┄ ... + │ ┃ U2 ┃ ┃ U6 ┃ + S3┄┄┺━━━━┹┄┲━━━━┱┄┺━━━━┹┄ + │ ┃ U4 ┃ + S4┄┄┄┄┄┄┄┄┄┺━━━━┹┄┄┄┄┄┄┄┄ + ``` + + However, in our case, we want two time-evolution engines to share a single state. In order to achieve that, we can have one of them evolve the state from the right (just as before, `U#`), but have the second one evolve the state from the left (`V#`). This requires the state to also have bonds going of in that direction, rendering it a 2-dimensional MPO (`M#`) rather than the 1-dimensional MPS from before. + + ```python + MPO Evolution + + ┄┲━━━━┱┄┄┄┄┄┄┄┄┲━━━━┱┄┄M0┄┄┲━━━━┱┄┄┄┄┄┄┄┄┲━━━━┱┄ + ┃ V5 ┃ ┃ V1 ┃ │ ┃ U1 ┃ ┃ U5 ┃ + ┄┺━━━━┹┄┲━━━━┱┄┺━━━━┹┄┄M1┄┄┺━━━━┹┄┲━━━━┱┄┺━━━━┹┄ + ┃ V3 ┃ │ ┃ U3 ┃ + ... ┄┲━━━━┱┄┺━━━━┹┄┲━━━━┱┄┄M2┄┄┲━━━━┱┄┺━━━━┹┄┲━━━━┱┄ ... + ┃ V6 ┃ ┃ V2 ┃ │ ┃ U2 ┃ ┃ U6 ┃ + ┄┺━━━━┹┄┲━━━━┱┄┺━━━━┹┄┄M3┄┄┺━━━━┹┄┲━━━━┱┄┺━━━━┹┄ + ┃ V4 ┃ │ ┃ U4 ┃ + ┄┄┄┄┄┄┄┄┺━━━━┹┄┄┄┄┄┄┄┄┄M4┄┄┄┄┄┄┄┄┄┺━━━━┹┄┄┄┄┄┄┄┄ + ``` + + #### overlap + + + Compute the overlap of this state with the provided initial state. + + + A concrete implementation of this method should raise a [`TypeError`](https://docs.python.org/3/library/exceptions.html#TypeError "(in Python v3.13)") if the provided `initial_state` object is not supported by the implementing backend. + + + **Parameters** + + **initial\_state** ([*Any*](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")) – the initial state with which to compute the overlap. + + **Raises** + + [**TypeError**](https://docs.python.org/3/library/exceptions.html#TypeError "(in Python v3.13)") – if the provided initial state has an incompatible type. + + **Returns** + + The overlap of this state with the provided one. + + **Return type** + + [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)") + + + diff --git a/docs/api/qiskit-addon-mpf/costs.mdx b/docs/api/qiskit-addon-mpf/costs.mdx new file mode 100644 index 00000000000..9523dc06f26 --- /dev/null +++ b/docs/api/qiskit-addon-mpf/costs.mdx @@ -0,0 +1,283 @@ +--- +title: costs (latest version) +description: API reference for qiskit_addon_mpf.costs in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_mpf.costs +--- + + + + + +# Cost Functions + +`qiskit_addon_mpf.costs` + +Cost functions for MPF coefficients. + +This module provides a number of optimization problem generator functions, each implementing a different cost function as the problem’s target objective. All of the functions provided by this module take a linear system of equations ([`LSE`](#qiskit_addon_mpf.costs.LSE "qiskit_addon_mpf.costs.LSE")) encoding the parameters of the optimization problem as their first argument. + +### LSE + + + Bases: [`NamedTuple`](https://docs.python.org/3/library/typing.html#typing.NamedTuple "(in Python v3.13)") + + A `namedtuple` representing a linear system of equations. + +$$ +A x = b +$$ + + Create new instance of LSE(A, b) + + **Parameters** + + * **A** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray "(in NumPy v2.1)")) + * **b** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray "(in NumPy v2.1)")) + + #### A + + + The left hand side of the LSE. + + + #### b + + + The right hand side of the LSE. + + + #### count + + + Return number of occurrences of value. + + + #### index + + + Return first index of value. + + Raises ValueError if the value is not present. + + + #### solve + + + Return the solution to this LSE: $x=A^{-1}b$. + + **Returns** + + The solution to this LSE. + + **Raises** + + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)") – if this LSE is parameterized with unassigned values. + * [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)") – if this LSE does not include a row ensuring that $\sum_i x_i == 1$ which is a requirement for valid MPF coefficients. + + **Return type** + + [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray "(in NumPy v2.1)") + + + #### x + + + Returns the \$x\$ [`Variable`](https://www.cvxpy.org/api_reference/cvxpy.expressions.html#cvxpy.expressions.variable.Variable "(in CVXPY v1.6)"). + + + +## Optimization problem constructors + +### setup\_exact\_problem + + + Construct a [`cvxpy.Problem`](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem "(in CVXPY v1.6)") for finding the exact MPF coefficients. + + + The coefficients found via this optimization problem will be identical to the analytical ones obtained from the [`LSE.solve()`](#qiskit_addon_mpf.costs.LSE.solve "qiskit_addon_mpf.costs.LSE.solve") method. This additional interface exists to highlight the parallel to the other cost functions provided by this module. It also serves educational purposes for how to approach optimization problems targeting MPF coefficients. + + + The optimization problem constructed by this function is defined as follows: + + * the cost function minimizes the L1-norm ([`norm1`](https://www.cvxpy.org/api_reference/cvxpy.atoms.other_atoms.html#cvxpy.atoms.norm1.norm1 "(in CVXPY v1.6)")) of the variables ([`LSE.x`](#qiskit_addon_mpf.costs.LSE.x "qiskit_addon_mpf.costs.LSE.x")) + + * the constraints correspond to each equation of the [`LSE`](#qiskit_addon_mpf.costs.LSE "qiskit_addon_mpf.costs.LSE"): + +$$ +\sum_j A_{ij} x_j = b_i +$$ + + Here is an example: + + ```python + >>> from qiskit_addon_mpf.costs import setup_exact_problem + >>> from qiskit_addon_mpf.static import setup_static_lse + >>> lse = setup_static_lse([1,2,3], order=2, symmetric=True) + >>> problem, coeffs = setup_exact_problem(lse) + >>> print(problem) + minimize norm1(x) + subject to Sum([1. 1. 1.] @ x, None, False) == 1.0 + Sum([1. 0.25 0.11111111] @ x, None, False) == 0.0 + Sum([1. 0.0625 0.01234568] @ x, None, False) == 0.0 + ``` + + You can then solve the problem and access the expansion coefficients like so: + + ```python + >>> final_cost = problem.solve() + >>> print(coeffs.value) + [ 0.04166667 -1.06666667 2.025 ] + ``` + + **Parameters** + + **lse** ([*LSE*](#qiskit_addon_mpf.costs.LSE "qiskit_addon_mpf.costs.lse.LSE")) – the linear system of equations from which to build the model. + + **Returns** + + The optimization problem and coefficients variable. + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\[[*Problem*](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem "(in CVXPY v1.6)"), [*Variable*](https://www.cvxpy.org/api_reference/cvxpy.expressions.html#cvxpy.expressions.variable.Variable "(in CVXPY v1.6)")] + + **References** + + **\[1]: A. Carrera Vazquez et al., Quantum 7, 1067 (2023).** + + [https://quantum-journal.org/papers/q-2023-07-25-1067/](https://quantum-journal.org/papers/q-2023-07-25-1067/) + + +### setup\_sum\_of\_squares\_problem + + + Construct a [`cvxpy.Problem`](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem "(in CVXPY v1.6)") for finding approximate MPF coefficients. + + The optimization problem constructed by this function is defined as follows: + + * the cost function minimizes the sum of squares ([`sum_squares()`](https://www.cvxpy.org/api_reference/cvxpy.atoms.other_atoms.html#cvxpy.atoms.sum_squares.sum_squares "(in CVXPY v1.6)")) of the distances to an exact solution for all equations of the [`LSE`](#qiskit_addon_mpf.costs.LSE "qiskit_addon_mpf.costs.LSE"): + +$$ +\sum_i \left( \sum_j A_{ij} x_j - b_i \right)^2 +$$ + + * two constraints are set: + + 1. the variables must sum to 1: $\sum_i x_i == 1$ + 2. the L1-norm ([`norm1`](https://www.cvxpy.org/api_reference/cvxpy.atoms.other_atoms.html#cvxpy.atoms.norm1.norm1 "(in CVXPY v1.6)")) of the variables is bounded by `max_l1_norm` + + Here is an example: + + ```python + >>> from qiskit_addon_mpf.costs import setup_sum_of_squares_problem + >>> from qiskit_addon_mpf.static import setup_static_lse + >>> lse = setup_static_lse([1,2,3], order=2, symmetric=True) + >>> problem, coeffs = setup_sum_of_squares_problem(lse, max_l1_norm=3.0) + >>> print(problem) + minimize quad_over_lin(Vstack([1. 1. 1.] @ x + -1.0, + [1. 0.25 0.11111111] @ x + -0.0, + [1. 0.0625 0.01234568] @ x + -0.0), 1.0) + subject to Sum(x, None, False) == 1.0 + norm1(x) <= 3.0 + ``` + + You can then solve the problem and access the expansion coefficients like so: + + ```python + >>> final_cost = problem.solve() + >>> print(coeffs.value) + [ 0.03513467 -1. 1.96486533] + ``` + + **Parameters** + + * **lse** ([*LSE*](#qiskit_addon_mpf.costs.LSE "qiskit_addon_mpf.costs.lse.LSE")) – the linear system of equations from which to build the model. + * **max\_l1\_norm** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – the upper limit to use for the constrain of the L1-norm of the variables. + + **Returns** + + The optimization problem and coefficients variable. + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\[[*Problem*](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem "(in CVXPY v1.6)"), [*Variable*](https://www.cvxpy.org/api_reference/cvxpy.expressions.html#cvxpy.expressions.variable.Variable "(in CVXPY v1.6)")] + + **References** + + **\[1]: S. Zhuk et al., arXiv:2306.12569 (2023).** + + [https://arxiv.org/abs/2306.12569](https://arxiv.org/abs/2306.12569) + + +### setup\_frobenius\_problem + + + Construct a [`cvxpy.Problem`](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem "(in CVXPY v1.6)") for finding approximate MPF coefficients. + + The optimization problem constructed by this function is defined as follows: + + * the cost function minimizes the following quadratic expression: + +$$ +1 + x^T A x - 2 x^T b +$$ + + As shown in \[1] and \[2], this expression arises from the Frobenius norm of the error between an exact time evolution state and a dynamic MPF. As such, taking the [`LSE`](#qiskit_addon_mpf.costs.LSE "qiskit_addon_mpf.costs.LSE") constructed by [`setup_dynamic_lse()`](dynamic#setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse") and plugging it into this function will yield Eq. (20) of \[1] (which is identical to Eq. (2) of \[2]), which we repeat below + +$$ +1 + \sum_{i,j} A_{ij}(t) x_i(t) x_j(t) - 2 \sum_i b_i(t) x_i(t) \, , +$$ + + where \$A\$ and \$b\$ of our [`LSE`](#qiskit_addon_mpf.costs.LSE "qiskit_addon_mpf.costs.LSE") correspond to the Gram matrix (\$M\$ in \[1] and \[2]) and the overlap vector (\$L\$ in \[1] and \[2]), respectively. Additionally, we use \$x(t)\$ to denote the MPF variables (or coefficients) rather than \$c\$ in \[1] and \[2]. + + * two constraints are set: + + 1. the variables must sum to 1: $\sum_i x_i == 1$ + 2. the L1-norm ([`norm1`](https://www.cvxpy.org/api_reference/cvxpy.atoms.other_atoms.html#cvxpy.atoms.norm1.norm1 "(in CVXPY v1.6)")) of the variables is bounded by `max_l1_norm` + + Below is an example which uses the `lse` object constructed in the example for [`setup_dynamic_lse()`](dynamic#setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse"). + + ```python + >>> from qiskit_addon_mpf.costs import setup_frobenius_problem + >>> problem, coeffs = setup_frobenius_problem(lse, max_l1_norm=3.0) + >>> print(problem) + minimize 1.0 + QuadForm(x, [[1.00 1.00] + [1.00 1.00]]) + -[2.00003171 1.99997911] @ x + subject to Sum(x, None, False) == 1.0 + norm1(x) <= 3.0 + ``` + + You can then solve the problem and access the expansion coefficients like so: + + ```python + >>> final_cost = problem.solve() + >>> print(coeffs.value) + [0.50596416 0.49403584] + ``` + + **Parameters** + + * **lse** ([*LSE*](#qiskit_addon_mpf.costs.LSE "qiskit_addon_mpf.costs.lse.LSE")) – the linear system of equations from which to build the model. + * **max\_l1\_norm** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – the upper limit to use for the constrain of the L1-norm of the variables. + + **Returns** + + The optimization problem and coefficients variable. + + **Return type** + + [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\[[*Problem*](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem "(in CVXPY v1.6)"), [*Variable*](https://www.cvxpy.org/api_reference/cvxpy.expressions.html#cvxpy.expressions.variable.Variable "(in CVXPY v1.6)")] + + **References** + + **\[1]: S. Zhuk et al., arXiv:2306.12569 (2023).** + + [https://arxiv.org/abs/2306.12569](https://arxiv.org/abs/2306.12569) + + **\[2]: N. Robertson et al., arXiv:2407.17405v2 (2024).** + + [https://arxiv.org/abs/2407.17405v2](https://arxiv.org/abs/2407.17405v2) + + diff --git a/docs/api/qiskit-addon-mpf/dynamic.mdx b/docs/api/qiskit-addon-mpf/dynamic.mdx new file mode 100644 index 00000000000..118d1872e1f --- /dev/null +++ b/docs/api/qiskit-addon-mpf/dynamic.mdx @@ -0,0 +1,281 @@ +--- +title: dynamic (latest version) +description: API reference for qiskit_addon_mpf.dynamic in the latest version of qiskit-addon-mpf +in_page_toc_min_heading_level: 2 +python_api_type: module +python_api_name: qiskit_addon_mpf.dynamic +--- + + + + + +# Dynamic MPFs + +`qiskit_addon_mpf.dynamic` + +Dynamic MPF coefficients. + +This module provides the generator function for the linear system of equations ([`LSE`](costs#lse "qiskit_addon_mpf.costs.LSE")) for computing dynamic (that is, time-dependent) MPF coefficients. + +### setup\_dynamic\_lse + + + Return the linear system of equations for computing dynamic MPF coefficients. + + This function uses the [`DynamicMPF`](#qiskit_addon_mpf.dynamic.DynamicMPF "qiskit_addon_mpf.dynamic.DynamicMPF") algorithm to compute the components of the Gram matrix ([`LSE.A`](costs#a "qiskit_addon_mpf.costs.LSE.A"), $M$ in \[1] and \[2]) and the overlap vector ([`LSE.b`](costs#b "qiskit_addon_mpf.costs.LSE.b"), $L$ in \[1] and \[2]) for the provided time-evolution parameters. + + The elements of the Gram matrix, $M_{ij}$, and overlap vector, $L_i$, are defined as + +$$ +\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 $\rho(t)$ is the exact time-evolution state at time $t$ and $\rho_{k_i}(t)$ is the time-evolution state approximated using $k_i$ Trotter steps. + + Computing the dynamic (that is, time-dependent) MPF coefficients from $M$ and $L$ amounts to finding a solution to the [`LSE`](costs#lse "qiskit_addon_mpf.costs.LSE") (similarly to how the [`static`](static#module-qiskit_addon_mpf.static "qiskit_addon_mpf.static") MPF coefficients are computed) while enforcing the constraint that all coefficients must sum to 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`](costs#module-qiskit_addon_mpf.costs "qiskit_addon_mpf.costs") module. The one suggested by \[1] and \[2] is the [`setup_frobenius_problem()`](costs#setup_frobenius_problem "qiskit_addon_mpf.costs.setup_frobenius_problem"). + + Evaluating every element $M_{ij}$ and $L_i$ requires computing the overlap between two time-evolution states. The [`DynamicMPF`](#qiskit_addon_mpf.dynamic.DynamicMPF "qiskit_addon_mpf.dynamic.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`](backends#module-qiskit_addon_mpf.backends "qiskit_addon_mpf.backends") module. + + Below, we provide an example using the [`quimb_tebd`](backends-quimb-tebd#module-qiskit_addon_mpf.backends.quimb_tebd "qiskit_addon_mpf.backends.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`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)"), we also initialize the Hamiltonian using that library. + + ```python + >>> 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 ($\psi_{in}$ in \[1] and $\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`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)"): + + ```python + >>> trotter_steps = [3, 4] + >>> time = 0.9 + ``` + + ```python + >>> from quimb.tensor import MPS_neel_state + >>> initial_state = MPS_neel_state(num_qubits) + ``` + + Since we must run the full [`DynamicMPF`](#qiskit_addon_mpf.dynamic.DynamicMPF "qiskit_addon_mpf.dynamic.DynamicMPF") algorithm for computing every element of $M_{ij}$ and $L_i$, we must provide factory methods for initializing the input arguments of the [`DynamicMPF`](#qiskit_addon_mpf.dynamic.DynamicMPF "qiskit_addon_mpf.dynamic.DynamicMPF") instances. To this end, we must provide three functions. To construct these, we will use the [`functools.partial()`](https://docs.python.org/3/library/functools.html#functools.partial "(in Python v3.13)") function. + + ```python + >>> from functools import partial + ``` + + First, we need a function to initialize an empty time-evolution state (see also [`DynamicMPF.evolution_state`](#qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state "qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state") for more details). This constructor function may not take any positional or keyword arguments and must return a [`State`](backends#state "qiskit_addon_mpf.backends.State") object. + + ```python + >>> 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`](#qiskit_addon_mpf.dynamic.DynamicMPF.lhs "qiskit_addon_mpf.dynamic.DynamicMPF.lhs") and [`DynamicMPF.rhs`](#qiskit_addon_mpf.dynamic.DynamicMPF.rhs "qiskit_addon_mpf.dynamic.DynamicMPF.rhs") for more details). These functions should follow the [`ExactEvolverFactory`](#qiskit_addon_mpf.dynamic.ExactEvolverFactory "qiskit_addon_mpf.dynamic.ExactEvolverFactory") and [`ApproxEvolverFactory`](#qiskit_addon_mpf.dynamic.ApproxEvolverFactory "qiskit_addon_mpf.dynamic.ApproxEvolverFactory") protocols, respectively. + + The [`ExactEvolverFactory`](#qiskit_addon_mpf.dynamic.ExactEvolverFactory "qiskit_addon_mpf.dynamic.ExactEvolverFactory") function should take a [`State`](backends#state "qiskit_addon_mpf.backends.State") object as its only positional argument and should return a [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.Evolver") object, which will be used for computing the LHS of the $L_i$ elements (i.e. it should produce the exact time-evolution state, $\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`](https://quimb.readthedocs.io/en/latest/autoapi/quimb/index.html#module-quimb "(in quimb v1.8)")-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. + + ```python + >>> 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`](#qiskit_addon_mpf.dynamic.ApproxEvolverFactory "qiskit_addon_mpf.dynamic.ApproxEvolverFactory") function should also take a [`State`](backends#state "qiskit_addon_mpf.backends.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`](backends#evolver "qiskit_addon_mpf.backends.Evolver") object which produces the approximate time-evolution states, $\rho_{k_i}(t)$, where $k_i$ is determined by the chosen time step, `dt`. As such, these instances will be used for computing the RHS of the $L_i$ as well as both sides of the $M_{ij}$ elements. + + Here, we use a second-order Suzuki-Trotter formula with the same truncation settings as before. + + ```python + >>> 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()`](#qiskit_addon_mpf.dynamic.setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse") function to obtain the [`LSE`](costs#lse "qiskit_addon_mpf.costs.LSE") described at the top. + + ```python + >>> 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*](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")*\[*[*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")*]*) – the sequence of trotter steps to be used. + * **time** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – the total target evolution time. + * **identity\_factory** ([*IdentityStateFactory*](#qiskit_addon_mpf.dynamic.IdentityStateFactory "qiskit_addon_mpf.dynamic.IdentityStateFactory")) – a function to generate an empty [`State`](backends#state "qiskit_addon_mpf.backends.State") object. + * **exact\_evolver\_factory** ([*ExactEvolverFactory*](#qiskit_addon_mpf.dynamic.ExactEvolverFactory "qiskit_addon_mpf.dynamic.ExactEvolverFactory")) – a function to initialize the [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.Evolver") instance which produces the exact time-evolution state, $\rho(t)$. + * **approx\_evolver\_factory** ([*ApproxEvolverFactory*](#qiskit_addon_mpf.dynamic.ApproxEvolverFactory "qiskit_addon_mpf.dynamic.ApproxEvolverFactory")) – a function to initialize the [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.Evolver") instance which produces the approximate time-evolution state, $\rho_{k_i}(t)$, for different values of $k_i$ depending on the provided time step, `dt`. + * **initial\_state** ([*Any*](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")) – the initial state ($\psi_{in}$ or $\psi_0$) with respect to which to compute the elements $M_{ij}$ of [`LSE.A`](costs#a "qiskit_addon_mpf.costs.LSE.A") and $L_i$ of [`LSE.b`](costs#b "qiskit_addon_mpf.costs.LSE.b"). The type of this object must match the tensor network backend chosen for the previous arguments. + + **Returns** + + The [`LSE`](costs#lse "qiskit_addon_mpf.costs.LSE") to find the dynamic MPF coefficients as described above. + + **Return type** + + [*LSE*](costs#lse "qiskit_addon_mpf.costs.lse.LSE") + + **References** + + **\[1]: S. Zhuk et al., arXiv:2306.12569 (2023).** + + [https://arxiv.org/abs/2306.12569](https://arxiv.org/abs/2306.12569) + + **\[2]: N. Robertson et al., arXiv:2407.17405v2 (2024).** + + [https://arxiv.org/abs/2407.17405v2](https://arxiv.org/abs/2407.17405v2) + + +## Factory Protocols + +The following protocols define the function signatures for the various object factory arguments. + +### IdentityStateFactory + + + Bases: [`Protocol`](https://docs.python.org/3/library/typing.html#typing.Protocol "(in Python v3.13)") + + The factory function protocol for constructing an identity [`State`](backends#state "qiskit_addon_mpf.backends.State") instance. + + As explained in more detail in [`setup_dynamic_lse()`](#qiskit_addon_mpf.dynamic.setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse"), this factory function is called to initialize the [`DynamicMPF.evolution_state`](#qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state "qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state") with an identity or empty state. This function should not take any arguments and return a [`State`](backends#state "qiskit_addon_mpf.backends.State") instance. + + +### ExactEvolverFactory + + + Bases: [`Protocol`](https://docs.python.org/3/library/typing.html#typing.Protocol "(in Python v3.13)") + + The factory function protocol for constructing an exact [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.Evolver") instance. + + As explained in more detail in [`setup_dynamic_lse()`](#qiskit_addon_mpf.dynamic.setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse"), this factory function is called to initialize the [`DynamicMPF.lhs`](#qiskit_addon_mpf.dynamic.DynamicMPF.lhs "qiskit_addon_mpf.dynamic.DynamicMPF.lhs") instances of [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.Evolver") which produce the exact time-evolution state, $\rho(t)$, when computing the elements $L_i$. + + +### ApproxEvolverFactory + + + Bases: [`Protocol`](https://docs.python.org/3/library/typing.html#typing.Protocol "(in Python v3.13)") + + The factory function protocol for constructing an approximate [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.Evolver") instance. + + As explained in more detail in [`setup_dynamic_lse()`](#qiskit_addon_mpf.dynamic.setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse"), this factory function is called to initialize either the [`DynamicMPF.rhs`](#qiskit_addon_mpf.dynamic.DynamicMPF.rhs "qiskit_addon_mpf.dynamic.DynamicMPF.rhs") instances of [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.Evolver") when computing the elements $L_i$ or both sides ([`DynamicMPF.lhs`](#qiskit_addon_mpf.dynamic.DynamicMPF.lhs "qiskit_addon_mpf.dynamic.DynamicMPF.lhs") and [`DynamicMPF.rhs`](#qiskit_addon_mpf.dynamic.DynamicMPF.rhs "qiskit_addon_mpf.dynamic.DynamicMPF.rhs")) when computing elements $M_{ij}$. Since these approximate time evolution states depend on the Trotter step ($\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 + + + Bases: [`object`](https://docs.python.org/3/library/functions.html#object "(in Python v3.13)") + + The dynamic MPF algorithm. + + Instantiated with a LHS and RHS [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.Evolver") this algorithm will [`evolve()`](#qiskit_addon_mpf.dynamic.DynamicMPF.evolve "qiskit_addon_mpf.dynamic.DynamicMPF.evolve") a shared [`State`](backends#state "qiskit_addon_mpf.backends.State") up to a target evolution time. Afterwards, the [`DynamicMPF.overlap()`](#qiskit_addon_mpf.dynamic.DynamicMPF.overlap "qiskit_addon_mpf.dynamic.DynamicMPF.overlap") of the time-evolved [`State`](backends#state "qiskit_addon_mpf.backends.State") with some initial state can be computed. See [`setup_dynamic_lse()`](#qiskit_addon_mpf.dynamic.setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse") for a more detailed explanation on how this is used to compute the elements $M_{ij}$ and $L_i$ making up the [`LSE`](costs#lse "qiskit_addon_mpf.costs.LSE") of the dynamic MPF coefficients. + + **References** + + **\[1]: S. Zhuk et al., arXiv:2306.12569 (2023).** + + [https://arxiv.org/abs/2306.12569](https://arxiv.org/abs/2306.12569) + + **\[2]: N. Robertson et al., arXiv:2407.17405 (2024).** + + [https://arxiv.org/abs/2307.17405](https://arxiv.org/abs/2307.17405) + + Construct a [`DynamicMPF`](#qiskit_addon_mpf.dynamic.DynamicMPF "qiskit_addon_mpf.dynamic.DynamicMPF") instance. + + **Parameters** + + * **evolution\_state** ([*State*](backends#state "qiskit_addon_mpf.backends.State")) – the state to be shared by the LHS and RHS time-evolution engines. + * **lhs** ([*Evolver*](backends#evolver "qiskit_addon_mpf.backends.Evolver")) – the LHS time-evolution engine. + * **rhs** ([*Evolver*](backends#evolver "qiskit_addon_mpf.backends.Evolver")) – the RHS time-evolution engine. + + #### evolution\_state + + + The state shared between the LHS and RHS time-evolution engines. + + + #### evolve + + + Evolve the dynamic MPF algorithm up to the provided time. + + This actually runs the dynamic MPF algorithm by time-evolving [`DynamicMPF.evolution_state`](#qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state "qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state") up to the specified time using the LHS and RHS [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.Evolver") instances. + + **Parameters** + + **time** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – the total target evolution time. + + **Raises** + + [**RuntimeError**](https://docs.python.org/3/library/exceptions.html#RuntimeError "(in Python v3.13)") – if the LHS and RHS evolved times are not equal at the end. + + **Return type** + + None + + + #### lhs + + + The LHS time-evolution engine. + + + #### overlap + + + Compute the overlap of [`DynamicMPF.evolution_state`](#qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state "qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state") with the provided state. + + + The type of the provided `initial_state` will depend on the chosen backend used for the [`State`](backends#state "qiskit_addon_mpf.backends.State") and [`Evolver`](backends#evolver "qiskit_addon_mpf.backends.Evolver") instances provided to this [`DynamicMPF`](#qiskit_addon_mpf.dynamic.DynamicMPF "qiskit_addon_mpf.dynamic.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()`](#qiskit_addon_mpf.dynamic.setup_dynamic_lse "qiskit_addon_mpf.dynamic.setup_dynamic_lse") for more details. + + + **Parameters** + + **initial\_state** ([*Any*](https://docs.python.org/3/library/typing.html#typing.Any "(in Python v3.13)")) – the initial state with which to compute the overlap. + + **Raises** + + [**TypeError**](https://docs.python.org/3/library/exceptions.html#TypeError "(in Python v3.13)") – if the provided initial state has an incompatible type. + + **Returns** + + The overlap of [`DynamicMPF.evolution_state`](#qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state "qiskit_addon_mpf.dynamic.DynamicMPF.evolution_state") with the provided one. + + **Return type** + + [complex](https://docs.python.org/3/library/functions.html#complex "(in Python v3.13)") + + + #### rhs + + + The RHS time-evolution engine. + + + diff --git a/docs/api/qiskit-addon-mpf/index.mdx b/docs/api/qiskit-addon-mpf/index.mdx index 59edc3fbee9..fd950e85c0d 100644 --- a/docs/api/qiskit-addon-mpf/index.mdx +++ b/docs/api/qiskit-addon-mpf/index.mdx @@ -8,4 +8,7 @@ description: Index of all the modules in the latest version of qiskit-addon-mpf. # `qiskit-addon-mpf` API reference * [Static MPFs (`qiskit_addon_mpf.static`)](static) +* [Dynamic MPFs (`qiskit_addon_mpf.dynamic`)](dynamic) +* [Cost Functions (`qiskit_addon_mpf.costs`)](costs) +* [Backends (`qiskit_addon_mpf.backends`)](backends) diff --git a/docs/api/qiskit-addon-mpf/release-notes.mdx b/docs/api/qiskit-addon-mpf/release-notes.mdx index b226ad00c60..36dd6a58c67 100644 --- a/docs/api/qiskit-addon-mpf/release-notes.mdx +++ b/docs/api/qiskit-addon-mpf/release-notes.mdx @@ -10,3 +10,28 @@ in_page_toc_max_heading_level: 2 # Multi-product formulas (MPF) release notes + + + + +## Upcoming release (`33/merge`) + + + +### New Features + +* Adds the ability to compute dynamic (i.e. time-dependent) MPF coefficients. For more details, refer to [`qiskit_addon_mpf.dynamic`](dynamic#module-qiskit_addon_mpf.dynamic "qiskit_addon_mpf.dynamic"). + + + +### Upgrade Notes + +* The code for the static MPF coefficients has been moved. It functions the same as before, but you have to update your imports and function names as summarized in the table below: + + | Old | New | + | ------------------------------------------------------------- | ----------------------------------------------------------------- | + | `from qiskit_addon_mpf.static import setup_lse` | `from qiskit_addon_mpf.static import setup_static_lse` | + | `from qiskit_addon_mpf.static import LSE` | `from qiskit_addon_mpf.costs import LSE` | + | `from qiskit_addon_mpf.static import setup_exact_model` | `from qiskit_addon_mpf.costs import setup_exact_problem` | + | `from qiskit_addon_mpf.static import setup_approximate_model` | `from qiskit_addon_mpf.costs import setup_sum_of_squares_problem` | + diff --git a/docs/api/qiskit-addon-mpf/static.mdx b/docs/api/qiskit-addon-mpf/static.mdx index b84043d5e89..098c8eacdea 100644 --- a/docs/api/qiskit-addon-mpf/static.mdx +++ b/docs/api/qiskit-addon-mpf/static.mdx @@ -14,81 +14,14 @@ python_api_name: qiskit_addon_mpf.static `qiskit_addon_mpf.static` -Static MPFs. +Static MPF coefficients. -## Linear system of equations utilities +This module provides the generator function for the linear system of equations ([`LSE`](costs#lse "qiskit_addon_mpf.costs.LSE")) for computing static (that is, time-independent) MPF coefficients. -### LSE +### setup\_static\_lse - - A `namedtuple` representing a linear system of equations. - -$$ -A x = b -$$ - - Create new instance of LSE(A, b) - - **Parameters** - - * **A** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray "(in NumPy v2.1)")) - * **b** ([*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray "(in NumPy v2.1)")) - - #### A - - - The left hand side of the LSE. - - - #### b - - - The right hand side of the LSE. - - - #### count - - - Return number of occurrences of value. - - - #### index - - - Return first index of value. - - Raises ValueError if the value is not present. - - - #### solve - - - Return the solution to this LSE: $x=A^{-1}b$. - - **Returns** - - The solution to this LSE. - - **Raises** - - [**ValueError**](https://docs.python.org/3/library/exceptions.html#ValueError "(in Python v3.13)") – if this LSE is parameterized with unassigned values. - - **Return type** - - [*ndarray*](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html#numpy.ndarray "(in NumPy v2.1)") - - - #### x - - - Returns the \$x\$ [`Variable`](https://www.cvxpy.org/api_reference/cvxpy.expressions.html#cvxpy.expressions.variable.Variable "(in CVXPY v1.5)"). - - - -### setup\_lse - - - Return the linear system of equations for computing the static MPF coefficients. + + Return the linear system of equations for computing static MPF coefficients. This function constructs the following linear system of equations: @@ -110,8 +43,8 @@ $$ Here is an example: ```python - >>> from qiskit_addon_mpf.static import setup_lse - >>> lse = setup_lse([1,2,3], order=2, symmetric=True) + >>> from qiskit_addon_mpf.static import setup_static_lse + >>> lse = setup_static_lse([1,2,3], order=2, symmetric=True) >>> print(lse.A) [[1. 1. 1. ] [1. 0.25 0.11111111] @@ -122,138 +55,33 @@ $$ **Parameters** - * **trotter\_steps** ([*list*](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")*\[*[*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")*] |* [*Parameter*](https://www.cvxpy.org/api_reference/cvxpy.expressions.html#cvxpy.expressions.constants.parameter.Parameter "(in CVXPY v1.5)")) – the sequence of trotter steps from which to build \$A\$. Rather than a list of integers, this may also be a [`Parameter`](https://www.cvxpy.org/api_reference/cvxpy.expressions.html#cvxpy.expressions.constants.parameter.Parameter "(in CVXPY v1.5)") instance of the desired size. In this case, the constructed [`LSE`](#qiskit_addon_mpf.static.LSE "qiskit_addon_mpf.static.LSE") is parameterized whose values must be assigned before it can be solved. - * **order** ([*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")) – the order of the individual product formulas making up the MPF. - * **symmetric** ([*bool*](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")) – whether the individual product formulas making up the MPF are symmetric. For example, the Lie-Trotter formula is not symmetric, while Suzuki-Trotter is. - - **Returns** - - An [`LSE`](#qiskit_addon_mpf.static.LSE "qiskit_addon_mpf.static.LSE"). - - **Return type** - - [*LSE*](#qiskit_addon_mpf.static.LSE "qiskit_addon_mpf.static.lse.LSE") - - -## Exact static MPF coefficients - -### setup\_exact\_model - - - Construct a [`cvxpy.Problem`](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem "(in CVXPY v1.5)") for finding exact static MPF coefficients. - - - The coefficients found via this optimization problem will be identical to the analytical ones obtained from the [`LSE.solve()`](#qiskit_addon_mpf.static.LSE.solve "qiskit_addon_mpf.static.LSE.solve") method. This additional interface exists to highlight the parallel to the [`setup_approximate_model()`](#qiskit_addon_mpf.static.setup_approximate_model "qiskit_addon_mpf.static.setup_approximate_model") interface. It also serves educational purposes for how-to approach optimization problems targeting MPF coefficients. - - - The optimization problem constructed by this class is defined as follows: - - * the cost function minimizes the L1-norm ([`norm1`](https://www.cvxpy.org/api_reference/cvxpy.atoms.other_atoms.html#cvxpy.atoms.norm1.norm1 "(in CVXPY v1.5)")) of the variables ([`LSE.x`](#qiskit_addon_mpf.static.LSE.x "qiskit_addon_mpf.static.LSE.x")) - - * the constraints correspond to each equation of the [`LSE`](#qiskit_addon_mpf.static.LSE "qiskit_addon_mpf.static.LSE"): + * **trotter\_steps** ([*list*](https://docs.python.org/3/library/stdtypes.html#list "(in Python v3.13)")*\[*[*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")*] |* [*Parameter*](https://www.cvxpy.org/api_reference/cvxpy.expressions.html#cvxpy.expressions.constants.parameter.Parameter "(in CVXPY v1.6)")) – the sequence of trotter steps from which to build \$A\$. Rather than a list of integers, this may also be a [`Parameter`](https://www.cvxpy.org/api_reference/cvxpy.expressions.html#cvxpy.expressions.constants.parameter.Parameter "(in CVXPY v1.6)") instance of the desired size. In this case, the constructed [`LSE`](costs#lse "qiskit_addon_mpf.costs.LSE") is parameterized whose values must be assigned before it can be solved. -$$ -\sum_j A_{ij} x_j = b_i -$$ - - Here is an example: - - ```python - >>> from qiskit_addon_mpf.static import setup_lse, setup_exact_model - >>> lse = setup_lse([1,2,3], order=2, symmetric=True) - >>> problem, coeffs = setup_exact_model(lse) - >>> print(problem) - minimize norm1(x) - subject to Sum([1. 1. 1.] @ x, None, False) == 1.0 - Sum([1. 0.25 0.11111111] @ x, None, False) == 0.0 - Sum([1. 0.0625 0.01234568] @ x, None, False) == 0.0 - ``` - - You can then solve the problem and extract the expansion coefficients like so: + * **order** ([*int*](https://docs.python.org/3/library/functions.html#int "(in Python v3.13)")) – the order of the individual product formulas making up the MPF. - ```python - >>> final_cost = problem.solve() - >>> print(coeffs.value) - [ 0.04166667 -1.06666667 2.025 ] - ``` + * **symmetric** ([*bool*](https://docs.python.org/3/library/functions.html#bool "(in Python v3.13)")) – - **Parameters** + whether the individual product formulas making up the MPF are symmetric. For example, the Lie-Trotter formula is not symmetric, while Suzuki-Trotter is. - **lse** ([*LSE*](#qiskit_addon_mpf.static.LSE "qiskit_addon_mpf.static.lse.LSE")) – the linear system of equations from which to build the model. + + Making use of this value is equivalent to the static MPF coefficient description provided by \[1]. In contrast, \[2] disregards the symmetry of the individual product formulas, effectively always setting `symmetric=False`. + **Returns** - The optimization problem and coefficients variable. + The [`LSE`](costs#lse "qiskit_addon_mpf.costs.LSE") to find the static MPF coefficients as described above. **Return type** - [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\[[*Problem*](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem "(in CVXPY v1.5)"), [*Variable*](https://www.cvxpy.org/api_reference/cvxpy.expressions.html#cvxpy.expressions.variable.Variable "(in CVXPY v1.5)")] + [*LSE*](costs#lse "qiskit_addon_mpf.costs.lse.LSE") **References** **\[1]: A. Carrera Vazquez et al., Quantum 7, 1067 (2023).** [https://quantum-journal.org/papers/q-2023-07-25-1067/](https://quantum-journal.org/papers/q-2023-07-25-1067/) - - -## Approximate static MPF coefficients - -### setup\_approximate\_model - - - Construct a [`cvxpy.Problem`](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem "(in CVXPY v1.5)") for finding approximate static MPF coefficients. - - The optimization problem constructed by this class is defined as follows: - - * the cost function minimizes the sum of squares ([`sum_squares()`](https://www.cvxpy.org/api_reference/cvxpy.atoms.other_atoms.html#cvxpy.atoms.sum_squares.sum_squares "(in CVXPY v1.5)")) of the distances to an exact solution for all equations of the [`LSE`](#qiskit_addon_mpf.static.LSE "qiskit_addon_mpf.static.LSE"): - -$$ -\sum_i \left( \sum_j A_{ij} x_j - b_i \right)^2 -$$ - - * two constraints are set: - - 1. the variables must sum to 1: $\sum_i x_i == 1$ - 2. the L1-norm ([`norm1`](https://www.cvxpy.org/api_reference/cvxpy.atoms.other_atoms.html#cvxpy.atoms.norm1.norm1 "(in CVXPY v1.5)")) of the variables is bounded by `max_l1_norm` - - Here is an example: - - ```python - >>> from qiskit_addon_mpf.static import setup_lse, setup_approximate_model - >>> lse = setup_lse([1,2,3], order=2, symmetric=True) - >>> problem, coeffs = setup_approximate_model(lse, max_l1_norm=3.0) - >>> print(problem) - minimize quad_over_lin(Vstack([1. 1. 1.] @ x + -1.0, - [1. 0.25 0.11111111] @ x + -0.0, - [1. 0.0625 0.01234568] @ x + -0.0), 1.0) - subject to Sum(x, None, False) == 1.0 - norm1(x) <= 3.0 - ``` - - You can then solve the problem and extract the expansion coefficients like so: - - ```python - >>> final_cost = problem.solve() - >>> print(coeffs.value) - [ 0.03513467 -1. 1.96486533] - ``` - - **Parameters** - - * **lse** ([*LSE*](#qiskit_addon_mpf.static.LSE "qiskit_addon_mpf.static.lse.LSE")) – the linear system of equations from which to build the model. - * **max\_l1\_norm** ([*float*](https://docs.python.org/3/library/functions.html#float "(in Python v3.13)")) – the upper limit to use for the constrain of the L1-norm of the variables. - - **Returns** - - The optimization problem and coefficients variable. - - **Return type** - - [tuple](https://docs.python.org/3/library/stdtypes.html#tuple "(in Python v3.13)")\[[*Problem*](https://www.cvxpy.org/api_reference/cvxpy.problems.html#cvxpy.Problem "(in CVXPY v1.5)"), [*Variable*](https://www.cvxpy.org/api_reference/cvxpy.expressions.html#cvxpy.expressions.variable.Variable "(in CVXPY v1.5)")] - - **References** - **\[1]: S. Zhuk et al., arXiv:2306.12569 (2023).** + **\[2]: S. Zhuk et al., arXiv:2306.12569 (2023).** [https://arxiv.org/abs/2306.12569](https://arxiv.org/abs/2306.12569) diff --git a/public/api/qiskit-addon-mpf/objects.inv b/public/api/qiskit-addon-mpf/objects.inv index 51ccd43abced02bee49dd88202351a12fda2bc01..4c171bea93d343f2c733f990ff74123a6b5436f9 100644 GIT binary patch delta 4291 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 literal 0 HcmV?d00001 diff --git a/public/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-quimb_layers-3.png b/public/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-quimb_layers-3.png new file mode 100644 index 0000000000000000000000000000000000000000..334d20f780c46e38cd0bc9e0a25f6395c588b1a5 GIT binary patch literal 43085 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

hz{yv&fh~FD()@cGGLP^yU?iG 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 z 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 PvsqD2^>B);(Y5~q5<_{R literal 0 HcmV?d00001 diff --git a/public/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-tenpy_layers-2.png b/public/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-tenpy_layers-2.png new file mode 100644 index 0000000000000000000000000000000000000000..ae87629f51567ba0708e23f1b8e373e17fb42f74 GIT binary patch literal 32884 zcmeFZcTiL7+WsFzL{Y>BC{iqd(p8#t5D^Fh(mM!>bRxYMMPLge5NXnT@4W^T0qG(1 z8k8PNq(dO&_r$%=IeVXXzo*T2-kIOb`6ClYNV2k6&wB3b{#@7n_KA`#B?TP?1OlOy zmwTuRfgHnwN7cy_;D2byelUV3Ax9Z)M>W_BM;BvzQ;4Fm<4bFpqqT*}HD^q?}f;7v}wl+$s5K+Y%;A0$35?`}dMKHuaY zN~ycXuTFY+s&6L{)^{JXzIqdO`qblNZ+xFhk{!1^os%qA5k*O+pYIzStvhV5l7FKy z=t(|JomHN~prs@dnal5_@w|$R=GC#+LAvMsuI(yZ_;BuIjf4D)9&Bj%sq3dc#>~dI zf7|vH-MF@yz}s%N!63dMW`=NRHNG5h9UK>=a<06V_zWosMpA*N5&9G+@Kh}HKmt5H zb$H_qo|@)Qg3|)=?LLnq0nc$aw@AU0fb1eUc(Q)~-xvP(ge;-A~rxu9Fp{wRpCXITr zTq=aktxbP&kVwy!R@;F=L9X5I6C~L@k9+mP{!IWIpMaFHodNZzOU%R!Q{U)oY2k#; z$iWN}$tS6>WAk7ca%IJYR_s#b`t3MMY$t_7uJAr;Z*Pwkge87%ZmzH%y%)kLraLz`N5^L# zHpp^<+N|znh4RWxc?zsuWNr{*=#v>M+g$tZvbD#K>-+cIi7DctMes6%H=`M!PYBG) zI}q3s)}d$RTLovBXrVkSQ8Z^G3*VI#Hz|y?dZH)dcLusbq)|f-4x3_2x!S?OXD$#A zCVxqm%irHW_P$+ez?mzltK(HxJ1e8LgrkEBaEuIM?&|Q9_z<~zn?iO3?#V3)&#a;9 zZ`&B;XEtcekL(-nXUnsN%T4u8XApLC9EXQ(V@#}ls zNpW!wghbJs-FtGvT@wSrh*Ra_4jQ=GUVR-Sh zAM?__0etx6Q`?;w9gT4*^l@FLPLC%FFJ5FmdUrV`A|k@Q$fa%)Dkm4ltf8f4HI%R8 zzFILnyY0?z{P}pp-uGZjG{Q@=F|W2(cYlAMOVdLkC)Zwq!e*%VWoTT+=fPk{6a2jv z^cHUvCdM7jHIr#&3E1foP9if;X_hV(U&g|#SVWo zyYGyeSs5&ByGO>vWPkD_x7x-G!qaahd8)!1@s*kdx*5gAcS0CMG|~7qm+iyNUh=I2 zdwYBEJqNz;rqvXB8fSg>&>u9BD5|a3u47_MP26oveNPHAN7*Pd;8p7w7ttma$*Vzx zzTQYt8_^@Qb9Dk$CNlSL9R(5!XRq*(*W(l03bpp5<8(`ISd~A=ro+B_j*gCE zrW)!7P0QUxZC)G6$oMn2e|tGlW7`r$E$qCaU63KB5Y0V^_1+b6S{_n_Z!H@UbS3uN zmCIj#d*J`(Wo(cGg;rJ`=6PbNkyrMR>jb4syVzRF30pG#>@`AX)FdNXS4^x-rmFFH zpWv&gws7yg1ThcI^XJdgiMkex}LXHqm4W>4mxT{K)1z~Q=3i6gl8MKA7rj~L>QGpg~ zQ`{sr%MmGBCuZ4(0u9+Vh!O0Mor6dp^_jD;?OYy+iO}TTL=VT)|@sn-~ z2_0X*BCG9YBBG))S5~aKbV?uER_WE$)EwQ!o0^)!(_>;T6IOe@eAa4PtMv<$J!`lf zlhXS&wZ2`Xqoa%PxfxRwcbyAA=CTvr`hMUY27~l9G*HYrjqXxRbS%zauetJZ5h)qh zqgcG9gkyao(KF?zo9J`oHtB-)8mo26d(j=6QJ`04xxX=o8LP;kgBc3!M$*n+bv;VCGllSL0E=+=6-Ra*FYBxZZG39KA<|>fX3{v%+=V zWNu+0FF*e=SQsjnmbuPr6FDTLC%!Iii9I(lF#(rVdandw!e<=ZCi0%Oy~m7}W%0L= z3JBg)iItGE7YO6LsgH7KPVY=pFLOeF4}AcXVt1|wf?b+xvT zkPuWsA&=i1+pvp~IGT~*Gx>7TKOg`z+;~*6hB&aD`f|EFm1#E&F|On8)fnOSRnXZj zVrz!k;xYUZ^$Q!X=+e9LD3_UxVJbNo<5q|PBTEL${`{@j8j`2iA4t$eMnU>kGh4bx=;K{7i?V5S z6nO4v1#oUWn-=D(@-U@0s0)>}8qr?)y!+%%j(vO?oZ3cKag1t4s?X8JG#V!%pZpQ0 zVnX@x<^x+x{ic@#0w~k=hq6r2w}MtARL^QbBw@X{~3Y z5(zmc3O3t);%56HD_^egt2V*Z%vIKnUE%QAqz~?$zRG$oJ2!HwMlf5t<4(2Db0T@Y?xQV&gP%!b?K&9QN)W-Y^pKbhU?R8zUptj4mtr$Z64Wa88g zdCCU1b+8*Cj|rnalfc8MTe2t*k2Vzd$snU9k$jm3-rB^CSi%2&&0dnpR4rL`GLIws z{NoBpQ_FFMMv5q5->1@xN+|(0|V+UU%uSt*w{zD4TWErwf618b}Q$G2uu zI&_&?sQWgC8ri!xSyxqBTB@5rq(JFF+Qb=OdJ$r6J=YOAR`M(mY=ak(_q&=WAa^bT zg=Edn!=qeg);ly-VKwI{e3e1s7ATR(sTj{Jy3pT$>B~QZJ_g>y8px;O9J13i+2!Tx zA8sk{goe=ZL&?aoBQdCXn!AnW(zrfvuBDZ+Wr@Pci;4u?+cH=FN>?Ujw>)FlS8&arD%jw`t+DPgt$5&3L4Rj!*3~zVkS88raqUmzp$o;`bd^Bi1S6&K6mTzZv{!Bwv5=2mlplI}S;AhYpP7VV5n{WJW}uAj9~PvxsfilDbJ zu=&(F%B{b8@jwm^3Z9JI)FP)JALXHL8+hUIM6txQv|zLB-kH2vYg%LH9I1tJS$C(R zt(|YNB|1q^gPZB&JRfYAWtz%6u7qx3#Ftj3`JaV?s{I4c2iALn-dn!&`>As7ZlPOt z#@#V$sIRac!Dy%Qe7@s%A4p(sb8-%Rd3%xn`PXv=26dX>zI}tIi>y^kH@I)ZnI90y zhP=7D@maHXEkixdEa8hXLf^{=7e(S8>8TkND}cJXbWL%noeHh8vU_WJx$egD5IJP}%KVs-ty zL0vO`ALDRH(qmO@MmV1&=pgM1tR6nJu%CFcK7xHav?5*f_}!_m!NQ5&IEw^PH`Oaw zt{gS-$oKX2(cOFg3pm#O4fYHpn-BGmn#Uuw6sTa4xeb&s2Q~+p7LK)6kFD*io6lWE zkJjs}Xl^r$LJe9)pBg)Tn%SS+Cij*X-u-c)SGl!zz90Ho@TfWuyz^jJH`*cH7SlU?imsI;U(u_i}^+90YqY0uE@SdZ+YEW^i-AL;IzyirwE#WYNMwQ2!eCH&8@R^=C)k*ZE-pvQ!#iAH zeQzs@vKP9}Se-t7VNL@@pttc92}~EHfPLiqwj5N@4yf~M=Djn%txw=1H>fSb92UJ zKnWg5GnJCa8{JM#J^V#CH{ydDGJU+9>}v35r?LJ$^ye_gbp5gVBFTmud&xI>t+^?N zb07=z=Kfos5XTH&G}oLer$Uk<8XB4GI%y~A(CEY7SN*kPeNCOpHjf`Xc&*QU!^&Zu z_8}KFH8q?$FwIt4r^Lh`EOJdNi(W;+NoIL>P;bQ^)@^KVMn*(z6=2S=`b}|a$~~M3 z-li-{;b*cQWGZ4ZeV{R4yWyVzbf-ozzW(#zQm*jFtQ9S$Tz*EEW&`_BkL*`^`zw=m zTJnOsuoB(ZG7IGggEI))V^iX*L+$LHI9U$OHx9y~iJ73_p>RF8TZND7aL%`C3Ciz- zd-*axX#{t~OLTF_MdyHFWUI2v;@nkL#q8W|Q!}$XkKHxR=)U>$I28p|RrrGk56Zzd zpgSY`p1zNiYHvurG_kP~6LdkSS)}8e`SXhS=IhEbZ-rzk?A})OsC+MQ$mhP9?aCe$ zSLwwP%3sE}4O3(?rx#21P7E@sF{wRX+?Yb1%ng+1sne(X6I`Zp-n}~$a#c`?*Z}D1 z8G^GY%sSUa#>I`Bq)3445a=APjk5eLOQrIo1??GFsNH>f-1e7cK704^#$Hvb~rN@}D;UJVco~4!9bnxut2h;4_@R~kB zhs_?`97V~u39tzjTTz9j4?Co7IZItTxSBQp?jX^7kJsanp{F7AT(>k>A)vCXe;_Sg zVbVfTVAN=slar&1@T^Jn+>l>IH#U9}+!KiGoGWeVbaH8t^U=fV6^$d~^623vpVO1J zu<6d%6S_Ehm{Sgz$v*WM!oeHatXJpuE`C4}1WKs{XOXL3`k3(Ny^T`ExajYaQ(eo* zS#fTbaYx(N8B`-Rgs4R78SYPf~ z%~x%4D;a|Md`=7w}ebW!9{#jBcqouI7)>^(tq zL^-p?w){nrjeeJv2b?w zIfJ<8$QR7(=C2QzaK|mwUhyqoM2~#ODxlw1RdSCgJkRFawX~RzL=8R2N!1Oa++3Y? zV`} z#6R*x*83DxhyiE{ZohqQd+Y&~Ib&ejPTvt@_|V|%%2&ux-^WSf2K`yeRkdeE9y;lS z6Gb{2D?aq`&`-G5JXVz^zo3-`lqtdN$C0tbQbOC{WRoNHfw;vyWDerLvQh(-3Q!_n>4+_$ggt)!K;*Sxx6V)ACWj*=$gd zmWJJ{ot_3M2GxLe>MPGwDj>RaVvsvbvN)0$ZsvQHL$|uzl_S}hQ(xHSa&+vjE&M^b zNOGi-Lx`=zI|hLfDeMRKAI>OOC@ri;bFdq}-xMc&Qu}tW=ZgKPChWB6;P0eVnX3*d z@MVO=gwBb9Dhx9szb-hLC+1N2Azo>FZ$B6uwr*nS4X4^8X9iE_Qc-G_d!iclp-CCY z7;eqzGs$Fqq!7^0B+*XY?B2}*kHIrrwPS?UxlJwIC+8u&;KvRn^+b^HSLOgpOQiMW zjr_voM|TE~=|f-75e$n5NRD59AmRH$@BRRW0-_xv4mmCuwF_SMdk&#JJr`{>^fmk@ z-stVyx3MBFwth1U3{^EX>WdfCy1E_{1Y~4nhyo&K_Y~xu=LmY5 zJ`hlmK^cg%>Pslp1HFq!!{8I&XwgSauSn@6yz2#Q#?nVdMjo|+7HJ;1DYmqbA$h1)L-12fhN+xm94<+nOUM-G`Df9gZ}7D=Uj;~xu_?MTSWx6ge198ThW$!IvWlTj#D#YE9j z2?5XnroMD(Ktvpr!Sbq(j^(LoX-?n2oFWK!p1R0tez3EOL8kas+D_(zogWG(cHDB* zvSM9}AdpW1c*>q{D`JwTtuUjPVl6l4yT_{So+YT|B@|_6%Yhrwz;aRJRB0nUluje7jVv+NB@T+{hi{-S~-rirm~5&=Kz~amfo9kpk*~6(TPu&NVg!# z-a!3yN9nOKaF*3lKr~aSAfH0O1^iDTmKm1hX>N1xWWmK{!ff5NBRk(%!CAcOpiKvi zxM;0{Ns$<^poxwACPxNbrsZ_0D5Z96LFasZ9tQqk)x*C09ftk)nxtRoK{MFNlZ&eh zgH}WyudRnJT7SBp(6di$_s9HPSxBlT)xnH5CzEC?P?T_VeYXTk4=g!9ejt3b{-lpD zhW+3A_~o3xN+G)PXKiP@fyTTlU>#)s~QmLsI5IWaT1?BTK%FMLP_#W)I*GfBy04rO+&g4KI2><|2Emxf1L=N zNT75>)!U#fLTAICd-5KAySwCXfMN=O;!QX?e_W_!Gm1S>UK${C*i=b@+5UwTTzf#Z zx1*$?;83;C2wMQe<25$~ho498foWizN1WiRE{^jZfs$49Y8 zDUNSya%jb_-7#z)CgnbJxS;3#5N8nO#-Fl!Z7c14R+6{wE#*Y@M~?ykQo+ysPT2_1 z$|WV3d)9UNsoKgc5BJm5q<*J%nGwU`Lfr0&G7?;;^iE&8z?i}PjIp@5cKYdM6qED5 zGmiE|$7ZCKLeUC;0jKB8{-gQUFqm!BJ;Ci%^5ZY8Qm`5gt@R!ch1G{}+sQV@Zd91B zU0nmeoWB_XhpS?@K`Z#wsZ+uZ^X~}MzMnroU}0s&ydq~rl2RQXiqFf-i%jwfZ>F~S zVs-GHrQ!pY3?Fa>epFtj?&8eBpT?=Cp;5!)FR*M@-PW!84I?95;{EYE4EOOjowFE3 z7#sRcMda(g?wbmFvdU&hUYwCa=!|4_{ylmyXd$8p@4^)M61SkU73c}RDj+22cE?`b zmtP$mIeJ9=)W^H5k>&1+FXR9m>6CeH!+rERn?*vx2sE<+9WqH+t~V?K9V9;2A5Y~G z$i%R)WPYom#nMjhep(~XlsFhd2YlVCNoPIDMh-T%oEEI#XrVX0TAyKDur|TiwZeM4 zE%snJPBFVfUkg#J_D!si!hAfDiaXDxKA|oPu~~@qbIa`v1{VhdM#$l#zKWeC<_lqQ0h(BO+n0+WS0Fvb;-Ut^${}xf{*&{MuzrPMU&hQ3wM9f8^I=_`vmC!Er#K!A3=6LxA3-`Yad8Z!Pc{M%-g-P@mo zs5u;0M(z?&iDwyv7X=&lLkKu2zY`WKBPCHY~XgJWYuY|=$%zN+O@Mu#0wGng}W zw}wqSlsQT!3Xi`0S>sob%b|*PTb4IVTcbZfQB*UX{0*{pdBe|7MD3QJAzlcaoR3|m z+_LW7yT@lcaX%v?gH1$4Pa%pke0){Y*4EY!_Pqf}vP3FE0@~r7roqw6w$a#2 zL9eRwd}N)l=8YeA0@pq`j$zn6f7KwhPXwiP;R_-M3eRLMZRH%zC5s9(2guM9oZXuZ zcBLgXHR63KuLKeRdLeaQC4q0juA>%`1P}?#lWwNzwQUb8ZKcfB?t4&ST#xn_oIrVO zu{=}&ii0TPjy=~Ioo6*%81&08*}IeoDv85laopm~0^JIzv2pZJTXrZk0w*JgFwk|$ ziN!-G3fu5V6EV?LTKh14Iyu4g@ zhFE@pHuH9<&!KdJh)ZR*@UoNTEz@^l;Pq>!w;{;IA(((6`UQMFEj9xgGB?9M%{Zt8n*^S>+t6Mi^p)R@cap`>#UD;@9B@J zUTbjB7Jf4CQR-&;&e2MFNyKgi_C(@=#4&i}+<|K&cnOn`{X?GmAFn|>Im@uYeZNf> zuvpOh{b-Onr?0dW@DNQ)=i=F|%3ySmJL|~qW?B2$Rbsm-AW%)qDq5qD1Qx)y^utJ3&UL>z>Y~8%J z?SBL`ncc=M&#Qx`GVJ;Zh2D(^+GZP6n8j2Js7^6rNI)zTk^U9Y%$a*m(uyb^o+(Nk zyXS>-yb_RN+-%-tjtKHfx?M_;6VgwyL^l-WDuj0a7!vn4-hq=>ER-y3l-g9tXdE-= z+JZEB(l3!e6;{>>*AM5%K6D6hiO4GbA~A%|>ir5>cJB9Ms|g-{!s%x|aNKK6wInI$ z`->Pdkb9mlO5JkQIi+Sw@itqi;4Mdo3r+UFA#Ie%mUDi1S(fZ}u_Xv^)qEDdrKiE} zt0_qZ>1qQOk4y)rmGr&1wZTN8VR@x2_rpUO0F$`Dp$Z%L)SVR<(Mb%ta3ztwrma`i z{4s5w!U^Q--+I%Wef#qV1K?qK!hO)wee@qlo8RnI+Wl0?qqQ>H22vqUbIGbBj&~9o zp5~CA6d+cul|P|OG2Nec*{w1Ek;G}|CgKl=%K^sP2FD@E78FYI7T5y>;Xn~Ca`=6m z>HbT}nYPejKw2(cy*j?QH&XH}GCVv5&=faOMrs-w%f3_@A}|IBc@}Nk`tC}sfK4oJ z7mH5aE#msg7l35-?FI_Rq9cM0G|7vo8L!guaB*qK%fAJPm0AA!_3OY?kiBab3OpQu z%{wnokz56@jPVElF@fF1v`}^~F2&|RDk^hN(9XmR=4nYv)Bz|BnkJSdx;*?{l#sHQ z9ZHbml1L6MOQ6BPjYLs$<_;AAEsw#8E6%B}7bVtP;EopAzhv!r7#|UFi9yu$PBPkV zx`|}yozH3FdjK)ol=-hooU!$PEOAy|0h%g6Br7&g)OyeLtH%k#hFU|eF2{3kcoOBM zkVB@S4}LoeKW9VlKzi*m`0Qj#%hjiEVWBl7=iY()GLR&HPwakk+08^GKw?)@3RG<~ z1~v8^gTrXfR@72Vqb_oS1|fuKRZ1SU=g9Cg)zl(sf^LyqtNuG3{oBR%n|E*hks%~g z_;6xUxa3F~aat+sLE0n+$)houd8oNsw_8zpA7E}qh_)YqYmbLhV7Vu_JNtbzMr*Bm z>T)U(RlSAXU#1Y{5_8zHa)njGiq#F0C1!|&A_UNKXahnuM0+8f?XJT$M_IKn+F z7?1Cn%1HM}Qd{Wje_TW>+4*bZB29`YZx8o3D~y{@fLoAC+9NhGF#|R>Ho)}MfQu|RjXBi)_K%SDf~{VQn3hpT)4Cz{c^ ziXzNGnHWFN_@G^8nVeXFWYO7WU7iiZ-rhO5csLU$dUdw4g;HmmooJZ451#dl-S3P30c!pqOsgPf@D{~ZvH7eyBvC6Zf8)R+` zAyN~0dGonAF3qhB9T=^46D6aL-Ax+@Dr z3(8=-sA(haNx^#c)inUiq$wvl%zo2U!Gjk#g|jA$7SsRfEbvp zbE&F*ClCtEMBorFUAT}6xXKWng#GLpnH!(C4+;B8grAOq)YJ!dc6PX4!l80m z2PH*fhpJF>8pbPCJ^0UgPTbCj1!iY&M>H}+aXe8RdD~qQFB-{W-{KhF-1ik@O)ds; z5<25I=%2ls=&_~(8UU@JjY;eVnVDI&!&&U>CUM_`dCEO@ZMT<)i+Wa_u~P+tQ?Al# zSxS_PS85ERcI)963kYH~Bl~@fkGWBlc98}8;romubDBF#O+W=zrtfIDe}f)0lpE=; z4v6WzMaP%Sm?+<&bUL+p8=vdx|1#>bT7;&^c3J*I4YE6e>nV&}Yp~v$Q&HkihZ(QQ z7tK9dN_d^^TbVF4lWzOI$b2rS>l2V`pN!5qi4qPsDJUrif%Gi*#=8><3NUoJZ?xa4 z@F5(XKu>$LP-`t>@`{ESTqaU{4%606$$-G3;TfJ}xQVxEz#ar7N{KMb1j<)!|HM6y zbGt+V?n$VurAR^|pXiAeVt8@s*fV!%7k;9hTcew>bNP>G4|?Jq?RFA>>Z>&p7Z>=H z$h?T&M9YpKgFcb-1ik#%I8RRilK`lW#_C*(-VW;W2&uX|CKr(iI{x4uV8gG~sn(t2 zF#c8i@92!c>WYZ>%9QAT$%WKNJ9)erKyi!@U>q>Om_Bd z;4K(R4SM~d`MSY*HHRA6bkmIE4Kr3zn7uJAmMpb)wSMX;2VX)hvAx^TY;>FX26VM< zTVrFZg+`MuKJ{~YT&<1)8K(bkM9rz=V##jwXLHbQX2EOiM<+svp8}xIFtDN(aFYtC z7-*)0#s+4$F4T#Yko=xIHZy{3*~+H>8AbtgdAm|6NXl7>+C`K0*d2owgz}|PpLF`d zCl%N!Ezs#Tb#17qY&YCU-Vt?ffL0b%Ws#nOpotQ`Lrj)plbK!bdk`bzHijQg(lknwm$R zBE*g(wU=M`Lsjp}1(Na`zxIZK!`DZsWEF} zm{DyayDtB>;36nceR{(M=H;meRjoyqWGB;A-l}Tn~yKt~}B^r5=r1eJk3Ot;ed-xC@ZFRdsw}C@HuV3w2PERlU6kG z09Dm5NLM`-rmo4-P}4`H>h!&YnQi*pO1_lL(hr#rP<~I$| zv^+TpmWIfpr0Yw{IvKTTdO252Kj!9kaIux^NHmMtMp0<-px$nG0!MYPI>IAZDc?&* z>u|V|bx1WMKK}KK!3*zpG~QUcy#1Lu=?S+D?*41$KX(v8zeuu19Cz=k5WD7y zUOS_@!@xcd@Rj9{=})>1?oI{EFM1OTY{n~z4R=KfJkih(g<6J>6*z7$x6NTL4+C%4 zH;vH+s|xI}VBC|)e=&=4Ja~@@uixHJLk3bOLO0a`;vss;zWeN9p^5AEAfQ6@!TZ$Y zP;-<%QXqaI{E2#aLGj*Nh^?7x15ssqFxB8G~zoo=`D`ot3@FB%%l+ zDu&5o)ATsWv_%q1^Uu$^Kh2z>1*YG_o=n$W* zpA+L^$?=LbtVVhBtYQJ!ss9b^D3H(QsAc1$0NLT`Z02);J$0A~OVPqD&Y~CW zYpmDpCs*O#)YI^Okpma?-S;~pZ|xVw<$oID`1l5BLi0{L@up|EA<7#0oYP-CPn9P1 zaN^J4-kYC~6kU3v19A8;jcn>%5fc1_B3~IJWnMzZqu%!(8{a9+yD=yhK=oFN((piv zi)epatHX-hOx9|Yz34^(-dy3iZ|}4^rU4Q`M}m86=td)8Q$Z0AGnk`tit0iJf+U_6 zZ&a%gJ<5Y^W+vueD2%eL7cVDCtH!9|bnw__Sq{7V=}Y)y@o@-NniJzS+)@~(@jYh= zxmn)pPiRw^Djq(1WV!ymrK7i3OGoD;Fv+KZM8N7qjT%_ZVViOMuR%jpQ%dR;Fs@!= zVk!bY#T=k(*Vos_%GA^WPxg^;J z^Cd2;=c#-?Pns19#{=aE+hXGPDZ6Lvp+0+4Eq;WPRa;-4ZdyJV|MZ90%x37M^SDjz zdh1nuv;-hplfV^*1KF>^8V56uj&gN<4~x;0palckKIqQF>t~IgAu6)?mII=M$PyukN)kg%!RF_eS;aUViT5hdYPs%g*OS%N`^&CQ976@!m%IsOzvXb$M$rwYE3uYDxvVqka?_c1P@j}##m-M@=LeSMh6A*J^K zcDl=82#|OG#aOqGl)hp zyL2YsrN7JHSSbF_{LMdbu_1jnn(0cz=t93VZn;rudrvK-G2#`H6ue3d{srBS$j3o&-%cl(=9&HTd zHDwBuWEmH|r4tz>{}B`9zv-L*rf>e6zWEQ*H%rUVCG(nDM>#eX)yMx4=@}%Fo=B*{ zn8H~i>3LL8!xk=FwYyC^kW60w?hv~4vIa{ynp07|wIf)4637)|>ieH1(-RnEP$)5! ztUv!V?m$O1!KDSSj5UV*Jg$-ZLZ$#R{!n1|viIxQD_;_$h*>&~o@uxsm(wVa@&*L1G5S zcC~#XUYg20G2vE5hDQb$8GOB4`xj}Pl-3dgq1r2_&?y~u1K7WQCsKgbfSQq!TfTPY zy~seG7LWXmEu(2BH;_M(XH461t+-y$vCco=f{x}6t;|F`jdmT^H=T^j2M)Eg5v=l$ z(5r?;XSw22-<%3%PhF5a&2i@JZ&XJ_Ww&;PVo9Pg48a~XZ>U(!Hx4pG)0#_VGfqXF zg<*+3aOY^bMiX0%4Aser`C}G4Ss((nQ{5IeGz(>-ky}DX7yeT6FC=j|GHM7BKa)6` z@>D*m2c|v)FaL24r-hiq$(c7td&p+Y$^Nv{+qvLh8RdSABM7lKG=tPV43!d%Yt=adsp^3oMDPPtji@j=g>Q9KhS?9Ic!rm00Gg`h}2UxmmJ^m ze5ungvpONRo#5id)TL%%m@j=A`=s|{C$O1YnQ&=zw6lR6{Mc(nnQy{#7KbonIbn5f zn^CRg#PgoW@GAm>#jRFkeg*E|a4JOj#9=g&^Mg^VVx*S? zcvNyfxOI4Mr|8bu2~M!=RtM5mNA?0YbflvLfhLbd+fk{`NNmmH`t&Mc?%$8w1Sq?h zuT$o*st@8y%gP2DJY4cR%{Rd%z{18xv@sAp%mwQ=W#2EpBKNdn=Q)Fi)vpH}ZA3SI zU3Ins_6OV?kB^(Y*v(z_sE#X)8rX{&y7Xt=*r8o)xgiSmPVXb7Th7zkj4@CbCG9-D!L|pZlTB?u0`q(OL$=vVX9a4H2z{ z04(JhHG0F-f!xdi@t~m4(BVp(aXz<==Zdj>@{Rl5Fgm=Lv(8i*pNOsx$I4}7B^4{} zQb2WwX5m*)sug>V1IMSG9=dv}2kZ?mGw_CEJO$2}M1X0oqFM~cT)sZ>jFAm4?9e)C z_V%uf+B_@wKw1la^>3o2V&Zm#+Bs@uWj|aAGv7lEz>tvkRR2A2($ebd^@)lEkQ;Rs zl@y>4#MZxD{7G&=0vN>5+n4eQx0{WQHfY6;_GZSaU`g#7dJ8XWwmxhluvc-tvtgI0 z*$WO+Kqw}^qsw7jBAsY?_~xJ^yHs#BzcAJ5(7kS}YNfTxW13>Auv4#*alqB2ZmW@` zs~fK+=knK#j;8@zh|z)v?;c<`=eaEgsk{is7GCZ!{zH3O@+T1gQ_50{9^3qy7>?p0 z-=ljeO^$t#fa*tAm`w+|F(Nu>&AI2txPRp{1FqGL16koU``)w`6b^nb7U`~c*NyFZ zNgu?W3k1C8+@1>1O(bmG+?q;CN(tMCKKNxLkXyd-E2>$1dn*yC?7eZ(DySS;(2$;0 zltWNE7x+b<$B4t=BFx*MI6C`|#Zm=ogi&>bY_cv*0k<@VDnozJcXaM|0?C~-(XGS0 zg5lgth2kJ7(>lV4Xj8?yCq6%mVdlaiBF0({YtJ3JGXCQG+|*P)_keXO+R$Ad5I%sW zA}?IL=+wsGV%`(4u-UC8vB(|*jS!eU5a&{X8$u%y!=q!hPkB^~QHN3}KP@PjphB$y z8h>adgjf-?PVTd8K3LdRlfOg1j%Du@4cB7raf>&4V=+8p8{J3qq0Q;W#FUQBNn%RJ z$TccSApvljD{2lxHHkL~KZO2O-NPpQxV9#4P$OBqOY!L;GTa*v>4ZkgmKT9ves?Tu6W+l)l~VC)eD@2-PajsuZ^6;k?@UwPSMnYfN?^9=0|Ee#?yFM z`sh9V5&`=7@xVll!&Q0-bQG7~)_@u?00E;yWNd6M7zhFq3b-oZp+H5jsXcB`1|gc} zqZ14F&otl3=RQ{a;s4=80aD0u@*P2Q3SeKO0U0^s2Sy|&8s_y0@EPjr=EC6@K+H#; zn6iur3wwg?WfXHSpYlFf9cmzj_zJwjQ-Z*ZKcm-{3b-p1)3_ud*wHdskZh({Gy_9c z^uX@SrO5$FUN!L{RT@2|{rnFD1t1XgiG!xVgE-ig{EH6&i44^^Y#@2?0lw zFmRGfHqL9hAeqZZK@HOAIg2KgwSmBbfkyNtOZ0~{ zQ*|vJ13JjXzpS#J^K_ZWk>ma?V3r=**gn+fq1oxPOO8ESn$ahkjuQbZ`0S`$Zn46P zR}DWf3+WrvXo1lV;0N^iz|C5_VZda5@I~&5VbQy?EN1z;ITsI?-ITq{_1%2DQip7m z%&@AchTfdbMT^Yg)5)g4=HXO|7(|@Sj}G_8ijDowG$XTB(!ga`2n>tF-5t!+0LsB?}!LDYkz%pHmOjjl5~|HJUvyBjygkG#LQX+%7`v=BDcE zMy|%i1;OU$=WP)+r-+%IX(=jm#AFL6u)aL;;bRMEjvO>$?6WG-EMz3zdWU70o0>WqRM9Q;z|W9N74&rEkiXiSOhq7UuUX zEXD#=ookjdDo$?F(!PaWJfXob+!+(S;Ue#Cj#Y3+1DESSzD^mR$Ic2cSvfgX0F#+sx-CZoLc&m0 zWZ$q07V{tR8OTnMP1g|!=CC^xgE@mjD4Pg)L3J+0O&eZO10p2FTE5I|AaVebpzeF$0=HMndWUL>b~pfS zfE{iKIE-23!5F7LWgnax9)OOa?O~&$jt(esq#GEBMYXs)H#>X#XHX{)1a%6Y6lU)M zTi2N)sDzKvfe-%XAI)SM(X>{(&C&y#M_L1R)0B#}t2t>#mcyj4#7>OE|Hf>zLeFZo ztZ@}+pYM6wxMawJZe*Tb-R-JT0&ZCIzvcf)is&`8J!cLSo0m2A*Sg0JMz;S>ko;se z6zB&}1Jl;dzoF*PTm+`=im07Kj8-Fx_-DgUlS_m#0~<0K{hm$Bm1%Y%Y5V&^Ub6py z+VpEa+tB7!0njG?++^7{L&X6(vn8AysC!N7-YV8q0=h0+V9S`{^D zg7}mBX15?eNWW^Rt7n6$SHuB=_jq}UW9ujxgw=b+cH@7}*uj={ZX^nM2wSZE6D+Q=`-14 zbW@?2B%BdVTf|@*!gDJ!J??u4|IM1}L92VDK-rw|k=g@7eW^zTOU%9jk9O7{tZyJu zw9T|6;kJa4kIEDL(jNpFyCfFkThY4}Nu(DGH?TkCTq?^yCTW zdZ@PzaeY1ZM>iSwKzEqok#0v}_1;xCmL=T7z!N(dOQ^w*?rwNd#?3jBF2&cG=tEKJ28OFvI=}V8?l7@pK`T_+GO6&PonoYWSV1#=(UopF)t{;=sOM z0%^>Qhx~}iMO#%Yq>>Z^3TEEIAO0NyiK-&Z{z4f^g9LHU@(c4PUet(7)v{-2=47V_G8@dOBd$Cy zu7aVxfgH8%35VXLK#9W?VVAXhBRob6*W-dn1BIBjdXCfgaRncQ(pVTzgNL@THmm>r z^dn+qM;`rllY#PhEHRx~w~n$R2SZj4TH!Y{m~P3>xXYESa&lqe0!Q^VZU@D%m5GUW ztJj@OY>~%I#^j66L<`I*VCmOaVf1hSaco!Fyoz{}j^5+W6DbaGxj9KhEEDjJge)-9 z$r3R14fh5*anI^0uU&)F>}Sq$XTfrMLw58F$G^WX(#f5%GK!2>Vo_Gqa_uEKS|*M~ zVyE&+3H#-C1$IaaOwQEPw)n9$B~`ny0Wv$PxnM}vqT*AyEkk;e;qP#c8r|UFF4^%Q zWauOQOSlB3EF#bs!*BJ|sQXvu*XGOl=k*U_U6__1A4xG7@F}vL9vU9YY#WHa1jdKT zP#-f_B$hH@m}Od~auPQf?P-0vo0co>Pv@x_$NX`gn(pbp3>fH9(`43qo=+(K&v_1; z*}uhe49}V=ifpLwiC2tx%tt6O;Pj0XJ`}K1OL7on2tbQK`fG%pRSy++EqmjanX}Zy zypK|Wr!ESNPe>?iG$2n(-~{te&L~Gt%$Tw9Wd;wjkeW;VrL0@@-1NeL2R~_prMMGj zW1oX7`=swj;Cidk{?mb3pyc}xhZ8^qwl_L?tY*K49}$OFb|;8beOlkN87-Aj7Tbj9Vm9p|yt_y4tb=J8POe;c0`EedrCMNG>?5h`0`i;AI$EM@N? zTb6_v%V?2OC|Sy`M%gK{#%LoP`&P&#Ni##1W(K3-`P?{5zf-5q?~mt?=k@&EtC`o_ z?)!UxKi})R-j_N|Blmir1uc~-w`~vvzkp~`BAiLNK-%xov8-r5;K3aS#2D(;tC~nr z#GsUQJWnX;^sOL>&jy^H_c>-dWc;whoLw1*u_tyr-7N?-Xy2jx>u5VF}l|(j# zDF;y&%cCoJb{w&{PZQEf7)0|!uAQBoog$D3Zyd~ad3j?9G|QiUcM(4{adG(?B!TVm zv2mYCp>x~Qz!h7u8HQQSu%aA(Y{aMllp85kT;_MIJ@ywab)w8-5D7u%dJe*s_t*!Z1bP$wMF9p#L&}}^y8sN&p*YT zpvrz)!|x7Z9j9sAzk>~TC+QDmO-`$%wWgH4cRgmr<=|Bx8_SwCMv2{h8v*nvH;BVr zakBL|u77gGA!{sn?~Nqn9lxnU}WD44!Jw%9;3G-7&aH#y3B;XQ-& z$IXchEthy%SuX!MrrOR~rrK+R9b&JyIEkmeCKYXH4j~P?fK@M(^9j5J%Ht(fB||azj4X=ojYu*)4Dd(%uXQvht z_0PBu$DN6eM&B^pAe|?o(R{Vk@0^8$mvhfvN-Vk+q@~}kv^395(cVpkk2#RmH0C8- zDtwZ11+E9y{Y{g_w&4ic zzH>i_>gelh4YRFUClEgEc4Rl7kIJ1FFb4x4sqP?`U3c)^W_z8!sn|YS0^R#w1Ppx0 zy!CBrz|1i?1yz>O&Hv%wu{m3)|cvp7bV6%>u+8<#qNHa zV?d}8mZ=HGwC5`^3wK9f{O6wO7D~<1dL8>AU2recLjdNj~JN$3zNBEdTt^!IRRsHtYrZ-oQ zl6374+o#%s973wzxJGyP2|BzrR02K2pt+7^k{M;$Bsb(wFB%RED4dBl5zg2_MI&Pr zSpgS=JLI?h?NC)W!$qX)LH1v)Z{oFpja0qcwccEfU+GQq3t2+U5d&&%eZ3)^&Si<; zt%LYp6oG&Vym-+Lmj6eU$W*gba3m}3)HWJ%tVR@B3rgT8b=oZ9*0D*8>(!+z>88Kv zy?*~;YuugAqUR<9+eX{v45L@;gTdu+*Yw(1sM?IQU(#ua0|9jQeK2`*(A^ttuQ{u0 z!T;vEZb`-p-7dxP?z;$C4cK#Ek=5u(Vq*@^Y?0Na4+9lE-ptR5GnwF?Vx##CK74Fz z@0mYs_-a>@ldTZ1y}qf9sF8K~QqST@Kl$8##VoNuTyW9)a`e3TE9o+P_~XPgsp?mm z1ELr6p5MBY-nT%An`*dk zUjTdE1>(k8i~u(uUpma2b}S}c^YG!evHn{6`ZJNf^F6|9~-=J!tkJ#l_D2Iu*MtTFP4`Q@-fe!>~4n z=8Y$XzI>@6X8!mX0LtM^xdm_s5pb>yA%BO8fCX;yRHai<;%4ckpGv6VzCt~Dccpv+ ze$V14vdjQYe>?Jtv*0HQy2E?5v*n}%G0k0ZxFdbZ8H8Fs?@6Ip|{A9#5%&eW}}s1o&Sw-iHi|@*w zxe&EW={W8~sa_6N}foGnt+ z-C8%k`XiM%>28k2oxUX%@!=}ZS^*&zE*G&-18Z|u#vyl#>-or+q(BU&YN-~N`Bp#Q zLn1RLo#EHB+d4O%KPaTxA*{hamhw80S($)7_^Rqf)1_6{uLe#dV09s*HIFxNl5Rwu z!7X7-_h>bbN^5!e4rPG9>U|oSeORsn|E71~lVN|a#M)n0r!d|yMZB56t`OzW-gTnc z&PUwD`7@CC(7R+q?f@NVP8cedo#LOpnE%VbHIF0zb?#>M5OFYgES|DWsxs@cQpd+b zJxY06iyMRIK>>$4Hrb@sly_sE9nAtiK!0#>bl>9!{D^*pM)+e}ZE|aJ19!XJ>vX*Z z`3n)p8Su?^#%EXwzaY8iFyMs9O}?#fKqB3`%K>b4tz>4G$H?pIG5v^_Bl^{f{!yw{ zd$v^0So5ABgDaaLY*|?+y>ZcOemTBz3+JWq9|S1T7w~|B4X3 z5VaW1klj-SytNY^s{`WK#)UWcjQh=u$70S-yeL$5eH&02hR%UOWxI?_LDT31t16K# zThw3}8S_#Q0h;Wc16NyfER;dqt|q>@wq8=osZ)wROd=i_Mx!?F$tCVP>PkT89syAk zkkof*G@5ZpLGmat%>e3&fTm}|mlrQy#Ninb(xx-ITnax4piueC2VGP^V4?kpMz8?o z#5=_gG=hrFqDI-Rp#pn>>lhPIxd1gG^NOUhnYJkEWo>N>oR~fG95R-RuRmDTfW=~) zprBw8Qve9qmVR4Nrtc8woT{?rxt}9M*Sq~QAsVHUdjbeszm)1!(O*8PQ@vRZ^%@pgnybZ!ljXR0WW?TNEHM zQlB%GC&l-~vxj(Qs1fx&V#iD%E!WZcEdk6*S4cP!n4?LMWptRDmsAxJ$*b+n4li?tG3RI6RN`x9 z<1I%a-f}inV_5LUbXK9%XU%GIF4({NPVr_luJ~cF0HxA1XzGxk_zjbyFzFxf)F9Z< z)bv8Kbzs!Mt>Eg;($=KB6cyZHVtK9vqTUdo_C>WQf5fM`zsbxpM#gEoH9R0;5HX}Gk zsTDxcY0}PKW%Bv1!M_M8q+d>0B$h7jb!zV>#V=Qeu^;3ry*maH!{_B1zWQf<>$6@s zP9)GQ)`9%fz6oTRpNY)qZS*sJHQ||qzCI>mLQE(?_%+|{Vqps#D5uTIGJ12e%n>fZ z20O7tL6-?s%Vdu{Mqs-O3)fhX`*`Ui>ysxP;Pnl+P1-oFuqz9KCs;i=ANfR_@ptMj z(giOz{4=u;J(CKi*`@PC0$OF9-7RN0EV@;@JdlS&62sb_p?|a_GDbHlEj_(ETs4+1 z+1+z=bc9GFYr#ko4pLhp4j1SQpj}HehU`gdHkMFN%U7pG+<~Ba&N>Ui2&#f5cHoop*S^|_XwdyBa%Oe2Z&D& z+bmYteTPDEV1ZRi7jXU4EYge_!v05?E<_1oVRcw8#r&0j^Q1clf~jH_kY>P~oa&sR zqW@!V_=n<_zlLT05MFMSJ$i2yQzdC!6JQi7vZH*Ib+4D6?mK>R$Zrt0Cf&ggkj4wp zNA^Gap27lzf0ZzWvCB~7vJG3pVsz2-5?Q}R7+(mMtT1r9^xpMSzO$H&Zjrp1f$--D z7Deq*WuJ4A)~C~4(ypRDXZFMt@ZGF39(g-@ji==zj9L|efRiLboqz~L0}yEnD18(( zf(6JfV;BQ)n^GrBY9(NAVz3BS1ZJxY<(bI_C{RIEIRG**Wcq=*>+{EidS?1;G=?b= zU+ZC^heTKkW(R{3ZxBH==j~llYSxjDT5=d3oOUKbE6bXdb>g2s&N7YkW2?35%nq~l z-5WN1wIg(nbQW@&yF_`?n#yalaE^5LGhrC0R-i)|KOLM!ZhJQH?QylN(DK1l_q)A* z*I!b7i8jHgC@A}!uHg~(kc5p;8^_8!K^<3ea&m!}saY!Yy-fbDoY-3YWdWs7RbH;cW(z0g{h5}FzU!Q zgK?x6e<7!X+7=?)lj@jVd=ON2M79P92GVZW1E4|jtCXFuP!6WA6rJYi2h7nb735qHbh`aG@mEWuO8>{suvY;E_-j2<2a zWr9ZIrK5+qxNi85n{9t|^|irkom_=`L(^UdTe#zI_&;bHUp_(ys~MT>NN{a;d%I8p z^B47`PMHTXH%flYk1$fU-qcY_gM(ZcJI}y5FYD_qhFK zmKDLo2TQs-E|A6+Lv2rJZuBBIEG6`-`&wZI2y@!W=^-&OE)`K~t2WM~D1Va$ZXnk^ z>9@jDeKp6(!ip)$@sqT(Kqm@22&cbbF-tZTHOy>$#-*GIt5q$Po({YQW*2Gt9%D$N zu5~qqCe~XFhOWqbj-TwCk($6904#Ou#pwg2XyEe_IgEM3Y;RTf)5OHeZWMk>TE2{B zr>~Yg19K29F%NAQ{Nu8j#i3P_0R;iFV|R2R*HHA*^xR>=*p|0b*3)JX}oJ&7kYql3t(hzi^G9 zHSp}(pSZBNhj}TmOfdDl6&Bg~eLM8h^K!*s@Mca%xeB4+4?{UYU(S5!MWy!LE{+Q4 zzn^-)dQ~ey%!J-5CK2q2(q}()FR5xMw5jD$q_;wC2iV8-01?*V(P4HUj89~EorDwS zl@i(%8_JGPDQ*R-Gs)$1ujxPZ%m6&>XsPEAQojN^FEt0x%7Bwe4E8H@a~LWh>KWLG ziWcktg=#j){}t8Dti)Xxn8=vzQd0V0KA3izmq@w@J_}(M0MWp8xz{%Yl8pKWIS)#N zApXl~#fi5UrXS3+oITi=qVku4Q4A$h=+>_ZJymL8QCM#GcvD+j+w806<(4ozIK{}) z6+tCMg5$2Da%^l2Y#FDJY7OoCc}=5dz)Jnar9Be!Y^OWY9`zyCr5zSJM<*YIg7$fl z%5~U#2ZV?n%TEn=$1fc_Q<(9+4JEx^Iw2E-@v>whIY=kosz2oB@N zAB{I~S4usDLx}b(bo`i^t2{T~kYSL28bzkR&;hW8k6tXW^Pr(nPHgJXzDW6zbqskP zlWuQFKEWPx_{cF+qXP^9q45cI_ky?AwFi7{JnT`2KPs>zs`PRo?}5|m!>yWz)AHHtrK@$~M6!@} zTq>}=?1nlYL0UZ;^X7Dw02p?nF{_#UH+~dF*>B>}zJ>K`2CaIuq(eYFnrHC3C$Cl* zCuYI~?5rEt0Sd2mjMkznk)#n&6CUE zLmet4wZowaLehqQu8+~gFE%Q~ocYQ|9NJj*-z7jSbs1yNZNzx%ExRy@stgm3u!RNGx6VELct1Ou}kIn!psMQ_VC+Y5j+a&nMh z^BNt6)vg~K=F=Z-B)z}XG5$ym;K?_OZ~0^tHf6rdYYKncwY28pbWST5F{H0v!7qqIa3;;2rG^RxNuO48(r32nxSrhg>qu#1c=xoA|f^UB^S(~ zB_+a(x*?-hg?}!aaX+R&(U=P!znyS=FRHBD_Y({)9c0OV7c7cAlrs}yGYH-QF&<@R zW(FkQSV|pB_|G%@@My*+ZX-F5;d)43@G6Uisa<-fs%YG;Y_Tcs$$-go@0>%!3r^pa#J0pNdjY-Gz{C_+WzL5>ERg)TxmThjFR`D5Rg-7 zB%P85Jq7{((Y5{THPKYnKeyleCS}i0mS{11vGz9gFA62!Hxi)cM0m8wK6I9=j}i-n z+kCzW5l+~P+9&Gc_extwn6TbjSj8aNsWkZ>nrEytBinSr$-sr(_ z+!qe)(2m1oCu1zQr_UetyrT>D>YD26v@`zG66F)BQ0@v8y7sAIVh&O=2U>sbJ&m`& ztP&6s6A))fNjN zw%a^m8h6odF~c`capt9}qOxFBN)of|7j8WC(;XqOTiwD^k(|p{%NpzRprw%O(YWVxArd7Y&EZOeJOXJEaT zh$aTxBYEGQ(m23QjXPzKhB97&yqzk>1e0$6R|)HYf{MBGV3nQ4L+Dv^#7J@GU0OQ_ z08UMDP_zS%?fkX>@s5{fRj~b?q^r_Z6*Jdd{`W2BcY&+(CzAhPYySV8@33$DPPO6J jMxS|9?>Fz9?wO_0-goPqxl!%#aVYEo?fu!RmgoNmu(imU literal 0 HcmV?d00001 diff --git a/public/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-tenpy_layers-3.png b/public/images/api/qiskit-addon-mpf/qiskit_addon_mpf-backends-tenpy_layers-3.png new file mode 100644 index 0000000000000000000000000000000000000000..334d20f780c46e38cd0bc9e0a25f6395c588b1a5 GIT binary patch literal 43085 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

hz{yv&fh~FD()@cGGLP^yU?iG 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 z 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 PvsqD2^>B);(Y5~q5<_{R literal 0 HcmV?d00001