qomputing-simulator 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- examples/library_usage.py +30 -0
- qomputing_simulator/__init__.py +22 -0
- qomputing_simulator/circuit.py +231 -0
- qomputing_simulator/circuit_builders.py +185 -0
- qomputing_simulator/cli.py +121 -0
- qomputing_simulator/engine/__init__.py +7 -0
- qomputing_simulator/engine/measurements.py +26 -0
- qomputing_simulator/engine/registry.py +32 -0
- qomputing_simulator/engine/result.py +31 -0
- qomputing_simulator/engine/statevector.py +49 -0
- qomputing_simulator/examples/__init__.py +2 -0
- qomputing_simulator/examples/demo_circuits.py +126 -0
- qomputing_simulator/gates/__init__.py +27 -0
- qomputing_simulator/gates/multi_qubit.py +60 -0
- qomputing_simulator/gates/single_qubit.py +204 -0
- qomputing_simulator/gates/two_qubit.py +196 -0
- qomputing_simulator/linalg.py +62 -0
- qomputing_simulator/run.py +85 -0
- qomputing_simulator/simulator.py +6 -0
- qomputing_simulator/xeb.py +77 -0
- qomputing_simulator-0.1.0.dist-info/METADATA +314 -0
- qomputing_simulator-0.1.0.dist-info/RECORD +27 -0
- qomputing_simulator-0.1.0.dist-info/WHEEL +5 -0
- qomputing_simulator-0.1.0.dist-info/entry_points.txt +2 -0
- qomputing_simulator-0.1.0.dist-info/top_level.txt +4 -0
- tests/test_parity.py +125 -0
- tools/cirq_comparison.py +419 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Shared tensor and linear algebra helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Dict, List, Tuple
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def initial_state(num_qubits: int, *, dtype: np.dtype) -> np.ndarray:
|
|
11
|
+
size = 1 << num_qubits
|
|
12
|
+
state = np.zeros(size, dtype=dtype)
|
|
13
|
+
state[0] = 1.0 + 0j
|
|
14
|
+
return state
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def axis_for_qubit(qubit: int) -> int:
|
|
18
|
+
"""Return tensor axis index for the given little-endian qubit."""
|
|
19
|
+
return -(qubit + 1)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def reshape_state(state: np.ndarray, num_qubits: int) -> np.ndarray:
|
|
23
|
+
return state.reshape((2,) * num_qubits)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def swap_axes(tensor: np.ndarray, axis_a: int, axis_b: int) -> np.ndarray:
|
|
27
|
+
return np.swapaxes(tensor, axis_a, axis_b)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def select_indices(num_qubits: int, indices: Dict[int, int]) -> Tuple[slice, ...]:
|
|
31
|
+
slices = [slice(None)] * num_qubits
|
|
32
|
+
for axis, value in indices.items():
|
|
33
|
+
slices[axis] = value
|
|
34
|
+
return tuple(slices)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def apply_unitary(
|
|
38
|
+
state: np.ndarray,
|
|
39
|
+
qubits: List[int],
|
|
40
|
+
matrix: np.ndarray,
|
|
41
|
+
num_qubits: int,
|
|
42
|
+
) -> np.ndarray:
|
|
43
|
+
qubits = list(qubits)
|
|
44
|
+
if not qubits:
|
|
45
|
+
return state
|
|
46
|
+
matrix = np.asarray(matrix, dtype=state.dtype)
|
|
47
|
+
dimension = 1 << len(qubits)
|
|
48
|
+
if matrix.shape != (dimension, dimension):
|
|
49
|
+
raise ValueError("Unitary size does not match qubit count")
|
|
50
|
+
|
|
51
|
+
tensor = reshape_state(state, num_qubits)
|
|
52
|
+
axes = [axis_for_qubit(q) for q in qubits]
|
|
53
|
+
dest_axes = list(range(-len(qubits), 0))
|
|
54
|
+
tensor = np.moveaxis(tensor, axes, dest_axes)
|
|
55
|
+
|
|
56
|
+
leading_shape = tensor.shape[:-len(qubits)]
|
|
57
|
+
reshaped = tensor.reshape(-1, dimension).T
|
|
58
|
+
transformed = matrix @ reshaped
|
|
59
|
+
tensor = transformed.T.reshape(*leading_shape, *([2] * len(qubits)))
|
|
60
|
+
tensor = np.moveaxis(tensor, dest_axes, axes)
|
|
61
|
+
return tensor.reshape(state.shape)
|
|
62
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""High-level library API to run the state vector simulator."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Union
|
|
8
|
+
|
|
9
|
+
from .circuit import QuantumCircuit
|
|
10
|
+
from .circuit_builders import random_circuit
|
|
11
|
+
from .simulator import SimulationResult, StateVectorSimulator
|
|
12
|
+
from .xeb import LinearXEBResult, run_linear_xeb_experiment
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def load_circuit(path: Union[Path, str]) -> QuantumCircuit:
|
|
16
|
+
"""Load a circuit from a JSON file.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
path: Path to a JSON file with keys "num_qubits" and "gates".
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
QuantumCircuit ready for run() or run_xeb().
|
|
23
|
+
"""
|
|
24
|
+
path = Path(path)
|
|
25
|
+
with path.open("r", encoding="utf-8") as f:
|
|
26
|
+
payload = json.load(f)
|
|
27
|
+
return QuantumCircuit.from_dict(payload)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def run(
|
|
31
|
+
circuit: Union[QuantumCircuit, Path, str],
|
|
32
|
+
shots: int = 0,
|
|
33
|
+
seed: int | None = None,
|
|
34
|
+
simulator: StateVectorSimulator | None = None,
|
|
35
|
+
) -> SimulationResult:
|
|
36
|
+
"""Run a circuit and return the simulation result.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
circuit: A QuantumCircuit, or a path to a JSON circuit file.
|
|
40
|
+
shots: Number of measurement shots to sample (0 = state vector only, no sampling).
|
|
41
|
+
seed: Random seed for reproducible sampling.
|
|
42
|
+
simulator: Optional simulator instance; a new one is created if not provided.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
SimulationResult with final_state, probabilities, and (if shots > 0) samples and counts.
|
|
46
|
+
"""
|
|
47
|
+
if not isinstance(circuit, QuantumCircuit):
|
|
48
|
+
circuit = load_circuit(circuit)
|
|
49
|
+
sim = simulator or StateVectorSimulator()
|
|
50
|
+
return sim.run(circuit, shots=shots, seed=seed)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def run_xeb(
|
|
54
|
+
circuit: Union[QuantumCircuit, Path, str],
|
|
55
|
+
shots: int,
|
|
56
|
+
seed: int | None = None,
|
|
57
|
+
simulator: StateVectorSimulator | None = None,
|
|
58
|
+
) -> LinearXEBResult:
|
|
59
|
+
"""Run a linear XEB experiment: simulate the circuit, sample measurements, compute fidelity.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
circuit: A QuantumCircuit, or a path to a JSON circuit file.
|
|
63
|
+
shots: Number of measurement shots (must be > 0).
|
|
64
|
+
seed: Random seed for reproducibility.
|
|
65
|
+
simulator: Optional simulator instance.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
LinearXEBResult with fidelity, samples, and sample_probabilities.
|
|
69
|
+
"""
|
|
70
|
+
if not isinstance(circuit, QuantumCircuit):
|
|
71
|
+
circuit = load_circuit(circuit)
|
|
72
|
+
return run_linear_xeb_experiment(
|
|
73
|
+
circuit,
|
|
74
|
+
simulator=simulator,
|
|
75
|
+
shots=shots,
|
|
76
|
+
seed=seed,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
__all__ = [
|
|
81
|
+
"load_circuit",
|
|
82
|
+
"run",
|
|
83
|
+
"run_xeb",
|
|
84
|
+
"random_circuit",
|
|
85
|
+
]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Cross-entropy benchmarking utilities."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Dict, Iterable, List, Optional
|
|
7
|
+
|
|
8
|
+
from .circuit import QuantumCircuit
|
|
9
|
+
from .simulator import StateVectorSimulator
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class LinearXEBResult:
|
|
14
|
+
"""Summary of a linear XEB experiment."""
|
|
15
|
+
|
|
16
|
+
circuit: QuantumCircuit
|
|
17
|
+
fidelity: float
|
|
18
|
+
shots: int
|
|
19
|
+
samples: List[str]
|
|
20
|
+
ideal_probabilities: List[float]
|
|
21
|
+
sample_probabilities: Dict[str, float]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def compute_linear_xeb_fidelity(
|
|
25
|
+
ideal_probabilities: Iterable[float],
|
|
26
|
+
samples: Iterable[str],
|
|
27
|
+
) -> float:
|
|
28
|
+
samples = list(samples)
|
|
29
|
+
if not samples:
|
|
30
|
+
raise ValueError("XEB fidelity requires at least one sample")
|
|
31
|
+
|
|
32
|
+
num_qubits = len(samples[0])
|
|
33
|
+
dimension = 1 << num_qubits
|
|
34
|
+
|
|
35
|
+
probs = list(ideal_probabilities)
|
|
36
|
+
if len(probs) != dimension:
|
|
37
|
+
raise ValueError("Ideal probability vector size does not match bitstring width")
|
|
38
|
+
|
|
39
|
+
prob_lookup = {format(index, f"0{num_qubits}b"): float(p) for index, p in enumerate(probs)}
|
|
40
|
+
average_p = sum(prob_lookup[bitstring] for bitstring in samples) / len(samples)
|
|
41
|
+
fidelity = dimension * average_p - 1.0
|
|
42
|
+
return fidelity
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def run_linear_xeb_experiment(
|
|
46
|
+
circuit: QuantumCircuit,
|
|
47
|
+
simulator: Optional[StateVectorSimulator] = None,
|
|
48
|
+
*,
|
|
49
|
+
shots: int,
|
|
50
|
+
seed: int | None = None,
|
|
51
|
+
) -> LinearXEBResult:
|
|
52
|
+
if shots <= 0:
|
|
53
|
+
raise ValueError("XEB experiment requires shots > 0")
|
|
54
|
+
simulator = simulator or StateVectorSimulator()
|
|
55
|
+
result = simulator.run(circuit, shots=shots, seed=seed)
|
|
56
|
+
if result.samples is None:
|
|
57
|
+
raise RuntimeError("Simulator did not return measurement samples")
|
|
58
|
+
fidelity = compute_linear_xeb_fidelity(result.probabilities, result.samples)
|
|
59
|
+
sample_probabilities = _relative_frequencies(result.samples)
|
|
60
|
+
return LinearXEBResult(
|
|
61
|
+
circuit=circuit,
|
|
62
|
+
fidelity=fidelity,
|
|
63
|
+
shots=shots,
|
|
64
|
+
samples=result.samples,
|
|
65
|
+
ideal_probabilities=result.probabilities,
|
|
66
|
+
sample_probabilities=sample_probabilities,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _relative_frequencies(samples: Iterable[str]) -> Dict[str, float]:
|
|
71
|
+
counts: Dict[str, int] = {}
|
|
72
|
+
total = 0
|
|
73
|
+
for bitstring in samples:
|
|
74
|
+
counts[bitstring] = counts.get(bitstring, 0) + 1
|
|
75
|
+
total += 1
|
|
76
|
+
return {bitstring: count / total for bitstring, count in counts.items()}
|
|
77
|
+
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qomputing-simulator
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Quantum computing state vector simulator with linear XEB benchmarking
|
|
5
|
+
Author: Qomputing Simulator Maintainers
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: quantum,simulation,state vector,xeb
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: numpy<3.0,>=1.24
|
|
18
|
+
Requires-Dist: cirq<2.0,>=1.6
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
21
|
+
Provides-Extra: build
|
|
22
|
+
Requires-Dist: build>=1.0; extra == "build"
|
|
23
|
+
|
|
24
|
+
# Qomputing Simulator
|
|
25
|
+
|
|
26
|
+
Qomputing Simulator is a lightweight, pure Python toolkit for simulating quantum state vectors and running linear cross-entropy benchmarking (XEB) experiments end-to-end.
|
|
27
|
+
|
|
28
|
+
**Will `pip install qomputing-simulator` work?**
|
|
29
|
+
- **Yes**, after you publish the package to [PyPI](https://pypi.org) (see “Publish to PyPI” below). Until then, pip won’t find it.
|
|
30
|
+
- **Until then**, install from the repo: in the project folder run `pip install .`, or from anywhere run
|
|
31
|
+
`pip install git+https://github.com/d2Anubis/state-vector-simulator.git`
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## How people install (step-by-step)
|
|
36
|
+
|
|
37
|
+
**If the package is on PyPI** (after you publish), users can do:
|
|
38
|
+
|
|
39
|
+
1. **Install the package**
|
|
40
|
+
```bash
|
|
41
|
+
pip install qomputing-simulator
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2. **Use the CLI** (optional)
|
|
45
|
+
```bash
|
|
46
|
+
qomputing-sim random-circuit --qubits 3 --depth 5 --shots 1000
|
|
47
|
+
qomputing-sim simulate --circuit path/to/circuit.json --shots 512
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
3. **Use it in Python**
|
|
51
|
+
```python
|
|
52
|
+
from qomputing_simulator import run, QuantumCircuit, load_circuit, run_xeb, random_circuit
|
|
53
|
+
|
|
54
|
+
circuit = QuantumCircuit(2)
|
|
55
|
+
circuit.h(0).cx(0, 1)
|
|
56
|
+
result = run(circuit, shots=1000, seed=42)
|
|
57
|
+
print(result.counts)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Optional:** Create a virtual environment first (recommended):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
python3 -m venv .venv
|
|
64
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
65
|
+
pip install qomputing-simulator
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Optional extras:** `pip install qomputing-simulator[dev]` (adds pytest), `pip install qomputing-simulator[build]` (adds build tool).
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Where you push and how to publish (maintainer)
|
|
73
|
+
|
|
74
|
+
### 1. Push code to GitHub (or GitLab, etc.)
|
|
75
|
+
|
|
76
|
+
- **Where:** Your Git remote (e.g. GitHub).
|
|
77
|
+
- Create a repo if needed, then from your project folder:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
git remote add origin https://github.com/YOUR_USERNAME/qomputing-simulator.git
|
|
81
|
+
git add .
|
|
82
|
+
git commit -m "Rename to qomputing-simulator"
|
|
83
|
+
git push -u origin main
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**GitHub permission (browser redirect + passcode):** If `git push` asks for login, use GitHub’s web flow so you’re redirected to GitHub to approve:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
./scripts/github-auth.sh
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
That script uses the [GitHub CLI](https://cli.github.com/) (`gh`). It will open your browser → you log in on GitHub → GitHub shows a one-time code → you paste the code back in the terminal. After that, `git push origin main` works without a password.
|
|
93
|
+
If you don’t have `gh`: install it (e.g. `brew install gh` on macOS), then run `./scripts/github-auth.sh` again.
|
|
94
|
+
|
|
95
|
+
- People can clone and install from source: `git clone https://github.com/YOUR_USERNAME/qomputing-simulator.git` then `pip install .` in the repo.
|
|
96
|
+
|
|
97
|
+
### 2. Publish to PyPI (so anyone can `pip install qomputing-simulator`)
|
|
98
|
+
|
|
99
|
+
PyPI is the default place pip installs from. Steps:
|
|
100
|
+
|
|
101
|
+
1. **Create accounts**
|
|
102
|
+
- [pypi.org](https://pypi.org/) (for real releases)
|
|
103
|
+
- [test.pypi.org](https://test.pypi.org/) (optional, for testing uploads)
|
|
104
|
+
|
|
105
|
+
2. **Install build tools**
|
|
106
|
+
```bash
|
|
107
|
+
pip install build twine
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
3. **Build the package**
|
|
111
|
+
```bash
|
|
112
|
+
cd /path/to/simulator
|
|
113
|
+
python -m build
|
|
114
|
+
```
|
|
115
|
+
This creates `dist/qomputing_simulator-0.1.0-py3-none-any.whl` and `dist/qomputing_simulator-0.1.0.tar.gz`.
|
|
116
|
+
|
|
117
|
+
4. **Upload to Test PyPI (optional)**
|
|
118
|
+
```bash
|
|
119
|
+
twine upload --repository testpypi dist/*
|
|
120
|
+
```
|
|
121
|
+
When prompted, use your Test PyPI username and password (or token). Test install with:
|
|
122
|
+
`pip install --index-url https://test.pypi.org/simple/ qomputing-simulator`
|
|
123
|
+
|
|
124
|
+
5. **Upload to PyPI (real release)**
|
|
125
|
+
```bash
|
|
126
|
+
twine upload dist/*
|
|
127
|
+
```
|
|
128
|
+
Use your PyPI username and password, or an [API token](https://pypi.org/manage/account/token/).
|
|
129
|
+
|
|
130
|
+
6. **Later releases:** Bump `version` in `pyproject.toml`, run `python -m build` again, then `twine upload dist/*`. You cannot reuse the same version number on PyPI.
|
|
131
|
+
|
|
132
|
+
After step 5, anyone can run `pip install qomputing-simulator` without cloning the repo.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Quick Start (development / from source)
|
|
137
|
+
|
|
138
|
+
### Install from source (development or local)
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
git clone https://github.com/YOUR_USERNAME/qomputing-simulator.git
|
|
142
|
+
cd qomputing-simulator
|
|
143
|
+
python3 -m venv .venv
|
|
144
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
145
|
+
pip install --upgrade pip
|
|
146
|
+
pip install -e ".[dev]"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
- `pip install -e .` installs the simulator and Cirq; the optional `[dev]` extra adds `pytest`.
|
|
150
|
+
- To install as a normal (non-editable) library: `pip install .` (no `-e`).
|
|
151
|
+
|
|
152
|
+
### Build wheels only (for offline or custom install)
|
|
153
|
+
|
|
154
|
+
From the project root:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
pip install build
|
|
158
|
+
python -m build
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Install the wheel anywhere: `pip install dist/qomputing_simulator-0.1.0-py3-none-any.whl`
|
|
162
|
+
|
|
163
|
+
### Offline / no wheel build
|
|
164
|
+
|
|
165
|
+
If you cannot use pip to fetch the package:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
export PYTHONPATH="$PWD"
|
|
169
|
+
python -m qomputing_simulator.cli random-circuit --qubits 3 --depth 5 --shots 1000
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Repository Layout
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
qomputing_simulator/
|
|
176
|
+
├── circuit.py # QuantumCircuit builder, JSON (de)serialization
|
|
177
|
+
├── gates/ # Single-, two-, and multi-qubit gate handlers
|
|
178
|
+
├── engine/ # StateVectorSimulator core, result dataclass, sampling
|
|
179
|
+
├── linalg.py # Shared tensor/linear algebra helpers
|
|
180
|
+
├── cli.py # CLI entry point (`qomputing-sim`)
|
|
181
|
+
├── xeb.py # Linear XEB fidelity helpers
|
|
182
|
+
├── tools/cirq_comparison.py # Parity harness against Cirq
|
|
183
|
+
└── tests/ # Pytest parity checks for representative gates
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## CLI Usage
|
|
187
|
+
|
|
188
|
+
- Run a random-circuit XEB benchmark:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
qomputing-sim random-circuit --qubits 3 --depth 5 --shots 1000
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Use `--single-qubit-gates/--two-qubit-gates/--multi-qubit-gates` to override the default gate pools (`["h","rx","ry","rz","s","t"]`, `["cx","cz","swap"]`, none).
|
|
195
|
+
|
|
196
|
+
- Simulate a circuit defined in JSON:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
qomputing-sim simulate --circuit circuits/example.json --shots 512 --seed 123
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Library usage
|
|
203
|
+
|
|
204
|
+
You can run the simulator from Python:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
from qomputing_simulator import (
|
|
208
|
+
QuantumCircuit,
|
|
209
|
+
load_circuit,
|
|
210
|
+
run,
|
|
211
|
+
run_xeb,
|
|
212
|
+
random_circuit,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Build a circuit and run (state vector only if shots=0)
|
|
216
|
+
circuit = QuantumCircuit(2)
|
|
217
|
+
circuit.h(0).cx(0, 1)
|
|
218
|
+
result = run(circuit, shots=1000, seed=42)
|
|
219
|
+
print(result.final_state, result.probabilities, result.counts)
|
|
220
|
+
|
|
221
|
+
# Load from JSON
|
|
222
|
+
circuit = load_circuit("circuits/example.json")
|
|
223
|
+
result = run(circuit, shots=512)
|
|
224
|
+
|
|
225
|
+
# Random circuit and linear XEB
|
|
226
|
+
circuit = random_circuit(num_qubits=3, depth=5, seed=7)
|
|
227
|
+
xeb_result = run_xeb(circuit, shots=1000, seed=7)
|
|
228
|
+
print(xeb_result.fidelity, xeb_result.sample_probabilities)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
See `examples/library_usage.py` for a runnable example.
|
|
232
|
+
|
|
233
|
+
## Example Circuits
|
|
234
|
+
|
|
235
|
+
Ready-made demonstrations live in `qomputing_simulator/examples/demo_circuits.py`. After activating your environment, run them as a module from the project root:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
python -m qomputing_simulator.examples.demo_circuits --example bell
|
|
239
|
+
python -m qomputing_simulator.examples.demo_circuits --example deutsch-jozsa --oracle balanced --shots 1024 --seed 7
|
|
240
|
+
python -m qomputing_simulator.examples.demo_circuits --example ghz --shots 1000 --seed 123
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Each command prints the final state vector, measurement probabilities, and (when `--shots > 0`) sampled counts. Use `--example bell|deutsch-jozsa|ghz` and, for Deutsch–Jozsa, pick `--oracle constant|balanced`.
|
|
244
|
+
|
|
245
|
+
## Circuit Specification
|
|
246
|
+
|
|
247
|
+
Circuits are defined as JSON documents of the following structure:
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"num_qubits": 2,
|
|
252
|
+
"gates": [
|
|
253
|
+
{"name": "h", "targets": [0]},
|
|
254
|
+
{"name": "cx", "controls": [0], "targets": [1]},
|
|
255
|
+
{"name": "rz", "targets": [0], "params": {"theta": 1.5708}}
|
|
256
|
+
]
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Supported gate names (and their parameters):
|
|
261
|
+
|
|
262
|
+
- Single-qubit: `id`, `x`, `y`, `z`, `h`, `s`, `sdg`, `t`, `tdg`, `sx`, `sxdg`, `rx(θ)`, `ry(θ)`, `rz(θ)`, `u1(λ)`, `u2(φ,λ)`, `u3(θ,φ,λ)`
|
|
263
|
+
- Two-qubit: `cx`, `cy`, `cz`, `cp(φ)`, `csx`, `swap`, `iswap`, `sqrtiswap`, `rxx(θ)`, `ryy(θ)`, `rzz(θ)`
|
|
264
|
+
- Multi-qubit: `ccx`, `ccz`, `cswap`
|
|
265
|
+
|
|
266
|
+
## Testing & Validation
|
|
267
|
+
|
|
268
|
+
1. **Unit tests (Pytest)**
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
pytest
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
The tests execute representative single-, two-, and three-qubit circuits and assert that our simulator matches Cirq to ≤1e-7 after global phase alignment.
|
|
275
|
+
|
|
276
|
+
2. **Parity harness against Cirq**
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
export PYTHONPATH="$PWD" # only needed if not pip-installed
|
|
280
|
+
python tools/cirq_comparison.py \
|
|
281
|
+
--min-qubits 1 --max-qubits 5 \
|
|
282
|
+
--depths 3 5 \
|
|
283
|
+
--circuits-per-config 3 \
|
|
284
|
+
--shots 256 \
|
|
285
|
+
--seed 7
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The summary at the end reports maximum amplitude/probability/XEB deviations. Pass `--help` to explore gate-pool overrides or larger qubit ranges. For qubits ≥20, allocate ample RAM (≥16 GB) and expect runtimes of multiple minutes.
|
|
289
|
+
|
|
290
|
+
3. **Large-scale sweep (optional)**
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
python tools/cirq_comparison.py \
|
|
294
|
+
--min-qubits 5 --max-qubits 25 \
|
|
295
|
+
--depths 5 \
|
|
296
|
+
--circuits-per-config 1 \
|
|
297
|
+
--shots 0 \
|
|
298
|
+
--seed 42 \
|
|
299
|
+
> comparison_results_25q.txt
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
This tests state-vector parity without sampling. Inspect the resulting file for per-configuration error logs and the summary block.
|
|
303
|
+
|
|
304
|
+
## Development Workflow
|
|
305
|
+
|
|
306
|
+
- Run `pytest` before committing.
|
|
307
|
+
- Use `qomputing-sim random-circuit` to generate sample workloads or JSONs for reproducible scenarios.
|
|
308
|
+
- Benchmark changes with `tools/cirq_comparison.py` to confirm parity with Cirq remains within tolerance.
|
|
309
|
+
- Generated artifacts (`comparison_results*.txt`, `__pycache__/`, virtual environments) are ignored via `.gitignore`.
|
|
310
|
+
|
|
311
|
+
## License
|
|
312
|
+
|
|
313
|
+
MIT
|
|
314
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
examples/library_usage.py,sha256=9E8NZWo7LXJsAOwBcXaDZVAemFD3Rou7VhSH2xr73wc,925
|
|
2
|
+
qomputing_simulator/__init__.py,sha256=F-qleLgIba0I4wKurAM8sgwvsVSvxsqBUu9XF3c5omM,568
|
|
3
|
+
qomputing_simulator/circuit.py,sha256=K2Mx7KDfD-rTEx_nslG9AJ78jZtpfcu1C9BN95pDzpc,8959
|
|
4
|
+
qomputing_simulator/circuit_builders.py,sha256=RZ5iT95FaWqom_Qm1iHPTCP9wYaVzkR6OTlhmoAHv3U,6234
|
|
5
|
+
qomputing_simulator/cli.py,sha256=RronVNZqUchDdgitXrI6YKfps012oH-JwISe39oYkcs,4047
|
|
6
|
+
qomputing_simulator/linalg.py,sha256=BeJldEZ-d_KUGKNONSofj3MOq0rxsT3eTCrvx2D3oBQ,1793
|
|
7
|
+
qomputing_simulator/run.py,sha256=ubLZYpFDPaRYIOLEaE2ayEXaZJq_hyA3vqTc3vbiNik,2530
|
|
8
|
+
qomputing_simulator/simulator.py,sha256=ZOtbHALrwdKlfte_lN_QFDLD514uxEElfUM1vqX-E8Y,180
|
|
9
|
+
qomputing_simulator/xeb.py,sha256=RdQdfOyHShhHvXLuFf_F6sUKY0yLiJ11DYcG958yloA,2378
|
|
10
|
+
qomputing_simulator/engine/__init__.py,sha256=IELlRtL7sGCVv600o1sJ5LBMMoryZhJ8Y65i9xh5MFw,179
|
|
11
|
+
qomputing_simulator/engine/measurements.py,sha256=SPDCw0XT7pbb4vRlo8ZgAWWjcs0rVh_Q5SGeh6-09Jw,698
|
|
12
|
+
qomputing_simulator/engine/registry.py,sha256=F6BYAh7pOCWpRx83AgtWldjLS4bKQXGN8e66UriZ3eo,871
|
|
13
|
+
qomputing_simulator/engine/result.py,sha256=wXNvPIR73EGJvGg3okkyONo9Yo63BdjDodxqzzg6Dlo,857
|
|
14
|
+
qomputing_simulator/engine/statevector.py,sha256=fMscMx-HRmtIsdqCvunFTc9F2LWaaKmn9hT3LgeSv1c,1510
|
|
15
|
+
qomputing_simulator/examples/__init__.py,sha256=daEdpEyAJIa8b2VkCqSKcw8PaExcB6Qro80XNes_sHA,2
|
|
16
|
+
qomputing_simulator/examples/demo_circuits.py,sha256=YZQx5F58XJrKRmho8CQILtsGoGlI8Rrxww2LujpLVTA,4021
|
|
17
|
+
qomputing_simulator/gates/__init__.py,sha256=oCMKx4LQw51luGZUJcIPZooZ1-A002DPR6Z3fKbP1Dc,836
|
|
18
|
+
qomputing_simulator/gates/multi_qubit.py,sha256=PFUEqOhPbRlYYEuTZ8VxNJVKBNmcL7DqsG0-TklG2QA,1933
|
|
19
|
+
qomputing_simulator/gates/single_qubit.py,sha256=gPQSNfKXk7--QU3lj8jAVPDLnW6rMkMx6RB4CN1CqQI,6213
|
|
20
|
+
qomputing_simulator/gates/two_qubit.py,sha256=ud7eC3UonLiMBlP4jItC6DZfycffmqsW4yDmp_nBkLA,6505
|
|
21
|
+
tests/test_parity.py,sha256=Gj62r_9k5v8YvLnis0558oz6nswmVHXfmtf9q6a0JJE,4225
|
|
22
|
+
tools/cirq_comparison.py,sha256=Pd611E4k6dF2avp3q1uZGN7Svp4xJtmo6OvGKFNtg0Y,15217
|
|
23
|
+
qomputing_simulator-0.1.0.dist-info/METADATA,sha256=OyAMitN9FHKiowdnS2_e23yTQ_BWwj97bOkpaundJjg,10411
|
|
24
|
+
qomputing_simulator-0.1.0.dist-info/WHEEL,sha256=YLJXdYXQ2FQ0Uqn2J-6iEIC-3iOey8lH3xCtvFLkd8Q,91
|
|
25
|
+
qomputing_simulator-0.1.0.dist-info/entry_points.txt,sha256=Zh1QINR7M1e4WDAR_kHLcIWLRR4sj81hb-C8BIgNRW4,63
|
|
26
|
+
qomputing_simulator-0.1.0.dist-info/top_level.txt,sha256=Rz0CNs42KK3erTfrENj93ujTb3GxuKz0dEBZHsywAlI,41
|
|
27
|
+
qomputing_simulator-0.1.0.dist-info/RECORD,,
|