Metadata-Version: 2.4
Name: qitesse
Version: 0.2.0
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Development Status :: 3 - Alpha
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Dist: sphinx>=8.2 ; extra == 'docs'
Provides-Extra: docs
License-File: LICENSE
Summary: High-throughput CPU backend for repeated evaluation of parameterized quantum circuits
Author-email: Osama Elmahdy <you@example.com>
License: MIT
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# qitesse
[![PyPI Version](https://img.shields.io/pypi/v/qitesse.svg)](https://pypi.org/project/qitesse/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/OsamaMIT/qitesse/blob/main/LICENSE)
[![Python Versions](https://img.shields.io/pypi/pyversions/qitesse.svg)](https://pypi.org/project/qitesse/)

**qitesse** is a high-throughput CPU backend for repeated evaluation of parameterized quantum circuits.

qitesse is built upon qitesse-sim, the **high-performance CPU-based state-vector execution engine** for quantum circuits, fully built in Rust.

This PyPI module provides a Python interface designed for hybrid quantum algorithms, repeated circuit evaluation, backend integration, and low-overhead CPU execution from Python.

## Features

- Rust-based CPU statevector simulator with a Python API
- One-off circuit execution through `Gate` and `Circuit`
- Compiled parameterized circuits through `CircuitSpec`, `Parameter`, and `CompiledCircuit`
- Reusable zero-copy parameter buffers through `ParamBuffer` and `ParamBatchBuffer`
- Expectation-value workflows for Pauli observables and Hamiltonians
- Batch expectation execution for parameter sweeps and optimizer loops
- Gradient APIs for compiled circuits via parameter-shift evaluation
- Reusable `ExecutionContext` buffers for repeated scalar execution
- Full statevector output for both one-off and compiled execution paths
- Mid-circuit `measure`, `reset`, and `barrier` operations
- Custom unitary operations with `Gate.unitary(...)`
- Controlled custom unitaries with `Gate.controlled_unitary(...)`
- Common single-, two-, and multi-qubit gates
- Read the Docs documentation with autogenerated API reference pages

## Installation

qitesse requires **Python 3.8+**. Install it via pip:

```bash
pip install qitesse
```

Or install from source:

```bash
git clone https://github.com/OsamaMIT/qitesse.git

pip install maturin

maturin develop --release
```
To run examples:

`python examples/h_example.py`

`python examples/qft._example.py`

`python examples/custom_unitary.py`

## Documentation

The documentation is now set up for Read the Docs with automatic API generation.

- Entry point: [docs/index.rst](docs/index.rst)
- Current features: [docs/current_features.rst](docs/current_features.rst)
- Compiled execution guide: [docs/guides/compiled_execution.rst](docs/guides/compiled_execution.rst)
- Generated API reference root: [docs/api/index.rst](docs/api/index.rst)
- Read the Docs config: [.readthedocs.yaml](.readthedocs.yaml)

To add a new public class to the API docs, add it once in [docs/api/index.rst](docs/api/index.rst). Sphinx will generate the class page and include its methods and attributes automatically.

## Current Capabilities

qitesse currently has two main usage modes:

1. General-purpose simulation with `Gate` and `Circuit` for one-off execution.
2. Compiled execution with `CircuitSpec` and `CompiledCircuit` for repeated parameterized workloads.

The compiled path currently supports:

- reusable zero-copy parameter buffers
- scalar expectation evaluation
- batched expectation evaluation
- scalar gradients
- batched gradients
- reusable execution contexts
- statevector inspection when needed

The simulator path currently supports:

- standard single-qubit gates
- controlled and multi-qubit gates
- custom unitaries
- measurement, reset, and barrier operations

## Compiled Circuits

```python
import numpy as np
import qitesse

spec = qitesse.CircuitSpec(2)
theta = spec.param("theta")

spec.ry(0, theta)
spec.cx(0, 1)

compiled = spec.compile()
observable = qitesse.Observable.pauli_z(1)

value = compiled.expectation(np.array([0.4], dtype=np.float32), observable)
gradient = compiled.gradient(np.array([0.4], dtype=np.float32), observable)
value_again, grad_again = compiled.value_and_gradient(
    np.array([0.4], dtype=np.float32),
    observable,
)
state = compiled.statevector(np.array([0.4], dtype=np.float32))

params_batch = np.array([[0.1], [0.2], [0.3]], dtype=np.float32)
values = compiled.batch_expectation(params_batch, observable)
grads = compiled.batch_gradient(params_batch, observable)

context = compiled.execution_context()
value_again = context.expectation(compiled, np.array([0.5], dtype=np.float32), observable)
grad_again = context.gradient(compiled, np.array([0.5], dtype=np.float32), observable)
```

This execution path is intended for repeated evaluation of the same circuit structure with different parameter values.

## Backend Integration

The compiled execution path is the primary integration surface for higher-level libraries.

The intended backend pattern is:

1. Translate a framework circuit into `CircuitSpec`
2. Compile once per circuit structure
3. Keep parameters in contiguous `numpy.float32` arrays
4. Call `expectation`, `batch_expectation`, `gradient`, or `value_and_gradient`

For sequential scalar calls, reuse `compiled.execution_context()` to keep internal buffers alive.

For sweeps, minibatches, or optimizer batches, prefer `batch_expectation(...)` and `batch_gradient(...)` instead of looping in Python.

## Supported Gates

Single-qubit gates:

- `i`
- `x`
- `y`
- `z`
- `h`
- `s`
- `sdg`
- `t`
- `tdg`
- `rx`
- `ry`
- `rz`
- `p` / `phase`
- `u`

Two-qubit gates:

- `cnot` / `cx`
- `cy`
- `cz`
- `ch`
- `swap`
- `iswap`
- `crx`
- `cry`
- `crz`
- `cp` / `cphase`
- `cu`

Three-qubit and larger:

- `ccx` / `toffoli`
- `cswap` / `fredkin`
- `mcx`
- `mcz`
- `mcp` / `mcphase`
- `controlled_unitary`

Circuit operations:

- `measure`
- `reset`
- `barrier`

Custom unitaries:

```python
import numpy as np
import qitesse

hadamard = np.array([[1, 1], [1, -1]], dtype=np.complex64) / np.sqrt(2)

circuit = qitesse.Circuit([
    qitesse.Gate.unitary([0], hadamard),
    qitesse.Gate.controlled_unitary([0], [1], hadamard),
])

state = circuit.run(2)
```

Use `run_with_measurements(num_qubits)` if the circuit contains measurement gates and you want the observed bit values back.

## Planned Features
- Additional simulation backends

## Contributing
Contributions are welcome! To contribute:

1. Fork the repository
2. Create a new branch (feature-branch)
3. Commit your changes and open a pull request

## License
This project is licensed under the MIT License. See the LICENSE file for details.

