Metadata-Version: 2.4
Name: Qiberis
Version: 0.1.0
Summary: A backend-agnostic quantum circuit API: write once, run on Qiskit, Cirq, and PennyLane simulators.
Author: Rex
License: MIT
Keywords: quantum computing,qiskit,cirq,pennylane
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: qiskit
Requires-Dist: qiskit>=2.0; extra == "qiskit"
Requires-Dist: qiskit-aer>=0.17; extra == "qiskit"
Provides-Extra: cirq
Requires-Dist: cirq>=1.3; extra == "cirq"
Provides-Extra: pennylane
Requires-Dist: pennylane>=0.35; extra == "pennylane"
Requires-Dist: pennylane-lightning>=0.35; extra == "pennylane"
Provides-Extra: all
Requires-Dist: Qiberis[cirq,pennylane,qiskit]; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Dynamic: license-file

# Qiberis

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Qiskit Ecosystem](https://img.shields.io/badge/Qiskit-Ecosystem-blueviolet)](https://www.ibm.com/quantum/ecosystem)

A small, backend-agnostic quantum circuit API. Write a circuit once against
a minimal intermediate representation (IR), and run it unmodified on
**Qiskit Aer**, **Cirq**, or **PennyLane (lightning.qubit)** — with results
returned in one normalized format.

```python
from qiberis import Circuit
from qiberis.backends.qiskit_backend import QiskitAerBackend
from qiberis.backends.cirq_backend import CirqSimulatorBackend
from qiberis.backends.pennylane_backend import PennyLaneLightningBackend

# Build a 3-qubit GHZ state, once.
circuit = Circuit(3)
circuit.h(0).cx(0, 1).cx(1, 2).measure_all()

for backend_cls in (QiskitAerBackend, CirqSimulatorBackend, PennyLaneLightningBackend):
    backend = backend_cls()
    result = backend.run(circuit, shots=1000)
    print(result)
```

## Why

Qiskit, Cirq, and PennyLane each have their own circuit objects, gate names,
execution APIs, and — critically — their own bit-ordering conventions for
returned counts. Comparing results across them, or writing code that should
work regardless of which simulator is installed, means re-solving the same
translation problem every time. `Qiberis` solves it once.

## Install

```bash
pip install -e ".[all]"       # all three backends
pip install -e ".[qiskit]"    # just Qiskit Aer
pip install -e ".[cirq]"      # just Cirq
pip install -e ".[pennylane]" # just PennyLane
```

Each backend is an optional dependency — the core package
(`qiberis.Circuit`, `qiberis.Result`) has zero hard dependencies, and each
adapter raises a clear `ImportError` telling you what to install if you try
to use a backend you haven't installed.

## Architecture

```
qiberis/
  circuit.py          # Circuit + Instruction: the backend-agnostic IR
  result.py           # Result: normalized counts/probabilities
  backends/
    base.py           # Backend ABC — one method: run(circuit, shots) -> Result
    qiskit_backend.py
    cirq_backend.py
    pennylane_backend.py
tests/
  test_cross_backend.py  # runs the same circuits on every installed backend
                          # and checks they agree with each other
```

Supported gates: `h, x, y, z, s, t, rx, ry, rz, cx, cz, swap, ccx, barrier,
measure`. Extending to a new gate means adding one line to each adapter's
translation table.

## Bit-ordering convention

This is the part that silently breaks most "universal circuit" projects.
Qiskit's native count strings are **little-endian** (clbit 0 is the
*rightmost* character); Cirq and PennyLane's `qml.counts(wires=...)` are
naturally ordered with the first wire/clbit **leftmost**.

**Qiberis's convention:** in every `Result.counts` key, the leftmost
character is always clbit/qubit 0. The Qiskit adapter reverses its native
strings to match; Cirq and PennyLane need no adjustment. This is covered by
a dedicated regression test, `test_bit_ordering`, which runs an asymmetric
circuit (X on qubit 0 only) through every backend and checks all three
report the same string.

## Adding a new backend

1. Create `qiberis/backends/your_backend.py`
2. Subclass `Backend`, implement `run(self, circuit, shots) -> Result`
3. Translate `Circuit.instructions` into your library's native circuit object
4. Normalize your library's raw output into Qiberis's bit-ordering convention
5. Add your backend to the `BACKENDS` list in `tests/test_cross_backend.py`
   — the existing GHZ, bit-ordering, and cross-agreement tests will
   immediately validate it against the others

## Roadmap

- [ ] Real hardware backends (IBM Quantum, AWS Braket QPUs) behind the same interface
- [ ] A transpiler/optimization pass operating directly on the IR
- [ ] Parametric circuits / variational workflows (bind params without rebuilding)
- [ ] Statevector + expectation-value result modes, not just counts
- [ ] More gates: `u`, `crx/cry/crz`, `iswap`, multi-controlled gates

## License

MIT
