Metadata-Version: 2.4
Name: lightrider
Version: 0.3.0
Summary: Quantum circuit simulation (statevector + stabilizer) with IQM cloud submission, quantum random numbers from IQM bit pools, and QRNG synthetic data with provable provenance.
Author: Light Rider
License: Apache-2.0
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.21
Provides-Extra: live
Requires-Dist: lr-entropy>=0.1.0; extra == "live"
Provides-Extra: pandas
Requires-Dist: pandas>=1.5; extra == "pandas"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pandas>=1.5; extra == "dev"

# lightrider — quantum circuits, quantum random numbers & QRNG synthetic data

`lightrider` ships three layers:

1. **A circuit simulator & cloud runner** — build arbitrary circuits with a
   qiskit-style `Circuit` API and run them on one of three backends: a
   speed-focused dense **statevector** simulator, a Stim-style **stabilizer**
   (Clifford) simulator, or **IQM hardware** in the cloud via the Light Rider
   proxy. Every backend declares the gate set it supports.
2. **A QRNG primitive** — `IQM_sirius(...)` draws quantum random numbers from a
   bundled IQM bit pool (Hadamard coin-flip circuits across 10 qubits,
   SHA-256 debiased). Fully offline.
3. **A synthetic-data engine** — `Synthesizer` fits a Gaussian copula to your
   tabular data and generates new rows whose **every random draw comes from a
   quantum source**, shipping each dataset with a **signed provenance
   manifest**.

No torch. No network required (simulators and the QRNG pool are local).
Upgrade to IQM hardware or live, signed, multi-source entropy by pointing it
at a Light Rider endpoint.

## Install

```bash
pip install lightrider                 # numpy only
pip install "lightrider[live]"         # + lr-entropy SDK (live EMS entropy)
pip install "lightrider[pandas]"       # + DataFrame in/out
```

## Quantum circuit simulation & cloud jobs

```python
from lightrider import Circuit, get_backend

circ = Circuit(2)
circ.h(0)
circ.cx(0, 1)
circ.measure_all()

# local, exact, fast — shots are sampled in one vectorized pass
job = get_backend("statevector").run(circ, shots=100_000, seed=42)
print(job.result().counts)             # {'00': 50121, '11': 49879}

# local, Stim-style stabilizer tableau — Clifford circuits at 100s of qubits,
# mid-circuit measurement supported
job = get_backend("stabilizer").run(circ, shots=1000)

# cloud — IQM QPU through the Light Rider proxy (lr_ API key, never IQM tokens)
iqm = get_backend("iqm", endpoint="https://quantum.lightrider.example",
                  api_key="lr_...")
job = iqm.run(circ, shots=1000)        # returns immediately
print(job.status())                    # WAITING / PROCESSING / COMPLETED
print(job.result().counts)             # polls until terminal
```

### The three backends

| Backend | Where | Gate set | Best for |
|---------|-------|----------|----------|
| `lightrider_statevector` (alias `statevector`) | local | full set (`h x y z s sdg t tdg sx rx ry rz p r u cx cy cz ch swap cp rxx ryy rzz ccx cswap`) | exact simulation ≤ 24 qubits; huge shot counts are ~free |
| `lightrider_stabilizer` (aliases `stabilizer`, `stim`) | local | Clifford subset (`x y z h s sdg sx cx cy cz swap`) | Clifford circuits to hundreds of qubits, mid-circuit measurement |
| `iqm` (alias `cloud`) | cloud | full set, transpiled server-side to IQM's native `r` (prx) + `cz` | real-hardware runs via the Light Rider IQM proxy |

`list_backends()` reports each backend's gate set programmatically, and
`run()` rejects a circuit up front if it uses unsupported gates
(`UnsupportedGateError`) — a job that submits will also execute.

Custom composite gates expand to primitives at append time:

```python
from lightrider import custom_gate

@custom_gate(num_qubits=2)
def bell_pair(c, qubits, params):
    a, b = qubits
    c.h(a)
    c.cx(a, b)

circ = Circuit(3)
circ.append(bell_pair, [0, 1])
```

