justinwoodring / laravel-qiskit
Laravel PHP package for IBM Quantum / Qiskit Runtime
Fund package maintenance!
Requires
- php: ^8.2
- illuminate/cache: ^10.0|^11.0|^12.0|^13.0
- illuminate/console: ^10.0|^11.0|^12.0|^13.0
- illuminate/database: ^10.0|^11.0|^12.0|^13.0
- illuminate/events: ^10.0|^11.0|^12.0|^13.0
- illuminate/http: ^10.0|^11.0|^12.0|^13.0
- illuminate/queue: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- guzzlehttp/guzzle: ^7.0
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
This package is auto-updated.
Last update: 2026-04-25 03:38:31 UTC
README
Quantum computing for Laravel — submit circuits, poll results, and handle IBM Quantum jobs just like you'd handle anything else in your app.
Overview
laravel-qiskit is a first-class Laravel package for IBM Quantum / Qiskit Runtime. It brings quantum job submission into the Laravel ecosystem you already know — Eloquent models, queued jobs, events, Artisan commands, and a fluent facade — so you can focus on your circuits instead of the API plumbing.
Features
- Fluent circuit builder — chainable gate API with OPENQASM 3.0 serialization
- Sampler & Estimator primitives — mirrors the Qiskit Runtime primitive interface
- Async job dispatch — jobs go through Laravel's queue; polling happens automatically via a background job chain
- Event-driven results — listen for
QuantumJobCompletedand get counts or expectation values - Session management — open, close, or
run()a session with auto-close - Backend discovery — filter backends by qubit count, queue depth, and availability
- Eloquent model —
QuantumJobwith scopes, status constants, and aPrimitiveResultaccessor - Artisan commands —
qiskit:install,qiskit:jobs,qiskit:status,qiskit:cancel,qiskit:backends
Requirements
- PHP 8.2+
- Laravel 10, 11, 12, or 13
- An IBM Quantum account (API key + Service CRN)
Installation
composer require justinwoodring/laravel-qiskit
Publish the config and run migrations:
php artisan qiskit:install
Add your credentials to .env:
QISKIT_API_KEY=your-ibm-quantum-api-key QISKIT_SERVICE_CRN=crn:v1:bluemix:public:quantum-computing:us-east:... QISKIT_DEFAULT_BACKEND=ibm_brisbane
Quick Start
Build a circuit
use JustinWoodring\LaravelQiskit\Circuit\Circuit; // Bell state — maximally entangled 2-qubit state $circuit = Circuit::new(2, 2) ->h(0) ->cx(0, 1) ->measure(); echo $circuit->toQasm();
OPENQASM 3.0;
include "stdgates.inc";
qubit[2] q;
bit[2] c;
h q[0];
cx q[0], q[1];
c[0] = measure q[0];
c[1] = measure q[1];
Submit a Sampler job (async)
use JustinWoodring\LaravelQiskit\Facades\Qiskit; $job = Qiskit::sampler('ibm_brisbane') ->addPub($circuit, shots: 4096) ->dispatch() // → PendingJob ->dispatch(); // → QuantumJob (Eloquent model, enqueues to queue) // $job->id, $job->status, $job->backend ...
Start your queue worker to process the submission and polling:
php artisan queue:work
Listen for results
// app/Providers/EventServiceProvider.php use JustinWoodring\LaravelQiskit\Events\QuantumJobCompleted; protected $listen = [ QuantumJobCompleted::class => [ App\Listeners\HandleQuantumResults::class, ], ];
// app/Listeners/HandleQuantumResults.php public function handle(QuantumJobCompleted $event): void { $counts = $event->result->getCounts(); // ['00' => 2048, '11' => 2048] }
Estimator with observables
use JustinWoodring\LaravelQiskit\Circuit\Circuit; use JustinWoodring\LaravelQiskit\Facades\Qiskit; $ansatz = Circuit::new(2) ->withParameters(['theta']) ->ry('theta', 0) ->cx(0, 1); $job = Qiskit::estimator() ->addPub($ansatz->bind(['theta' => M_PI / 3]), observables: ['ZZ', 'XI']) ->dispatch() ->dispatch();
Sessions
Reserve a backend across multiple jobs to avoid re-queuing between iterations:
Qiskit::sessions()->run('ibm_brisbane', function (string $sessionId) { Qiskit::sampler()->addPub($circuit1)->inSession($sessionId)->dispatch()->dispatch(); Qiskit::sampler()->addPub($circuit2)->inSession($sessionId)->dispatch()->dispatch(); // Session closes automatically when the callback returns });
Backend discovery
// All online real hardware with at least 100 qubits $backends = Qiskit::backends() ->filter() ->online() ->simulator(false) ->withMinQubits(100) ->withMaxQueueDepth(30) ->get();
Artisan Commands
# Publish config + run migrations php artisan qiskit:install # List jobs php artisan qiskit:jobs php artisan qiskit:jobs --status=completed --limit=50 # Check job status php artisan qiskit:status 42 php artisan qiskit:status cj1abc123def --ibm-id # Cancel a job php artisan qiskit:cancel 42 # List backends php artisan qiskit:backends php artisan qiskit:backends --online
Configuration
After running qiskit:install, edit config/qiskit.php:
return [ 'api_key' => env('QISKIT_API_KEY'), 'service_crn' => env('QISKIT_SERVICE_CRN'), 'base_url' => env('QISKIT_BASE_URL', 'https://us-east.quantum-computing.cloud.ibm.com'), 'default_backend' => env('QISKIT_DEFAULT_BACKEND', 'ibm_brisbane'), 'polling' => [ 'interval' => env('QISKIT_POLL_INTERVAL', 10), // seconds 'max_attempts' => env('QISKIT_POLL_MAX_ATTEMPTS', 360), // ~1 hour 'queue' => env('QISKIT_POLL_QUEUE', null), ], 'http' => [ 'timeout' => env('QISKIT_HTTP_TIMEOUT', 30), 'retry' => ['times' => 3, 'sleep' => 1000], ], ];
Events
| Event | Payload |
|---|---|
QuantumJobSubmitted |
$job, $ibmJobId |
QuantumJobCompleted |
$job, $result (PrimitiveResult) |
QuantumJobFailed |
$job, $reason |
QuantumJobCancelled |
$job |
Circuit Gates
| Method | Gate |
|---|---|
h(q) |
Hadamard |
x(q) y(q) z(q) |
Pauli X / Y / Z |
s(q) t(q) |
S / T phase |
rx(θ, q) ry(θ, q) rz(φ, q) |
Rotation gates |
cx(c, t) / cnot(c, t) |
Controlled-X |
cz(c, t) |
Controlled-Z |
swap(a, b) |
SWAP |
ccx(c1, c2, t) / toffoli(...) |
Toffoli |
measure() |
Measure all qubits |
measureQubit(q, c) |
Measure qubit q into classical bit c |
Parameterized circuits:
$circuit = Circuit::new(1) ->withParameters(['theta']) ->ry('theta', 0) ->bind(['theta' => 1.5707]);
Testing
composer install ./vendor/bin/phpunit
Tests use Orchestra Testbench with an in-memory SQLite database and faked HTTP responses — no real IBM Quantum credentials needed.
Demo
A full demo Laravel app lives in demo/. See demo/README.md for setup instructions.
License
MIT — see LICENSE.