Metadata-Version: 2.4
Name: unitarylab
Version: 1.2.1
Summary: A Python package for quantum simulator from UnitaryLab.
Author: UnitaryLab
License-Expression: LicenseRef-UnitaryLab-LICENSE
Requires-Python: <3.13,>=3.10
Description-Content-Type: text/markdown
License-File: LICENSE.zh-CN
License-File: LICENSE.en
Requires-Dist: numpy
Requires-Dist: scipy
Requires-Dist: torch
Requires-Dist: matplotlib
Requires-Dist: pylatexenc
Requires-Dist: scikit-learn
Requires-Dist: sympy
Requires-Dist: mpmath
Dynamic: license-file

<div align="center">

<h1>unitarylab</h1>

<p>
  <strong>A Python quantum circuit simulator for building, executing, analyzing, and exporting quantum circuits.</strong><br/>
  <strong>面向量子电路构建、执行、分析与导出的 Python 量子模拟器。</strong>
</p>

<p>
  <img src="https://img.shields.io/badge/Python-3.10%20%7C%203.11%20%7C%203.12-3b82f6?style=flat-square&logo=python&logoColor=white" alt="Python 3.10, 3.11, and 3.12"/>
  <img src="https://img.shields.io/badge/Backend-NumPy%20%7C%20PyTorch%20%7C%20C%2B%2B%20%7C%20TensorNet-7c3aed?style=flat-square" alt="NumPy, PyTorch, C++, and TensorNet backends"/>
  <img src="https://img.shields.io/badge/Interface-Circuit-f59e0b?style=flat-square" alt="Circuit interface"/>
  <img src="https://img.shields.io/badge/License-UnitaryLab-22c55e?style=flat-square" alt="UnitaryLab license"/>
</p>

<p>
  <a href="#english">English</a>
  &middot;
  <a href="#chinese">中文</a>
</p>

</div>

---

<a name="english"></a>

## English

### What is unitarylab?

