Skip to content

QuantumPropertyManager (deprecated) ​

Deprecated in 3.0

QuantumPropertyManager and LegacyQuantumRecorder are deprecated in quantum-forge 3.0. They keep working through 3.x and are removed in 4.0. New code should declare properties with quantum() and let handles carry their own gates, measurement, and lifecycle. Migrating to 3.0 maps every manager call to its handle equivalent.

This page is a reference for code that still uses the manager. The 3.x manager works as an adapter, so a game can move over one system at a time: handles and a manager can live in the same program without claiming each other's WASM properties.

What the manager does ​

QuantumPropertyManager pools raw WASM properties behind string ids. A game extends it (or holds one) and calls gates through getModule(), using the WASM names:

typescript
import { QuantumPropertyManager, ensureLoaded } from "quantum-forge/quantum";

await ensureLoaded();

class MyRegistry extends QuantumPropertyManager {
  constructor() {
    super({ dimension: 2 });
  }

  spawn(id: string): void {
    const prop = this.acquireProperty(); // starts at |0⟩
    this.getModule().hadamard(prop);
    this.setProperty(id, prop);
  }

  collapse(id: string): number {
    const prop = this.getProperty(id);
    if (!prop) return 0;
    const [value] = this.getModule().measure_properties([prop]);
    this.deleteProperty(id);
    this.releaseProperty(prop, value); // reset to |0⟩ and return to the pool
    return value;
  }
}

Constructor options ​

OptionTypeDefaultDescription
dimensionnumber2Number of basis states per property
loggerLoggerInterfaceundefinedOptional structured logger

The dimension cannot exceed the loaded build's maximum (3 in the Qutrit Edition, 2 in the Qubit Edition). A manager constructed with a larger one fails when it creates its first property.

Public API ​

MemberDescription
acquireProperty()A property at |0⟩: pops one from the pool, or creates a fresh one
releaseProperty(prop, value)Reset from the measured value to |0⟩ and push onto the pool
setProperty(id, prop)Register a property under a string id
getProperty(id)The WASM property for an id, or undefined
hasProperty(id)Whether an id is registered
deleteProperty(id)Remove the id mapping. Does not release the property
removeProperty(id)Measure, release, and delete in one call
getModule()The WASM module, for gates and queries
dimensionThe configured dimension (read-only)
clear()Drop every id mapping and empty the pool
sizeNumber of registered properties
poolSizeNumber of pooled properties
setRecorder(recorder)Attach a LegacyQuantumRecorder
getRecorder()The attached recorder, or undefined

Measured values are basis indices (0, 1, ...), not declared values. Predicates are WASM objects built with prop.is(value) and prop.is_not(value), passed as the last argument of a getModule() gate. A predicated discrete gate passes undefined for the fraction: m.cycle(target, undefined, [control.is(1)]). Passing 1 there runs the fractional gate at 1.0, which reaches the same state by a slower path.

Pooling does not shrink a shared state

releaseProperty() resets a property but leaves it where it was. A property that ever interacted with another stays inside that shared state after release, so reusing it from the pool can put a "fresh" property into an old group and count against its qudit limit. dispose() on a 3.0 handle avoids this: it destroys a qudit that still shares a state instead of caching it.

LegacyQuantumRecorder ​

LegacyQuantumRecorder is the 2.x QuantumRecorder under a new name. It records operations on one manager, and it is the only way to replay a log recorded by 2.x. In 3.0, new QuantumRecorder(manager) throws a TypeError that points here.

typescript
import { LegacyQuantumRecorder } from "quantum-forge/quantum";

const recorder = new LegacyQuantumRecorder(registry);
registry.setRecorder(recorder);
recorder.startRecording();

Once attached, the recorder logs the manager's lifecycle calls (acquireProperty, releaseProperty, setProperty, deleteProperty) by itself. Gates are not logged automatically. Record each one with recordOp():

typescript
const m = registry.getModule();
m.cycle(prop);
const index = recorder.getIndex(prop);
if (index !== undefined) recorder.recordOp({ op: "cycle", index, fraction: 1 });

const log = recorder.stopRecording(); // QuantumOperation[]

replayLog(log) clears the manager, then replays each operation in order onto fresh WASM properties, with every measurement forced to its recorded outcome. Afterwards registry.getProperty(id) returns a property in the recorded state.

MethodDescription
new LegacyQuantumRecorder(manager)Create a recorder for one manager
startRecording()Begin recording and reset the log
stopRecording()Stop and return the log, a QuantumOperation[]
isRecording()Whether recording is active
getOperationLog()A copy of the log, even while recording
replayLog(ops)Clear the manager and replay from scratch
recordOp(op)Record a gate operation
getIndex(prop)The recorded index for a property
buildWasmPredicates(specs)WASM predicates from PredicateSpec[]
serializePredicates(specs)Predicates in log form

How replay reads fraction ​

For cycle, shift, hadamard, and y, an entry with fraction: 1 and no predicates replays as the discrete gate. Any other fraction, or any predicates, replays through the fractional call. clock and i_swap always replay through the fractional call. So a fractional gate applied at exactly 1.0 with no predicates comes back as the discrete gate.

The legacy log is a bare array with no version field. QuantumRecorder in 3.0 uses a different format, { version: 1, entries }, and neither recorder reads the other's logs. See Recording and replay.

Powered by Quantum Forge