From 1ec5adab40c4f30ed9ce137e0daf370814e2e091 Mon Sep 17 00:00:00 2001 From: Hadar01 Date: Sun, 10 May 2026 13:56:36 +0530 Subject: [PATCH 01/10] docs: add MPS simulator documentation - Add docs/mps.md: covers what MPS is, MPSStateSpace and MPSSimulator C++ APIs, current limitations, and a comparison table vs qsim/qsimh - Update docs/overview.md: mention MPS as a third simulator alongside qsim and qsimh, add it to the operations list - Update docs/_book.yaml: register mps.md in the Guides nav section Fixes #1048 --- docs/_book.yaml | 2 + docs/mps.md | 156 +++++++++++++++++++++++++++++++++++++++++++++++ docs/overview.md | 11 +++- 3 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 docs/mps.md diff --git a/docs/_book.yaml b/docs/_book.yaml index 2e045ddea..61f5445f5 100644 --- a/docs/_book.yaml +++ b/docs/_book.yaml @@ -55,6 +55,8 @@ upper_tabs: path: /qsim/cirq_interface - title: "C++ templates" path: /qsim/type_reference + - title: "MPS simulator" + path: /qsim/mps - title: "C++ builds with Bazel" path: /qsim/bazel - title: "Docker builds" diff --git a/docs/mps.md b/docs/mps.md new file mode 100644 index 000000000..193f42f54 --- /dev/null +++ b/docs/mps.md @@ -0,0 +1,156 @@ +# The MPS Simulator + +qsim includes a **Matrix Product State (MPS)** simulator alongside its standard +state-vector and hybrid Schrödinger-Feynman simulators. While the full +state-vector simulator (`qsim`) stores the entire quantum state in memory — which +grows exponentially with the number of qubits — the MPS simulator takes a +different approach that can be much more memory-efficient for certain kinds of +circuits. + +## What is a Matrix Product State? + +A Matrix Product State is a way of representing a quantum state as a chain of +tensors, one per qubit, connected together. Instead of storing one giant +exponentially-large vector, you store a sequence of small matrices. The "bond +dimension" (often written as χ or `bond_dim`) controls how much entanglement the +representation can capture: a higher bond dimension is more accurate but uses more +memory and takes longer to simulate. + +The catch — and the reason this is so useful — is that many quantum circuits of +practical interest don't generate a lot of entanglement. For those circuits, a +small bond dimension works great, and you can simulate far more qubits than a +full state-vector simulator could handle. + +The trade-off is that MPS simulation is **approximate for highly entangled circuits**. +When a gate creates entanglement that exceeds the bond dimension, the simulator +truncates it (using SVD). For low-entanglement circuits (e.g., 1D nearest-neighbor +circuits, QAOA with shallow depth), the results are exact or very close to exact. + +## Where to find the implementation + +The MPS simulator lives in two C++ header files: + +- [`lib/mps_simulator.h`](https://github.com/quantumlib/qsim/blob/main/lib/mps_simulator.h) + — the `MPSSimulator` class, which applies gates to an MPS. +- [`lib/mps_statespace.h`](https://github.com/quantumlib/qsim/blob/main/lib/mps_statespace.h) + — the `MPSStateSpace` class, which manages MPS memory, sampling, and inner products. + +Both live in the `qsim::mps` namespace. + +## Using MPSStateSpace + +`MPSStateSpace` handles everything related to creating and manipulating the MPS +object itself. + +### Creating a state + +```cpp +// Requires num_qubits >= 2 and bond_dim >= 2. +auto state = MPSStateSpace::Create(num_qubits, bond_dim); +``` + +### Initializing to |0⟩ + +```cpp +MPSStateSpace::SetStateZero(state); +``` + +### Copying a state + +```cpp +MPSStateSpace::Copy(src_state, dest_state); +``` + +### Computing inner products + +```cpp +// Full complex inner product +auto ip = MPSStateSpace::InnerProduct(state1, state2); + +// Real part only +auto rip = MPSStateSpace::RealInnerProduct(state1, state2); +``` + +### Sampling + +```cpp +// Draw one sample +std::vector sample; +MPSStateSpace::SampleOnce(state, scratch, scratch2, &rng, &sample); + +// Draw multiple samples +std::vector> results(num_samples); +MPSStateSpace::Sample(state, scratch, scratch2, num_samples, seed, &results); +``` + +Note that sampling requires two additional scratch MPS objects of the same size +as the state. These are used as working memory during the sequential sampling +process. + +### Reduced density matrices + +You can compute the 2×2 reduced density matrix (1-RDM) for any single qubit: + +```cpp +float rdm[8]; // 2x2 complex matrix = 8 floats +MPSStateSpace::ReduceDensityMatrix(state, scratch, qubit_index, rdm); +``` + +## Using MPSSimulator + +`MPSSimulator` applies quantum gates to an MPS state. + +### Applying gates + +```cpp +MPSSimulator sim(/* ForArgs */); + +// Apply a 1-qubit gate +sim.ApplyGate({qubit_index}, gate_matrix, state); + +// Apply a 2-qubit gate (must be adjacent) +sim.ApplyGate({qubit_a, qubit_b}, gate_matrix, state); +``` + +When a 2-qubit gate is applied, the simulator: +1. Contracts the two neighboring MPS tensors into one combined tensor. +2. Applies the gate matrix. +3. Uses **Singular Value Decomposition (SVD)** to split the result back into two + tensors. +4. Keeps only the top `bond_dim` singular values, truncating the rest. + +This is the key step where approximation happens. If the true quantum state +needs more entanglement than `bond_dim` allows, some information is lost. + +## Current limitations + +The MPS simulator is actively developed but not yet complete. As of now: + +- **Only 1-qubit and 2-qubit gates are supported.** Support for 3+ qubit gates + is not yet implemented (commented placeholders exist in the source). +- **Controlled gates are not yet implemented.** `ApplyControlledGate` exists but + is a stub (`// TODO`). +- **Expectation values are not yet implemented.** `ExpectationValue` currently + returns a placeholder value of `(-10, -10)`. +- **No Python interface.** The MPS simulator is currently only accessible through + C++. It is not yet exposed via the `qsimcirq` Python package. +- **2-qubit gates must act on adjacent qubits.** Non-adjacent 2-qubit gates + require SWAP networks (not handled automatically). + +## When to use MPS vs. state-vector simulation + +| Situation | Recommended simulator | +|---|---| +| Circuit has low entanglement (1D, shallow QAOA, etc.) | MPS | +| You want exact results for any circuit | qsim (state-vector) | +| Many qubits, low depth | MPS | +| Deep random circuits | qsim or qsimh | +| You need a Python interface | qsim or qsimh (via qsimcirq) | + +## Further reading + +- [Vidal, G. "Efficient Simulation of One-Dimensional Quantum Many-Body Systems"](https://arxiv.org/abs/quant-ph/0310089) + — the foundational paper on MPS simulation of quantum circuits. +- [qsim overview](./overview.md) — description of all simulators in qsim. +- [C++ template reference](./type_reference.md) — description of template + parameters like `For`, `fp_type`, etc., used throughout qsim including MPS. diff --git a/docs/overview.md b/docs/overview.md index ce91c9ed8..18008e96c 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -19,7 +19,7 @@ or try the runnable ## Design -The git repository for qsim includes two top-level libraries for simulation: +The git repository for qsim includes three libraries for simulation: - **qsim** is a Schrödinger state-vector simulator designed to run on a single machine. It produces the full state vector as output which, @@ -28,6 +28,13 @@ The git repository for qsim includes two top-level libraries for simulation: execution on a cluster of machines. It produces amplitudes for user-specified output bitstrings. Compared to qsim, by limiting what it returns, qsimh can simulate more qubits. +- **MPS** is a truncated Matrix Product State simulator. Instead of storing + the full state vector, it represents the quantum state as a chain of + small tensors — one per qubit — connected by a configurable "bond + dimension". This makes it much more memory-efficient for circuits with + low entanglement (such as shallow or 1D-structured circuits), at the + cost of being approximate for highly entangled states. See the + [MPS simulator docs](./mps.md) for details. These libraries can be invoked either directly or through the qsim-Cirq interface to perform the following operations: @@ -38,6 +45,8 @@ interface to perform the following operations: (qsim only). - Calculate amplitudes for user-specified result bitstrings. With qsimh, this is trivially parallelizable across several machines. +- Simulate circuits with low entanglement at reduced memory cost (MPS only, + C++ only). Circuits of up to 30 qubits can be simulated in qsim with ~16GB of RAM; each additional qubit doubles the RAM requirement. In contrast, careful From cad38dbaafdbb9a6daf4ad8b5474abac781ad29a Mon Sep 17 00:00:00 2001 From: Hadar01 Date: Sun, 10 May 2026 14:10:38 +0530 Subject: [PATCH 02/10] docs: remove em dashes from mps.md for cleaner prose --- docs/mps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mps.md b/docs/mps.md index 193f42f54..b4d55532d 100644 --- a/docs/mps.md +++ b/docs/mps.md @@ -16,7 +16,7 @@ dimension" (often written as χ or `bond_dim`) controls how much entanglement th representation can capture: a higher bond dimension is more accurate but uses more memory and takes longer to simulate. -The catch — and the reason this is so useful — is that many quantum circuits of +The catch, and the reason this is so useful, is that many quantum circuits of practical interest don't generate a lot of entanglement. For those circuits, a small bond dimension works great, and you can simulate far more qubits than a full state-vector simulator could handle. From c42cbc99fbfabf62c879aa9370242ff3cbf26961 Mon Sep 17 00:00:00 2001 From: Aarush <112254386+Hadar01@users.noreply.github.com> Date: Sun, 10 May 2026 14:25:59 +0530 Subject: [PATCH 03/10] Update docs/mps.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- docs/mps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mps.md b/docs/mps.md index b4d55532d..5d3020e3a 100644 --- a/docs/mps.md +++ b/docs/mps.md @@ -46,7 +46,7 @@ object itself. ```cpp // Requires num_qubits >= 2 and bond_dim >= 2. -auto state = MPSStateSpace::Create(num_qubits, bond_dim); +auto state = MPSStateSpace::Create(num_qubits, bond_dim); ``` ### Initializing to |0⟩ From 6e48ecbb3fe8b8993adbed641220a4fd835875ef Mon Sep 17 00:00:00 2001 From: Aarush <112254386+Hadar01@users.noreply.github.com> Date: Sun, 10 May 2026 14:26:13 +0530 Subject: [PATCH 04/10] Update docs/mps.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- docs/mps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mps.md b/docs/mps.md index 5d3020e3a..0fc7c0615 100644 --- a/docs/mps.md +++ b/docs/mps.md @@ -103,7 +103,7 @@ MPSStateSpace::ReduceDensityMatrix(state, scratch, qubit_index, rdm); ### Applying gates ```cpp -MPSSimulator sim(/* ForArgs */); +MPSSimulator sim(/* ForArgs */); // Apply a 1-qubit gate sim.ApplyGate({qubit_index}, gate_matrix, state); From 92e55ea047aa339ce6cbaf5e4eff677d4a91d5a8 Mon Sep 17 00:00:00 2001 From: Aarush <112254386+Hadar01@users.noreply.github.com> Date: Sun, 10 May 2026 14:26:35 +0530 Subject: [PATCH 05/10] Update docs/mps.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- docs/mps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mps.md b/docs/mps.md index 0fc7c0615..e67816408 100644 --- a/docs/mps.md +++ b/docs/mps.md @@ -92,7 +92,7 @@ process. You can compute the 2×2 reduced density matrix (1-RDM) for any single qubit: ```cpp -float rdm[8]; // 2x2 complex matrix = 8 floats +float rdm[8]; // Use double if fp_type is double MPSStateSpace::ReduceDensityMatrix(state, scratch, qubit_index, rdm); ``` From 82f98b7c3d4ee8683a7d11726d708e65346547be Mon Sep 17 00:00:00 2001 From: Aarush <112254386+Hadar01@users.noreply.github.com> Date: Thu, 14 May 2026 15:28:09 +0530 Subject: [PATCH 06/10] Update docs/mps.md Co-authored-by: Michael Hucka --- docs/mps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mps.md b/docs/mps.md index e67816408..fdffc236f 100644 --- a/docs/mps.md +++ b/docs/mps.md @@ -1,6 +1,6 @@ # The MPS Simulator -qsim includes a **Matrix Product State (MPS)** simulator alongside its standard +qsim includes a Matrix Product State (MPS) simulator alongside its standard state-vector and hybrid Schrödinger-Feynman simulators. While the full state-vector simulator (`qsim`) stores the entire quantum state in memory — which grows exponentially with the number of qubits — the MPS simulator takes a From ffe09ecae86d14d823ecf18a1364397df8b3b463 Mon Sep 17 00:00:00 2001 From: Aarush <112254386+Hadar01@users.noreply.github.com> Date: Thu, 14 May 2026 15:28:26 +0530 Subject: [PATCH 07/10] Update docs/mps.md Co-authored-by: Michael Hucka --- docs/mps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mps.md b/docs/mps.md index fdffc236f..6fdb85dc4 100644 --- a/docs/mps.md +++ b/docs/mps.md @@ -9,7 +9,7 @@ circuits. ## What is a Matrix Product State? -A Matrix Product State is a way of representing a quantum state as a chain of +A _matrix product state_ is a way of representing a quantum state as a chain of tensors, one per qubit, connected together. Instead of storing one giant exponentially-large vector, you store a sequence of small matrices. The "bond dimension" (often written as χ or `bond_dim`) controls how much entanglement the From 4a6867b18b5b08c9e148bb4f5e2496965ff44f01 Mon Sep 17 00:00:00 2001 From: Aarush <112254386+Hadar01@users.noreply.github.com> Date: Thu, 14 May 2026 15:28:40 +0530 Subject: [PATCH 08/10] Update docs/mps.md Co-authored-by: Michael Hucka --- docs/mps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mps.md b/docs/mps.md index 6fdb85dc4..9e5cfdcce 100644 --- a/docs/mps.md +++ b/docs/mps.md @@ -10,7 +10,7 @@ circuits. ## What is a Matrix Product State? A _matrix product state_ is a way of representing a quantum state as a chain of -tensors, one per qubit, connected together. Instead of storing one giant +tensors, one per qubit, connected together. Instead of storing one exponentially-large vector, you store a sequence of small matrices. The "bond dimension" (often written as χ or `bond_dim`) controls how much entanglement the representation can capture: a higher bond dimension is more accurate but uses more From 38b6ac7c67f14ce8749372ce17e1cf51f32543b8 Mon Sep 17 00:00:00 2001 From: Aarush <112254386+Hadar01@users.noreply.github.com> Date: Thu, 14 May 2026 15:55:28 +0530 Subject: [PATCH 09/10] Improve clarity on matrix product states and limitations Enhanced explanations of matrix product states and their limitations. Clarified the role of bond dimension and approximation in MPS simulation. --- docs/mps.md | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/docs/mps.md b/docs/mps.md index 9e5cfdcce..1e8cb6fda 100644 --- a/docs/mps.md +++ b/docs/mps.md @@ -10,25 +10,27 @@ circuits. ## What is a Matrix Product State? A _matrix product state_ is a way of representing a quantum state as a chain of -tensors, one per qubit, connected together. Instead of storing one -exponentially-large vector, you store a sequence of small matrices. The "bond -dimension" (often written as χ or `bond_dim`) controls how much entanglement the -representation can capture: a higher bond dimension is more accurate but uses more -memory and takes longer to simulate. - -The catch, and the reason this is so useful, is that many quantum circuits of +tensors, one per qubit, connected together. Instead of storing one +exponentially-large vector, you store a sequence of small matrices. The +_bond dimension_ (often written as χ or `bond_dim`) controls how much +*entanglement* (quantum correlations between qubits) the representation can +capture: a higher bond dimension is more accurate but uses more memory and takes +longer to simulate. + +The catch, and the reason MPS is so useful, is that many quantum circuits of practical interest don't generate a lot of entanglement. For those circuits, a -small bond dimension works great, and you can simulate far more qubits than a +small bond dimension works well, and you can simulate far more qubits than a full state-vector simulator could handle. -The trade-off is that MPS simulation is **approximate for highly entangled circuits**. -When a gate creates entanglement that exceeds the bond dimension, the simulator -truncates it (using SVD). For low-entanglement circuits (e.g., 1D nearest-neighbor -circuits, QAOA with shallow depth), the results are exact or very close to exact. +The trade-off is that MPS simulation only provides approximate results for +highly entangled circuits. When a gate creates entanglement that exceeds the +bond dimension, the simulator truncates it (using Singular Value Decomposition, +or SVD). For low-entanglement circuits (e.g., 1D nearest-neighbor circuits, +QAOA with shallow depth), the results are exact or very close to exact. ## Where to find the implementation -The MPS simulator lives in two C++ header files: +The qsim MPS simulation interface lives in two C++ header files: - [`lib/mps_simulator.h`](https://github.com/quantumlib/qsim/blob/main/lib/mps_simulator.h) — the `MPSSimulator` class, which applies gates to an MPS. @@ -115,26 +117,25 @@ sim.ApplyGate({qubit_a, qubit_b}, gate_matrix, state); When a 2-qubit gate is applied, the simulator: 1. Contracts the two neighboring MPS tensors into one combined tensor. 2. Applies the gate matrix. -3. Uses **Singular Value Decomposition (SVD)** to split the result back into two - tensors. +3. Uses SVD to split the result back into two tensors. 4. Keeps only the top `bond_dim` singular values, truncating the rest. -This is the key step where approximation happens. If the true quantum state -needs more entanglement than `bond_dim` allows, some information is lost. +Step 4, the truncation step, is where approximation happens. If the true quantum +state needs more entanglement than `bond_dim` allows, some information is lost. ## Current limitations The MPS simulator is actively developed but not yet complete. As of now: -- **Only 1-qubit and 2-qubit gates are supported.** Support for 3+ qubit gates +- _Only 1-qubit and 2-qubit gates are supported._ Support for 3+ qubit gates is not yet implemented (commented placeholders exist in the source). -- **Controlled gates are not yet implemented.** `ApplyControlledGate` exists but +- _Controlled gates are not yet implemented._ `ApplyControlledGate` exists but is a stub (`// TODO`). -- **Expectation values are not yet implemented.** `ExpectationValue` currently +- _Expectation values are not yet implemented._ `ExpectationValue` currently returns a placeholder value of `(-10, -10)`. -- **No Python interface.** The MPS simulator is currently only accessible through +- _No Python interface._ The MPS simulator is currently only accessible through C++. It is not yet exposed via the `qsimcirq` Python package. -- **2-qubit gates must act on adjacent qubits.** Non-adjacent 2-qubit gates +- _2-qubit gates must act on adjacent qubits._ Non-adjacent 2-qubit gates require SWAP networks (not handled automatically). ## When to use MPS vs. state-vector simulation From 94c526b21ba4d229a914af20344fddfcad33c6de Mon Sep 17 00:00:00 2001 From: Aarush <112254386+Hadar01@users.noreply.github.com> Date: Fri, 15 May 2026 12:33:22 +0530 Subject: [PATCH 10/10] Specify 'Singular Value Decomposition' in MPS steps Clarify SVD terminology in the MPS documentation. --- docs/mps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mps.md b/docs/mps.md index 1e8cb6fda..8a5967875 100644 --- a/docs/mps.md +++ b/docs/mps.md @@ -117,7 +117,7 @@ sim.ApplyGate({qubit_a, qubit_b}, gate_matrix, state); When a 2-qubit gate is applied, the simulator: 1. Contracts the two neighboring MPS tensors into one combined tensor. 2. Applies the gate matrix. -3. Uses SVD to split the result back into two tensors. +3. Uses Singular Value Decomposition (SVD) to split the result back into two tensors. 4. Keeps only the top `bond_dim` singular values, truncating the rest. Step 4, the truncation step, is where approximation happens. If the true quantum