Metadata-Version: 2.4
Name: qart-qiskit-provider
Version: 2.0.0
Summary: Quantum Art Qiskit Provider for the QaaS platform
Author: Quantum Art Ltd.
Author-email: Quantum Art Ltd. <info@quantum-art.tech>
License-Expression: LicenseRef-Quantum-Art-Proprietary
License-File: LICENSE
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: qiskit>=2.2.3
Requires-Dist: httpx>=0.28.0
Requires-Python: >=3.12
Project-URL: Homepage, https://quantum-art.tech
Description-Content-Type: text/markdown

# Quantum Art Qiskit Provider

A custom Qiskit provider for interfacing with Quantum Art's QaaS (Quantum as a Service) platform.
Execute quantum circuits on our backends with built-in transpilation and simulation.

## Prerequisites

- Python >= 3.12
- Qiskit
- Valid Quantum Art API token

## Installation

```bash
pip install qart-qiskit-provider
```

## Quick Start

Set your API token once as an environment variable. This is the recommended way
to keep credentials out of your code:

```bash
export QART_API_KEY=your-token
```

```python
from qiskit import QuantumCircuit
from qart.qiskit_provider.qart_provider import QartProvider

provider = QartProvider()
backend = provider.get_backend("Montage-E")

# Create a Bell state circuit.
circuit = QuantumCircuit(2, 2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure([0, 1], [0, 1])

# Execute the circuit and collect results.
job = backend.run(circuit, shots=100)
result = job.result()
print(result.get_counts())
```

By default, the SDK connects to the Quantum Art production service.

If you need to choose a token dynamically, you can still pass it explicitly:

```python
provider = QartProvider(access_token="your-token")
```

## Available Backends

Backends are discovered dynamically from the QaaS server. Use `provider.backends()` to list backend objects.

```python
print([b.name for b in provider.backends()])  # ['Montage-E', ...]
backend = provider.get_backend("Montage-E")
```

## Usage Examples

### Job Lifecycle

```python
from qiskit import QuantumCircuit
from qart.qiskit_provider.qart_provider import QartProvider

provider = QartProvider()
backend = provider.get_backend("Montage-E")

# Build a GHZ circuit.
qc = QuantumCircuit(4, 4)
qc.h(0)
for i in range(3):
    qc.cx(i, i + 1)
qc.measure(range(4), range(4))

# Submit and track.
job = backend.run(qc, shots=100)
print(f"Job ID: {job.job_id()}")
print(f"Status: {job.status()}")

# Wait for result.
result = job.result()
print(f"Counts: {result.get_counts()}")
```

### Cancel a Job

```python
job = backend.run(circuit, shots=100)
job.cancel()
print(job.status())  # CANCELLED
```

### Job Management by ID

```python
job_id = job.job_id()

# Check status directly on the backend.
status = backend.status(job_id)

# Retrieve result with timeout.
result = backend.result(job_id, query_timeout=120)

# Cancel by ID.
backend.cancel(job_id)
```

## Configuration Options

| Parameter                | Type  | Default | Description                              |
|--------------------------|-------|---------|------------------------------------------|
| `shots`                  | int   | 100     | Number of circuit executions (>= 1)      |
| `query_timeout`          | int   | None    | Timeout for result polling (seconds)     |
| `parameters`             | dict  | `{}`    | Free-form server-side job parameters     |
| `metadata`               | dict  | `{}`    | Free-form string job metadata            |

`memory`, `parameters`, `metadata`, and SDK identity metadata are included
internally in the provider HTTP payload for server-side schema alignment. The SDK
also sends `User-Agent`, `X-QART-Client`, `X-QART-Client-Version`, and
`X-QART-API-Version` headers on every API request. For now, the API version is
derived from the SDK package major version.

Use `parameters` for backend-specific or experimental server options. The SDK
only checks that `parameters` is a JSON-serializable dictionary; the server is
responsible for validating supported keys and values.

Use `metadata` for job annotations that should not affect execution. Metadata must
be a dictionary of string keys and string values. The server may give special
meaning to well-known keys such as `label`.

```python
job = backend.run(
    circuit,
    shots=100,
    parameters={
        "ideal_simulation": True,
        "compile": True,
    },
    metadata={"label": "calibration-run", "project": "qv"},
)
```

## API Reference

### QartProvider

```python
QartProvider(access_token=None)
```

Recommended authentication: set the `QART_API_KEY` environment variable and use
`QartProvider()`. For dynamic-token use cases, pass `access_token` explicitly.
An explicit `access_token` takes precedence over `QART_API_KEY`.

- `backends(name=None, filters=None, **kwargs)` -- list available backend objects
- `get_backend(name)` -- get a backend instance (name is required)

### QartBackend

- `run(circuit, **options)` -- submit a circuit, returns `QartJob`
- `status(job_id)` -- get job status by ID
- `result(job_id, query_timeout=None)` -- get result by ID (waits for completion)
- `cancel(job_id)` -- cancel a job by ID

### QartJob

- `job_id()` -- unique job identifier
- `status()` -- current status (QUEUED, RUNNING, DONE, ERROR, CANCELLED)
- `result(timeout=None)` -- wait for completion and return a Qiskit `Result`
- `cancel()` -- cancel the job

## Running Tests

```bash
# Unit tests only (no server required).
pytest test/unit -v

# All tests including E2E (requires running QaaS server).
export QART_API_KEY=your-token
export QART_BASE_URL=https://qaas.quantum-art.tech
export QART_BACKEND_NAME=gpu_sim
pytest test/ -v
```

E2E tests in `test/test_api.py` are automatically skipped when
`QART_API_KEY` is not set. `QART_BASE_URL` and `QART_BACKEND_NAME` are optional;
they default to `http://localhost:8080` and `gpu_sim`.

## Release Process

- Version is defined in `pyproject.toml` under `[project].version`.
- Follow semantic versioning:
  - Patch (`x.y.Z`) for bug fixes.
  - Minor (`x.Y.0`) for backward-compatible features.
  - Major (`X.0.0`) for breaking changes.
- Publish only artifacts produced by CI pipelines (not local machine builds).
- Update `CHANGELOG.md` for every customer-facing release.

## Troubleshooting

**Authentication Error** -- Verify your API token.

**Circuit Too Large** -- Reduce to the backend's qubit limit (check `backend.target.num_qubits`).

**Timeout** -- Increase `query_timeout` or check job status with `backend.status(job_id)`.

## Logging

By default, this SDK does not emit logs unless your application configures Python logging.

For local troubleshooting, you can enable SDK console logs explicitly:

```python
import logging
from qart.qiskit_provider import configure_diagnostic_logging

configure_diagnostic_logging(logging.DEBUG)
```
