@qamposer/react 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -46
- package/dist/{index-BbUFQqpD.d.cts → index-BghK68a6.d.cts} +1 -1
- package/dist/{index-BbUFQqpD.d.ts → index-BghK68a6.d.ts} +1 -1
- package/dist/index.cjs +81 -33
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +81 -33
- package/dist/visualization.cjs +81 -33
- package/dist/visualization.d.cts +1 -1
- package/dist/visualization.d.ts +1 -1
- package/dist/visualization.js +81 -33
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -6,14 +6,15 @@ Qamposer is a modular, open-source quantum composer that can be embedded into yo
|
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
9
|
-
> **Coming Soon** - npm package publication is in progress.
|
|
10
|
-
|
|
11
9
|
```bash
|
|
12
|
-
# Not yet available
|
|
13
10
|
npm install @qamposer/react
|
|
14
11
|
```
|
|
15
12
|
|
|
16
|
-
For
|
|
13
|
+
For the full version with visualization (Q-sphere, histograms), also install Plotly:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install plotly.js-basic-dist-min react-plotly.js
|
|
17
|
+
```
|
|
17
18
|
|
|
18
19
|
## Examples
|
|
19
20
|
|
|
@@ -38,32 +39,27 @@ Quantum mechanics and simulation results can be directly leveraged as game logic
|
|
|
38
39
|
### Basic Usage (QamposerMicro)
|
|
39
40
|
|
|
40
41
|
```tsx
|
|
41
|
-
import { QamposerMicro
|
|
42
|
-
import "@qamposer/react/styles.css";
|
|
42
|
+
import { QamposerMicro } from '@qamposer/react';
|
|
43
43
|
|
|
44
44
|
function App() {
|
|
45
|
-
return
|
|
46
|
-
<QamposerMicro
|
|
47
|
-
adapter={qiskitAdapter("http://localhost:8000")}
|
|
48
|
-
onSimulationComplete={(event) => {
|
|
49
|
-
console.log("Result:", event.result);
|
|
50
|
-
console.log("QASM:", event.qasm);
|
|
51
|
-
}}
|
|
52
|
-
/>
|
|
53
|
-
);
|
|
45
|
+
return <QamposerMicro />;
|
|
54
46
|
}
|
|
55
47
|
```
|
|
56
48
|
|
|
49
|
+
> **Note**: By default, QamposerMicro runs in editor-only mode (no simulation). To enable simulation, see [With Backend](#with-backend-simulation) below.
|
|
50
|
+
|
|
57
51
|
### Full Version with Visualization (Qamposer)
|
|
58
52
|
|
|
53
|
+
The full version includes visualization components (histograms, Q-sphere) that require simulation results, so a backend adapter is needed:
|
|
54
|
+
|
|
59
55
|
```tsx
|
|
60
|
-
import { Qamposer } from
|
|
61
|
-
import
|
|
56
|
+
import { Qamposer } from '@qamposer/react/visualization';
|
|
57
|
+
import { qiskitAdapter } from '@qamposer/react';
|
|
62
58
|
|
|
63
59
|
function App() {
|
|
64
60
|
return (
|
|
65
61
|
<Qamposer
|
|
66
|
-
adapter={qiskitAdapter(
|
|
62
|
+
adapter={qiskitAdapter('http://localhost:8080')}
|
|
67
63
|
defaultTheme="dark"
|
|
68
64
|
showThemeToggle
|
|
69
65
|
/>
|
|
@@ -101,11 +97,24 @@ This library provides two preset components to fit different use cases:
|
|
|
101
97
|
|
|
102
98
|
## Backend Requirements
|
|
103
99
|
|
|
104
|
-
|
|
100
|
+
The React components work standalone for circuit editing. To run quantum simulations, you need the `qamposer-backend` server.
|
|
101
|
+
|
|
102
|
+
### Editor-Only Mode
|
|
103
|
+
|
|
104
|
+
By default, components run in editor-only mode without requiring a backend:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
import { QamposerMicro } from '@qamposer/react';
|
|
108
|
+
|
|
109
|
+
// No backend required - editor-only mode (default)
|
|
110
|
+
<QamposerMicro />;
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### With Backend (Simulation)
|
|
105
114
|
|
|
106
|
-
|
|
115
|
+
To enable quantum simulation, start the backend and pass the `qiskitAdapter`:
|
|
107
116
|
|
|
108
|
-
|
|
117
|
+
Assuming localhost is used here, but please specify the actual deployment destination for the backend.
|
|
109
118
|
|
|
110
119
|
```bash
|
|
111
120
|
# Clone and setup qamposer-backend
|
|
@@ -114,17 +123,16 @@ poetry install
|
|
|
114
123
|
poetry run uvicorn backend.main:app --host 0.0.0.0 --port 8080 --reload
|
|
115
124
|
```
|
|
116
125
|
|
|
117
|
-
The backend will start at `http://localhost:8000` by default.
|
|
118
|
-
|
|
119
|
-
### Editor-Only Mode (No Backend)
|
|
120
|
-
|
|
121
|
-
If you only need the circuit editor without simulation capabilities, use the `noopAdapter`:
|
|
122
|
-
|
|
123
126
|
```tsx
|
|
124
|
-
import { QamposerMicro,
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
import { QamposerMicro, qiskitAdapter } from '@qamposer/react';
|
|
128
|
+
|
|
129
|
+
<QamposerMicro
|
|
130
|
+
adapter={qiskitAdapter('http://localhost:8080')}
|
|
131
|
+
onSimulationComplete={(event) => {
|
|
132
|
+
console.log('Result:', event.result);
|
|
133
|
+
console.log('QASM:', event.qasm);
|
|
134
|
+
}}
|
|
135
|
+
/>;
|
|
128
136
|
```
|
|
129
137
|
|
|
130
138
|
## API Reference
|
|
@@ -139,7 +147,7 @@ interface QamposerProps {
|
|
|
139
147
|
onCircuitChange?: (circuit: Circuit) => void;
|
|
140
148
|
|
|
141
149
|
// Simulation
|
|
142
|
-
adapter?: SimulationAdapter; // Backend adapter
|
|
150
|
+
adapter?: SimulationAdapter; // Backend adapter (default: noopAdapter)
|
|
143
151
|
onSimulationComplete?: (event: SimulationCompleteEvent) => void;
|
|
144
152
|
|
|
145
153
|
// Configuration
|
|
@@ -149,7 +157,7 @@ interface QamposerProps {
|
|
|
149
157
|
className?: string;
|
|
150
158
|
showHeader?: boolean; // Default: true
|
|
151
159
|
title?: string; // Default: 'Qamposer'
|
|
152
|
-
defaultTheme?:
|
|
160
|
+
defaultTheme?: 'light' | 'dark'; // Default: 'dark'
|
|
153
161
|
showThemeToggle?: boolean; // Default: true
|
|
154
162
|
|
|
155
163
|
// Layout (Qamposer only)
|
|
@@ -169,31 +177,31 @@ interface QamposerConfig {
|
|
|
169
177
|
}
|
|
170
178
|
```
|
|
171
179
|
|
|
172
|
-
### Adapters
|
|
180
|
+
<!-- ### Adapters
|
|
173
181
|
|
|
174
182
|
```tsx
|
|
175
183
|
// Qiskit Backend Adapter
|
|
176
|
-
import { qiskitAdapter } from
|
|
184
|
+
import { qiskitAdapter } from '@qamposer/react';
|
|
177
185
|
|
|
178
|
-
const adapter = qiskitAdapter(
|
|
186
|
+
const adapter = qiskitAdapter('http://localhost:8000');
|
|
179
187
|
|
|
180
188
|
// With options
|
|
181
189
|
const adapter = qiskitAdapter({
|
|
182
|
-
baseUrl:
|
|
183
|
-
headers: { Authorization:
|
|
190
|
+
baseUrl: 'http://localhost:8000',
|
|
191
|
+
headers: { Authorization: 'Bearer token' },
|
|
184
192
|
timeout: 30000,
|
|
185
193
|
});
|
|
186
194
|
|
|
187
195
|
// No-op Adapter (editor only, no simulation)
|
|
188
|
-
import { noopAdapter } from
|
|
189
|
-
```
|
|
196
|
+
import { noopAdapter } from '@qamposer/react';
|
|
197
|
+
``` -->
|
|
190
198
|
|
|
191
|
-
### useQamposer Hook
|
|
199
|
+
<!-- ### useQamposer Hook
|
|
192
200
|
|
|
193
201
|
For building custom UIs, use the `useQamposer` hook within a `QamposerProvider`:
|
|
194
202
|
|
|
195
203
|
```tsx
|
|
196
|
-
import { QamposerProvider, useQamposer } from '@qamposer/react';
|
|
204
|
+
import { QamposerProvider, useQamposer, qiskitAdapter } from '@qamposer/react';
|
|
197
205
|
|
|
198
206
|
function CustomEditor() {
|
|
199
207
|
const {
|
|
@@ -212,14 +220,24 @@ function CustomEditor() {
|
|
|
212
220
|
);
|
|
213
221
|
}
|
|
214
222
|
|
|
223
|
+
// Editor-only mode (default)
|
|
215
224
|
function App() {
|
|
216
225
|
return (
|
|
217
|
-
<QamposerProvider
|
|
226
|
+
<QamposerProvider>
|
|
218
227
|
<CustomEditor />
|
|
219
228
|
</QamposerProvider>
|
|
220
229
|
);
|
|
221
230
|
}
|
|
222
|
-
|
|
231
|
+
|
|
232
|
+
// With backend simulation
|
|
233
|
+
function AppWithSimulation() {
|
|
234
|
+
return (
|
|
235
|
+
<QamposerProvider adapter={qiskitAdapter('http://localhost:8080')}>
|
|
236
|
+
<CustomEditor />
|
|
237
|
+
</QamposerProvider>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
``` -->
|
|
223
241
|
|
|
224
242
|
<!-- ### Individual Components -->
|
|
225
243
|
|
|
@@ -240,7 +258,7 @@ import { QSphereView, ResultsPanel } from '@qamposer/react/visualization';
|
|
|
240
258
|
## OpenQASM Utilities
|
|
241
259
|
|
|
242
260
|
```tsx
|
|
243
|
-
import { circuitToQasm, qasmToCircuit } from
|
|
261
|
+
import { circuitToQasm, qasmToCircuit } from '@qamposer/react';
|
|
244
262
|
|
|
245
263
|
// Convert Circuit to OpenQASM
|
|
246
264
|
const qasm = circuitToQasm(circuit);
|
|
@@ -284,7 +302,7 @@ The library uses CSS variables for theming. You can customize colors by overridi
|
|
|
284
302
|
Or use the theme hook:
|
|
285
303
|
|
|
286
304
|
```tsx
|
|
287
|
-
import { useTheme } from
|
|
305
|
+
import { useTheme } from '@qamposer/react';
|
|
288
306
|
|
|
289
307
|
function ThemeToggle() {
|
|
290
308
|
const { theme, toggleTheme } = useTheme();
|
|
@@ -310,6 +328,11 @@ For `Qamposer` (full version) with visualization:
|
|
|
310
328
|
}
|
|
311
329
|
```
|
|
312
330
|
|
|
331
|
+
## Support & Stability
|
|
332
|
+
|
|
333
|
+
- This library is under active development.
|
|
334
|
+
- Please report issues via [GitHub Issues](https://github.com/QAMP-62/qamposer-react/issues).
|
|
335
|
+
|
|
313
336
|
## License
|
|
314
337
|
|
|
315
338
|
Licensed under the Apache 2.0.
|
package/dist/index.cjs
CHANGED
|
@@ -321,6 +321,38 @@ function QamposerProvider({
|
|
|
321
321
|
react.useEffect(() => {
|
|
322
322
|
adapter.isAvailable().then(setCanSimulate);
|
|
323
323
|
}, [adapter]);
|
|
324
|
+
const autoSimRequestId = react.useRef(0);
|
|
325
|
+
react.useEffect(() => {
|
|
326
|
+
if (!canSimulate || circuit.gates.length === 0) {
|
|
327
|
+
if (circuit.gates.length === 0) {
|
|
328
|
+
setResult(null);
|
|
329
|
+
}
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const requestId = ++autoSimRequestId.current;
|
|
333
|
+
setStatus("simulating");
|
|
334
|
+
setError(null);
|
|
335
|
+
const request = {
|
|
336
|
+
qubits: circuit.qubits,
|
|
337
|
+
gates: circuit.gates.map(({ id: _, ...gate }) => gate),
|
|
338
|
+
shots: 1024,
|
|
339
|
+
profile: { type: "ideal" }
|
|
340
|
+
};
|
|
341
|
+
adapter.simulate(request).then((simulationResult) => {
|
|
342
|
+
if (autoSimRequestId.current !== requestId) return;
|
|
343
|
+
setResult(simulationResult);
|
|
344
|
+
setStatus("idle");
|
|
345
|
+
onSimulationComplete?.({
|
|
346
|
+
result: simulationResult,
|
|
347
|
+
circuit: { ...circuit },
|
|
348
|
+
qasm: circuitToQasm(circuit)
|
|
349
|
+
});
|
|
350
|
+
}).catch((err) => {
|
|
351
|
+
if (autoSimRequestId.current !== requestId) return;
|
|
352
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
353
|
+
setStatus("error");
|
|
354
|
+
});
|
|
355
|
+
}, [circuit, canSimulate, adapter, onSimulationComplete]);
|
|
324
356
|
const addGate = react.useCallback(
|
|
325
357
|
(gate) => {
|
|
326
358
|
if (circuit.gates.length >= config.maxGates) {
|
|
@@ -490,6 +522,7 @@ function QamposerProvider({
|
|
|
490
522
|
}, [circuit]);
|
|
491
523
|
const simulate = react.useCallback(
|
|
492
524
|
async (shots = 1024, profile) => {
|
|
525
|
+
autoSimRequestId.current++;
|
|
493
526
|
if (!canSimulate) {
|
|
494
527
|
throw new Error("Simulation adapter is not available");
|
|
495
528
|
}
|
|
@@ -2303,6 +2336,11 @@ var css3 = `.simulation-controls__run-btn {
|
|
|
2303
2336
|
border-color: var(--qamposer-accent, #4285f4);
|
|
2304
2337
|
background: rgba(66, 133, 244, 0.1);
|
|
2305
2338
|
}
|
|
2339
|
+
.simulation-controls__backend-item--disabled {
|
|
2340
|
+
opacity: 0.5;
|
|
2341
|
+
cursor: not-allowed;
|
|
2342
|
+
pointer-events: none;
|
|
2343
|
+
}
|
|
2306
2344
|
.simulation-controls__backend-item-content {
|
|
2307
2345
|
flex: 1;
|
|
2308
2346
|
min-width: 0;
|
|
@@ -2334,6 +2372,10 @@ var css3 = `.simulation-controls__run-btn {
|
|
|
2334
2372
|
background: rgba(237, 137, 54, 0.2);
|
|
2335
2373
|
color: #ed8936;
|
|
2336
2374
|
}
|
|
2375
|
+
.simulation-controls__backend-type--real {
|
|
2376
|
+
background: rgba(160, 174, 192, 0.2);
|
|
2377
|
+
color: #a0aec0;
|
|
2378
|
+
}
|
|
2337
2379
|
.simulation-controls__backend-desc {
|
|
2338
2380
|
margin: 0;
|
|
2339
2381
|
font-size: 0.75rem;
|
|
@@ -2425,7 +2467,7 @@ function SimulationControls({
|
|
|
2425
2467
|
const [isDialogOpen, setIsDialogOpen] = react.useState(false);
|
|
2426
2468
|
const [shots, setShots] = react.useState(1024);
|
|
2427
2469
|
const [backends, setBackends] = react.useState([]);
|
|
2428
|
-
const [selectedBackendId, setSelectedBackendId] = react.useState("
|
|
2470
|
+
const [selectedBackendId, setSelectedBackendId] = react.useState("");
|
|
2429
2471
|
const [isLoadingBackends, setIsLoadingBackends] = react.useState(false);
|
|
2430
2472
|
const [backendError, setBackendError] = react.useState(false);
|
|
2431
2473
|
react.useEffect(() => {
|
|
@@ -2433,8 +2475,13 @@ function SimulationControls({
|
|
|
2433
2475
|
setIsLoadingBackends(true);
|
|
2434
2476
|
setBackendError(false);
|
|
2435
2477
|
adapter.getBackends().then((result) => {
|
|
2436
|
-
|
|
2437
|
-
|
|
2478
|
+
const nonIdealBackends = result.filter((b) => b.backend_type !== "ideal");
|
|
2479
|
+
setBackends(nonIdealBackends);
|
|
2480
|
+
const firstFake = nonIdealBackends.find((b) => b.backend_type === "noisy_fake");
|
|
2481
|
+
if (firstFake) {
|
|
2482
|
+
setSelectedBackendId(firstFake.id);
|
|
2483
|
+
}
|
|
2484
|
+
if (nonIdealBackends.length === 0 && !canSimulate) {
|
|
2438
2485
|
setBackendError(true);
|
|
2439
2486
|
}
|
|
2440
2487
|
}).finally(() => setIsLoadingBackends(false));
|
|
@@ -2442,13 +2489,10 @@ function SimulationControls({
|
|
|
2442
2489
|
}, [isDialogOpen, adapter, canSimulate]);
|
|
2443
2490
|
const selectedBackend = backends.find((b) => b.id === selectedBackendId);
|
|
2444
2491
|
const buildProfile = () => {
|
|
2445
|
-
if (!selectedBackend || selectedBackend.backend_type === "
|
|
2446
|
-
return { type: "
|
|
2492
|
+
if (!selectedBackend || selectedBackend.backend_type === "noisy_fake") {
|
|
2493
|
+
return selectedBackend ? { type: "noisy_fake", backend_name: selectedBackend.id } : void 0;
|
|
2447
2494
|
}
|
|
2448
|
-
return
|
|
2449
|
-
type: "noisy_fake",
|
|
2450
|
-
backend_name: selectedBackend.id
|
|
2451
|
-
};
|
|
2495
|
+
return void 0;
|
|
2452
2496
|
};
|
|
2453
2497
|
const handleRun = async () => {
|
|
2454
2498
|
if (circuit.gates.length === 0) {
|
|
@@ -2535,31 +2579,35 @@ function SimulationControls({
|
|
|
2535
2579
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__error-title", children: "Backend unavailable" }),
|
|
2536
2580
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__error-desc", children: "Cannot connect to the simulation backend. Please check that the server is running and CORS is configured correctly." })
|
|
2537
2581
|
] })
|
|
2538
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) =>
|
|
2539
|
-
"
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
{
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2582
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => {
|
|
2583
|
+
const isReal = backend.backend_type === "real";
|
|
2584
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2585
|
+
"button",
|
|
2586
|
+
{
|
|
2587
|
+
type: "button",
|
|
2588
|
+
className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""} ${isReal ? "simulation-controls__backend-item--disabled" : ""}`,
|
|
2589
|
+
onClick: () => !isReal && setSelectedBackendId(backend.id),
|
|
2590
|
+
disabled: isReal,
|
|
2591
|
+
children: [
|
|
2592
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-content", children: [
|
|
2593
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-header", children: [
|
|
2594
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
|
|
2595
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2596
|
+
"span",
|
|
2597
|
+
{
|
|
2598
|
+
className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
|
|
2599
|
+
children: backend.backend_type === "noisy_fake" ? "Noisy" : "Real"
|
|
2600
|
+
}
|
|
2601
|
+
)
|
|
2602
|
+
] }),
|
|
2603
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__backend-desc", children: isReal ? "Coming soon" : backend.description || `${backend.num_qubits} qubits` })
|
|
2555
2604
|
] }),
|
|
2556
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
2557
|
-
]
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
)) })
|
|
2605
|
+
selectedBackendId === backend.id && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, {}) })
|
|
2606
|
+
]
|
|
2607
|
+
},
|
|
2608
|
+
backend.id
|
|
2609
|
+
);
|
|
2610
|
+
}) })
|
|
2563
2611
|
] })
|
|
2564
2612
|
] }),
|
|
2565
2613
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__dialog-footer", children: [
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { Q as QamposerProviderProps$1, T as Theme, C as Circuit, S as SimulationAdapter, a as SimulationCompleteEvent, b as QamposerConfig, c as QamposerContextValue, d as QasmParseResult } from './index-
|
|
3
|
-
export { h as CircuitRequest, G as Gate, g as GateInfo, f as GateType, j as QSpherePoint, i as SimulationResult, e as ThemeProvider, u as useTheme } from './index-
|
|
2
|
+
import { Q as QamposerProviderProps$1, T as Theme, C as Circuit, S as SimulationAdapter, a as SimulationCompleteEvent, b as QamposerConfig, c as QamposerContextValue, d as QasmParseResult } from './index-BghK68a6.cjs';
|
|
3
|
+
export { h as CircuitRequest, G as Gate, g as GateInfo, f as GateType, j as QSpherePoint, i as SimulationResult, e as ThemeProvider, u as useTheme } from './index-BghK68a6.cjs';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
5
|
|
|
6
6
|
interface QamposerMicroProps extends Omit<QamposerProviderProps$1, 'children'> {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { Q as QamposerProviderProps$1, T as Theme, C as Circuit, S as SimulationAdapter, a as SimulationCompleteEvent, b as QamposerConfig, c as QamposerContextValue, d as QasmParseResult } from './index-
|
|
3
|
-
export { h as CircuitRequest, G as Gate, g as GateInfo, f as GateType, j as QSpherePoint, i as SimulationResult, e as ThemeProvider, u as useTheme } from './index-
|
|
2
|
+
import { Q as QamposerProviderProps$1, T as Theme, C as Circuit, S as SimulationAdapter, a as SimulationCompleteEvent, b as QamposerConfig, c as QamposerContextValue, d as QasmParseResult } from './index-BghK68a6.js';
|
|
3
|
+
export { h as CircuitRequest, G as Gate, g as GateInfo, f as GateType, j as QSpherePoint, i as SimulationResult, e as ThemeProvider, u as useTheme } from './index-BghK68a6.js';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
5
|
|
|
6
6
|
interface QamposerMicroProps extends Omit<QamposerProviderProps$1, 'children'> {
|
package/dist/index.js
CHANGED
|
@@ -319,6 +319,38 @@ function QamposerProvider({
|
|
|
319
319
|
useEffect(() => {
|
|
320
320
|
adapter.isAvailable().then(setCanSimulate);
|
|
321
321
|
}, [adapter]);
|
|
322
|
+
const autoSimRequestId = useRef(0);
|
|
323
|
+
useEffect(() => {
|
|
324
|
+
if (!canSimulate || circuit.gates.length === 0) {
|
|
325
|
+
if (circuit.gates.length === 0) {
|
|
326
|
+
setResult(null);
|
|
327
|
+
}
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const requestId = ++autoSimRequestId.current;
|
|
331
|
+
setStatus("simulating");
|
|
332
|
+
setError(null);
|
|
333
|
+
const request = {
|
|
334
|
+
qubits: circuit.qubits,
|
|
335
|
+
gates: circuit.gates.map(({ id: _, ...gate }) => gate),
|
|
336
|
+
shots: 1024,
|
|
337
|
+
profile: { type: "ideal" }
|
|
338
|
+
};
|
|
339
|
+
adapter.simulate(request).then((simulationResult) => {
|
|
340
|
+
if (autoSimRequestId.current !== requestId) return;
|
|
341
|
+
setResult(simulationResult);
|
|
342
|
+
setStatus("idle");
|
|
343
|
+
onSimulationComplete?.({
|
|
344
|
+
result: simulationResult,
|
|
345
|
+
circuit: { ...circuit },
|
|
346
|
+
qasm: circuitToQasm(circuit)
|
|
347
|
+
});
|
|
348
|
+
}).catch((err) => {
|
|
349
|
+
if (autoSimRequestId.current !== requestId) return;
|
|
350
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
351
|
+
setStatus("error");
|
|
352
|
+
});
|
|
353
|
+
}, [circuit, canSimulate, adapter, onSimulationComplete]);
|
|
322
354
|
const addGate = useCallback(
|
|
323
355
|
(gate) => {
|
|
324
356
|
if (circuit.gates.length >= config.maxGates) {
|
|
@@ -488,6 +520,7 @@ function QamposerProvider({
|
|
|
488
520
|
}, [circuit]);
|
|
489
521
|
const simulate = useCallback(
|
|
490
522
|
async (shots = 1024, profile) => {
|
|
523
|
+
autoSimRequestId.current++;
|
|
491
524
|
if (!canSimulate) {
|
|
492
525
|
throw new Error("Simulation adapter is not available");
|
|
493
526
|
}
|
|
@@ -2301,6 +2334,11 @@ var css3 = `.simulation-controls__run-btn {
|
|
|
2301
2334
|
border-color: var(--qamposer-accent, #4285f4);
|
|
2302
2335
|
background: rgba(66, 133, 244, 0.1);
|
|
2303
2336
|
}
|
|
2337
|
+
.simulation-controls__backend-item--disabled {
|
|
2338
|
+
opacity: 0.5;
|
|
2339
|
+
cursor: not-allowed;
|
|
2340
|
+
pointer-events: none;
|
|
2341
|
+
}
|
|
2304
2342
|
.simulation-controls__backend-item-content {
|
|
2305
2343
|
flex: 1;
|
|
2306
2344
|
min-width: 0;
|
|
@@ -2332,6 +2370,10 @@ var css3 = `.simulation-controls__run-btn {
|
|
|
2332
2370
|
background: rgba(237, 137, 54, 0.2);
|
|
2333
2371
|
color: #ed8936;
|
|
2334
2372
|
}
|
|
2373
|
+
.simulation-controls__backend-type--real {
|
|
2374
|
+
background: rgba(160, 174, 192, 0.2);
|
|
2375
|
+
color: #a0aec0;
|
|
2376
|
+
}
|
|
2335
2377
|
.simulation-controls__backend-desc {
|
|
2336
2378
|
margin: 0;
|
|
2337
2379
|
font-size: 0.75rem;
|
|
@@ -2423,7 +2465,7 @@ function SimulationControls({
|
|
|
2423
2465
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
2424
2466
|
const [shots, setShots] = useState(1024);
|
|
2425
2467
|
const [backends, setBackends] = useState([]);
|
|
2426
|
-
const [selectedBackendId, setSelectedBackendId] = useState("
|
|
2468
|
+
const [selectedBackendId, setSelectedBackendId] = useState("");
|
|
2427
2469
|
const [isLoadingBackends, setIsLoadingBackends] = useState(false);
|
|
2428
2470
|
const [backendError, setBackendError] = useState(false);
|
|
2429
2471
|
useEffect(() => {
|
|
@@ -2431,8 +2473,13 @@ function SimulationControls({
|
|
|
2431
2473
|
setIsLoadingBackends(true);
|
|
2432
2474
|
setBackendError(false);
|
|
2433
2475
|
adapter.getBackends().then((result) => {
|
|
2434
|
-
|
|
2435
|
-
|
|
2476
|
+
const nonIdealBackends = result.filter((b) => b.backend_type !== "ideal");
|
|
2477
|
+
setBackends(nonIdealBackends);
|
|
2478
|
+
const firstFake = nonIdealBackends.find((b) => b.backend_type === "noisy_fake");
|
|
2479
|
+
if (firstFake) {
|
|
2480
|
+
setSelectedBackendId(firstFake.id);
|
|
2481
|
+
}
|
|
2482
|
+
if (nonIdealBackends.length === 0 && !canSimulate) {
|
|
2436
2483
|
setBackendError(true);
|
|
2437
2484
|
}
|
|
2438
2485
|
}).finally(() => setIsLoadingBackends(false));
|
|
@@ -2440,13 +2487,10 @@ function SimulationControls({
|
|
|
2440
2487
|
}, [isDialogOpen, adapter, canSimulate]);
|
|
2441
2488
|
const selectedBackend = backends.find((b) => b.id === selectedBackendId);
|
|
2442
2489
|
const buildProfile = () => {
|
|
2443
|
-
if (!selectedBackend || selectedBackend.backend_type === "
|
|
2444
|
-
return { type: "
|
|
2490
|
+
if (!selectedBackend || selectedBackend.backend_type === "noisy_fake") {
|
|
2491
|
+
return selectedBackend ? { type: "noisy_fake", backend_name: selectedBackend.id } : void 0;
|
|
2445
2492
|
}
|
|
2446
|
-
return
|
|
2447
|
-
type: "noisy_fake",
|
|
2448
|
-
backend_name: selectedBackend.id
|
|
2449
|
-
};
|
|
2493
|
+
return void 0;
|
|
2450
2494
|
};
|
|
2451
2495
|
const handleRun = async () => {
|
|
2452
2496
|
if (circuit.gates.length === 0) {
|
|
@@ -2533,31 +2577,35 @@ function SimulationControls({
|
|
|
2533
2577
|
/* @__PURE__ */ jsx("p", { className: "simulation-controls__error-title", children: "Backend unavailable" }),
|
|
2534
2578
|
/* @__PURE__ */ jsx("p", { className: "simulation-controls__error-desc", children: "Cannot connect to the simulation backend. Please check that the server is running and CORS is configured correctly." })
|
|
2535
2579
|
] })
|
|
2536
|
-
] }) : /* @__PURE__ */ jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) =>
|
|
2537
|
-
"
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
{
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2580
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => {
|
|
2581
|
+
const isReal = backend.backend_type === "real";
|
|
2582
|
+
return /* @__PURE__ */ jsxs(
|
|
2583
|
+
"button",
|
|
2584
|
+
{
|
|
2585
|
+
type: "button",
|
|
2586
|
+
className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""} ${isReal ? "simulation-controls__backend-item--disabled" : ""}`,
|
|
2587
|
+
onClick: () => !isReal && setSelectedBackendId(backend.id),
|
|
2588
|
+
disabled: isReal,
|
|
2589
|
+
children: [
|
|
2590
|
+
/* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-content", children: [
|
|
2591
|
+
/* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-header", children: [
|
|
2592
|
+
/* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
|
|
2593
|
+
/* @__PURE__ */ jsx(
|
|
2594
|
+
"span",
|
|
2595
|
+
{
|
|
2596
|
+
className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
|
|
2597
|
+
children: backend.backend_type === "noisy_fake" ? "Noisy" : "Real"
|
|
2598
|
+
}
|
|
2599
|
+
)
|
|
2600
|
+
] }),
|
|
2601
|
+
/* @__PURE__ */ jsx("p", { className: "simulation-controls__backend-desc", children: isReal ? "Coming soon" : backend.description || `${backend.num_qubits} qubits` })
|
|
2553
2602
|
] }),
|
|
2554
|
-
/* @__PURE__ */ jsx("
|
|
2555
|
-
]
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
)) })
|
|
2603
|
+
selectedBackendId === backend.id && /* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsx(CheckIcon, {}) })
|
|
2604
|
+
]
|
|
2605
|
+
},
|
|
2606
|
+
backend.id
|
|
2607
|
+
);
|
|
2608
|
+
}) })
|
|
2561
2609
|
] })
|
|
2562
2610
|
] }),
|
|
2563
2611
|
/* @__PURE__ */ jsxs("div", { className: "simulation-controls__dialog-footer", children: [
|
package/dist/visualization.cjs
CHANGED
|
@@ -319,6 +319,38 @@ function QamposerProvider({
|
|
|
319
319
|
react.useEffect(() => {
|
|
320
320
|
adapter.isAvailable().then(setCanSimulate);
|
|
321
321
|
}, [adapter]);
|
|
322
|
+
const autoSimRequestId = react.useRef(0);
|
|
323
|
+
react.useEffect(() => {
|
|
324
|
+
if (!canSimulate || circuit.gates.length === 0) {
|
|
325
|
+
if (circuit.gates.length === 0) {
|
|
326
|
+
setResult(null);
|
|
327
|
+
}
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const requestId = ++autoSimRequestId.current;
|
|
331
|
+
setStatus("simulating");
|
|
332
|
+
setError(null);
|
|
333
|
+
const request = {
|
|
334
|
+
qubits: circuit.qubits,
|
|
335
|
+
gates: circuit.gates.map(({ id: _, ...gate }) => gate),
|
|
336
|
+
shots: 1024,
|
|
337
|
+
profile: { type: "ideal" }
|
|
338
|
+
};
|
|
339
|
+
adapter.simulate(request).then((simulationResult) => {
|
|
340
|
+
if (autoSimRequestId.current !== requestId) return;
|
|
341
|
+
setResult(simulationResult);
|
|
342
|
+
setStatus("idle");
|
|
343
|
+
onSimulationComplete?.({
|
|
344
|
+
result: simulationResult,
|
|
345
|
+
circuit: { ...circuit },
|
|
346
|
+
qasm: circuitToQasm(circuit)
|
|
347
|
+
});
|
|
348
|
+
}).catch((err) => {
|
|
349
|
+
if (autoSimRequestId.current !== requestId) return;
|
|
350
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
351
|
+
setStatus("error");
|
|
352
|
+
});
|
|
353
|
+
}, [circuit, canSimulate, adapter, onSimulationComplete]);
|
|
322
354
|
const addGate = react.useCallback(
|
|
323
355
|
(gate) => {
|
|
324
356
|
if (circuit.gates.length >= config.maxGates) {
|
|
@@ -488,6 +520,7 @@ function QamposerProvider({
|
|
|
488
520
|
}, [circuit]);
|
|
489
521
|
const simulate = react.useCallback(
|
|
490
522
|
async (shots = 1024, profile) => {
|
|
523
|
+
autoSimRequestId.current++;
|
|
491
524
|
if (!canSimulate) {
|
|
492
525
|
throw new Error("Simulation adapter is not available");
|
|
493
526
|
}
|
|
@@ -2999,6 +3032,11 @@ var css6 = `.simulation-controls__run-btn {
|
|
|
2999
3032
|
border-color: var(--qamposer-accent, #4285f4);
|
|
3000
3033
|
background: rgba(66, 133, 244, 0.1);
|
|
3001
3034
|
}
|
|
3035
|
+
.simulation-controls__backend-item--disabled {
|
|
3036
|
+
opacity: 0.5;
|
|
3037
|
+
cursor: not-allowed;
|
|
3038
|
+
pointer-events: none;
|
|
3039
|
+
}
|
|
3002
3040
|
.simulation-controls__backend-item-content {
|
|
3003
3041
|
flex: 1;
|
|
3004
3042
|
min-width: 0;
|
|
@@ -3030,6 +3068,10 @@ var css6 = `.simulation-controls__run-btn {
|
|
|
3030
3068
|
background: rgba(237, 137, 54, 0.2);
|
|
3031
3069
|
color: #ed8936;
|
|
3032
3070
|
}
|
|
3071
|
+
.simulation-controls__backend-type--real {
|
|
3072
|
+
background: rgba(160, 174, 192, 0.2);
|
|
3073
|
+
color: #a0aec0;
|
|
3074
|
+
}
|
|
3033
3075
|
.simulation-controls__backend-desc {
|
|
3034
3076
|
margin: 0;
|
|
3035
3077
|
font-size: 0.75rem;
|
|
@@ -3121,7 +3163,7 @@ function SimulationControls({
|
|
|
3121
3163
|
const [isDialogOpen, setIsDialogOpen] = react.useState(false);
|
|
3122
3164
|
const [shots, setShots] = react.useState(1024);
|
|
3123
3165
|
const [backends, setBackends] = react.useState([]);
|
|
3124
|
-
const [selectedBackendId, setSelectedBackendId] = react.useState("
|
|
3166
|
+
const [selectedBackendId, setSelectedBackendId] = react.useState("");
|
|
3125
3167
|
const [isLoadingBackends, setIsLoadingBackends] = react.useState(false);
|
|
3126
3168
|
const [backendError, setBackendError] = react.useState(false);
|
|
3127
3169
|
react.useEffect(() => {
|
|
@@ -3129,8 +3171,13 @@ function SimulationControls({
|
|
|
3129
3171
|
setIsLoadingBackends(true);
|
|
3130
3172
|
setBackendError(false);
|
|
3131
3173
|
adapter.getBackends().then((result) => {
|
|
3132
|
-
|
|
3133
|
-
|
|
3174
|
+
const nonIdealBackends = result.filter((b) => b.backend_type !== "ideal");
|
|
3175
|
+
setBackends(nonIdealBackends);
|
|
3176
|
+
const firstFake = nonIdealBackends.find((b) => b.backend_type === "noisy_fake");
|
|
3177
|
+
if (firstFake) {
|
|
3178
|
+
setSelectedBackendId(firstFake.id);
|
|
3179
|
+
}
|
|
3180
|
+
if (nonIdealBackends.length === 0 && !canSimulate) {
|
|
3134
3181
|
setBackendError(true);
|
|
3135
3182
|
}
|
|
3136
3183
|
}).finally(() => setIsLoadingBackends(false));
|
|
@@ -3138,13 +3185,10 @@ function SimulationControls({
|
|
|
3138
3185
|
}, [isDialogOpen, adapter, canSimulate]);
|
|
3139
3186
|
const selectedBackend = backends.find((b) => b.id === selectedBackendId);
|
|
3140
3187
|
const buildProfile = () => {
|
|
3141
|
-
if (!selectedBackend || selectedBackend.backend_type === "
|
|
3142
|
-
return { type: "
|
|
3188
|
+
if (!selectedBackend || selectedBackend.backend_type === "noisy_fake") {
|
|
3189
|
+
return selectedBackend ? { type: "noisy_fake", backend_name: selectedBackend.id } : void 0;
|
|
3143
3190
|
}
|
|
3144
|
-
return
|
|
3145
|
-
type: "noisy_fake",
|
|
3146
|
-
backend_name: selectedBackend.id
|
|
3147
|
-
};
|
|
3191
|
+
return void 0;
|
|
3148
3192
|
};
|
|
3149
3193
|
const handleRun = async () => {
|
|
3150
3194
|
if (circuit.gates.length === 0) {
|
|
@@ -3231,31 +3275,35 @@ function SimulationControls({
|
|
|
3231
3275
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__error-title", children: "Backend unavailable" }),
|
|
3232
3276
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__error-desc", children: "Cannot connect to the simulation backend. Please check that the server is running and CORS is configured correctly." })
|
|
3233
3277
|
] })
|
|
3234
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) =>
|
|
3235
|
-
"
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
{
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3278
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => {
|
|
3279
|
+
const isReal = backend.backend_type === "real";
|
|
3280
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3281
|
+
"button",
|
|
3282
|
+
{
|
|
3283
|
+
type: "button",
|
|
3284
|
+
className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""} ${isReal ? "simulation-controls__backend-item--disabled" : ""}`,
|
|
3285
|
+
onClick: () => !isReal && setSelectedBackendId(backend.id),
|
|
3286
|
+
disabled: isReal,
|
|
3287
|
+
children: [
|
|
3288
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-content", children: [
|
|
3289
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-header", children: [
|
|
3290
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
|
|
3291
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3292
|
+
"span",
|
|
3293
|
+
{
|
|
3294
|
+
className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
|
|
3295
|
+
children: backend.backend_type === "noisy_fake" ? "Noisy" : "Real"
|
|
3296
|
+
}
|
|
3297
|
+
)
|
|
3298
|
+
] }),
|
|
3299
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__backend-desc", children: isReal ? "Coming soon" : backend.description || `${backend.num_qubits} qubits` })
|
|
3251
3300
|
] }),
|
|
3252
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
3253
|
-
]
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
)) })
|
|
3301
|
+
selectedBackendId === backend.id && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, {}) })
|
|
3302
|
+
]
|
|
3303
|
+
},
|
|
3304
|
+
backend.id
|
|
3305
|
+
);
|
|
3306
|
+
}) })
|
|
3259
3307
|
] })
|
|
3260
3308
|
] }),
|
|
3261
3309
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__dialog-footer", children: [
|
package/dist/visualization.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { Q as QamposerProviderProps, T as Theme } from './index-
|
|
2
|
+
import { Q as QamposerProviderProps, T as Theme } from './index-BghK68a6.cjs';
|
|
3
3
|
import 'react';
|
|
4
4
|
|
|
5
5
|
interface QamposerProps extends Omit<QamposerProviderProps, 'children'> {
|
package/dist/visualization.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { Q as QamposerProviderProps, T as Theme } from './index-
|
|
2
|
+
import { Q as QamposerProviderProps, T as Theme } from './index-BghK68a6.js';
|
|
3
3
|
import 'react';
|
|
4
4
|
|
|
5
5
|
interface QamposerProps extends Omit<QamposerProviderProps, 'children'> {
|
package/dist/visualization.js
CHANGED
|
@@ -313,6 +313,38 @@ function QamposerProvider({
|
|
|
313
313
|
useEffect(() => {
|
|
314
314
|
adapter.isAvailable().then(setCanSimulate);
|
|
315
315
|
}, [adapter]);
|
|
316
|
+
const autoSimRequestId = useRef(0);
|
|
317
|
+
useEffect(() => {
|
|
318
|
+
if (!canSimulate || circuit.gates.length === 0) {
|
|
319
|
+
if (circuit.gates.length === 0) {
|
|
320
|
+
setResult(null);
|
|
321
|
+
}
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const requestId = ++autoSimRequestId.current;
|
|
325
|
+
setStatus("simulating");
|
|
326
|
+
setError(null);
|
|
327
|
+
const request = {
|
|
328
|
+
qubits: circuit.qubits,
|
|
329
|
+
gates: circuit.gates.map(({ id: _, ...gate }) => gate),
|
|
330
|
+
shots: 1024,
|
|
331
|
+
profile: { type: "ideal" }
|
|
332
|
+
};
|
|
333
|
+
adapter.simulate(request).then((simulationResult) => {
|
|
334
|
+
if (autoSimRequestId.current !== requestId) return;
|
|
335
|
+
setResult(simulationResult);
|
|
336
|
+
setStatus("idle");
|
|
337
|
+
onSimulationComplete?.({
|
|
338
|
+
result: simulationResult,
|
|
339
|
+
circuit: { ...circuit },
|
|
340
|
+
qasm: circuitToQasm(circuit)
|
|
341
|
+
});
|
|
342
|
+
}).catch((err) => {
|
|
343
|
+
if (autoSimRequestId.current !== requestId) return;
|
|
344
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
345
|
+
setStatus("error");
|
|
346
|
+
});
|
|
347
|
+
}, [circuit, canSimulate, adapter, onSimulationComplete]);
|
|
316
348
|
const addGate = useCallback(
|
|
317
349
|
(gate) => {
|
|
318
350
|
if (circuit.gates.length >= config.maxGates) {
|
|
@@ -482,6 +514,7 @@ function QamposerProvider({
|
|
|
482
514
|
}, [circuit]);
|
|
483
515
|
const simulate = useCallback(
|
|
484
516
|
async (shots = 1024, profile) => {
|
|
517
|
+
autoSimRequestId.current++;
|
|
485
518
|
if (!canSimulate) {
|
|
486
519
|
throw new Error("Simulation adapter is not available");
|
|
487
520
|
}
|
|
@@ -2993,6 +3026,11 @@ var css6 = `.simulation-controls__run-btn {
|
|
|
2993
3026
|
border-color: var(--qamposer-accent, #4285f4);
|
|
2994
3027
|
background: rgba(66, 133, 244, 0.1);
|
|
2995
3028
|
}
|
|
3029
|
+
.simulation-controls__backend-item--disabled {
|
|
3030
|
+
opacity: 0.5;
|
|
3031
|
+
cursor: not-allowed;
|
|
3032
|
+
pointer-events: none;
|
|
3033
|
+
}
|
|
2996
3034
|
.simulation-controls__backend-item-content {
|
|
2997
3035
|
flex: 1;
|
|
2998
3036
|
min-width: 0;
|
|
@@ -3024,6 +3062,10 @@ var css6 = `.simulation-controls__run-btn {
|
|
|
3024
3062
|
background: rgba(237, 137, 54, 0.2);
|
|
3025
3063
|
color: #ed8936;
|
|
3026
3064
|
}
|
|
3065
|
+
.simulation-controls__backend-type--real {
|
|
3066
|
+
background: rgba(160, 174, 192, 0.2);
|
|
3067
|
+
color: #a0aec0;
|
|
3068
|
+
}
|
|
3027
3069
|
.simulation-controls__backend-desc {
|
|
3028
3070
|
margin: 0;
|
|
3029
3071
|
font-size: 0.75rem;
|
|
@@ -3115,7 +3157,7 @@ function SimulationControls({
|
|
|
3115
3157
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
3116
3158
|
const [shots, setShots] = useState(1024);
|
|
3117
3159
|
const [backends, setBackends] = useState([]);
|
|
3118
|
-
const [selectedBackendId, setSelectedBackendId] = useState("
|
|
3160
|
+
const [selectedBackendId, setSelectedBackendId] = useState("");
|
|
3119
3161
|
const [isLoadingBackends, setIsLoadingBackends] = useState(false);
|
|
3120
3162
|
const [backendError, setBackendError] = useState(false);
|
|
3121
3163
|
useEffect(() => {
|
|
@@ -3123,8 +3165,13 @@ function SimulationControls({
|
|
|
3123
3165
|
setIsLoadingBackends(true);
|
|
3124
3166
|
setBackendError(false);
|
|
3125
3167
|
adapter.getBackends().then((result) => {
|
|
3126
|
-
|
|
3127
|
-
|
|
3168
|
+
const nonIdealBackends = result.filter((b) => b.backend_type !== "ideal");
|
|
3169
|
+
setBackends(nonIdealBackends);
|
|
3170
|
+
const firstFake = nonIdealBackends.find((b) => b.backend_type === "noisy_fake");
|
|
3171
|
+
if (firstFake) {
|
|
3172
|
+
setSelectedBackendId(firstFake.id);
|
|
3173
|
+
}
|
|
3174
|
+
if (nonIdealBackends.length === 0 && !canSimulate) {
|
|
3128
3175
|
setBackendError(true);
|
|
3129
3176
|
}
|
|
3130
3177
|
}).finally(() => setIsLoadingBackends(false));
|
|
@@ -3132,13 +3179,10 @@ function SimulationControls({
|
|
|
3132
3179
|
}, [isDialogOpen, adapter, canSimulate]);
|
|
3133
3180
|
const selectedBackend = backends.find((b) => b.id === selectedBackendId);
|
|
3134
3181
|
const buildProfile = () => {
|
|
3135
|
-
if (!selectedBackend || selectedBackend.backend_type === "
|
|
3136
|
-
return { type: "
|
|
3182
|
+
if (!selectedBackend || selectedBackend.backend_type === "noisy_fake") {
|
|
3183
|
+
return selectedBackend ? { type: "noisy_fake", backend_name: selectedBackend.id } : void 0;
|
|
3137
3184
|
}
|
|
3138
|
-
return
|
|
3139
|
-
type: "noisy_fake",
|
|
3140
|
-
backend_name: selectedBackend.id
|
|
3141
|
-
};
|
|
3185
|
+
return void 0;
|
|
3142
3186
|
};
|
|
3143
3187
|
const handleRun = async () => {
|
|
3144
3188
|
if (circuit.gates.length === 0) {
|
|
@@ -3225,31 +3269,35 @@ function SimulationControls({
|
|
|
3225
3269
|
/* @__PURE__ */ jsx("p", { className: "simulation-controls__error-title", children: "Backend unavailable" }),
|
|
3226
3270
|
/* @__PURE__ */ jsx("p", { className: "simulation-controls__error-desc", children: "Cannot connect to the simulation backend. Please check that the server is running and CORS is configured correctly." })
|
|
3227
3271
|
] })
|
|
3228
|
-
] }) : /* @__PURE__ */ jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) =>
|
|
3229
|
-
"
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
{
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3272
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => {
|
|
3273
|
+
const isReal = backend.backend_type === "real";
|
|
3274
|
+
return /* @__PURE__ */ jsxs(
|
|
3275
|
+
"button",
|
|
3276
|
+
{
|
|
3277
|
+
type: "button",
|
|
3278
|
+
className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""} ${isReal ? "simulation-controls__backend-item--disabled" : ""}`,
|
|
3279
|
+
onClick: () => !isReal && setSelectedBackendId(backend.id),
|
|
3280
|
+
disabled: isReal,
|
|
3281
|
+
children: [
|
|
3282
|
+
/* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-content", children: [
|
|
3283
|
+
/* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-header", children: [
|
|
3284
|
+
/* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
|
|
3285
|
+
/* @__PURE__ */ jsx(
|
|
3286
|
+
"span",
|
|
3287
|
+
{
|
|
3288
|
+
className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
|
|
3289
|
+
children: backend.backend_type === "noisy_fake" ? "Noisy" : "Real"
|
|
3290
|
+
}
|
|
3291
|
+
)
|
|
3292
|
+
] }),
|
|
3293
|
+
/* @__PURE__ */ jsx("p", { className: "simulation-controls__backend-desc", children: isReal ? "Coming soon" : backend.description || `${backend.num_qubits} qubits` })
|
|
3245
3294
|
] }),
|
|
3246
|
-
/* @__PURE__ */ jsx("
|
|
3247
|
-
]
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
)) })
|
|
3295
|
+
selectedBackendId === backend.id && /* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsx(CheckIcon, {}) })
|
|
3296
|
+
]
|
|
3297
|
+
},
|
|
3298
|
+
backend.id
|
|
3299
|
+
);
|
|
3300
|
+
}) })
|
|
3253
3301
|
] })
|
|
3254
3302
|
] }),
|
|
3255
3303
|
/* @__PURE__ */ jsxs("div", { className: "simulation-controls__dialog-footer", children: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qamposer/react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React components for quantum circuit composition",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -26,8 +26,7 @@
|
|
|
26
26
|
"types": "./dist/visualization.d.cts",
|
|
27
27
|
"default": "./dist/visualization.cjs"
|
|
28
28
|
}
|
|
29
|
-
}
|
|
30
|
-
"./styles.css": "./dist/styles.css"
|
|
29
|
+
}
|
|
31
30
|
},
|
|
32
31
|
"files": [
|
|
33
32
|
"dist"
|
|
@@ -77,6 +76,7 @@
|
|
|
77
76
|
"eslint": "^9.39.2",
|
|
78
77
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
79
78
|
"happy-dom": "^20.4.0",
|
|
79
|
+
"prettier": "^3.8.1",
|
|
80
80
|
"react": "^19.0.0",
|
|
81
81
|
"react-dom": "^19.0.0",
|
|
82
82
|
"sass": "^1.97.1",
|