quantum-forge 2.5.1 → 2.6.0

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.
@@ -56,7 +56,13 @@ declare function phase_rotate(predicates: Predicate[], angle: number): void;
56
56
  declare function measure_properties(props: QuantumProperty[]): number[];
57
57
  declare function forced_measure_properties(props: QuantumProperty[], forcedValues: number[]): number[];
58
58
  declare function measure_predicate(predicates: Predicate[]): number;
59
+ /** Force a predicate measurement to a specific outcome.
60
+ * If the forced value is impossible (zero probability), falls back to
61
+ * stochastic measurement and returns the actual outcome instead of throwing. */
59
62
  declare function forced_measure_predicate(predicates: Predicate[], forcedValue: number): number;
63
+ /** Get the probability that all predicates are simultaneously satisfied.
64
+ * Read-only — does not collapse or modify quantum state. */
65
+ declare function predicate_probability(predicates: Predicate[]): number;
60
66
  declare function probabilities(props: QuantumProperty[]): Array<{
61
67
  probability: number;
62
68
  qudit_values: number[];
@@ -96,7 +102,7 @@ interface BatchResult {
96
102
  */
97
103
  declare function executeBatch(ops: BatchOp[]): BatchResult;
98
104
  /** Numeric opcode values matching the C++ OpCode enum for tape encoding. */
99
- declare const OP: {
105
+ declare const OP$1: {
100
106
  readonly CYCLE: 0;
101
107
  readonly SHIFT: 1;
102
108
  readonly CLOCK: 2;
@@ -112,7 +118,7 @@ declare const OP: {
112
118
  * [11, nq, -1, NaN, angle, 0, a[0]..a[nq-1], b[0]..b[nq-1]] */
113
119
  readonly ROTATE_BASIS_PAIR: 11;
114
120
  };
115
- type OpNum = typeof OP[keyof typeof OP];
121
+ type OpNum = typeof OP$1[keyof typeof OP$1];
116
122
  /**
117
123
  * Fast-path batch execution using a pre-encoded Float64Array tape.
118
124
  *
@@ -178,7 +184,6 @@ declare class QuantumForge {
178
184
 
179
185
  type __quantum_forge_api_mjs_BatchOp = BatchOp;
180
186
  type __quantum_forge_api_mjs_BatchResult = BatchResult;
181
- declare const __quantum_forge_api_mjs_OP: typeof OP;
182
187
  type __quantum_forge_api_mjs_OpCode = OpCode;
183
188
  type __quantum_forge_api_mjs_OpNum = OpNum;
184
189
  type __quantum_forge_api_mjs_Predicate = Predicate;
@@ -201,6 +206,7 @@ declare const __quantum_forge_api_mjs_inverse_hadamard: typeof inverse_hadamard;
201
206
  declare const __quantum_forge_api_mjs_measure_predicate: typeof measure_predicate;
202
207
  declare const __quantum_forge_api_mjs_measure_properties: typeof measure_properties;
203
208
  declare const __quantum_forge_api_mjs_phase_rotate: typeof phase_rotate;
209
+ declare const __quantum_forge_api_mjs_predicate_probability: typeof predicate_probability;
204
210
  declare const __quantum_forge_api_mjs_probabilities: typeof probabilities;
205
211
  declare const __quantum_forge_api_mjs_reduced_density_matrix: typeof reduced_density_matrix;
206
212
  declare const __quantum_forge_api_mjs_reset: typeof reset;
@@ -210,7 +216,7 @@ declare const __quantum_forge_api_mjs_x: typeof x;
210
216
  declare const __quantum_forge_api_mjs_y: typeof y;
211
217
  declare const __quantum_forge_api_mjs_z: typeof z;
212
218
  declare namespace __quantum_forge_api_mjs {
213
- export { type __quantum_forge_api_mjs_BatchOp as BatchOp, type __quantum_forge_api_mjs_BatchResult as BatchResult, __quantum_forge_api_mjs_OP as OP, type __quantum_forge_api_mjs_OpCode as OpCode, type __quantum_forge_api_mjs_OpNum as OpNum, __quantum_forge_api_mjs_Predicate as Predicate, __quantum_forge_api_mjs_QuantumForge as QuantumForge, __quantum_forge_api_mjs_QuantumProperty as QuantumProperty, __quantum_forge_api_mjs_QuantumSimulation as QuantumSimulation, __quantum_forge_api_mjs_clock as clock, __quantum_forge_api_mjs_cycle as cycle, __quantum_forge_api_mjs_executeBatch as executeBatch, __quantum_forge_api_mjs_executeBatchTape as executeBatchTape, __quantum_forge_api_mjs_forced_measure_predicate as forced_measure_predicate, __quantum_forge_api_mjs_forced_measure_properties as forced_measure_properties, __quantum_forge_api_mjs_hadamard as hadamard, __quantum_forge_api_mjs_i_swap as i_swap, __quantum_forge_api_mjs_inverse_hadamard as inverse_hadamard, __quantum_forge_api_mjs_measure_predicate as measure_predicate, __quantum_forge_api_mjs_measure_properties as measure_properties, __quantum_forge_api_mjs_phase_rotate as phase_rotate, __quantum_forge_api_mjs_probabilities as probabilities, __quantum_forge_api_mjs_reduced_density_matrix as reduced_density_matrix, __quantum_forge_api_mjs_reset as reset, __quantum_forge_api_mjs_shift as shift, __quantum_forge_api_mjs_swap as swap, __quantum_forge_api_mjs_x as x, __quantum_forge_api_mjs_y as y, __quantum_forge_api_mjs_z as z };
219
+ export { type __quantum_forge_api_mjs_BatchOp as BatchOp, type __quantum_forge_api_mjs_BatchResult as BatchResult, OP$1 as OP, type __quantum_forge_api_mjs_OpCode as OpCode, type __quantum_forge_api_mjs_OpNum as OpNum, __quantum_forge_api_mjs_Predicate as Predicate, __quantum_forge_api_mjs_QuantumForge as QuantumForge, __quantum_forge_api_mjs_QuantumProperty as QuantumProperty, __quantum_forge_api_mjs_QuantumSimulation as QuantumSimulation, __quantum_forge_api_mjs_clock as clock, __quantum_forge_api_mjs_cycle as cycle, __quantum_forge_api_mjs_executeBatch as executeBatch, __quantum_forge_api_mjs_executeBatchTape as executeBatchTape, __quantum_forge_api_mjs_forced_measure_predicate as forced_measure_predicate, __quantum_forge_api_mjs_forced_measure_properties as forced_measure_properties, __quantum_forge_api_mjs_hadamard as hadamard, __quantum_forge_api_mjs_i_swap as i_swap, __quantum_forge_api_mjs_inverse_hadamard as inverse_hadamard, __quantum_forge_api_mjs_measure_predicate as measure_predicate, __quantum_forge_api_mjs_measure_properties as measure_properties, __quantum_forge_api_mjs_phase_rotate as phase_rotate, __quantum_forge_api_mjs_predicate_probability as predicate_probability, __quantum_forge_api_mjs_probabilities as probabilities, __quantum_forge_api_mjs_reduced_density_matrix as reduced_density_matrix, __quantum_forge_api_mjs_reset as reset, __quantum_forge_api_mjs_shift as shift, __quantum_forge_api_mjs_swap as swap, __quantum_forge_api_mjs_x as x, __quantum_forge_api_mjs_y as y, __quantum_forge_api_mjs_z as z };
214
220
  }
215
221
 
216
222
  /**
@@ -494,4 +500,20 @@ declare class QuantumRecorder implements QuantumRecorderHook {
494
500
  private _replayPredicates;
495
501
  }
496
502
 
497
- export { type BatchOp, type BatchResult, type OpCode, type OpNum, type PredicateSpec$1 as PredicateSpec, type QuantumOperation, QuantumPropertyManager, QuantumRecorder, type QuantumRecorderHook, type SerializedPredicate, ensureLoaded, getAttribution, getMaxDimension, getMaxQudits, getMaxStateSize, getModule, getQuantumForge, getVersion, getWasmMemoryBytes, isReady, registerServiceWorker, setWasmBasePath, startBackgroundLoad, useQuantumForgeBuild };
503
+ /** Numeric opcode constants for tape encoding. Matches C++ OpCode enum. */
504
+ declare const OP: {
505
+ readonly CYCLE: 0;
506
+ readonly SHIFT: 1;
507
+ readonly CLOCK: 2;
508
+ readonly X: 3;
509
+ readonly Z: 4;
510
+ readonly Y: 5;
511
+ readonly HADAMARD: 6;
512
+ readonly INVERSE_HADAMARD: 7;
513
+ readonly SWAP: 8;
514
+ readonly I_SWAP: 9;
515
+ readonly PHASE_ROTATE: 10;
516
+ readonly ROTATE_BASIS_PAIR: 11;
517
+ };
518
+
519
+ export { type BatchOp, type BatchResult, OP, type OpCode, type OpNum, type PredicateSpec$1 as PredicateSpec, type QuantumOperation, QuantumPropertyManager, QuantumRecorder, type QuantumRecorderHook, type SerializedPredicate, ensureLoaded, getAttribution, getMaxDimension, getMaxQudits, getMaxStateSize, getModule, getQuantumForge, getVersion, getWasmMemoryBytes, isReady, registerServiceWorker, setWasmBasePath, startBackgroundLoad, useQuantumForgeBuild };
@@ -518,7 +518,24 @@ var QuantumRecorder = class {
518
518
  return preds;
519
519
  }
520
520
  };
521
+
522
+ // src/quantum/index.ts
523
+ var OP = {
524
+ CYCLE: 0,
525
+ SHIFT: 1,
526
+ CLOCK: 2,
527
+ X: 3,
528
+ Z: 4,
529
+ Y: 5,
530
+ HADAMARD: 6,
531
+ INVERSE_HADAMARD: 7,
532
+ SWAP: 8,
533
+ I_SWAP: 9,
534
+ PHASE_ROTATE: 10,
535
+ ROTATE_BASIS_PAIR: 11
536
+ };
521
537
  export {
538
+ OP,
522
539
  QuantumPropertyManager,
523
540
  QuantumRecorder,
524
541
  ensureLoaded,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/quantum/QuantumForgeLoader.ts","../../src/quantum/QuantumPropertyManager.ts","../../src/quantum/QuantumRecorder.ts"],"sourcesContent":["/**\n * Quantum Forge Loader - Lazy loader for Quantum Forge WASM module\n *\n * Defers WASM loading from the critical path while preloading in background\n * so it's ready when needed. If not ready, callers can show loading UI.\n * \n * IMPORTANT: Quantum Forge is built from source and copied to dist/ as\n * quantum-forge-web-api.mjs (not an npm package). Run 'npm run setup' to build.\n */\n\nimport type { LoggerInterface } from \"../logging/Logger\";\n\n// Type for the quantum forge module\ntype QuantumForgeModuleType = typeof import(\"./quantum-forge-api.mjs\");\n\n// Configurable base path for WASM artifacts\nlet wasmBasePath = \"/quantum-forge\";\n\n/**\n * Set the base URL path where Quantum Forge WASM files are served.\n * Default is \"/quantum-forge\" which matches the Vite plugin's serve path.\n * Consumers using the Vite plugin don't need to call this.\n */\nexport function setWasmBasePath(path: string): void {\n wasmBasePath = path.endsWith(\"/\") ? path.slice(0, -1) : path;\n}\n\n/**\n * Select a named WASM build variant (e.g. \"d7n10\").\n * Sugar for `setWasmBasePath(\"/quantum-forge-{name}\")`.\n *\n * Must be called before `ensureLoaded()`. If the module is already loaded,\n * a warning is logged and the call is ignored.\n */\nexport function useQuantumForgeBuild(name: string): void {\n if (isInitialized) {\n logger?.warn?.(\n `useQuantumForgeBuild(\"${name}\") called after module already loaded — ignoring. Call before ensureLoaded().`,\n \"QuantumForgeLoader\",\n );\n return;\n }\n setWasmBasePath(`/quantum-forge-${name}`);\n}\n\n// Cache the module and initialization state\nlet quantumForgeModule: QuantumForgeModuleType | null = null;\nlet initPromise: Promise<void> | null = null;\nlet isInitialized = false;\nlet loadStarted = false;\n\n// Logger reference (set during startBackgroundLoad)\nlet logger: LoggerInterface | undefined;\n\n/**\n * Start loading the WASM module in the background.\n * Call this after the page has rendered (e.g., after DOMContentLoaded or initial paint).\n */\nexport function startBackgroundLoad(loggerRef?: LoggerInterface): void {\n if (loadStarted) return;\n loadStarted = true;\n logger = loggerRef;\n\n // Use requestIdleCallback if available, otherwise setTimeout\n const scheduleLoad = (callback: () => void) => {\n if (typeof requestIdleCallback === \"function\") {\n requestIdleCallback(callback, { timeout: 2000 });\n } else {\n setTimeout(callback, 100);\n }\n };\n\n scheduleLoad(() => {\n logger?.info?.(\"Starting background Quantum Forge load\", \"QuantumForgeLoader\");\n // Trigger the load but don't await - let it happen in background\n ensureLoaded().catch((err) => {\n logger?.warn?.(\n `Background Quantum Forge load failed: ${err?.message ?? err}`,\n \"QuantumForgeLoader\",\n );\n });\n });\n}\n\n/**\n * Ensure Quantum Forge is loaded and initialized.\n * Returns a promise that resolves when the module is ready.\n * Can be called multiple times - will return the same promise.\n */\nexport async function ensureLoaded(): Promise<void> {\n if (isInitialized) return;\n\n if (initPromise) {\n await initPromise;\n return;\n }\n\n initPromise = (async () => {\n const startTime = performance.now();\n logger?.info?.(\"Loading Quantum Forge WASM module...\", \"QuantumForgeLoader\");\n\n // Dynamic import of Quantum Forge WASM module from the configured base path\n const modulePath = `${wasmBasePath}/quantum-forge-web-api.mjs`;\n const mod = (await import(/* @vite-ignore */ modulePath)) as QuantumForgeModuleType;\n quantumForgeModule = mod;\n\n // Initialize the WASM\n await mod.QuantumForge.initialize();\n\n const version = mod.QuantumForge.getVersion();\n const maxDim = mod.QuantumForge.getMaxDimension();\n const maxQudits = mod.QuantumForge.getMaxQudits();\n const elapsed = (performance.now() - startTime).toFixed(0);\n\n logger?.info?.(\n `Quantum Forge v${version} ready in ${elapsed}ms (max dim: ${maxDim}, max qudits: ${maxQudits})`,\n \"QuantumForgeLoader\",\n );\n\n console.log(\n \"%c\\u269B Powered by Quantum Forge %c quantumnative.io \",\n \"background: #6366f1; color: white; padding: 2px 6px; border-radius: 3px 0 0 3px; font-weight: bold;\",\n \"background: #1e1b4b; color: #c7d2fe; padding: 2px 6px; border-radius: 0 3px 3px 0;\",\n );\n\n isInitialized = true;\n })();\n\n // Handle errors by clearing the promise so retry is possible\n initPromise.catch(() => {\n initPromise = null;\n });\n\n await initPromise;\n}\n\n/**\n * Check if Quantum Forge is ready to use (non-blocking).\n */\nexport function isReady(): boolean {\n return isInitialized;\n}\n\n/**\n * Get the loaded module. Throws if not loaded.\n * For synchronous access after ensuring it's loaded.\n */\nexport function getModule(): typeof import(\"./quantum-forge-api.mjs\") {\n if (!quantumForgeModule || !isInitialized) {\n throw new Error(\"QuantumForge not loaded. Call ensureLoaded() first and await it.\");\n }\n return quantumForgeModule;\n}\n\n/**\n * Get the QuantumForge class from the loaded module.\n */\nexport function getQuantumForge(): typeof import(\"./quantum-forge-api.mjs\").QuantumForge {\n return getModule().QuantumForge;\n}\n\n/**\n * Convenience re-exports for common operations.\n * These will throw if module not loaded.\n */\nexport function getVersion(): string {\n return getQuantumForge().getVersion();\n}\n\nexport function getMaxDimension(): number {\n return getQuantumForge().getMaxDimension();\n}\n\nexport function getMaxQudits(): number {\n return getQuantumForge().getMaxQudits();\n}\n\nexport function getMaxStateSize(): number {\n return getQuantumForge().getMaxStateSize();\n}\n\n/**\n * Get the WASM memory bytes (for analytics).\n */\nexport function getWasmMemoryBytes(): number | null {\n if (!isInitialized) return null;\n try {\n const qf = getQuantumForge() as any;\n return typeof qf.getMemoryBytes === \"function\" ? qf.getMemoryBytes() : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the required attribution text for display in your application.\n * Include this in a user-visible location (credits screen, about page, etc.).\n */\nexport function getAttribution(): string {\n return \"Powered by Quantum Forge \\u2014 \\u00A9 Quantum Native \\u2014 quantumnative.io\";\n}\n\n/**\n * Register the Quantum Forge service worker for offline WASM caching.\n * Call once from your game controller after page load.\n * The SW caches WASM artifacts on first fetch so subsequent loads work offline.\n *\n * @param swPath - Path to the service worker file. Default: \"/quantum-forge-sw.js\"\n */\nexport async function registerServiceWorker(\n swPath = \"/quantum-forge-sw.js\",\n): Promise<ServiceWorkerRegistration | null> {\n if (!(\"serviceWorker\" in navigator)) return null;\n try {\n const reg = await navigator.serviceWorker.register(swPath);\n logger?.info?.(`Service worker registered (scope: ${reg.scope})`, \"QuantumForgeLoader\");\n return reg;\n } catch (err) {\n logger?.warn?.(\n `Service worker registration failed: ${err instanceof Error ? err.message : err}`,\n \"QuantumForgeLoader\",\n );\n return null;\n }\n}\n","/**\n * QuantumPropertyManager — manages quantum property lifecycles.\n *\n * Handles the common pattern of acquiring, pooling, and releasing WASM\n * QuantumProperty handles. Games either extend this class or compose it\n * to add game-specific quantum operations via getModule().\n *\n * Property pooling is critical: measured/removed properties are recycled\n * to avoid growing the tensor product and hitting qudit limits.\n *\n * For opt-in operation recording, attach a QuantumRecorder via setRecorder().\n */\n\nimport { getModule } from \"./QuantumForgeLoader\";\nimport type { LoggerInterface } from \"../logging/Logger\";\nimport type { QuantumProperty as QFProperty } from \"./quantum-forge-api.mjs\";\n\nexport interface PredicateSpec {\n property: QFProperty;\n value: number;\n isEqual: boolean;\n}\n\nexport interface QuantumRecorderHook {\n onAcquire?(prop: QFProperty): void;\n onRelease?(prop: QFProperty, value: number): void;\n onSetProperty?(id: string, prop: QFProperty): void;\n onDeleteProperty?(id: string): void;\n}\n\nexport class QuantumPropertyManager {\n readonly dimension: number;\n private properties: Map<string, QFProperty> = new Map();\n private pool: QFProperty[] = [];\n protected logger?: LoggerInterface;\n private _recorder?: QuantumRecorderHook;\n\n constructor(options: { dimension?: number; logger?: LoggerInterface } = {}) {\n this.dimension = options.dimension ?? 2;\n this.logger = options.logger;\n }\n\n // -- Recorder hook --\n\n /** Attach an optional recorder for operation logging. */\n setRecorder(recorder: QuantumRecorderHook | undefined): void {\n this._recorder = recorder;\n }\n\n /** Get the currently attached recorder, if any. */\n getRecorder(): QuantumRecorderHook | undefined {\n return this._recorder;\n }\n\n // -- Property lifecycle --\n\n /**\n * Get a property at |0⟩ — reuses a pooled one if available,\n * otherwise creates a fresh standalone property.\n */\n acquireProperty(): QFProperty {\n let prop: QFProperty;\n if (this.pool.length > 0) {\n prop = this.pool.pop()!;\n } else {\n prop = getModule().QuantumForge.createQuantumProperty(this.dimension);\n }\n this._recorder?.onAcquire?.(prop);\n return prop;\n }\n\n /**\n * Return a property to the pool after resetting it to |0⟩.\n * Uses the `reset` primitive which applies non-fractional cycles —\n * correct for all dimensions (no superposition created).\n */\n releaseProperty(prop: QFProperty, measuredValue: number): void {\n this._recorder?.onRelease?.(prop, measuredValue);\n getModule().reset(prop, measuredValue);\n this.pool.push(prop);\n }\n\n // -- ID mapping --\n\n setProperty(id: string, prop: QFProperty): void {\n this._recorder?.onSetProperty?.(id, prop);\n this.properties.set(id, prop);\n }\n\n getProperty(id: string): QFProperty | undefined {\n return this.properties.get(id);\n }\n\n deleteProperty(id: string): void {\n this._recorder?.onDeleteProperty?.(id);\n this.properties.delete(id);\n }\n\n hasProperty(id: string): boolean {\n return this.properties.has(id);\n }\n\n // -- Public operations --\n\n /**\n * Remove a property by ID: measure it, pool the handle, delete the mapping.\n */\n removeProperty(id: string): void {\n const prop = this.properties.get(id);\n if (prop) {\n const [value] = getModule().measure_properties([prop]);\n this.releaseProperty(prop, value);\n }\n this.deleteProperty(id);\n }\n\n /** Clear all properties, pool, and recorder. */\n clear(): void {\n this.properties.clear();\n this.pool = [];\n }\n\n get size(): number {\n return this.properties.size;\n }\n\n get poolSize(): number {\n return this.pool.length;\n }\n\n // -- WASM module access --\n\n getModule(): ReturnType<typeof getModule> {\n return getModule();\n }\n\n // -- Internal access for QuantumRecorder replay --\n\n /** @internal — used by QuantumRecorder.replayLog() to restore pool state. */\n _setPool(pool: QFProperty[]): void {\n this.pool = pool;\n }\n\n /** @internal — used by QuantumRecorder to enumerate live handles. */\n _getProperties(): Map<string, QFProperty> {\n return this.properties;\n }\n\n /** @internal — used by QuantumRecorder to enumerate pool handles. */\n _getPool(): QFProperty[] {\n return this.pool;\n }\n}\n","/**\n * QuantumRecorder — opt-in recording and replay of quantum operations.\n *\n * Attach to a QuantumPropertyManager via `manager.setRecorder(recorder)`.\n * When recording is active, lifecycle hooks log every state-mutating\n * operation. The log can be replayed via replayLog() to recreate\n * identical quantum state — measurements are forced to their recorded\n * outcomes using forced_measure_properties.\n *\n * For gate recording, call wrapGate() around each WASM gate call.\n */\n\nimport { getModule } from \"./QuantumForgeLoader\";\nimport type { QuantumPropertyManager, QuantumRecorderHook } from \"./QuantumPropertyManager\";\nimport type { QuantumOperation, SerializedPredicate } from \"./QuantumOperationLog\";\nimport type { QuantumProperty as QFProperty, Predicate as QFPredicate } from \"./quantum-forge-api.mjs\";\n\nexport interface PredicateSpec {\n property: QFProperty;\n value: number;\n isEqual: boolean;\n}\n\nexport class QuantumRecorder implements QuantumRecorderHook {\n private _recording = false;\n private _log: QuantumOperation[] = [];\n private _handleToIndex: Map<QFProperty, number> = new Map();\n private _nextIndex = 0;\n private readonly _manager: QuantumPropertyManager;\n\n constructor(manager: QuantumPropertyManager) {\n this._manager = manager;\n }\n\n // -- QuantumRecorderHook implementation --\n\n onAcquire(prop: QFProperty): void {\n if (!this._recording) return;\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n this._log.push({ op: \"acquire\", index });\n }\n\n onRelease(prop: QFProperty, value: number): void {\n if (!this._recording) return;\n const index = this._handleToIndex.get(prop);\n if (index !== undefined) {\n this._log.push({ op: \"release\", index, value });\n }\n }\n\n onSetProperty(id: string, prop: QFProperty): void {\n if (!this._recording) return;\n const index = this._handleToIndex.get(prop);\n if (index !== undefined) {\n this._log.push({ op: \"assign\", index, id });\n }\n }\n\n onDeleteProperty(id: string): void {\n if (!this._recording) return;\n this._log.push({ op: \"unassign\", id });\n }\n\n // -- Gate recording --\n\n /**\n * Build WASM predicate objects from PredicateSpec array.\n */\n buildWasmPredicates(specs: PredicateSpec[]): QFPredicate[] {\n return specs.map((s) =>\n s.isEqual ? s.property.is(s.value) : s.property.is_not(s.value),\n );\n }\n\n /**\n * Serialize predicates for the operation log.\n */\n serializePredicates(specs: PredicateSpec[]): SerializedPredicate[] | undefined {\n if (specs.length === 0) return undefined;\n return specs.map((s) => {\n const index = this._handleToIndex.get(s.property);\n return {\n propertyIndex: index ?? -1,\n value: s.value,\n isEqual: s.isEqual,\n };\n });\n }\n\n /**\n * Record a gate operation. Call this when recording is active\n * and you want to log a gate call for replay.\n */\n recordOp(op: QuantumOperation): void {\n if (!this._recording) return;\n this._log.push(op);\n }\n\n /**\n * Get the recorded index for a property handle.\n */\n getIndex(prop: QFProperty): number | undefined {\n return this._handleToIndex.get(prop);\n }\n\n // -- Recording API --\n\n /** Begin recording quantum operations. Resets any existing log. */\n startRecording(): void {\n this._recording = true;\n this._log = [];\n this._handleToIndex.clear();\n this._nextIndex = 0;\n\n // Assign indices to all currently-live handles so operations\n // on pre-existing properties are tracked correctly.\n for (const prop of this._manager._getProperties().values()) {\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n }\n for (const prop of this._manager._getPool()) {\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n }\n }\n\n /** Stop recording and return the captured log. */\n stopRecording(): QuantumOperation[] {\n this._recording = false;\n return [...this._log];\n }\n\n /** Whether recording is currently active. */\n isRecording(): boolean {\n return this._recording;\n }\n\n /** Get a copy of the current operation log (even while recording). */\n getOperationLog(): QuantumOperation[] {\n return [...this._log];\n }\n\n /**\n * Replay an operation log to recreate quantum state from scratch.\n * Clears all existing state on the manager first. Measurements are\n * forced to their recorded outcomes via forced_measure_properties.\n */\n replayLog(operations: QuantumOperation[]): void {\n // Clear manager state\n this._manager.clear();\n this._recording = false;\n this._log = [];\n this._handleToIndex.clear();\n this._nextIndex = 0;\n\n const module = getModule();\n const dimension = this._manager.dimension;\n const indexToHandle = new Map<number, QFProperty>();\n const replayPool: QFProperty[] = [];\n\n for (const entry of operations) {\n switch (entry.op) {\n case \"acquire\": {\n let prop: QFProperty;\n if (replayPool.length > 0) {\n prop = replayPool.pop()!;\n } else {\n prop = module.QuantumForge.createQuantumProperty(dimension);\n }\n indexToHandle.set(entry.index, prop);\n break;\n }\n\n case \"release\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n module.reset(prop, entry.value);\n replayPool.push(prop);\n }\n break;\n }\n\n case \"assign\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n this._manager._getProperties().set(entry.id, prop);\n }\n break;\n }\n\n case \"unassign\": {\n this._manager._getProperties().delete(entry.id);\n break;\n }\n\n case \"cycle\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.cycle(prop);\n } else {\n module.cycle(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"shift\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.shift(prop);\n } else {\n module.shift(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"i_swap\": {\n const prop1 = indexToHandle.get(entry.index1);\n const prop2 = indexToHandle.get(entry.index2);\n if (prop1 && prop2) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.i_swap(prop1, prop2, entry.fraction, preds);\n }\n break;\n }\n\n case \"clock\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.clock(prop, entry.fraction, preds);\n }\n break;\n }\n\n case \"y\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.y(prop);\n } else {\n module.y(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"hadamard\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.hadamard(prop);\n } else {\n module.hadamard(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"inverse_hadamard\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.inverse_hadamard(prop, preds);\n }\n break;\n }\n\n case \"swap\": {\n const prop1 = indexToHandle.get(entry.index1);\n const prop2 = indexToHandle.get(entry.index2);\n if (prop1 && prop2) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.swap(prop1, prop2, preds);\n }\n break;\n }\n\n case \"phase_rotate\": {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (preds) {\n module.phase_rotate(preds, entry.angle);\n }\n break;\n }\n\n case \"measure_predicate\": {\n // During replay, we don't force measure_predicate outcomes —\n // the state should be deterministic from prior forced measurements.\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (preds) {\n module.measure_predicate(preds);\n }\n break;\n }\n\n case \"reset\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n module.reset(prop, entry.value);\n }\n break;\n }\n\n case \"measure\": {\n const props = entry.indices.map((i) => indexToHandle.get(i)).filter(Boolean) as QFProperty[];\n if (props.length === entry.indices.length) {\n module.forced_measure_properties(props, entry.outcomes);\n }\n break;\n }\n }\n }\n\n // Restore internal pool from replay pool\n this._manager._setPool(replayPool);\n\n // Rebuild _handleToIndex from indexToHandle for future recording\n this._handleToIndex.clear();\n for (const [index, handle] of indexToHandle) {\n this._handleToIndex.set(handle, index);\n }\n this._nextIndex = operations.reduce((max, op) => {\n if (\"index\" in op && typeof op.index === \"number\") return Math.max(max, op.index + 1);\n if (\"index1\" in op) {\n const dualOp = op as { index1: number; index2: number };\n return Math.max(max, dualOp.index1 + 1, dualOp.index2 + 1);\n }\n if (\"indices\" in op) {\n const measureOp = op as { indices: number[] };\n const maxIdx = Math.max(...measureOp.indices);\n return Math.max(max, maxIdx + 1);\n }\n return max;\n }, 0);\n }\n\n // -- Private helpers --\n\n private _replayPredicates(\n serialized: SerializedPredicate[] | undefined,\n indexToHandle: Map<number, QFProperty>,\n ): QFPredicate[] | undefined {\n if (!serialized || serialized.length === 0) return undefined;\n const preds: QFPredicate[] = [];\n for (const sp of serialized) {\n const prop = indexToHandle.get(sp.propertyIndex);\n if (!prop) return undefined;\n preds.push(sp.isEqual ? prop.is(sp.value) : prop.is_not(sp.value));\n }\n return preds;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/quantum/QuantumForgeLoader.ts","../../src/quantum/QuantumPropertyManager.ts","../../src/quantum/QuantumRecorder.ts","../../src/quantum/index.ts"],"sourcesContent":["/**\n * Quantum Forge Loader - Lazy loader for Quantum Forge WASM module\n *\n * Defers WASM loading from the critical path while preloading in background\n * so it's ready when needed. If not ready, callers can show loading UI.\n * \n * IMPORTANT: Quantum Forge is built from source and copied to dist/ as\n * quantum-forge-web-api.mjs (not an npm package). Run 'npm run setup' to build.\n */\n\nimport type { LoggerInterface } from \"../logging/Logger\";\n\n// Type for the quantum forge module\ntype QuantumForgeModuleType = typeof import(\"./quantum-forge-api.mjs\");\n\n// Configurable base path for WASM artifacts\nlet wasmBasePath = \"/quantum-forge\";\n\n/**\n * Set the base URL path where Quantum Forge WASM files are served.\n * Default is \"/quantum-forge\" which matches the Vite plugin's serve path.\n * Consumers using the Vite plugin don't need to call this.\n */\nexport function setWasmBasePath(path: string): void {\n wasmBasePath = path.endsWith(\"/\") ? path.slice(0, -1) : path;\n}\n\n/**\n * Select a named WASM build variant (e.g. \"d7n10\").\n * Sugar for `setWasmBasePath(\"/quantum-forge-{name}\")`.\n *\n * Must be called before `ensureLoaded()`. If the module is already loaded,\n * a warning is logged and the call is ignored.\n */\nexport function useQuantumForgeBuild(name: string): void {\n if (isInitialized) {\n logger?.warn?.(\n `useQuantumForgeBuild(\"${name}\") called after module already loaded — ignoring. Call before ensureLoaded().`,\n \"QuantumForgeLoader\",\n );\n return;\n }\n setWasmBasePath(`/quantum-forge-${name}`);\n}\n\n// Cache the module and initialization state\nlet quantumForgeModule: QuantumForgeModuleType | null = null;\nlet initPromise: Promise<void> | null = null;\nlet isInitialized = false;\nlet loadStarted = false;\n\n// Logger reference (set during startBackgroundLoad)\nlet logger: LoggerInterface | undefined;\n\n/**\n * Start loading the WASM module in the background.\n * Call this after the page has rendered (e.g., after DOMContentLoaded or initial paint).\n */\nexport function startBackgroundLoad(loggerRef?: LoggerInterface): void {\n if (loadStarted) return;\n loadStarted = true;\n logger = loggerRef;\n\n // Use requestIdleCallback if available, otherwise setTimeout\n const scheduleLoad = (callback: () => void) => {\n if (typeof requestIdleCallback === \"function\") {\n requestIdleCallback(callback, { timeout: 2000 });\n } else {\n setTimeout(callback, 100);\n }\n };\n\n scheduleLoad(() => {\n logger?.info?.(\"Starting background Quantum Forge load\", \"QuantumForgeLoader\");\n // Trigger the load but don't await - let it happen in background\n ensureLoaded().catch((err) => {\n logger?.warn?.(\n `Background Quantum Forge load failed: ${err?.message ?? err}`,\n \"QuantumForgeLoader\",\n );\n });\n });\n}\n\n/**\n * Ensure Quantum Forge is loaded and initialized.\n * Returns a promise that resolves when the module is ready.\n * Can be called multiple times - will return the same promise.\n */\nexport async function ensureLoaded(): Promise<void> {\n if (isInitialized) return;\n\n if (initPromise) {\n await initPromise;\n return;\n }\n\n initPromise = (async () => {\n const startTime = performance.now();\n logger?.info?.(\"Loading Quantum Forge WASM module...\", \"QuantumForgeLoader\");\n\n // Dynamic import of Quantum Forge WASM module from the configured base path\n const modulePath = `${wasmBasePath}/quantum-forge-web-api.mjs`;\n const mod = (await import(/* @vite-ignore */ modulePath)) as QuantumForgeModuleType;\n quantumForgeModule = mod;\n\n // Initialize the WASM\n await mod.QuantumForge.initialize();\n\n const version = mod.QuantumForge.getVersion();\n const maxDim = mod.QuantumForge.getMaxDimension();\n const maxQudits = mod.QuantumForge.getMaxQudits();\n const elapsed = (performance.now() - startTime).toFixed(0);\n\n logger?.info?.(\n `Quantum Forge v${version} ready in ${elapsed}ms (max dim: ${maxDim}, max qudits: ${maxQudits})`,\n \"QuantumForgeLoader\",\n );\n\n console.log(\n \"%c\\u269B Powered by Quantum Forge %c quantumnative.io \",\n \"background: #6366f1; color: white; padding: 2px 6px; border-radius: 3px 0 0 3px; font-weight: bold;\",\n \"background: #1e1b4b; color: #c7d2fe; padding: 2px 6px; border-radius: 0 3px 3px 0;\",\n );\n\n isInitialized = true;\n })();\n\n // Handle errors by clearing the promise so retry is possible\n initPromise.catch(() => {\n initPromise = null;\n });\n\n await initPromise;\n}\n\n/**\n * Check if Quantum Forge is ready to use (non-blocking).\n */\nexport function isReady(): boolean {\n return isInitialized;\n}\n\n/**\n * Get the loaded module. Throws if not loaded.\n * For synchronous access after ensuring it's loaded.\n */\nexport function getModule(): typeof import(\"./quantum-forge-api.mjs\") {\n if (!quantumForgeModule || !isInitialized) {\n throw new Error(\"QuantumForge not loaded. Call ensureLoaded() first and await it.\");\n }\n return quantumForgeModule;\n}\n\n/**\n * Get the QuantumForge class from the loaded module.\n */\nexport function getQuantumForge(): typeof import(\"./quantum-forge-api.mjs\").QuantumForge {\n return getModule().QuantumForge;\n}\n\n/**\n * Convenience re-exports for common operations.\n * These will throw if module not loaded.\n */\nexport function getVersion(): string {\n return getQuantumForge().getVersion();\n}\n\nexport function getMaxDimension(): number {\n return getQuantumForge().getMaxDimension();\n}\n\nexport function getMaxQudits(): number {\n return getQuantumForge().getMaxQudits();\n}\n\nexport function getMaxStateSize(): number {\n return getQuantumForge().getMaxStateSize();\n}\n\n/**\n * Get the WASM memory bytes (for analytics).\n */\nexport function getWasmMemoryBytes(): number | null {\n if (!isInitialized) return null;\n try {\n const qf = getQuantumForge() as any;\n return typeof qf.getMemoryBytes === \"function\" ? qf.getMemoryBytes() : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the required attribution text for display in your application.\n * Include this in a user-visible location (credits screen, about page, etc.).\n */\nexport function getAttribution(): string {\n return \"Powered by Quantum Forge \\u2014 \\u00A9 Quantum Native \\u2014 quantumnative.io\";\n}\n\n/**\n * Register the Quantum Forge service worker for offline WASM caching.\n * Call once from your game controller after page load.\n * The SW caches WASM artifacts on first fetch so subsequent loads work offline.\n *\n * @param swPath - Path to the service worker file. Default: \"/quantum-forge-sw.js\"\n */\nexport async function registerServiceWorker(\n swPath = \"/quantum-forge-sw.js\",\n): Promise<ServiceWorkerRegistration | null> {\n if (!(\"serviceWorker\" in navigator)) return null;\n try {\n const reg = await navigator.serviceWorker.register(swPath);\n logger?.info?.(`Service worker registered (scope: ${reg.scope})`, \"QuantumForgeLoader\");\n return reg;\n } catch (err) {\n logger?.warn?.(\n `Service worker registration failed: ${err instanceof Error ? err.message : err}`,\n \"QuantumForgeLoader\",\n );\n return null;\n }\n}\n","/**\n * QuantumPropertyManager — manages quantum property lifecycles.\n *\n * Handles the common pattern of acquiring, pooling, and releasing WASM\n * QuantumProperty handles. Games either extend this class or compose it\n * to add game-specific quantum operations via getModule().\n *\n * Property pooling is critical: measured/removed properties are recycled\n * to avoid growing the tensor product and hitting qudit limits.\n *\n * For opt-in operation recording, attach a QuantumRecorder via setRecorder().\n */\n\nimport { getModule } from \"./QuantumForgeLoader\";\nimport type { LoggerInterface } from \"../logging/Logger\";\nimport type { QuantumProperty as QFProperty } from \"./quantum-forge-api.mjs\";\n\nexport interface PredicateSpec {\n property: QFProperty;\n value: number;\n isEqual: boolean;\n}\n\nexport interface QuantumRecorderHook {\n onAcquire?(prop: QFProperty): void;\n onRelease?(prop: QFProperty, value: number): void;\n onSetProperty?(id: string, prop: QFProperty): void;\n onDeleteProperty?(id: string): void;\n}\n\nexport class QuantumPropertyManager {\n readonly dimension: number;\n private properties: Map<string, QFProperty> = new Map();\n private pool: QFProperty[] = [];\n protected logger?: LoggerInterface;\n private _recorder?: QuantumRecorderHook;\n\n constructor(options: { dimension?: number; logger?: LoggerInterface } = {}) {\n this.dimension = options.dimension ?? 2;\n this.logger = options.logger;\n }\n\n // -- Recorder hook --\n\n /** Attach an optional recorder for operation logging. */\n setRecorder(recorder: QuantumRecorderHook | undefined): void {\n this._recorder = recorder;\n }\n\n /** Get the currently attached recorder, if any. */\n getRecorder(): QuantumRecorderHook | undefined {\n return this._recorder;\n }\n\n // -- Property lifecycle --\n\n /**\n * Get a property at |0⟩ — reuses a pooled one if available,\n * otherwise creates a fresh standalone property.\n */\n acquireProperty(): QFProperty {\n let prop: QFProperty;\n if (this.pool.length > 0) {\n prop = this.pool.pop()!;\n } else {\n prop = getModule().QuantumForge.createQuantumProperty(this.dimension);\n }\n this._recorder?.onAcquire?.(prop);\n return prop;\n }\n\n /**\n * Return a property to the pool after resetting it to |0⟩.\n * Uses the `reset` primitive which applies non-fractional cycles —\n * correct for all dimensions (no superposition created).\n */\n releaseProperty(prop: QFProperty, measuredValue: number): void {\n this._recorder?.onRelease?.(prop, measuredValue);\n getModule().reset(prop, measuredValue);\n this.pool.push(prop);\n }\n\n // -- ID mapping --\n\n setProperty(id: string, prop: QFProperty): void {\n this._recorder?.onSetProperty?.(id, prop);\n this.properties.set(id, prop);\n }\n\n getProperty(id: string): QFProperty | undefined {\n return this.properties.get(id);\n }\n\n deleteProperty(id: string): void {\n this._recorder?.onDeleteProperty?.(id);\n this.properties.delete(id);\n }\n\n hasProperty(id: string): boolean {\n return this.properties.has(id);\n }\n\n // -- Public operations --\n\n /**\n * Remove a property by ID: measure it, pool the handle, delete the mapping.\n */\n removeProperty(id: string): void {\n const prop = this.properties.get(id);\n if (prop) {\n const [value] = getModule().measure_properties([prop]);\n this.releaseProperty(prop, value);\n }\n this.deleteProperty(id);\n }\n\n /** Clear all properties, pool, and recorder. */\n clear(): void {\n this.properties.clear();\n this.pool = [];\n }\n\n get size(): number {\n return this.properties.size;\n }\n\n get poolSize(): number {\n return this.pool.length;\n }\n\n // -- WASM module access --\n\n getModule(): ReturnType<typeof getModule> {\n return getModule();\n }\n\n // -- Internal access for QuantumRecorder replay --\n\n /** @internal — used by QuantumRecorder.replayLog() to restore pool state. */\n _setPool(pool: QFProperty[]): void {\n this.pool = pool;\n }\n\n /** @internal — used by QuantumRecorder to enumerate live handles. */\n _getProperties(): Map<string, QFProperty> {\n return this.properties;\n }\n\n /** @internal — used by QuantumRecorder to enumerate pool handles. */\n _getPool(): QFProperty[] {\n return this.pool;\n }\n}\n","/**\n * QuantumRecorder — opt-in recording and replay of quantum operations.\n *\n * Attach to a QuantumPropertyManager via `manager.setRecorder(recorder)`.\n * When recording is active, lifecycle hooks log every state-mutating\n * operation. The log can be replayed via replayLog() to recreate\n * identical quantum state — measurements are forced to their recorded\n * outcomes using forced_measure_properties.\n *\n * For gate recording, call wrapGate() around each WASM gate call.\n */\n\nimport { getModule } from \"./QuantumForgeLoader\";\nimport type { QuantumPropertyManager, QuantumRecorderHook } from \"./QuantumPropertyManager\";\nimport type { QuantumOperation, SerializedPredicate } from \"./QuantumOperationLog\";\nimport type { QuantumProperty as QFProperty, Predicate as QFPredicate } from \"./quantum-forge-api.mjs\";\n\nexport interface PredicateSpec {\n property: QFProperty;\n value: number;\n isEqual: boolean;\n}\n\nexport class QuantumRecorder implements QuantumRecorderHook {\n private _recording = false;\n private _log: QuantumOperation[] = [];\n private _handleToIndex: Map<QFProperty, number> = new Map();\n private _nextIndex = 0;\n private readonly _manager: QuantumPropertyManager;\n\n constructor(manager: QuantumPropertyManager) {\n this._manager = manager;\n }\n\n // -- QuantumRecorderHook implementation --\n\n onAcquire(prop: QFProperty): void {\n if (!this._recording) return;\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n this._log.push({ op: \"acquire\", index });\n }\n\n onRelease(prop: QFProperty, value: number): void {\n if (!this._recording) return;\n const index = this._handleToIndex.get(prop);\n if (index !== undefined) {\n this._log.push({ op: \"release\", index, value });\n }\n }\n\n onSetProperty(id: string, prop: QFProperty): void {\n if (!this._recording) return;\n const index = this._handleToIndex.get(prop);\n if (index !== undefined) {\n this._log.push({ op: \"assign\", index, id });\n }\n }\n\n onDeleteProperty(id: string): void {\n if (!this._recording) return;\n this._log.push({ op: \"unassign\", id });\n }\n\n // -- Gate recording --\n\n /**\n * Build WASM predicate objects from PredicateSpec array.\n */\n buildWasmPredicates(specs: PredicateSpec[]): QFPredicate[] {\n return specs.map((s) =>\n s.isEqual ? s.property.is(s.value) : s.property.is_not(s.value),\n );\n }\n\n /**\n * Serialize predicates for the operation log.\n */\n serializePredicates(specs: PredicateSpec[]): SerializedPredicate[] | undefined {\n if (specs.length === 0) return undefined;\n return specs.map((s) => {\n const index = this._handleToIndex.get(s.property);\n return {\n propertyIndex: index ?? -1,\n value: s.value,\n isEqual: s.isEqual,\n };\n });\n }\n\n /**\n * Record a gate operation. Call this when recording is active\n * and you want to log a gate call for replay.\n */\n recordOp(op: QuantumOperation): void {\n if (!this._recording) return;\n this._log.push(op);\n }\n\n /**\n * Get the recorded index for a property handle.\n */\n getIndex(prop: QFProperty): number | undefined {\n return this._handleToIndex.get(prop);\n }\n\n // -- Recording API --\n\n /** Begin recording quantum operations. Resets any existing log. */\n startRecording(): void {\n this._recording = true;\n this._log = [];\n this._handleToIndex.clear();\n this._nextIndex = 0;\n\n // Assign indices to all currently-live handles so operations\n // on pre-existing properties are tracked correctly.\n for (const prop of this._manager._getProperties().values()) {\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n }\n for (const prop of this._manager._getPool()) {\n const index = this._nextIndex++;\n this._handleToIndex.set(prop, index);\n }\n }\n\n /** Stop recording and return the captured log. */\n stopRecording(): QuantumOperation[] {\n this._recording = false;\n return [...this._log];\n }\n\n /** Whether recording is currently active. */\n isRecording(): boolean {\n return this._recording;\n }\n\n /** Get a copy of the current operation log (even while recording). */\n getOperationLog(): QuantumOperation[] {\n return [...this._log];\n }\n\n /**\n * Replay an operation log to recreate quantum state from scratch.\n * Clears all existing state on the manager first. Measurements are\n * forced to their recorded outcomes via forced_measure_properties.\n */\n replayLog(operations: QuantumOperation[]): void {\n // Clear manager state\n this._manager.clear();\n this._recording = false;\n this._log = [];\n this._handleToIndex.clear();\n this._nextIndex = 0;\n\n const module = getModule();\n const dimension = this._manager.dimension;\n const indexToHandle = new Map<number, QFProperty>();\n const replayPool: QFProperty[] = [];\n\n for (const entry of operations) {\n switch (entry.op) {\n case \"acquire\": {\n let prop: QFProperty;\n if (replayPool.length > 0) {\n prop = replayPool.pop()!;\n } else {\n prop = module.QuantumForge.createQuantumProperty(dimension);\n }\n indexToHandle.set(entry.index, prop);\n break;\n }\n\n case \"release\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n module.reset(prop, entry.value);\n replayPool.push(prop);\n }\n break;\n }\n\n case \"assign\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n this._manager._getProperties().set(entry.id, prop);\n }\n break;\n }\n\n case \"unassign\": {\n this._manager._getProperties().delete(entry.id);\n break;\n }\n\n case \"cycle\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.cycle(prop);\n } else {\n module.cycle(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"shift\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.shift(prop);\n } else {\n module.shift(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"i_swap\": {\n const prop1 = indexToHandle.get(entry.index1);\n const prop2 = indexToHandle.get(entry.index2);\n if (prop1 && prop2) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.i_swap(prop1, prop2, entry.fraction, preds);\n }\n break;\n }\n\n case \"clock\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.clock(prop, entry.fraction, preds);\n }\n break;\n }\n\n case \"y\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.y(prop);\n } else {\n module.y(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"hadamard\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (entry.fraction === 1 && !preds) {\n module.hadamard(prop);\n } else {\n module.hadamard(prop, entry.fraction, preds);\n }\n }\n break;\n }\n\n case \"inverse_hadamard\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.inverse_hadamard(prop, preds);\n }\n break;\n }\n\n case \"swap\": {\n const prop1 = indexToHandle.get(entry.index1);\n const prop2 = indexToHandle.get(entry.index2);\n if (prop1 && prop2) {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n module.swap(prop1, prop2, preds);\n }\n break;\n }\n\n case \"phase_rotate\": {\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (preds) {\n module.phase_rotate(preds, entry.angle);\n }\n break;\n }\n\n case \"measure_predicate\": {\n // During replay, we don't force measure_predicate outcomes —\n // the state should be deterministic from prior forced measurements.\n const preds = this._replayPredicates(entry.predicates, indexToHandle);\n if (preds) {\n module.measure_predicate(preds);\n }\n break;\n }\n\n case \"reset\": {\n const prop = indexToHandle.get(entry.index);\n if (prop) {\n module.reset(prop, entry.value);\n }\n break;\n }\n\n case \"measure\": {\n const props = entry.indices.map((i) => indexToHandle.get(i)).filter(Boolean) as QFProperty[];\n if (props.length === entry.indices.length) {\n module.forced_measure_properties(props, entry.outcomes);\n }\n break;\n }\n }\n }\n\n // Restore internal pool from replay pool\n this._manager._setPool(replayPool);\n\n // Rebuild _handleToIndex from indexToHandle for future recording\n this._handleToIndex.clear();\n for (const [index, handle] of indexToHandle) {\n this._handleToIndex.set(handle, index);\n }\n this._nextIndex = operations.reduce((max, op) => {\n if (\"index\" in op && typeof op.index === \"number\") return Math.max(max, op.index + 1);\n if (\"index1\" in op) {\n const dualOp = op as { index1: number; index2: number };\n return Math.max(max, dualOp.index1 + 1, dualOp.index2 + 1);\n }\n if (\"indices\" in op) {\n const measureOp = op as { indices: number[] };\n const maxIdx = Math.max(...measureOp.indices);\n return Math.max(max, maxIdx + 1);\n }\n return max;\n }, 0);\n }\n\n // -- Private helpers --\n\n private _replayPredicates(\n serialized: SerializedPredicate[] | undefined,\n indexToHandle: Map<number, QFProperty>,\n ): QFPredicate[] | undefined {\n if (!serialized || serialized.length === 0) return undefined;\n const preds: QFPredicate[] = [];\n for (const sp of serialized) {\n const prop = indexToHandle.get(sp.propertyIndex);\n if (!prop) return undefined;\n preds.push(sp.isEqual ? prop.is(sp.value) : prop.is_not(sp.value));\n }\n return preds;\n }\n}\n","export {\n startBackgroundLoad,\n ensureLoaded,\n isReady,\n getModule,\n getQuantumForge,\n getVersion,\n getMaxDimension,\n getMaxQudits,\n getMaxStateSize,\n getWasmMemoryBytes,\n setWasmBasePath,\n useQuantumForgeBuild,\n getAttribution,\n registerServiceWorker,\n} from \"./QuantumForgeLoader\";\nexport { QuantumPropertyManager } from \"./QuantumPropertyManager\";\nexport type { PredicateSpec, QuantumRecorderHook } from \"./QuantumPropertyManager\";\nexport { QuantumRecorder } from \"./QuantumRecorder\";\nexport type { QuantumOperation, SerializedPredicate } from \"./QuantumOperationLog\";\nexport type { OpCode, BatchOp, BatchResult, OpNum } from \"./quantum-forge-api.mjs\";\n\n/** Numeric opcode constants for tape encoding. Matches C++ OpCode enum. */\nexport const OP = {\n CYCLE: 0, SHIFT: 1, CLOCK: 2,\n X: 3, Z: 4, Y: 5,\n HADAMARD: 6, INVERSE_HADAMARD: 7,\n SWAP: 8, I_SWAP: 9,\n PHASE_ROTATE: 10,\n ROTATE_BASIS_PAIR: 11,\n} as const;\n"],"mappings":"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","names":[]}
@@ -54,7 +54,13 @@ declare function phase_rotate(predicates: Predicate[], angle: number): void;
54
54
  declare function measure_properties(props: QuantumProperty[]): number[];
55
55
  declare function forced_measure_properties(props: QuantumProperty[], forcedValues: number[]): number[];
56
56
  declare function measure_predicate(predicates: Predicate[]): number;
57
+ /** Force a predicate measurement to a specific outcome.
58
+ * If the forced value is impossible (zero probability), falls back to
59
+ * stochastic measurement and returns the actual outcome instead of throwing. */
57
60
  declare function forced_measure_predicate(predicates: Predicate[], forcedValue: number): number;
61
+ /** Get the probability that all predicates are simultaneously satisfied.
62
+ * Read-only — does not collapse or modify quantum state. */
63
+ declare function predicate_probability(predicates: Predicate[]): number;
58
64
  declare function probabilities(props: QuantumProperty[]): Array<{
59
65
  probability: number;
60
66
  qudit_values: number[];
@@ -174,4 +180,4 @@ declare class QuantumForge {
174
180
  static getMaxStateSize(): number;
175
181
  }
176
182
 
177
- export { type BatchOp, type BatchResult, OP, type OpCode, type OpNum, Predicate, QuantumForge, QuantumProperty, QuantumSimulation, clock, cycle, executeBatch, executeBatchTape, forced_measure_predicate, forced_measure_properties, hadamard, i_swap, inverse_hadamard, measure_predicate, measure_properties, phase_rotate, probabilities, reduced_density_matrix, reset, shift, swap, x, y, z };
183
+ export { type BatchOp, type BatchResult, OP, type OpCode, type OpNum, Predicate, QuantumForge, QuantumProperty, QuantumSimulation, clock, cycle, executeBatch, executeBatchTape, forced_measure_predicate, forced_measure_properties, hadamard, i_swap, inverse_hadamard, measure_predicate, measure_properties, phase_rotate, predicate_probability, probabilities, reduced_density_matrix, reset, shift, swap, x, y, z };
@@ -177,6 +177,11 @@ function forced_measure_predicate(predicates, forcedValue) {
177
177
  const cppPredicates = predicates.map((pred) => pred.getCppInstance());
178
178
  return wasmModule.forced_measure_predicate(cppPredicates, forcedValue);
179
179
  }
180
+ function predicate_probability(predicates) {
181
+ if (!wasmModule) throw new Error("QuantumForge not initialized. Call QuantumForge.initialize() first.");
182
+ const cppPredicates = predicates.map((pred) => pred.getCppInstance());
183
+ return wasmModule.predicate_probability(cppPredicates);
184
+ }
180
185
  function probabilities(props) {
181
186
  if (!wasmModule) throw new Error("QuantumForge not initialized. Call QuantumForge.initialize() first.");
182
187
  const cppProps = props.map((prop) => prop.getCppInstance());
@@ -292,6 +297,7 @@ export {
292
297
  measure_predicate,
293
298
  measure_properties,
294
299
  phase_rotate,
300
+ predicate_probability,
295
301
  probabilities,
296
302
  reduced_density_matrix,
297
303
  reset,
@@ -54,7 +54,13 @@ declare function phase_rotate(predicates: Predicate[], angle: number): void;
54
54
  declare function measure_properties(props: QuantumProperty[]): number[];
55
55
  declare function forced_measure_properties(props: QuantumProperty[], forcedValues: number[]): number[];
56
56
  declare function measure_predicate(predicates: Predicate[]): number;
57
+ /** Force a predicate measurement to a specific outcome.
58
+ * If the forced value is impossible (zero probability), falls back to
59
+ * stochastic measurement and returns the actual outcome instead of throwing. */
57
60
  declare function forced_measure_predicate(predicates: Predicate[], forcedValue: number): number;
61
+ /** Get the probability that all predicates are simultaneously satisfied.
62
+ * Read-only — does not collapse or modify quantum state. */
63
+ declare function predicate_probability(predicates: Predicate[]): number;
58
64
  declare function probabilities(props: QuantumProperty[]): Array<{
59
65
  probability: number;
60
66
  qudit_values: number[];
@@ -174,4 +180,4 @@ declare class QuantumForge {
174
180
  static getMaxStateSize(): number;
175
181
  }
176
182
 
177
- export { type BatchOp, type BatchResult, OP, type OpCode, type OpNum, Predicate, QuantumForge, QuantumProperty, QuantumSimulation, clock, cycle, executeBatch, executeBatchTape, forced_measure_predicate, forced_measure_properties, hadamard, i_swap, inverse_hadamard, measure_predicate, measure_properties, phase_rotate, probabilities, reduced_density_matrix, reset, shift, swap, x, y, z };
183
+ export { type BatchOp, type BatchResult, OP, type OpCode, type OpNum, Predicate, QuantumForge, QuantumProperty, QuantumSimulation, clock, cycle, executeBatch, executeBatchTape, forced_measure_predicate, forced_measure_properties, hadamard, i_swap, inverse_hadamard, measure_predicate, measure_properties, phase_rotate, predicate_probability, probabilities, reduced_density_matrix, reset, shift, swap, x, y, z };
@@ -177,6 +177,11 @@ function forced_measure_predicate(predicates, forcedValue) {
177
177
  const cppPredicates = predicates.map((pred) => pred.getCppInstance());
178
178
  return wasmModule.forced_measure_predicate(cppPredicates, forcedValue);
179
179
  }
180
+ function predicate_probability(predicates) {
181
+ if (!wasmModule) throw new Error("QuantumForge not initialized. Call QuantumForge.initialize() first.");
182
+ const cppPredicates = predicates.map((pred) => pred.getCppInstance());
183
+ return wasmModule.predicate_probability(cppPredicates);
184
+ }
180
185
  function probabilities(props) {
181
186
  if (!wasmModule) throw new Error("QuantumForge not initialized. Call QuantumForge.initialize() first.");
182
187
  const cppProps = props.map((prop) => prop.getCppInstance());
@@ -292,6 +297,7 @@ export {
292
297
  measure_predicate,
293
298
  measure_properties,
294
299
  phase_rotate,
300
+ predicate_probability,
295
301
  probabilities,
296
302
  reduced_density_matrix,
297
303
  reset,
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quantum-forge",
3
- "version": "2.5.1",
3
+ "version": "2.6.0",
4
4
  "description": "Quantum Forge WASM loader, property manager, and Vite plugin for quantum game development (Qutrit Edition d3n12 + Qubit Edition d2n20).",
5
5
  "type": "module",
6
6
  "exports": {