@qamposer/react 0.1.1 → 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 +59 -42
- 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
|
@@ -39,32 +39,27 @@ Quantum mechanics and simulation results can be directly leveraged as game logic
|
|
|
39
39
|
### Basic Usage (QamposerMicro)
|
|
40
40
|
|
|
41
41
|
```tsx
|
|
42
|
-
import { QamposerMicro
|
|
43
|
-
import "@qamposer/react/styles.css";
|
|
42
|
+
import { QamposerMicro } from '@qamposer/react';
|
|
44
43
|
|
|
45
44
|
function App() {
|
|
46
|
-
return
|
|
47
|
-
<QamposerMicro
|
|
48
|
-
adapter={qiskitAdapter("http://localhost:8000")}
|
|
49
|
-
onSimulationComplete={(event) => {
|
|
50
|
-
console.log("Result:", event.result);
|
|
51
|
-
console.log("QASM:", event.qasm);
|
|
52
|
-
}}
|
|
53
|
-
/>
|
|
54
|
-
);
|
|
45
|
+
return <QamposerMicro />;
|
|
55
46
|
}
|
|
56
47
|
```
|
|
57
48
|
|
|
49
|
+
> **Note**: By default, QamposerMicro runs in editor-only mode (no simulation). To enable simulation, see [With Backend](#with-backend-simulation) below.
|
|
50
|
+
|
|
58
51
|
### Full Version with Visualization (Qamposer)
|
|
59
52
|
|
|
53
|
+
The full version includes visualization components (histograms, Q-sphere) that require simulation results, so a backend adapter is needed:
|
|
54
|
+
|
|
60
55
|
```tsx
|
|
61
|
-
import { Qamposer } from
|
|
62
|
-
import
|
|
56
|
+
import { Qamposer } from '@qamposer/react/visualization';
|
|
57
|
+
import { qiskitAdapter } from '@qamposer/react';
|
|
63
58
|
|
|
64
59
|
function App() {
|
|
65
60
|
return (
|
|
66
61
|
<Qamposer
|
|
67
|
-
adapter={qiskitAdapter(
|
|
62
|
+
adapter={qiskitAdapter('http://localhost:8080')}
|
|
68
63
|
defaultTheme="dark"
|
|
69
64
|
showThemeToggle
|
|
70
65
|
/>
|
|
@@ -102,11 +97,24 @@ This library provides two preset components to fit different use cases:
|
|
|
102
97
|
|
|
103
98
|
## Backend Requirements
|
|
104
99
|
|
|
105
|
-
|
|
100
|
+
The React components work standalone for circuit editing. To run quantum simulations, you need the `qamposer-backend` server.
|
|
101
|
+
|
|
102
|
+
### Editor-Only Mode
|
|
106
103
|
|
|
107
|
-
|
|
104
|
+
By default, components run in editor-only mode without requiring a backend:
|
|
108
105
|
|
|
109
|
-
|
|
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)
|
|
114
|
+
|
|
115
|
+
To enable quantum simulation, start the backend and pass the `qiskitAdapter`:
|
|
116
|
+
|
|
117
|
+
Assuming localhost is used here, but please specify the actual deployment destination for the backend.
|
|
110
118
|
|
|
111
119
|
```bash
|
|
112
120
|
# Clone and setup qamposer-backend
|
|
@@ -115,17 +123,16 @@ poetry install
|
|
|
115
123
|
poetry run uvicorn backend.main:app --host 0.0.0.0 --port 8080 --reload
|
|
116
124
|
```
|
|
117
125
|
|
|
118
|
-
The backend will start at `http://localhost:8000` by default.
|
|
119
|
-
|
|
120
|
-
### Editor-Only Mode (No Backend)
|
|
121
|
-
|
|
122
|
-
If you only need the circuit editor without simulation capabilities, use the `noopAdapter`:
|
|
123
|
-
|
|
124
126
|
```tsx
|
|
125
|
-
import { QamposerMicro,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
+
/>;
|
|
129
136
|
```
|
|
130
137
|
|
|
131
138
|
## API Reference
|
|
@@ -140,7 +147,7 @@ interface QamposerProps {
|
|
|
140
147
|
onCircuitChange?: (circuit: Circuit) => void;
|
|
141
148
|
|
|
142
149
|
// Simulation
|
|
143
|
-
adapter?: SimulationAdapter; // Backend adapter
|
|
150
|
+
adapter?: SimulationAdapter; // Backend adapter (default: noopAdapter)
|
|
144
151
|
onSimulationComplete?: (event: SimulationCompleteEvent) => void;
|
|
145
152
|
|
|
146
153
|
// Configuration
|
|
@@ -150,7 +157,7 @@ interface QamposerProps {
|
|
|
150
157
|
className?: string;
|
|
151
158
|
showHeader?: boolean; // Default: true
|
|
152
159
|
title?: string; // Default: 'Qamposer'
|
|
153
|
-
defaultTheme?:
|
|
160
|
+
defaultTheme?: 'light' | 'dark'; // Default: 'dark'
|
|
154
161
|
showThemeToggle?: boolean; // Default: true
|
|
155
162
|
|
|
156
163
|
// Layout (Qamposer only)
|
|
@@ -170,31 +177,31 @@ interface QamposerConfig {
|
|
|
170
177
|
}
|
|
171
178
|
```
|
|
172
179
|
|
|
173
|
-
### Adapters
|
|
180
|
+
<!-- ### Adapters
|
|
174
181
|
|
|
175
182
|
```tsx
|
|
176
183
|
// Qiskit Backend Adapter
|
|
177
|
-
import { qiskitAdapter } from
|
|
184
|
+
import { qiskitAdapter } from '@qamposer/react';
|
|
178
185
|
|
|
179
|
-
const adapter = qiskitAdapter(
|
|
186
|
+
const adapter = qiskitAdapter('http://localhost:8000');
|
|
180
187
|
|
|
181
188
|
// With options
|
|
182
189
|
const adapter = qiskitAdapter({
|
|
183
|
-
baseUrl:
|
|
184
|
-
headers: { Authorization:
|
|
190
|
+
baseUrl: 'http://localhost:8000',
|
|
191
|
+
headers: { Authorization: 'Bearer token' },
|
|
185
192
|
timeout: 30000,
|
|
186
193
|
});
|
|
187
194
|
|
|
188
195
|
// No-op Adapter (editor only, no simulation)
|
|
189
|
-
import { noopAdapter } from
|
|
190
|
-
```
|
|
196
|
+
import { noopAdapter } from '@qamposer/react';
|
|
197
|
+
``` -->
|
|
191
198
|
|
|
192
|
-
### useQamposer Hook
|
|
199
|
+
<!-- ### useQamposer Hook
|
|
193
200
|
|
|
194
201
|
For building custom UIs, use the `useQamposer` hook within a `QamposerProvider`:
|
|
195
202
|
|
|
196
203
|
```tsx
|
|
197
|
-
import { QamposerProvider, useQamposer } from '@qamposer/react';
|
|
204
|
+
import { QamposerProvider, useQamposer, qiskitAdapter } from '@qamposer/react';
|
|
198
205
|
|
|
199
206
|
function CustomEditor() {
|
|
200
207
|
const {
|
|
@@ -213,14 +220,24 @@ function CustomEditor() {
|
|
|
213
220
|
);
|
|
214
221
|
}
|
|
215
222
|
|
|
223
|
+
// Editor-only mode (default)
|
|
216
224
|
function App() {
|
|
217
225
|
return (
|
|
218
|
-
<QamposerProvider
|
|
226
|
+
<QamposerProvider>
|
|
219
227
|
<CustomEditor />
|
|
220
228
|
</QamposerProvider>
|
|
221
229
|
);
|
|
222
230
|
}
|
|
223
|
-
|
|
231
|
+
|
|
232
|
+
// With backend simulation
|
|
233
|
+
function AppWithSimulation() {
|
|
234
|
+
return (
|
|
235
|
+
<QamposerProvider adapter={qiskitAdapter('http://localhost:8080')}>
|
|
236
|
+
<CustomEditor />
|
|
237
|
+
</QamposerProvider>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
``` -->
|
|
224
241
|
|
|
225
242
|
<!-- ### Individual Components -->
|
|
226
243
|
|
|
@@ -241,7 +258,7 @@ import { QSphereView, ResultsPanel } from '@qamposer/react/visualization';
|
|
|
241
258
|
## OpenQASM Utilities
|
|
242
259
|
|
|
243
260
|
```tsx
|
|
244
|
-
import { circuitToQasm, qasmToCircuit } from
|
|
261
|
+
import { circuitToQasm, qasmToCircuit } from '@qamposer/react';
|
|
245
262
|
|
|
246
263
|
// Convert Circuit to OpenQASM
|
|
247
264
|
const qasm = circuitToQasm(circuit);
|
|
@@ -285,7 +302,7 @@ The library uses CSS variables for theming. You can customize colors by overridi
|
|
|
285
302
|
Or use the theme hook:
|
|
286
303
|
|
|
287
304
|
```tsx
|
|
288
|
-
import { useTheme } from
|
|
305
|
+
import { useTheme } from '@qamposer/react';
|
|
289
306
|
|
|
290
307
|
function ThemeToggle() {
|
|
291
308
|
const { theme, toggleTheme } = useTheme();
|
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",
|