qusim-np 1.0__tar.gz
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.
- qusim_np-1.0/LICENSE +21 -0
- qusim_np-1.0/PKG-INFO +205 -0
- qusim_np-1.0/README.md +178 -0
- qusim_np-1.0/pyproject.toml +45 -0
- qusim_np-1.0/qusim_np/__init__.py +40 -0
- qusim_np-1.0/qusim_np/config.py +46 -0
- qusim_np-1.0/qusim_np/deutsch_jozsa.py +119 -0
- qusim_np-1.0/qusim_np/gates.py +145 -0
- qusim_np-1.0/qusim_np/grover_search.py +275 -0
- qusim_np-1.0/qusim_np/qft.py +100 -0
- qusim_np-1.0/qusim_np/vqe.py +442 -0
- qusim_np-1.0/qusim_np.egg-info/PKG-INFO +205 -0
- qusim_np-1.0/qusim_np.egg-info/SOURCES.txt +20 -0
- qusim_np-1.0/qusim_np.egg-info/dependency_links.txt +1 -0
- qusim_np-1.0/qusim_np.egg-info/requires.txt +5 -0
- qusim_np-1.0/qusim_np.egg-info/top_level.txt +1 -0
- qusim_np-1.0/setup.cfg +4 -0
- qusim_np-1.0/tests/test_deutsch_jozsa.py +184 -0
- qusim_np-1.0/tests/test_gates.py +180 -0
- qusim_np-1.0/tests/test_grover_search.py +257 -0
- qusim_np-1.0/tests/test_qft.py +159 -0
- qusim_np-1.0/tests/test_vqe.py +464 -0
qusim_np-1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Furkan Nar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
qusim_np-1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: qusim-np
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: A minimal, readable quantum computing simulator: gates, state-vector algorithms, and VQE
|
|
5
|
+
Author-email: Furkan Nar <furkan_nar4185@outlook.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/furkannar/qusim-np
|
|
8
|
+
Project-URL: Repository, https://github.com/furkannar/qusim-np
|
|
9
|
+
Keywords: quantum,quantum-computing,simulation,vqe,grover,qft
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Intended Audience :: Education
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: numpy>=2.0.0
|
|
23
|
+
Requires-Dist: scipy>=1.11.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# qusim-np
|
|
29
|
+
|
|
30
|
+
**A minimal, readable quantum computing simulator in pure NumPy.**
|
|
31
|
+
|
|
32
|
+
State-vector gates, textbook quantum algorithms, and a working
|
|
33
|
+
Variational Quantum Eigensolver — in ~1,200 lines of well-documented,
|
|
34
|
+
well-tested code. Built for learning, teaching, and prototyping.
|
|
35
|
+
|
|
36
|
+
[](pyproject.toml)
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
[](tests/)
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Features
|
|
43
|
+
|
|
44
|
+
| Category | What you get |
|
|
45
|
+
|---|---|
|
|
46
|
+
| **Gates** | Pauli X/Y/Z, Hadamard, S, T, CNOT, SWAP, CZ, Toffoli, `rx`/`ry`/`rz` rotations |
|
|
47
|
+
| **Algorithms** | Grover search, Deutsch–Jozsa, Quantum Fourier Transform |
|
|
48
|
+
| **VQE** | Pauli-string Hamiltonians, hardware-efficient ansatz, `scipy` optimizer |
|
|
49
|
+
| **Performance** | 1- and 2-qubit gates applied to state vectors in O(n·2ⁿ) — no dense 2ⁿ×2ⁿ matrices in the hot path |
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install qusim-np
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
From source:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
git clone https://github.com/furkannar/qusim-np.git
|
|
61
|
+
cd qusim-np
|
|
62
|
+
pip install -e .
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Requires Python ≥ 3.10, NumPy ≥ 2.0, SciPy ≥ 1.11.
|
|
66
|
+
|
|
67
|
+
## Quick start
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
import qusim_np
|
|
71
|
+
|
|
72
|
+
# Grover's search — find state |101> among 8 possibilities
|
|
73
|
+
state, k, p = qusim_np.grover_search(3, marked_states=[5])
|
|
74
|
+
print(f"{k} iterations -> P(marked) = {p:.3f}")
|
|
75
|
+
|
|
76
|
+
# Deutsch-Jozsa — constant or balanced with ONE query
|
|
77
|
+
print(qusim_np.deutsch_jozsa_classify(3, lambda x: x % 2)) # 'balanced'
|
|
78
|
+
|
|
79
|
+
# Quantum Fourier Transform
|
|
80
|
+
F = qusim_np.qft_matrix(3) # 8x8 unitary
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### The math, briefly
|
|
84
|
+
|
|
85
|
+
Grover's algorithm rotates the state vector in the plane spanned by the
|
|
86
|
+
marked and unmarked subspaces. With $N = 2^n$ basis states and $M$ marked
|
|
87
|
+
states, each iteration rotates by
|
|
88
|
+
|
|
89
|
+
$$\theta = 2\arcsin\sqrt{\frac{M}{N}}, \qquad
|
|
90
|
+
k_{\mathrm{opt}} \approx \frac{\pi}{4}\sqrt{\frac{N}{M}}$$
|
|
91
|
+
|
|
92
|
+
so the marked states are amplified after $O(\sqrt{N/M})$ oracle queries.
|
|
93
|
+
|
|
94
|
+
The Quantum Fourier Transform is the unitary
|
|
95
|
+
|
|
96
|
+
$$F_{jk} = \frac{1}{\sqrt{N}}\,\omega^{jk}, \qquad
|
|
97
|
+
\omega = e^{2\pi i / N}, \qquad j,k = 0,\dots,N-1$$
|
|
98
|
+
|
|
99
|
+
## Variational Quantum Eigensolver
|
|
100
|
+
|
|
101
|
+
The flagship feature: find the ground-state energy of a Hamiltonian
|
|
102
|
+
written as a linear combination of Pauli strings,
|
|
103
|
+
|
|
104
|
+
$$H = \sum_{i=0}^{m-1} \alpha_i P_i, \qquad
|
|
105
|
+
P_i = \bigotimes_{k=0}^{n-1} \sigma_{i,k}, \qquad
|
|
106
|
+
\sigma_{i,k} \in \{I, X, Y, Z\}$$
|
|
107
|
+
|
|
108
|
+
by minimizing the variational energy
|
|
109
|
+
|
|
110
|
+
$$E(\theta) = \langle \psi(\theta) \,|\, H \,|\, \psi(\theta) \rangle$$
|
|
111
|
+
|
|
112
|
+
over the parameters of a hardware-efficient ansatz (HEA).
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
import numpy as np
|
|
116
|
+
import qusim_np
|
|
117
|
+
|
|
118
|
+
# H = 0.3·II + 1.2·ZZ - 0.8·XI - 0.8·IX (2 qubits)
|
|
119
|
+
coeffs = [0.3, 1.2, -0.8, -0.8]
|
|
120
|
+
strings = ["II", "ZZ", "XI", "IX"]
|
|
121
|
+
|
|
122
|
+
# Minimize <psi(theta)|H|psi(theta)> over a hardware-efficient ansatz
|
|
123
|
+
res = qusim_np.vqe_optimize(2, layers=2,
|
|
124
|
+
coefficients=coeffs, pauli_strings=strings)
|
|
125
|
+
print(f"VQE energy: {res.fun:.6f}")
|
|
126
|
+
|
|
127
|
+
# Exact answer for comparison (dense diagonalization)
|
|
128
|
+
H = qusim_np.hamiltonian(coeffs, strings)
|
|
129
|
+
print(f"Exact: {np.linalg.eigvalsh(H)[0]:.6f}")
|
|
130
|
+
# -> VQE energy: -1.700000 Exact: -1.700000
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### VQE building blocks
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
# Pauli strings: "XZI", ("X","Z","I"), or index tuples (1,3,0) — all equivalent
|
|
137
|
+
P = qusim_np.pauli_string_matrix("XZI") # 8x8 matrix, 3 qubits
|
|
138
|
+
|
|
139
|
+
# Expectation values WITHOUT building the 2^n x 2^n matrix
|
|
140
|
+
qusim_np.pauli_string_expval(state, "ZZ")
|
|
141
|
+
|
|
142
|
+
# Apply gates straight to state vectors (O(n·2^n), no big matrices)
|
|
143
|
+
state = qusim_np.initialize_uniform_superposition(2)
|
|
144
|
+
state = qusim_np.apply_single_qubit(state, qusim_np.gates.hadamard().matrix, 0)
|
|
145
|
+
state = qusim_np.apply_two_qubit(state, qusim_np.gates.cnot().matrix, 0, 1)
|
|
146
|
+
|
|
147
|
+
# Inspect the ansatz before optimizing
|
|
148
|
+
theta = np.zeros(qusim_np.hea_param_count(2, layers=2))
|
|
149
|
+
psi = qusim_np.hea_state(2, theta, layers=2)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Qubit convention
|
|
153
|
+
|
|
154
|
+
Qubit 0 is the **most significant bit** of the basis-state index:
|
|
155
|
+
|
|
156
|
+
$$|q_0 q_1 \dots q_{n-1}\rangle \;\longleftrightarrow\;
|
|
157
|
+
\sum_{k=0}^{n-1} q_k\, 2^{\,n-1-k}$$
|
|
158
|
+
|
|
159
|
+
A Pauli string `"XZI"` means X on qubit 0, Z on qubit 1, I on qubit 2 —
|
|
160
|
+
same convention as Qiskit and most textbooks.
|
|
161
|
+
|
|
162
|
+
## Project layout
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
qusim_np/
|
|
166
|
+
├── config.py # constants + Pauli matrices
|
|
167
|
+
├── gates.py # QuantumGate + gate constructors
|
|
168
|
+
├── grover_search.py # Hadamard transforms, oracle, diffusion, Grover
|
|
169
|
+
├── deutsch_jozsa.py # Deutsch-Jozsa algorithm
|
|
170
|
+
├── qft.py # QFT / inverse QFT
|
|
171
|
+
└── vqe.py # Pauli strings, Hamiltonians, HEA ansatz, VQE driver
|
|
172
|
+
tests/ # 178 tests
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Limitations
|
|
176
|
+
|
|
177
|
+
Honest scope notes — this is a teaching/reference simulator:
|
|
178
|
+
|
|
179
|
+
- **Dense state vectors**: memory is O(2ⁿ); practical limit ~15–20 qubits
|
|
180
|
+
- **No noise model**: pure-state simulation only (no decoherence, no sampling noise)
|
|
181
|
+
- **No circuit API**: you compose gates programmatically, not via a `QuantumCircuit` builder
|
|
182
|
+
- **Classical only**: no real-device or cloud backend integration
|
|
183
|
+
|
|
184
|
+
For production quantum computing, see [Qiskit](https://www.ibm.com/quantum/qiskit),
|
|
185
|
+
[PennyLane](https://pennylane.ai/), or [Cirq](https://quantumai.google/cirq).
|
|
186
|
+
|
|
187
|
+
## Development
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
pip install -e .[dev]
|
|
191
|
+
pytest # 178 tests, ~1s
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Contributions welcome — see the test suite for conventions.
|
|
195
|
+
|
|
196
|
+
## AI assistance
|
|
197
|
+
|
|
198
|
+
Parts of this codebase were written with assistance from **SWE-2 by
|
|
199
|
+
Cognition**, accessed through the **Devin** platform, for coding tasks
|
|
200
|
+
such as implementing algorithms, tests, and documentation. All
|
|
201
|
+
architectural and design decisions were made by the author.
|
|
202
|
+
|
|
203
|
+
## License
|
|
204
|
+
|
|
205
|
+
[MIT](LICENSE) © 2026 Furkan Nar
|
qusim_np-1.0/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# qusim-np
|
|
2
|
+
|
|
3
|
+
**A minimal, readable quantum computing simulator in pure NumPy.**
|
|
4
|
+
|
|
5
|
+
State-vector gates, textbook quantum algorithms, and a working
|
|
6
|
+
Variational Quantum Eigensolver — in ~1,200 lines of well-documented,
|
|
7
|
+
well-tested code. Built for learning, teaching, and prototyping.
|
|
8
|
+
|
|
9
|
+
[](pyproject.toml)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](tests/)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
| Category | What you get |
|
|
18
|
+
|---|---|
|
|
19
|
+
| **Gates** | Pauli X/Y/Z, Hadamard, S, T, CNOT, SWAP, CZ, Toffoli, `rx`/`ry`/`rz` rotations |
|
|
20
|
+
| **Algorithms** | Grover search, Deutsch–Jozsa, Quantum Fourier Transform |
|
|
21
|
+
| **VQE** | Pauli-string Hamiltonians, hardware-efficient ansatz, `scipy` optimizer |
|
|
22
|
+
| **Performance** | 1- and 2-qubit gates applied to state vectors in O(n·2ⁿ) — no dense 2ⁿ×2ⁿ matrices in the hot path |
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install qusim-np
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
From source:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git clone https://github.com/furkannar/qusim-np.git
|
|
34
|
+
cd qusim-np
|
|
35
|
+
pip install -e .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Requires Python ≥ 3.10, NumPy ≥ 2.0, SciPy ≥ 1.11.
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import qusim_np
|
|
44
|
+
|
|
45
|
+
# Grover's search — find state |101> among 8 possibilities
|
|
46
|
+
state, k, p = qusim_np.grover_search(3, marked_states=[5])
|
|
47
|
+
print(f"{k} iterations -> P(marked) = {p:.3f}")
|
|
48
|
+
|
|
49
|
+
# Deutsch-Jozsa — constant or balanced with ONE query
|
|
50
|
+
print(qusim_np.deutsch_jozsa_classify(3, lambda x: x % 2)) # 'balanced'
|
|
51
|
+
|
|
52
|
+
# Quantum Fourier Transform
|
|
53
|
+
F = qusim_np.qft_matrix(3) # 8x8 unitary
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### The math, briefly
|
|
57
|
+
|
|
58
|
+
Grover's algorithm rotates the state vector in the plane spanned by the
|
|
59
|
+
marked and unmarked subspaces. With $N = 2^n$ basis states and $M$ marked
|
|
60
|
+
states, each iteration rotates by
|
|
61
|
+
|
|
62
|
+
$$\theta = 2\arcsin\sqrt{\frac{M}{N}}, \qquad
|
|
63
|
+
k_{\mathrm{opt}} \approx \frac{\pi}{4}\sqrt{\frac{N}{M}}$$
|
|
64
|
+
|
|
65
|
+
so the marked states are amplified after $O(\sqrt{N/M})$ oracle queries.
|
|
66
|
+
|
|
67
|
+
The Quantum Fourier Transform is the unitary
|
|
68
|
+
|
|
69
|
+
$$F_{jk} = \frac{1}{\sqrt{N}}\,\omega^{jk}, \qquad
|
|
70
|
+
\omega = e^{2\pi i / N}, \qquad j,k = 0,\dots,N-1$$
|
|
71
|
+
|
|
72
|
+
## Variational Quantum Eigensolver
|
|
73
|
+
|
|
74
|
+
The flagship feature: find the ground-state energy of a Hamiltonian
|
|
75
|
+
written as a linear combination of Pauli strings,
|
|
76
|
+
|
|
77
|
+
$$H = \sum_{i=0}^{m-1} \alpha_i P_i, \qquad
|
|
78
|
+
P_i = \bigotimes_{k=0}^{n-1} \sigma_{i,k}, \qquad
|
|
79
|
+
\sigma_{i,k} \in \{I, X, Y, Z\}$$
|
|
80
|
+
|
|
81
|
+
by minimizing the variational energy
|
|
82
|
+
|
|
83
|
+
$$E(\theta) = \langle \psi(\theta) \,|\, H \,|\, \psi(\theta) \rangle$$
|
|
84
|
+
|
|
85
|
+
over the parameters of a hardware-efficient ansatz (HEA).
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
import numpy as np
|
|
89
|
+
import qusim_np
|
|
90
|
+
|
|
91
|
+
# H = 0.3·II + 1.2·ZZ - 0.8·XI - 0.8·IX (2 qubits)
|
|
92
|
+
coeffs = [0.3, 1.2, -0.8, -0.8]
|
|
93
|
+
strings = ["II", "ZZ", "XI", "IX"]
|
|
94
|
+
|
|
95
|
+
# Minimize <psi(theta)|H|psi(theta)> over a hardware-efficient ansatz
|
|
96
|
+
res = qusim_np.vqe_optimize(2, layers=2,
|
|
97
|
+
coefficients=coeffs, pauli_strings=strings)
|
|
98
|
+
print(f"VQE energy: {res.fun:.6f}")
|
|
99
|
+
|
|
100
|
+
# Exact answer for comparison (dense diagonalization)
|
|
101
|
+
H = qusim_np.hamiltonian(coeffs, strings)
|
|
102
|
+
print(f"Exact: {np.linalg.eigvalsh(H)[0]:.6f}")
|
|
103
|
+
# -> VQE energy: -1.700000 Exact: -1.700000
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### VQE building blocks
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
# Pauli strings: "XZI", ("X","Z","I"), or index tuples (1,3,0) — all equivalent
|
|
110
|
+
P = qusim_np.pauli_string_matrix("XZI") # 8x8 matrix, 3 qubits
|
|
111
|
+
|
|
112
|
+
# Expectation values WITHOUT building the 2^n x 2^n matrix
|
|
113
|
+
qusim_np.pauli_string_expval(state, "ZZ")
|
|
114
|
+
|
|
115
|
+
# Apply gates straight to state vectors (O(n·2^n), no big matrices)
|
|
116
|
+
state = qusim_np.initialize_uniform_superposition(2)
|
|
117
|
+
state = qusim_np.apply_single_qubit(state, qusim_np.gates.hadamard().matrix, 0)
|
|
118
|
+
state = qusim_np.apply_two_qubit(state, qusim_np.gates.cnot().matrix, 0, 1)
|
|
119
|
+
|
|
120
|
+
# Inspect the ansatz before optimizing
|
|
121
|
+
theta = np.zeros(qusim_np.hea_param_count(2, layers=2))
|
|
122
|
+
psi = qusim_np.hea_state(2, theta, layers=2)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Qubit convention
|
|
126
|
+
|
|
127
|
+
Qubit 0 is the **most significant bit** of the basis-state index:
|
|
128
|
+
|
|
129
|
+
$$|q_0 q_1 \dots q_{n-1}\rangle \;\longleftrightarrow\;
|
|
130
|
+
\sum_{k=0}^{n-1} q_k\, 2^{\,n-1-k}$$
|
|
131
|
+
|
|
132
|
+
A Pauli string `"XZI"` means X on qubit 0, Z on qubit 1, I on qubit 2 —
|
|
133
|
+
same convention as Qiskit and most textbooks.
|
|
134
|
+
|
|
135
|
+
## Project layout
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
qusim_np/
|
|
139
|
+
├── config.py # constants + Pauli matrices
|
|
140
|
+
├── gates.py # QuantumGate + gate constructors
|
|
141
|
+
├── grover_search.py # Hadamard transforms, oracle, diffusion, Grover
|
|
142
|
+
├── deutsch_jozsa.py # Deutsch-Jozsa algorithm
|
|
143
|
+
├── qft.py # QFT / inverse QFT
|
|
144
|
+
└── vqe.py # Pauli strings, Hamiltonians, HEA ansatz, VQE driver
|
|
145
|
+
tests/ # 178 tests
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Limitations
|
|
149
|
+
|
|
150
|
+
Honest scope notes — this is a teaching/reference simulator:
|
|
151
|
+
|
|
152
|
+
- **Dense state vectors**: memory is O(2ⁿ); practical limit ~15–20 qubits
|
|
153
|
+
- **No noise model**: pure-state simulation only (no decoherence, no sampling noise)
|
|
154
|
+
- **No circuit API**: you compose gates programmatically, not via a `QuantumCircuit` builder
|
|
155
|
+
- **Classical only**: no real-device or cloud backend integration
|
|
156
|
+
|
|
157
|
+
For production quantum computing, see [Qiskit](https://www.ibm.com/quantum/qiskit),
|
|
158
|
+
[PennyLane](https://pennylane.ai/), or [Cirq](https://quantumai.google/cirq).
|
|
159
|
+
|
|
160
|
+
## Development
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
pip install -e .[dev]
|
|
164
|
+
pytest # 178 tests, ~1s
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Contributions welcome — see the test suite for conventions.
|
|
168
|
+
|
|
169
|
+
## AI assistance
|
|
170
|
+
|
|
171
|
+
Parts of this codebase were written with assistance from **SWE-2 by
|
|
172
|
+
Cognition**, accessed through the **Devin** platform, for coding tasks
|
|
173
|
+
such as implementing algorithms, tests, and documentation. All
|
|
174
|
+
architectural and design decisions were made by the author.
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
[MIT](LICENSE) © 2026 Furkan Nar
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "qusim-np"
|
|
7
|
+
version = "1.0"
|
|
8
|
+
description = "A minimal, readable quantum computing simulator: gates, state-vector algorithms, and VQE"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
authors = [
|
|
12
|
+
{name = "Furkan Nar", email = "furkan_nar4185@outlook.com"},
|
|
13
|
+
]
|
|
14
|
+
keywords = ["quantum", "quantum-computing", "simulation", "vqe", "grover", "qft"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Intended Audience :: Science/Research",
|
|
18
|
+
"Intended Audience :: Education",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Scientific/Engineering :: Physics",
|
|
25
|
+
]
|
|
26
|
+
requires-python = ">=3.10"
|
|
27
|
+
dependencies = [
|
|
28
|
+
"numpy>=2.0.0",
|
|
29
|
+
"scipy>=1.11.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
dev = [
|
|
34
|
+
"pytest>=8.0.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Homepage = "https://github.com/furkannar/qusim-np"
|
|
39
|
+
Repository = "https://github.com/furkannar/qusim-np"
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.packages.find]
|
|
42
|
+
include = ["qusim_np*"]
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Quantum computing engine: gates, state-vector simulation, and algorithms."""
|
|
2
|
+
|
|
3
|
+
from qusim_np.config import QuantumConfig, config
|
|
4
|
+
from qusim_np.gates import (
|
|
5
|
+
QuantumGate,
|
|
6
|
+
pauli_x, pauli_y, pauli_z, hadamard, phase_gate, t_gate,
|
|
7
|
+
identity, cnot, swap, controlled_phase, toffoli, rx, ry, rz,
|
|
8
|
+
)
|
|
9
|
+
from qusim_np.grover_search import (
|
|
10
|
+
hadamard_transform, hadamard_matrix_closed_form,
|
|
11
|
+
initialize_uniform_superposition, grover_oracle, diffusion_operator,
|
|
12
|
+
grover_iteration, calculate_theta, calculate_optimal_iterations,
|
|
13
|
+
grover_search,
|
|
14
|
+
)
|
|
15
|
+
from qusim_np.deutsch_jozsa import (
|
|
16
|
+
deutsch_jozsa_oracle, deutsch_jozsa, deutsch_jozsa_classify,
|
|
17
|
+
)
|
|
18
|
+
from qusim_np.qft import (
|
|
19
|
+
qft_matrix, inverse_qft_matrix, qft_state, inverse_qft_state,
|
|
20
|
+
)
|
|
21
|
+
from qusim_np.vqe import (
|
|
22
|
+
pauli_string_matrix, apply_single_qubit, apply_two_qubit,
|
|
23
|
+
apply_pauli_string, pauli_string_expval, hamiltonian, expectation_value,
|
|
24
|
+
hea_param_count, hea_state, vqe_energy, vqe_optimize,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"QuantumConfig", "config", "QuantumGate",
|
|
29
|
+
"pauli_x", "pauli_y", "pauli_z", "hadamard", "phase_gate", "t_gate",
|
|
30
|
+
"identity", "cnot", "swap", "controlled_phase", "toffoli", "rx", "ry", "rz",
|
|
31
|
+
"hadamard_transform", "hadamard_matrix_closed_form",
|
|
32
|
+
"initialize_uniform_superposition", "grover_oracle", "diffusion_operator",
|
|
33
|
+
"grover_iteration", "calculate_theta", "calculate_optimal_iterations",
|
|
34
|
+
"grover_search",
|
|
35
|
+
"deutsch_jozsa_oracle", "deutsch_jozsa", "deutsch_jozsa_classify",
|
|
36
|
+
"qft_matrix", "inverse_qft_matrix", "qft_state", "inverse_qft_state",
|
|
37
|
+
"pauli_string_matrix", "apply_single_qubit", "apply_two_qubit",
|
|
38
|
+
"apply_pauli_string", "pauli_string_expval", "hamiltonian", "expectation_value",
|
|
39
|
+
"hea_param_count", "hea_state", "vqe_energy", "vqe_optimize",
|
|
40
|
+
]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
Quantum Computing Configuration
|
|
3
|
+
|
|
4
|
+
This module contains constants and configuration values used across
|
|
5
|
+
the quantum computing implementation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class QuantumConfig:
|
|
14
|
+
"""Configuration constants for quantum computing implementation."""
|
|
15
|
+
|
|
16
|
+
# Mathematical constants
|
|
17
|
+
SQRT_2: float = np.sqrt(2)
|
|
18
|
+
INV_SQRT_2: float = 1 / SQRT_2
|
|
19
|
+
|
|
20
|
+
# Quantum gate constants
|
|
21
|
+
HADAMARD_SCALE: float = INV_SQRT_2
|
|
22
|
+
|
|
23
|
+
# Grover's algorithm constants
|
|
24
|
+
# These will be computed dynamically based on n and M
|
|
25
|
+
# N = 2^n (total number of basis states)
|
|
26
|
+
# M = number of marked solutions
|
|
27
|
+
|
|
28
|
+
# Rotation gate constants
|
|
29
|
+
# theta parameter for Rx, Ry, Rz gates
|
|
30
|
+
DEFAULT_ROTATION_ANGLE: float = np.pi / 4
|
|
31
|
+
|
|
32
|
+
# SU(2) constraints
|
|
33
|
+
# Unitary: U^dagger * U = I
|
|
34
|
+
# Special Unitary: det(U) = 1
|
|
35
|
+
SU2_TOLERANCE: float = 1e-10
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# Global config instance
|
|
39
|
+
config = QuantumConfig()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Single-qubit Pauli matrices (used by VQE Hamiltonians and Pauli strings)
|
|
43
|
+
PAULI_I = np.array([[1, 0], [0, 1]], dtype=complex)
|
|
44
|
+
PAULI_X = np.array([[0, 1], [1, 0]], dtype=complex)
|
|
45
|
+
PAULI_Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
|
|
46
|
+
PAULI_Z = np.array([[1, 0], [0, -1]], dtype=complex)
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
qusim_np/deutsch_jozsa.py
|
|
3
|
+
Deutsch-Jozsa Algorithm
|
|
4
|
+
|
|
5
|
+
This module implements the Deutsch-Jozsa algorithm using the custom gates.
|
|
6
|
+
|
|
7
|
+
Deutsch-Jozsa Algorithm:
|
|
8
|
+
- Determines whether a function f: {0,1}^n -> {0,1} is constant or balanced
|
|
9
|
+
using a single quantum query (classically requires up to 2^{n-1} + 1 queries)
|
|
10
|
+
- n-qubit Hadamard transform: H^{\otimes n}
|
|
11
|
+
- Initial state: |s> = H^{\otimes n}|0>^{\otimes n} = (1/sqrt(N)) * sum_x |x>
|
|
12
|
+
- Oracle O_f: O_f|x> = (-1)^{f(x)}|x> (phase kickback, no ancilla needed)
|
|
13
|
+
- Final Hadamard transform: H^{\otimes n} again (H is self-inverse)
|
|
14
|
+
- If f is constant: measurement yields |0^n> with probability 1
|
|
15
|
+
- If f is balanced: amplitude of |0^n> is 0, so a nonzero outcome is certain
|
|
16
|
+
- Amplitude of |y> after final transform:
|
|
17
|
+
A_y = (1/N) * sum_x (-1)^{f(x)} (-1)^{x \cdot y} (Walsh-Hadamard transform)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import numpy as np
|
|
21
|
+
from qusim_np.grover_search import (
|
|
22
|
+
_validate_n, hadamard_transform, initialize_uniform_superposition
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _evaluate_f(f, N):
|
|
27
|
+
"""
|
|
28
|
+
Evaluate f on all N basis states.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
f: Callable f(x) -> bool/int, or a sequence of N bits
|
|
32
|
+
N: Number of basis states (2^n)
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
list: f-values for x = 0..N-1 as 0/1 ints
|
|
36
|
+
"""
|
|
37
|
+
if callable(f):
|
|
38
|
+
return [int(bool(f(x))) for x in range(N)]
|
|
39
|
+
values = list(f)
|
|
40
|
+
if len(values) != N:
|
|
41
|
+
raise ValueError(f"f sequence must have length {N}, got {len(values)}")
|
|
42
|
+
return [int(bool(v)) for v in values]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def deutsch_jozsa_oracle(n, f):
|
|
46
|
+
r"""
|
|
47
|
+
Construct the Deutsch-Jozsa oracle O_f that encodes f as a phase.
|
|
48
|
+
|
|
49
|
+
O_f|x> = (-1)^{f(x)}|x>, where f(x) = 1 picks up a phase of -1.
|
|
50
|
+
This is a diagonal unitary: diag((-1)^{f(0)}, ..., (-1)^{f(N-1)}).
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
n: Number of qubits
|
|
54
|
+
f: Function to evaluate - either a callable f(x) -> bool/int
|
|
55
|
+
or a sequence of N = 2^n bits (f(0), f(1), ..., f(N-1))
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
numpy.ndarray: The oracle matrix of shape (2^n, 2^n)
|
|
59
|
+
"""
|
|
60
|
+
_validate_n(n)
|
|
61
|
+
N = 2 ** n
|
|
62
|
+
values = _evaluate_f(f, N)
|
|
63
|
+
phases = np.array([1 - 2 * v for v in values]) # +1 if f=0, -1 if f=1
|
|
64
|
+
return np.diag(phases).astype(complex)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def deutsch_jozsa(n, f):
|
|
68
|
+
r"""
|
|
69
|
+
Run the Deutsch-Jozsa algorithm on function f.
|
|
70
|
+
|
|
71
|
+
Algorithm:
|
|
72
|
+
1. Initialize |s> = H^{\otimes n}|0^n>
|
|
73
|
+
2. Apply oracle: O_f|s>
|
|
74
|
+
3. Apply H^{\otimes n} again
|
|
75
|
+
4. Measure: |0^n> outcome implies f is constant
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
n: Number of qubits
|
|
79
|
+
f: Callable f(x) -> bool/int, or sequence of N = 2^n bits
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
tuple: (final_state, zero_probability)
|
|
83
|
+
final_state: state vector of shape (2^n,)
|
|
84
|
+
zero_probability: probability of measuring |0^n>;
|
|
85
|
+
~1.0 indicates constant, ~0.0 indicates balanced
|
|
86
|
+
"""
|
|
87
|
+
_validate_n(n)
|
|
88
|
+
|
|
89
|
+
# Step 1: uniform superposition
|
|
90
|
+
state = initialize_uniform_superposition(n)
|
|
91
|
+
|
|
92
|
+
# Step 2: oracle phase kickback
|
|
93
|
+
O = deutsch_jozsa_oracle(n, f)
|
|
94
|
+
state = O @ state
|
|
95
|
+
|
|
96
|
+
# Step 3: Hadamard transform again (H^{\otimes n} is self-inverse)
|
|
97
|
+
H_n = hadamard_transform(n)
|
|
98
|
+
state = H_n @ state
|
|
99
|
+
|
|
100
|
+
# Step 4: probability of measuring |0...0>
|
|
101
|
+
zero_probability = abs(state[0]) ** 2
|
|
102
|
+
|
|
103
|
+
return state, zero_probability
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def deutsch_jozsa_classify(n, f, threshold=0.5):
|
|
107
|
+
r"""
|
|
108
|
+
Classify f as 'constant' or 'balanced' using the Deutsch-Jozsa algorithm.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
n: Number of qubits
|
|
112
|
+
f: Callable f(x) -> bool/int, or sequence of N = 2^n bits
|
|
113
|
+
threshold: Decision boundary on P(|0^n>) (default 0.5)
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
str: 'constant' if P(|0^n>) > threshold, else 'balanced'
|
|
117
|
+
"""
|
|
118
|
+
_, p0 = deutsch_jozsa(n, f)
|
|
119
|
+
return "constant" if p0 > threshold else "balanced"
|