**Unitarylab** is the Python quantum simulator SDK developed by [UnitaryLab](https://unitarylab.com/). It provides a high-level `Circuit` interface backed by statevector and tensor-network execution, so you can move from circuit construction to simulation results and circuit inspection in a single workflow.

It is suitable for quantum-computing education, algorithm prototyping, research experiments, and integrating the [UnitaryLab Algorithms](https://pypi.org/project/unitarylab-algorithms/) library.

### Key Features

- **Simple circuit construction** — Build circuits with `Circuit`, `Register`, and `ClassicalRegister`.
- **Rich gate operations** — Use single-qubit, rotation, controlled, multi-controlled, SWAP, and custom unitary gates.
- **Statevector and tensor-network simulation** — Use dense statevector backends or an MPS-based TensorNet backend, then inspect probabilities, samples, expectation values, and measurement results through a common result interface.
- **Flexible backends** — Execute with NumPy, PyTorch, C++, or TensorNet on CPU; use PyTorch with CUDA-capable GPU environments when available.
- **Circuit inspection** — Visualize circuits using Matplotlib, text, or LaTeX, and analyze gate counts, circuit depth, and layer structure.
- **Circuit transformations** — Copy, invert, append, compose, and decompose circuits without changing the original circuit.
- **Interoperability** — Import and export circuits through OpenQASM 3.0 utilities.
- **Algorithm-ready foundation** — Use high-level modules such as QFT, QPE, LCU, HHL, QSP, QSVT, and Hamiltonian simulation.

### Installation

```bash
pip install unitarylab
```

#### CPU-only installation (optional)

If you do not need GPU acceleration, install the CPU-only build of PyTorch before installing `unitarylab`:

```bash
pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install unitarylab
```

Verify the installation:

```python
import unitarylab

print(unitarylab.__version__)
```


### Quick Start: Bell State

The following example creates a two-qubit Bell state, executes it, and reads its statevector and probabilities.

```python
from unitarylab import Circuit

# Create a 2-qubit circuit
qc = Circuit(2)

# Prepare (|00> + |11>) / sqrt(2)
qc.h(0)
qc.cx(0, 1)

# Execute the circuit
result = qc.execute()

print(result.state)
print(result.probabilities)
```

The probability distribution contains approximately 50% for `|00>` and 50% for `|11>`:

```python
{'00': 0.5, '11': 0.5}
```

`probabilities` uses binary computational-basis strings as keys. The simulator follows a little-endian qubit-ordering convention; keep this in mind when interpreting multi-qubit results.

### Common Gate Operations

`Circuit` provides single-qubit, rotation, controlled, multi-controlled, SWAP, and custom unitary operations. For example:

```python
import numpy as np
from unitarylab import Circuit

qc = Circuit(3)
qc.h(0)                              # Single-qubit gate
qc.rx(np.pi / 2, 1)                  # Rotation gate
qc.cx(0, 1)                          # Controlled gate
qc.mcx([0, 1], 2)                    # Multi-controlled gate
qc.swap(1, 2)                        # SWAP gate
qc.unitary(np.array([[0, 1], [1, 0]]), target=2)  # Custom unitary
```

Common single-qubit operations include `x`, `y`, `z`, `h`, `s`, `t`, `rx`, `ry`, `rz`, and `p`. Controlled and multi-controlled variants include `cx`, `cy`, `cz`, `ch`, `mcx`, `mcy`, `mcz`, and controlled rotation/phase operations.

### Measurements and Classical Registers

Create a classical register when you need classical measurement outcomes:

```python
from unitarylab import Circuit, Register, ClassicalRegister

qr = Register('q', 2)
cr = ClassicalRegister('c', 2)
qc = Circuit(qr, cr)

qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])

result = qc.execute(shots=1000, seed=42)
print(result.counts)
print(result.classical_results_map)
print(result.classical_registers)
```

For this Bell-state circuit, the two measured bits agree on every run: each count key is either `00` or `11`. `counts` aggregates all shots, while `classical_results_map`, `classical_registers`, and `state` describe the final shot.

### Execution Backends

`execute()` accepts an initial state and the `backend`, `device`, `dtype`, `shots`, `seed`, and `backend_options` options:

```python
# PyTorch backend on CPU (default backend)
result = qc.execute(backend='torch', device='cpu')

# NumPy backend on CPU
result = qc.execute(backend='numpy', device='cpu')

# C++ backend on CPU
result = qc.execute(backend='cpp', device='cpu')

# Tensor-network backend on CPU
result = qc.execute(
    backend='tensornet',
    device='cpu',
    backend_options={'max_bond': 64, 'cutoff': 1e-10, 'routing': 'auto'},
)

# PyTorch backend on GPU (requires a suitable PyTorch/CUDA environment)
result = qc.execute(backend='torch', device='gpu')
```

The TensorNet backend accepts a dense statevector, a `TensorNetState`, or a
list/tuple of open-boundary MPS site tensors:

```python
import numpy as np
from unitarylab import Circuit
from unitarylab.backend.tensornet import TensorNetState

qc = Circuit(2)
dense_state = np.array([1, 0, 0, 1], dtype=complex) / np.sqrt(2)
mps_state = TensorNetState.from_statevector(dense_state, max_bond=64)
result = qc.execute(initial_state=mps_state, backend='tensornet')

# Each tensor is ordered as (left bond, physical dimension 2, right bond).
# tensors[0] represents qubit 0.
result = qc.execute(initial_state=mps_state.tensors, backend='tensornet')
```

`initial_state` is copied before execution. Explicit `max_bond` and `cutoff`
values in `backend_options` override the values stored in `TensorNetState`;
otherwise the state settings are preserved. The `dtype` argument remains
authoritative and converts input tensors when necessary. Tensor-network
initial states are not implicitly contracted for statevector backends—call
`mps_state.to_statevector()` explicitly when that conversion is intended.

For precision-sensitive workloads, a dtype can also be supplied:

```python
import numpy as np

result = qc.execute(backend='torch', device='cpu', dtype=np.complex128)
```

### Working with Execution Results

Statevector backends return `ExecutionResult`; the TensorNet backend returns `TensorNetExecutionResult`, which provides the same public query interface using tensor-network contractions where possible.

| Interface | Description |
|-----------|-------------|
| `state` / `backend_state` | Read the dense NumPy statevector or inspect the native backend state. |
| `num_qubits` | Get the number of qubits represented by the result. |
| `probabilities` / `probability(...)` | Read the full distribution or one computational-basis probability. |
| `marginal_probabilities(...)` | Read the probability distribution for selected qubits. |
| `sample(...)` | Sample the final state without collapsing it. |
| `expectation(...)` | Evaluate a Pauli string, local observable, or sum of observable terms. |
| `measure(...)` | Measure selected qubits and collapse the stored result state. |
| `shots`, `counts`, `classical_results_map`, `classical_registers` | Inspect circuit-execution and classical-measurement results. |

```python
from unitarylab import Circuit

qc = Circuit(2)
qc.h(0)
qc.cx(0, 1)
result = qc.execute(backend='tensornet')

print(result.probability('0', qubits=[0]))
print(result.marginal_probabilities(qubits=[0, 1]))
print(result.sample(shots=1000, qubits=[0, 1], seed=42))
print(result.expectation('ZZ', qubits=[0, 1]))
```

`Circuit.execute(shots=...)` reruns the whole circuit and builds `counts` from in-circuit measurement gates. In contrast, `result.sample(shots=...)` samples the already computed final state without changing it; `result.measure(...)` does collapse the stored state.

For `TensorNetExecutionResult`, accessing `state` contracts the MPS into a dense vector, and accessing `probabilities` enumerates all `2**n` basis outcomes. For larger systems, prefer `probability(...)`, `marginal_probabilities(...)` on a small qubit subset, or local `expectation(...)` queries.

### Draw and Analyze Circuits

```python
# Display the circuit diagram. Matplotlib is the default output format.
# Text and LaTeX formats are also supported.
qc.draw()
# qc.draw(output="text")
# qc.draw(output="latex")

# Save the Matplotlib circuit diagram
qc.draw(filename="bell-state.png", title="Bell State")

# Analyze the circuit structure
info = qc.analyze()
info.show()

# Get the matrix representation of a small-scale circuit
matrix = qc.get_matrix()
```

`analyze()` is useful for checking gate counts, circuit depth, and layer structure before running larger experiments.

### Circuit Transformations

Circuit transformations return new circuit objects and leave the source circuit unchanged:

```python
qc = Circuit(2)
qc.h(0)
qc.cx(0, 1)

copied = qc.copy()
inverse = qc.inverse()
dagger = qc.dagger()
```

Circuits can also be appended or composed to build larger workflows from reusable circuit blocks.

### OpenQASM Import and Export

Export a circuit as OpenQASM 3.0 and reconstruct a new circuit from the generated source:

```python
qasm = qc.to_qasm()
restored = Circuit.from_qasm(qasm)

# OpenQASM 2.0 export is also available. from_qasm() detects the version.
qasm2 = qc.to_qasm2()
restored_qasm2 = Circuit.from_qasm(qasm2)
```

### Algorithm and Utility Library

The simulator provides high-level algorithm components through `unitarylab.library`:

| Area | Public interfaces |
|------|-------------------|
| Quantum Fourier transform | `QFT`, `IQFT` |
| Quantum phase estimation | `QPE` |
| Linear combination of unitaries | `LCU` |
| Hamiltonian simulation | `hamiltonian_simulation`, `QSP_hamiltonian_simulation` |
| Quantum signal processing | `QSP` |
| Quantum singular value transformation | `QSVT` |
| Block encoding | `block_encode` |
| Linear-system solving | `solve` |

These interfaces are the public algorithm API of the simulator. Internal implementation modules and private module names are not part of the documented API and may change between releases.

Example: construct a QFT circuit and embed it into a larger circuit:

```python
from unitarylab import Circuit
from unitarylab.library import QFT

qft = QFT(n=4)
qc = Circuit(4)
qc.append(qft, target=[0, 1, 2, 3])
qc.draw(title='Quantum Fourier Transform')
```

### Package Structure

```text
unitarylab/
├── core/               # Circuit, Register, and ClassicalRegister
├── backend/            # Gates, statevector/TensorNet execution, results, and QASM
├── circuit_analysis/   # Circuit structure analysis
├── drawer/             # Circuit drawing and text/LaTeX output
├── info/               # Information display utilities
├── codegen/             # Circuit code generation
├── transpiler/          # Circuit transformation and optimization
└── library/             # Public algorithm interfaces
```

Most users only need:

```python
from unitarylab import Circuit
```

### Further Documentation

- [UnitaryLab Website](https://unitarylab.com/)
- [Simulator User Manual](https://docs.unitarylab.com/en/docs/unitarylab-simulator-user-manual/)
- [UnitaryLab Algorithms on PyPI](https://pypi.org/project/unitarylab-algorithms/)

---

<a name="chinese"></a>

## 中文

### unitarylab 是什么？

**unitarylab** 是由 [UnitaryLab](https://unitarylab.com/) 开发的 Python 量子模拟器 SDK。它以高层 `Circuit` 接口为核心，提供状态向量和张量网络量子电路执行能力，帮助用户在同一套工作流中完成电路构建、模拟运行、结果读取和结构分析。

该模拟器适合量子计算教学、算法原型开发、科研实验，以及与 [UnitaryLab Algorithms](https://pypi.org/project/unitarylab-algorithms/) 算法库配合使用。

### 核心特性

- **简洁的电路构建接口** — 使用 `Circuit`、`Register` 和 `ClassicalRegister` 创建量子电路。
- **丰富的量子门操作** — 支持单量子比特门、旋转门、受控门、多重受控门、SWAP 门和自定义酉门。
- **状态向量与张量网络模拟** — 可选择稠密状态向量后端或基于 MPS 的 TensorNet 后端，并通过统一结果接口查询概率、采样、期望值和测量结果。
- **灵活的执行后端** — 支持 NumPy、PyTorch、C++ 和 TensorNet 在 CPU 执行，并可在合适的 CUDA 环境下使用 PyTorch GPU 加速。
- **电路可视化与分析** — 使用 Matplotlib、文本或 LaTeX 可视化电路，并分析门数、电路深度和层结构。
- **电路变换** — 支持复制、求逆、追加、组合和分解电路，原始电路不会被修改。
- **OpenQASM 互操作** — 通过 OpenQASM 3.0 工具导入和导出电路。
- **算法库基础设施** — 提供 QFT、QPE、LCU、HHL、QSP、QSVT 和哈密顿量模拟等高层模块。

### 安装

```bash
pip install unitarylab
```

#### 仅使用 CPU（可选）

如果不需要 GPU 加速，可先安装 PyTorch 的 CPU 版本，再安装 `unitarylab`：

```bash
pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install unitarylab
```

验证安装：

```python
import unitarylab
print(unitarylab.__version__)
```

### 快速开始：Bell 态

下面的示例创建一个两量子比特 Bell 态，执行电路并读取状态向量与概率分布。

```python
from unitarylab import Circuit

# 创建两量子比特电路
qc = Circuit(2)

# 制备 (|00> + |11>) / sqrt(2)
qc.h(0)
qc.cx(0, 1)

# 执行电路
result = qc.execute()
print(result.state)
print(result.probabilities)
```

运行结果中，`|00>` 和 `|11>` 的概率约各为 50%：

```python
{'00': 0.5, '11': 0.5}
```

`probabilities` 使用计算基二进制字符串作为键；解释多量子比特结果时，请注意模拟器采用 little-endian 的量子比特顺序约定。

### 常用量子门操作

`Circuit` 提供单量子比特门、旋转门、受控门、多重受控门、SWAP 门和自定义酉门。例如：

```python
import numpy as np
from unitarylab import Circuit

qc = Circuit(3)
qc.h(0)                              # 单量子比特门
qc.rx(np.pi / 2, 1)                  # 旋转门
qc.cx(0, 1)                          # 受控门
qc.mcx([0, 1], 2)                    # 多重受控门
qc.swap(1, 2)                        # SWAP 门
qc.unitary(np.array([[0, 1], [1, 0]]), target=2)  # 自定义酉门
```

常用单量子比特操作包括 `x`、`y`、`z`、`h`、`s`、`t`、`rx`、`ry`、`rz` 和 `p`。受控及多重受控操作包括 `cx`、`cy`、`cz`、`ch`、`mcx`、`mcy`、`mcz`，以及受控旋转门和相位门。

### 测量与经典寄存器

如果需要读取经典测量结果，应先创建经典寄存器：

```python
from unitarylab import Circuit, Register, ClassicalRegister

qr = Register('q', 2)
cr = ClassicalRegister('c', 2)
qc = Circuit(qr, cr)

qc.h(0)
qc.cx(0, 1)
qc.measure([0, 1], [0, 1])

result = qc.execute(shots=1000, seed=42)
print(result.counts)
print(result.classical_results_map)
print(result.classical_registers)
```

对于这个 Bell 态电路，两个测量比特在每次运行中都会保持一致，每个计数键只能是 `00` 或 `11`。`counts` 汇总所有 shots，而 `classical_results_map`、`classical_registers` 和 `state` 描述最后一次执行结果。

### 执行后端

`execute()` 支持初态，以及 `backend`、`device`、`dtype`、`shots`、`seed` 和 `backend_options` 参数：

```python
# PyTorch CPU 后端（默认后端）
result = qc.execute(backend='torch', device='cpu')

# NumPy CPU 后端
result = qc.execute(backend='numpy', device='cpu')

# C++ CPU 后端
result = qc.execute(backend='cpp', device='cpu')

# TensorNet CPU 后端
result = qc.execute(
    backend='tensornet',
    device='cpu',
    backend_options={'max_bond': 64, 'cutoff': 1e-10, 'routing': 'auto'},
)

# PyTorch GPU 后端（需要合适的 PyTorch/CUDA 环境）
result = qc.execute(backend='torch', device='gpu')
```

TensorNet 后端可以接受稠密状态向量、`TensorNetState`，或者由开放边界
MPS 站点张量组成的 list/tuple：

```python
import numpy as np
from unitarylab import Circuit
from unitarylab.backend.tensornet import TensorNetState

qc = Circuit(2)
dense_state = np.array([1, 0, 0, 1], dtype=complex) / np.sqrt(2)
mps_state = TensorNetState.from_statevector(dense_state, max_bond=64)
result = qc.execute(initial_state=mps_state, backend='tensornet')

# 每个张量的维度顺序为 (左键合维度, 物理维度 2, 右键合维度)。
# tensors[0] 对应 qubit 0。
result = qc.execute(initial_state=mps_state.tensors, backend='tensornet')
```

执行前会复制 `initial_state`。如果在 `backend_options` 中显式指定
`max_bond` 或 `cutoff`，这些配置优先于 `TensorNetState` 中保存的值；
否则保留状态自身配置。`dtype` 参数仍具有最高优先级，必要时会转换输入张量。
状态向量后端不会隐式收缩张量网络，需要转换时应显式调用
`mps_state.to_statevector()`。

对于对精度敏感的任务，也可以指定数据类型：

```python
import numpy as np

result = qc.execute(backend='torch', device='cpu', dtype=np.complex128)
```

### 使用执行结果

状态向量后端返回 `ExecutionResult`；TensorNet 后端返回 `TensorNetExecutionResult`。后者尽可能通过张量网络收缩实现相同的公开查询接口。

| 接口 | 说明 |
|------|------|
| `state` / `backend_state` | 读取稠密 NumPy 状态向量，或查看后端原生状态。 |
| `num_qubits` | 获取结果表示的量子比特数量。 |
| `probabilities` / `probability(...)` | 读取完整概率分布，或查询一个计算基结果的概率。 |
| `marginal_probabilities(...)` | 查询指定量子比特的边缘概率分布。 |
| `sample(...)` | 从最终状态采样，但不坍缩状态。 |
| `expectation(...)` | 计算 Pauli 串、局部可观测量或可观测量项之和的期望值。 |
| `measure(...)` | 测量指定量子比特，并坍缩结果对象保存的状态。 |
| `shots`、`counts`、`classical_results_map`、`classical_registers` | 查看电路执行次数和经典测量结果。 |

```python
from unitarylab import Circuit

qc = Circuit(2)
qc.h(0)
qc.cx(0, 1)
result = qc.execute(backend='tensornet')

print(result.probability('0', qubits=[0]))
print(result.marginal_probabilities(qubits=[0, 1]))
print(result.sample(shots=1000, qubits=[0, 1], seed=42))
print(result.expectation('ZZ', qubits=[0, 1]))
```

`Circuit.execute(shots=...)` 会重新运行整个电路，并根据线路内的测量门生成 `counts`。相比之下，`result.sample(shots=...)` 只对已经算出的最终状态进行采样，不会改变状态；`result.measure(...)` 则会坍缩结果对象保存的状态。

对于 `TensorNetExecutionResult`，访问 `state` 会把 MPS 收缩为稠密向量，访问 `probabilities` 会枚举全部 `2**n` 个计算基结果。处理较大系统时，应优先使用 `probability(...)`、针对少量量子比特的 `marginal_probabilities(...)`，或局部 `expectation(...)` 查询。

### 电路绘图与分析

```python
# 显示电路图，支持 Matplotlib（默认）、文本格式和 LaTeX
qc.draw()
# qc.draw(output="text")
# qc.draw(output="latex")

# 保存 Matplotlib 电路图
qc.draw(filename='bell-state.png', title='Bell State')

# 分析电路结构
info = qc.analyze()
info.show()

# 获取小规模电路的矩阵
matrix = qc.get_matrix()
```

`analyze()` 可用于在运行较大规模实验前检查门数量、电路深度和层结构。

### 电路变换

电路变换会返回新的电路对象，不会修改源电路：

```python
qc = Circuit(2)
qc.h(0)
qc.cx(0, 1)

copied = qc.copy()
inverse = qc.inverse()
dagger = qc.dagger()  
```

还可以通过追加或组合电路，将可复用的电路模块构建成更大的工作流。

### OpenQASM 导入与导出

可以将电路导出为 OpenQASM 3.0，并根据生成的源码重建电路：

```python
qasm = qc.to_qasm()
restored = Circuit.from_qasm(qasm)

# 也支持导出 OpenQASM 2.0；from_qasm() 会自动识别版本。
qasm2 = qc.to_qasm2()
restored_qasm2 = Circuit.from_qasm(qasm2)
```

### 算法与工具库

模拟器通过 `unitarylab.library` 提供高层算法构件：

| 方向 | 公开接口 |
|------|----------|
| 量子傅里叶变换 | `QFT`、`IQFT` |
| 量子相位估计 | `QPE` |
| 线性组合酉算子 | `LCU` |
| 哈密顿量模拟 | `hamiltonian_simulation`、`QSP_hamiltonian_simulation` |
| 量子信号处理 | `QSP` |
| 量子奇异值变换 | `QSVT` |
| 块编码 | `block_encode` |
| 线性方程组求解 | `solve` |

以上接口构成模拟器公开的算法 API。内部实现模块和私有模块名称不属于文档化 API，后续版本中可能发生变化。

下面是构造 QFT 电路并将其嵌入更大电路的示例：

```python
from unitarylab import Circuit
from unitarylab.library import QFT

qft = QFT(n=4)
qc = Circuit(4)
qc.append(qft, target=[0, 1, 2, 3])
qc.draw(title='Quantum Fourier Transform')
```

### 包结构

```text
unitarylab/
├── core/               # Circuit、Register 和 ClassicalRegister
├── backend/            # 量子门、状态向量/TensorNet 执行、结果与 QASM 支持
├── circuit_analysis/   # 电路结构分析
├── drawer/             # 电路绘图及文本/LaTeX 输出
├── info/               # 信息展示工具
├── codegen/            # 电路代码生成
├── transpiler/         # 电路转换与优化
└── library/            # 公开算法接口
```

大多数用户只需要导入：

```python
from unitarylab import Circuit
```

### 更多文档

- [UnitaryLab 官方网站](https://unitarylab.com/)
- [Simulator 用户手册](https://docs.unitarylab.com/zh/docs/unitarylab-simulator-user-manual/)
- [UnitaryLab Algorithms（PyPI）](https://pypi.org/project/unitarylab-algorithms/)

# License

License: LicenseRef-UnitaryLab-LICENSE. 
The Chinese license text is authoritative; the English version is provided for reference only.