Circuits serialize to the `lr-circuit/v1` JSON payload (`circ.to_payload()`)
shared with the Light Rider proxy and `lr-entropy` SDK, and to a Stim-flavored
text format (`circ.to_text()` / `Circuit.from_text(...)`).

## Quantum random numbers

```python
from lightrider import IQM_sirius

IQM_sirius(5, 1, 100)            # → [42, 7, 88, 13, 56]
IQM_sirius(3, 0.0, 1.0, step=0.1)  # → [0.3, 0.8, 0.1]
```

Numbers are produced by **rejection sampling** over the debiased quantum bit
pool, so output is unbiased on any range.

## QRNG synthetic data

```python
from lightrider import Synthesizer

synth = Synthesizer(dataset_id="customers_v3").fit(df)   # df: DataFrame / dict / records
rows  = synth.generate(10_000)                           # QRNG-driven synthetic rows

synth.manifest.write("customers_v3.provenance.json")     # the certificate
print(synth.certificate())
```

### How it works — the provable pipeline

```
fit:   data ─▶ marginals (empirical CDF / category freqs)
             ─▶ normal scores  z = Φ⁻¹(rank)
             ─▶ correlation Σ = corr(z),  Cholesky  Σ = L Lᵀ

gen:   QRNG ─▶ U(0,1)          (quantum draws, recorded on the manifest)
             ─▶ Z₀ = Φ⁻¹(U)    (iid standard normals)
             ─▶ Z  = Z₀ Lᵀ     (impose learned correlation)
             ─▶ U' = Φ(Z)      (back to uniform, per column)
             ─▶ x  = F⁻¹(U')   (inverse marginal → synthetic value)
```

The copula reproduces each column's marginal distribution **and** the
correlations between columns; the randomness that selects each synthetic row is
quantum, not a PRNG. See `docs/qrng-synthetic-data.tex` (rendered:
`docs/qrng-synthetic-data.pdf`) for the full mathematical treatment.

### Entropy modes

| Mode | Provider | Provenance |
|------|----------|------------|
| **bundled-qrng** (default) | `BundledQrng` over the packaged IQM pool | real quantum bits, SHA-256 debiased, offline, *unsigned* |
| **live-attested** | `EntropySource` against a Light Rider EMS | multi-source extraction over GF(2¹²⁸), 800-90B health-tested, **post-quantum-signed receipts** |

```python
from lightrider import EntropySource, Synthesizer

src   = EntropySource("http://localhost:7081", dataset_id="customers_v3")
synth = Synthesizer(entropy=src).fit(df)
rows  = synth.generate(10_000)     # every draw carries a signed receipt
```

`EntropySource(allow_failover=True)` (the default) falls back to the OS CSPRNG
on any EMS error so a long job never blocks. Failover draws are flagged in the
manifest and excluded from the certificate's source list — the certificate
never overstates its provenance.

## Provenance is the product

Each dataset gets a sidecar manifest binding it to the entropy that produced it:

```json
{
  "dataset_id": "customers_v3", "model": "qrng-copula",
  "rows": 10000, "columns": ["age", "income", "tier", "region"],
  "entropy_mode": "live-attested", "fully_attested": true,
  "signature_alg": "ML-DSA-65", "post_quantum_signed": true,
  "sources_used": ["curby_q_jila_001", "qispace_kds_001"],
  "min_quality_score": 90, "health_all_pass": true,
  "extractors": ["SHAKE256"], "failover_used": false
}
```

For the offline default the same manifest reports `entropy_mode: "bundled-qrng"`,
`post_quantum_signed: false`, and the bundled IQM source — honest by construction.

## Demo / tests

```bash
python -m lightrider.demo --rows 2000 --out synthetic.csv --manifest cert.json
python -m lightrider.demo --endpoint http://localhost:7081 --rows 2000   # live

pytest tests -q
```

## Data source

The bundled pool is ~2 million bits collected from IQM Hadamard coin-flip
circuits across 10 qubits (capture metadata in
`iqm_capture_20260507_181448/metadata.json`). Live entropy is sourced from the
Light Rider EMS multi-source pipeline.
