Metadata-Version: 2.4
Name: qkan-sim-lib
Version: 0.3.0
Summary: From-scratch statevector qubit simulator with a Quantum Kolmogorov-Arnold Network (QKAN) layer on top, split into layered packages, plus a noise layer and cross-layer observability.
License: MIT License
        
        Copyright (c) 2026 ByteTheBait
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Classifier: License :: OSI Approved :: MIT License
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Dynamic: license-file

# Qkan-Sim-Lib

A from-scratch qubit simulation stack, split into layers, topped by a
small **Quantum Kolmogorov-Arnold Network (QKAN)**. No Qiskit/PennyLane/Cirq
dependency — just NumPy for the linear algebra.

```
5.   analysis          regression metrics, reports, and entanglement
                        diagnostics of a trained network
          |
4.   qkan               QKANEdge -> QKANLayer -> QKANNetwork, trained via
                        parameter-shift gradients; Trainer built to run
                        longer than 24 hours with checkpoint/resume
          |
3.5. noise                optional realism: depolarizing / amplitude- /
                        phase-damping channels, wraps a circuit and replays
                        it with noise injected (kept out of qkan training --
                        see noise/README.md for why)
          |
3.   gates               gate library (H, X, RX/RY/RZ, CNOT, ...) and the
                        QuantumCircuit DSL (Param/Input-driven gate sequences)
          |
2.   entanglement         the interaction mechanism: apply_operator lets
                        qubits affect each other; diagnostics measure how
                        entangled the result is (density matrix, purity,
                        entropy)
          |
1.   qubit_simulator       raw n-qubit statevector: init, storage, readout

   observability   (cross-layer, not numbered) a pub/sub event bus every
                    layer above can emit to -- see observability/README.md
```

Each layer only depends on the ones below it, is its own top-level Python
package, and has its own README with the details:

- [`qubit_simulator/`](qubit_simulator/README.md) — layer 1
- [`entanglement/`](entanglement/README.md) — layer 2
- [`gates/`](gates/README.md) — layer 3
- [`noise/`](noise/README.md) — layer 3.5 (bonus: realistic decoherence)
- [`qkan/`](qkan/README.md) — layer 4
- [`analysis/`](analysis/README.md) — layer 5
- [`observability/`](observability/README.md) — cross-layer event bus (bonus)

## Install

Requires Python >= 3.10.

```bash
pip install -e ".[dev]"   # numpy + pytest
```

## Run it

```bash
python main.py
```

This builds a small dataset (`y = sin(pi*x)`), trains a `[1, 4, 1]` QKAN
(2 qubits per edge) with `qkan.training.Trainer`, then hands the trained
network to the `analysis` layer for a text report (loss curve, MSE/MAE/R²,
predictions vs. targets) and a quantum diagnostic (how entangled each edge's
circuit actually gets across the dataset).

For a longer, checkpointed/resumable run:

```bash
python examples/train_small_qkan.py --max-epochs 0 --checkpoint runs/sin.pkl
# trains indefinitely; Ctrl+C (or kill) any time, rerun the same command to resume.
```

## Playground

```bash
python playground.py
```

A small terminal REPL over the whole stack — no new dependencies. Build a
register, apply gates, inspect entanglement/noise live, build and train a
QKAN, all interactively:

```
(qkan) qubits 2
(qkan) h 0
(qkan) cnot 0 1
(qkan) probs
|00>  ███████████████                 0.5000
|01>                                  0.0000
|10>                                  0.0000
|11>  ███████████████                 0.5000
(qkan) entropy 0
1.0000 bits
(qkan) noise depolarizing 0.1
(qkan) events on
(qkan) qkan build 1,4,1 2 2
(qkan) qkan train 100
```

Type `help` inside for the full command list.

## Testing

Each layer owns its own `tests/` directory (plus a root `tests/` for
`playground.py`):

```bash
pytest -q
```

## Why split it this way

The boundary between layers 2 and 3 is the one worth explaining: layer 2
(`entanglement`) owns the *only* function that mutates a `QuantumState`'s
amplitudes (`apply_operator`) plus the diagnostics for measuring entanglement
(reduced density matrix, purity, von Neumann entropy). Layer 3 (`gates`) owns
gate *names* and a circuit-building DSL, but always calls back down into
`apply_operator` to actually run anything — it never touches state directly.
That split means "how do qubits interact" and "what gates exist" are
independently testable and independently replaceable, and it's what lets
layer 5 reach directly into layer 2 to ask "is this trained QKAN edge
actually using entanglement, or just behaving like a classical function in a
quantum costume?" (see `analysis/quantum_diagnostics.py`).

Two more boundaries worth naming: `noise` wraps a `gates.circuit.QuantumCircuit`
from the outside rather than gates gaining a `noisy=True` flag, so the
noise-free path (which `qkan` training depends on for exact parameter-shift
gradients) never has to think about noise at all. And `observability` isn't
numbered — it's not "above" or "below" anything, every layer can optionally
emit to it, and it costs nothing when nobody's listening.
