quanta_sim
Version:
A comprehensive quantum computing simulator library with support for quantum circuits, gates, measurements, and classical conditional operations
1,398 lines (1,335 loc) • 68.2 kB
JavaScript
import { complex, matrix, abs, multiply, re, im, kron, zeros, divide, transpose, conj, add } from 'mathjs';
class ClassicalRegister {
constructor(name, size) {
this.name = name;
this.size = size;
this.bits = Array(size).fill(0);
}
setValue(bitIndex, value) {
if (bitIndex >= 0 && bitIndex < this.size) {
this.bits[bitIndex] = value ? 1 : 0;
}
}
getValue(bitIndex) {
return bitIndex >= 0 && bitIndex < this.size ? this.bits[bitIndex] : 0;
}
// Get the integer value of the entire register
getRegisterValue() {
let value = 0;
for (let i = 0; i < this.size; i++) {
value += this.bits[i] * Math.pow(2, i);
}
return value;
}
// Set the entire register to a specific integer value
setRegisterValue(value) {
const maxValue = Math.pow(2, this.size) - 1;
const clampedValue = Math.max(0, Math.min(value, maxValue));
for (let i = 0; i < this.size; i++) {
this.bits[i] = clampedValue >> i & 1;
}
}
toString() {
return this.bits.slice().reverse().join("");
}
clone() {
const clone = new ClassicalRegister(this.name, this.size);
clone.bits = [...this.bits];
return clone;
}
}
const c = (real, imag = 0) => complex(real, imag);
const quantumStates = {
"|0>": [[c(1)], [c(0)]],
"|1>": [[c(0)], [c(1)]],
"|+>": [[c(1 / Math.sqrt(2))], [c(1 / Math.sqrt(2))]],
"|->": [[c(1 / Math.sqrt(2))], [c(-1 / Math.sqrt(2))]],
"|i>": [[c(1 / Math.sqrt(2))], [c(0, 1 / Math.sqrt(2))]],
"|-i>": [[c(1 / Math.sqrt(2))], [c(0, -1 / Math.sqrt(2))]]
};
const gateMatrices = {
// Pauli Gates
X: [[c(0), c(1)], [c(1), c(0)]],
Y: [[c(0), c(0, -1)], [c(0, 1), c(0)]],
Z: [[c(1), c(0)], [c(0), c(-1)]],
// Hadamard
H: [[c(1 / Math.sqrt(2)), c(1 / Math.sqrt(2))], [c(1 / Math.sqrt(2)), c(-1 / Math.sqrt(2))]],
// Identity
I: [[c(1), c(0)], [c(0), c(1)]],
// Phase Gates (FIXED)
S: [[c(1), c(0)], [c(0), c(0, 1)]],
SDG: [[c(1), c(0)], [c(0), c(0, -1)]],
T: [[c(1), c(0)], [c(0), c(Math.cos(Math.PI / 4), Math.sin(Math.PI / 4))]],
TDG: [[c(1), c(0)], [c(0), c(Math.cos(Math.PI / 4), -Math.sin(Math.PI / 4))]],
// Square root of X (FIXED)
SX: [[c(0.5, 0.5), c(0.5, -0.5)], [c(0.5, -0.5), c(0.5, 0.5)]],
SXDG: [[c(0.5, -0.5), c(0.5, 0.5)], [c(0.5, 0.5), c(0.5, -0.5)]]
};
class Qubit {
constructor(initialState = "|0>") {
this.state = matrix(quantumStates[initialState]);
this.measured = false;
this.measurementResult = null;
}
reset() {
this.state = matrix(quantumStates["|0>"]);
this.measured = false;
this.measurementResult = null;
}
getStateVector() {
return this.state;
}
getProbabilities() {
const stateArray = this.state.toArray();
return {
"|0>": abs(stateArray[0][0]) ** 2,
"|1>": abs(stateArray[1][0]) ** 2
};
}
measure(config = new SimulatorConfiguration()) {
if (this.measured && !config.measurementDeferred) return this.measurementResult;
const probs = this.getProbabilities();
const prob0 = probs["|0>"];
const prob1 = probs["|1>"];
let result;
if (!config.measurementDeferred) {
// Collapse the state based on probabilities
if (Math.abs(prob0 - prob1) < 1e-10) {
// Equal probabilities
switch (config.equalProbabilityCollapse) {
case "0":
result = 0;
break;
case "1":
result = 1;
break;
case "random":
default:
result = Math.random() < 0.5 ? 0 : 1;
break;
}
} else {
// Choose the state with higher probability
result = prob0 > prob1 ? 0 : 1;
}
// Collapse the state
this.measurementResult = result;
this.state = matrix(result === 0 ? quantumStates["|0>"] : quantumStates["|1>"]);
this.measured = true;
} else {
// Deferred measurement - don't collapse
const random = Math.random();
result = random < prob0 ? 0 : 1;
}
return result;
}
}
class Gate {
constructor(name, matrix, parameters = [], qubits = []) {
this.name = name;
this.matrix = matrix;
this.parameters = parameters;
this.qubits = qubits;
this.isParametric = parameters.length > 0;
this.isControlled = false;
this.controlQubits = [];
this.targetQubits = [];
}
// Parametric gate constructors (FIXED)
static U(theta, phi, lambda) {
const cosTheta2 = Math.cos(theta / 2);
const sinTheta2 = Math.sin(theta / 2);
const matrix = [[c(cosTheta2), multiply(c(-sinTheta2), c(Math.cos(lambda), Math.sin(lambda)))], [multiply(c(sinTheta2), c(Math.cos(phi), Math.sin(phi))), multiply(c(cosTheta2), c(Math.cos(phi + lambda), Math.sin(phi + lambda)))]];
return new Gate("U", matrix, [theta, phi, lambda]);
}
static U1(lambda) {
return Gate.P(lambda); // U1 is equivalent to P gate
}
static U2(phi, lambda) {
return Gate.U(Math.PI / 2, phi, lambda);
}
static U3(theta, phi, lambda) {
return Gate.U(theta, phi, lambda);
}
static RX(theta) {
const cosTheta2 = Math.cos(theta / 2);
const sinTheta2 = Math.sin(theta / 2);
const matrix = [[c(cosTheta2), c(0, -sinTheta2)], [c(0, -sinTheta2), c(cosTheta2)]];
return new Gate("RX", matrix, [theta]);
}
static RY(theta) {
const cosTheta2 = Math.cos(theta / 2);
const sinTheta2 = Math.sin(theta / 2);
const matrix = [[c(cosTheta2), c(-sinTheta2)], [c(sinTheta2), c(cosTheta2)]];
return new Gate("RY", matrix, [theta]);
}
static RZ(phi) {
const matrix = [[c(Math.cos(-phi / 2), Math.sin(-phi / 2)), c(0)], [c(0), c(Math.cos(phi / 2), Math.sin(phi / 2))]];
return new Gate("RZ", matrix, [phi]);
}
static P(lambda) {
const matrix = [[c(1), c(0)], [c(0), c(Math.cos(lambda), Math.sin(lambda))]];
return new Gate("P", matrix, [lambda]);
}
// Two-qubit parametric gates (FIXED)
static RXX(theta) {
const cos = Math.cos(theta / 2);
const sin = Math.sin(theta / 2);
const matrix = [[c(cos), c(0), c(0), c(0, -sin)], [c(0), c(cos), c(0, -sin), c(0)], [c(0), c(0, -sin), c(cos), c(0)], [c(0, -sin), c(0), c(0), c(cos)]];
return new Gate("RXX", matrix, [theta]);
}
static RYY(theta) {
const cos = Math.cos(theta / 2);
const sin = Math.sin(theta / 2);
const matrix = [[c(cos), c(0), c(0), c(0, sin)], [c(0), c(cos), c(0, -sin), c(0)], [c(0), c(0, -sin), c(cos), c(0)], [c(0, sin), c(0), c(0), c(cos)]];
return new Gate("RYY", matrix, [theta]);
}
static RZZ(theta) {
const matrix = [[c(Math.cos(-theta / 2), Math.sin(-theta / 2)), c(0), c(0), c(0)], [c(0), c(Math.cos(theta / 2), Math.sin(theta / 2)), c(0), c(0)], [c(0), c(0), c(Math.cos(theta / 2), Math.sin(theta / 2)), c(0)], [c(0), c(0), c(0), c(Math.cos(-theta / 2), Math.sin(-theta / 2))]];
return new Gate("RZZ", matrix, [theta]);
}
// Standard controlled gates
static CNOT() {
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(0), c(1)], [c(0), c(0), c(1), c(0)]];
const gate = new Gate("CNOT", matrix);
gate.isControlled = true;
return gate;
}
static CZ() {
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(1), c(0)], [c(0), c(0), c(0), c(-1)]];
const gate = new Gate("CZ", matrix);
gate.isControlled = true;
return gate;
}
static CY() {
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(0), c(0, -1)], [c(0), c(0), c(0, 1), c(0)]];
const gate = new Gate("CY", matrix);
gate.isControlled = true;
return gate;
}
static CH() {
// Controlled Hadamard
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(1 / Math.sqrt(2)), c(1 / Math.sqrt(2))], [c(0), c(0), c(1 / Math.sqrt(2)), c(-1 / Math.sqrt(2))]];
const gate = new Gate("CH", matrix);
gate.isControlled = true;
return gate;
}
static CS() {
// Controlled S gate
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(1), c(0)], [c(0), c(0), c(0), c(0, 1)]];
const gate = new Gate("CS", matrix);
gate.isControlled = true;
return gate;
}
static CSDG() {
// Controlled S dagger gate
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(1), c(0)], [c(0), c(0), c(0), c(0, -1)]];
const gate = new Gate("CSDG", matrix);
gate.isControlled = true;
return gate;
}
static CT() {
// Controlled T gate
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(1), c(0)], [c(0), c(0), c(0), c(Math.cos(Math.PI / 4), Math.sin(Math.PI / 4))]];
const gate = new Gate("CT", matrix);
gate.isControlled = true;
return gate;
}
static CTDG() {
// Controlled T dagger gate
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(1), c(0)], [c(0), c(0), c(0), c(Math.cos(Math.PI / 4), -Math.sin(Math.PI / 4))]];
const gate = new Gate("CTDG", matrix);
gate.isControlled = true;
return gate;
}
static CSX() {
// Controlled sqrt(X) gate
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(0.5, 0.5), c(0.5, -0.5)], [c(0), c(0), c(0.5, -0.5), c(0.5, 0.5)]];
const gate = new Gate("CSX", matrix);
gate.isControlled = true;
return gate;
}
static CSXDG() {
// Controlled sqrt(X) dagger gate
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(0.5, -0.5), c(0.5, 0.5)], [c(0), c(0), c(0.5, 0.5), c(0.5, -0.5)]];
const gate = new Gate("CSXDG", matrix);
gate.isControlled = true;
return gate;
}
// Controlled parametric gates
static CU(theta, phi, lambda) {
// Controlled U gate
const cosTheta2 = Math.cos(theta / 2);
const sinTheta2 = Math.sin(theta / 2);
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(cosTheta2), multiply(c(-sinTheta2), c(Math.cos(lambda), Math.sin(lambda)))], [c(0), c(0), multiply(c(sinTheta2), c(Math.cos(phi), Math.sin(phi))), multiply(c(cosTheta2), c(Math.cos(phi + lambda), Math.sin(phi + lambda)))]];
const gate = new Gate("CU", matrix, [theta, phi, lambda]);
gate.isControlled = true;
return gate;
}
static CU1(lambda) {
// Controlled U1 gate (same as CP)
return Gate.CP(lambda);
}
static CU2(phi, lambda) {
// Controlled U2 gate
return Gate.CU(Math.PI / 2, phi, lambda);
}
static CU3(theta, phi, lambda) {
// Controlled U3 gate
return Gate.CU(theta, phi, lambda);
}
static CRX(theta) {
// Controlled RX gate
const cosTheta2 = Math.cos(theta / 2);
const sinTheta2 = Math.sin(theta / 2);
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(cosTheta2), c(0, -sinTheta2)], [c(0), c(0), c(0, -sinTheta2), c(cosTheta2)]];
const gate = new Gate("CRX", matrix, [theta]);
gate.isControlled = true;
return gate;
}
static CRY(theta) {
// Controlled RY gate
const cosTheta2 = Math.cos(theta / 2);
const sinTheta2 = Math.sin(theta / 2);
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(cosTheta2), c(-sinTheta2)], [c(0), c(0), c(sinTheta2), c(cosTheta2)]];
const gate = new Gate("CRY", matrix, [theta]);
gate.isControlled = true;
return gate;
}
static CRZ(phi) {
// Controlled RZ gate
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(Math.cos(-phi / 2), Math.sin(-phi / 2)), c(0)], [c(0), c(0), c(0), c(Math.cos(phi / 2), Math.sin(phi / 2))]];
const gate = new Gate("CRZ", matrix, [phi]);
gate.isControlled = true;
return gate;
}
static CP(lambda) {
// Controlled Phase gate
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(1), c(0)], [c(0), c(0), c(0), c(Math.cos(lambda), Math.sin(lambda))]];
const gate = new Gate("CP", matrix, [lambda]);
gate.isControlled = true;
return gate;
}
static SWAP() {
const matrix = [[c(1), c(0), c(0), c(0)], [c(0), c(0), c(1), c(0)], [c(0), c(1), c(0), c(0)], [c(0), c(0), c(0), c(1)]];
return new Gate("SWAP", matrix);
}
static CCX() {
const matrix = [[c(1), c(0), c(0), c(0), c(0), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0), c(0), c(0), c(0), c(0)], [c(0), c(0), c(1), c(0), c(0), c(0), c(0), c(0)], [c(0), c(0), c(0), c(1), c(0), c(0), c(0), c(0)], [c(0), c(0), c(0), c(0), c(1), c(0), c(0), c(0)], [c(0), c(0), c(0), c(0), c(0), c(1), c(0), c(0)], [c(0), c(0), c(0), c(0), c(0), c(0), c(0), c(1)], [c(0), c(0), c(0), c(0), c(0), c(0), c(1), c(0)]];
const gate = new Gate("CCX", matrix);
gate.isControlled = true;
return gate;
}
static RCCX() {
const matrix = [[c(1), c(0), c(0), c(0), c(0), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0), c(0), c(0), c(0), c(0)], [c(0), c(0), c(1), c(0), c(0), c(0), c(0), c(0)], [c(0), c(0), c(0), c(1), c(0), c(0), c(0), c(0)], [c(0), c(0), c(0), c(0), c(1), c(0), c(0), c(0)], [c(0), c(0), c(0), c(0), c(0), c(-1), c(0), c(0)], [c(0), c(0), c(0), c(0), c(0), c(0), c(0), c(1)], [c(0), c(0), c(0), c(0), c(0), c(0), c(1), c(0)]];
const gate = new Gate("RCCX", matrix);
gate.isControlled = true;
return gate;
}
// Four-qubit gates
static CCCX() {
const dim = 16;
const matrix = Array(dim).fill().map(() => Array(dim).fill(c(0)));
// Identity for all states except |1111⟩
for (let i = 0; i < dim - 2; i++) {
matrix[i][i] = c(1);
}
// Swap the last two states: |1110⟩ ↔ |1111⟩
matrix[14][15] = c(1); // |1110⟩ -> |1111⟩
matrix[15][14] = c(1); // |1111⟩ -> |1110⟩
const gate = new Gate("CCCX", matrix);
gate.isControlled = true;
return gate;
}
static FREDKIN() {
const matrix = [[c(1), c(0), c(0), c(0), c(0), c(0), c(0), c(0)], [c(0), c(1), c(0), c(0), c(0), c(0), c(0), c(0)], [c(0), c(0), c(1), c(0), c(0), c(0), c(0), c(0)], [c(0), c(0), c(0), c(1), c(0), c(0), c(0), c(0)], [c(0), c(0), c(0), c(0), c(1), c(0), c(0), c(0)], [c(0), c(0), c(0), c(0), c(0), c(0), c(1), c(0)], [c(0), c(0), c(0), c(0), c(0), c(1), c(0), c(0)], [c(0), c(0), c(0), c(0), c(0), c(0), c(0), c(1)]];
const gate = new Gate("FREDKIN", matrix);
gate.isControlled = true;
return gate;
}
}
class ClassicalCondition {
constructor(registerName, value, operator = "==") {
this.registerName = registerName;
this.value = value;
this.operator = operator; // '==', '!=', '>', '<', '>=', '<='
}
evaluate(registers) {
const register = registers.get(this.registerName);
if (!register) {
throw new Error(`Classical register '${this.registerName}' not found`);
}
const registerValue = register.getRegisterValue();
switch (this.operator) {
case "==":
return registerValue === this.value;
case "!=":
return registerValue !== this.value;
case ">":
return registerValue > this.value;
case "<":
return registerValue < this.value;
case ">=":
return registerValue >= this.value;
case "<=":
return registerValue <= this.value;
default:
return false;
}
}
toString() {
return `${this.registerName} ${this.operator} ${this.value}`;
}
}
class CircuitOperation {
constructor(gate, qubits, classicalOperations = [], condition = null) {
this.gate = gate;
this.qubits = qubits;
this.classicalOperations = classicalOperations; // Array of {registerName, bitIndex} for measurements
this.condition = condition; // ClassicalCondition object
this.type = "gate";
}
static measurement(qubit, registerName, bitIndex, condition = null) {
const op = new CircuitOperation(null, [qubit], [{
registerName,
bitIndex
}], condition);
op.type = "measurement";
return op;
}
static reset(qubit, condition = null) {
const op = new CircuitOperation(null, [qubit], [], condition);
op.type = "reset";
return op;
}
static barrier(qubits) {
const op = new CircuitOperation(null, qubits);
op.type = "barrier";
return op;
}
// Set classical condition using new ClassicalCondition
setCondition(registerName, value, operator = "==") {
this.condition = new ClassicalCondition(registerName, value, operator);
return this;
}
// Check if condition is satisfied using new ClassicalRegister system
isConditionSatisfied(registers) {
if (!this.condition) return true;
return this.condition.evaluate(registers);
}
toQASM() {
let conditionStr = "";
if (this.condition) {
conditionStr = `if (${this.condition.toString()}) `;
}
switch (this.type) {
case "gate":
return conditionStr + this._gateToQASM();
case "measurement":
const op = this.classicalOperations[0];
return conditionStr + `measure q[${this.qubits[0]}] -> ${op.registerName}[${op.bitIndex}];`;
case "reset":
return conditionStr + `reset q[${this.qubits[0]}];`;
case "barrier":
return `barrier ${this.qubits.map(q => `q[${q}]`).join(", ")};`;
default:
return "";
}
}
_gateToQASM() {
const gateName = this.gate.name.toLowerCase();
// Handle special QASM gate names
let qasmGateName = gateName;
if (gateName === "cnot") qasmGateName = "cx";
if (gateName === "ccx") qasmGateName = "ccx";
if (gateName === "cccx") qasmGateName = "c3x";
if (gateName === "sdg") qasmGateName = "sdg";
if (gateName === "tdg") qasmGateName = "tdg";
if (gateName === "fredkin") qasmGateName = "cswap";
const params = this.gate.parameters.length > 0 ? `(${this.gate.parameters.join(", ")})` : "";
const qubits = this.qubits.map(q => `q[${q}]`).join(", ");
return `${qasmGateName}${params} ${qubits};`;
}
}
class ComplexNumber {
constructor(real, imag = 0) {
this.real = real;
this.imag = imag;
}
static fromMathJS(complexNum) {
return new ComplexNumber(re(complexNum), im(complexNum));
}
magnitude() {
return Math.sqrt(this.real * this.real + this.imag * this.imag);
}
phase() {
return Math.atan2(this.imag, this.real);
}
toString() {
if (Math.abs(this.imag) < 1e-10) return `${this.real.toFixed(4)}`;
if (Math.abs(this.real) < 1e-10) return `${this.imag.toFixed(4)}i`;
const sign = this.imag >= 0 ? "+" : "";
return `${this.real.toFixed(4)}${sign}${this.imag.toFixed(4)}i`;
}
}
let SimulatorConfiguration$1 = class SimulatorConfiguration {
constructor() {
this.measurementDeferred = false;
this.equalProbabilityCollapse = "random"; // 'random', '0', '1'
}
setMeasurementDeferred(deferred) {
this.measurementDeferred = deferred;
return this;
}
setEqualProbabilityCollapse(strategy) {
if (!["random", "0", "1"].includes(strategy)) {
throw new Error("Equal probability collapse must be 'random', '0', or '1'");
}
this.equalProbabilityCollapse = strategy;
return this;
}
clone() {
const config = new SimulatorConfiguration();
config.measurementDeferred = this.measurementDeferred;
config.equalProbabilityCollapse = this.equalProbabilityCollapse;
return config;
}
};
class QuantumCircuit {
constructor(numQubits, classicalRegisters = {}, config = new SimulatorConfiguration$1()) {
this.numQubits = numQubits;
this.classicalRegisters = new Map();
// Handle classical registers - can be object or legacy number
if (typeof classicalRegisters === "number") {
// Legacy support: create default register 'c'
this.classicalRegisters.set("c", new ClassicalRegister("c", classicalRegisters));
} else if (typeof classicalRegisters === "object") {
// New format: {registerName: size, ...}
for (const [name, size] of Object.entries(classicalRegisters)) {
this.classicalRegisters.set(name, new ClassicalRegister(name, size));
}
}
// Ensure at least one classical register exists
if (this.classicalRegisters.size === 0) {
this.classicalRegisters.set("c", new ClassicalRegister("c", numQubits));
}
this.config = config.clone();
this.qubits = Array.from({
length: numQubits
}, () => new Qubit());
this.operations = [];
this.stateVector = this._initializeStateVector();
this.name = "quantum_circuit";
}
// Add classical register
addClassicalRegister(name, size) {
this.classicalRegisters.set(name, new ClassicalRegister(name, size));
return this;
}
// Get classical register
getClassicalRegister(name) {
return this.classicalRegisters.get(name);
}
// Get classical register value
getClassicalValue(registerName) {
const register = this.classicalRegisters.get(registerName);
return register ? register.getRegisterValue() : 0;
}
_initializeStateVector() {
let state = matrix([[c(1)], [c(0)]]);
for (let i = 1; i < this.numQubits; i++) {
state = kron(state, matrix([[c(1)], [c(0)]]));
}
return state;
}
// Enhanced measurement with proper classical register support
measure(qubit, registerName = "c", bitIndex = null, condition = null) {
const register = this.classicalRegisters.get(registerName);
if (!register) {
throw new Error(`Classical register '${registerName}' not found`);
}
const actualBitIndex = bitIndex !== null ? bitIndex : qubit;
if (actualBitIndex >= register.size) {
throw new Error(`Bit index ${actualBitIndex} out of range for register '${registerName}' (size ${register.size})`);
}
const operation = CircuitOperation.measurement(qubit, registerName, actualBitIndex, condition);
this.operations.push(operation);
// Apply measurement only if condition is satisfied
if (operation.isConditionSatisfied(this.classicalRegisters)) {
const result = this._performMeasurement(qubit);
register.setValue(actualBitIndex, result);
return result;
}
return null;
}
// Reset
reset(qubit, condition = null) {
const operation = CircuitOperation.reset(qubit, condition);
this.operations.push(operation);
// Apply reset only if condition is satisfied
if (operation.isConditionSatisfied(this.classicalRegisters)) {
this.qubits[qubit].reset();
this._updateStateVectorAfterReset(qubit);
}
return this;
}
_updateStateVectorAfterReset(qubit) {
// After reset, we need to update the state vector
this.stateVector = this._initializeStateVector();
// Reapply all operations except the reset
const tempOperations = [...this.operations];
this.operations = [];
for (const op of tempOperations) {
if (op.type !== "reset" && op.type !== "measurement") {
if (op.type === "gate") {
if (op.qubits.length === 1) {
this._applyUnaryGate(op.gate, op.qubits[0]);
} else if (op.qubits.length === 2) {
this._applyBinaryGate(op.gate, op.qubits[0], op.qubits[1]);
} else if (op.qubits.length === 3) {
this._applyTernaryGate(op.gate, op.qubits[0], op.qubits[1], op.qubits[2]);
} else if (op.qubits.length === 4) {
this._applyQuaternaryGate(op.gate, op.qubits[0], op.qubits[1], op.qubits[2], op.qubits[3]);
}
}
}
}
this.operations = tempOperations;
}
// Barrier
barrier(qubits) {
const qubitList = Array.isArray(qubits) ? qubits : [qubits];
this.operations.push(CircuitOperation.barrier(qubitList));
return this;
}
measureAll() {
const results = [];
for (let i = 0; i < this.numQubits && i < this.numClassicalBits; i++) {
results.push(this.measure(i, i));
}
return results;
}
_performMeasurement(qubit) {
const probs = this.getQubitProbabilities();
const prob0 = probs[qubit][0];
const prob1 = probs[qubit][1];
let result;
if (Math.abs(prob0 - prob1) < 1e-10) {
// Equal probabilities
switch (this.config.equalProbabilityCollapse) {
case "0":
result = 0;
break;
case "1":
result = 1;
break;
case "random":
default:
result = Math.random() < 0.5 ? 0 : 1;
break;
}
} else {
result = prob0 > prob1 ? 0 : 1;
}
if (!this.config.measurementDeferred) {
this._updateStateVectorAfterMeasurement(qubit, result);
}
return result;
}
_updateStateVectorAfterMeasurement(qubit, result) {
const n = this.numQubits;
const dim = Math.pow(2, n);
let newStateVector = zeros(dim, 1);
for (let i = 0; i < dim; i++) {
const binaryI = i.toString(2).padStart(n, "0");
const qubitState = parseInt(binaryI[n - 1 - qubit]);
if (qubitState === result) {
newStateVector.set([i, 0], this.stateVector.get([i, 0]));
}
}
const norm = this._calculateNorm(newStateVector);
if (norm > 1e-10) {
this.stateVector = divide(newStateVector, norm);
}
}
// Enhanced conditional methods
ifEqual(registerName, value) {
return {
then: callback => {
const condition = new ClassicalCondition(registerName, value, "==");
callback(this, condition);
return this;
}
};
}
ifNotEqual(registerName, value) {
return {
then: callback => {
const condition = new ClassicalCondition(registerName, value, "!=");
callback(this, condition);
return this;
}
};
}
ifGreater(registerName, value) {
return {
then: callback => {
const condition = new ClassicalCondition(registerName, value, ">");
callback(this, condition);
return this;
}
};
}
// Single qubit gates
applyGate(gateName, qubit, parameters = [], condition = null) {
let gate;
if (gateMatrices[gateName]) {
gate = new Gate(gateName, gateMatrices[gateName]);
} else {
switch (gateName.toUpperCase()) {
case "U":
gate = Gate.U(...parameters);
break;
case "U1":
gate = Gate.U1(parameters[0]);
break;
case "U2":
gate = Gate.U2(...parameters);
break;
case "U3":
gate = Gate.U3(...parameters);
break;
case "RX":
gate = Gate.RX(parameters[0]);
break;
case "RY":
gate = Gate.RY(parameters[0]);
break;
case "RZ":
gate = Gate.RZ(parameters[0]);
break;
case "P":
gate = Gate.P(parameters[0]);
break;
default:
throw new Error(`Unknown gate: ${gateName}`);
}
}
const operation = new CircuitOperation(gate, [qubit], [], condition);
this.operations.push(operation);
// Apply gate only if condition is satisfied
if (operation.isConditionSatisfied(this.classicalRegisters)) {
this._applyUnaryGate(gate, qubit);
}
return this;
}
applyTwoQubitGate(gateName, qubit1, qubit2, parameters = [], condition = null) {
let gate;
switch (gateName.toUpperCase()) {
case "CNOT":
case "CX":
gate = Gate.CNOT();
break;
case "CZ":
gate = Gate.CZ();
break;
case "CY":
gate = Gate.CY();
break;
case "CH":
gate = Gate.CH();
break;
case "CS":
gate = Gate.CS();
break;
case "CSDG":
gate = Gate.CSDG();
break;
case "CT":
gate = Gate.CT();
break;
case "CTDG":
gate = Gate.CTDG();
break;
case "CSX":
gate = Gate.CSX();
break;
case "CSXDG":
gate = Gate.CSXDG();
break;
case "SWAP":
gate = Gate.SWAP();
break;
case "RXX":
gate = Gate.RXX(parameters[0]);
break;
case "RYY":
gate = Gate.RYY(parameters[0]);
break;
case "RZZ":
gate = Gate.RZZ(parameters[0]);
break;
case "CU":
gate = Gate.CU(...parameters);
break;
case "CU1":
gate = Gate.CU1(parameters[0]);
break;
case "CU2":
gate = Gate.CU2(...parameters);
break;
case "CU3":
gate = Gate.CU3(...parameters);
break;
case "CRX":
gate = Gate.CRX(parameters[0]);
break;
case "CRY":
gate = Gate.CRY(parameters[0]);
break;
case "CRZ":
gate = Gate.CRZ(parameters[0]);
break;
case "CP":
gate = Gate.CP(parameters[0]);
break;
default:
throw new Error(`Unknown two-qubit gate: ${gateName}`);
}
const operation = new CircuitOperation(gate, [qubit1, qubit2], [], condition);
this.operations.push(operation);
// Apply gate only if condition is satisfied
if (operation.isConditionSatisfied(this.classicalRegisters)) {
this._applyBinaryGate(gate, qubit1, qubit2);
}
return this;
}
// Three qubit gates
applyThreeQubitGate(gateName, qubit1, qubit2, qubit3, condition = null) {
let gate;
switch (gateName.toUpperCase()) {
case "CCX":
case "TOFFOLI":
gate = Gate.CCX();
break;
case "RCCX":
gate = Gate.RCCX();
break;
case "FREDKIN":
case "CSWAP":
gate = Gate.FREDKIN();
break;
default:
throw new Error(`Unknown three-qubit gate: ${gateName}`);
}
const operation = new CircuitOperation(gate, [qubit1, qubit2, qubit3], [], condition);
this.operations.push(operation);
// Apply gate only if condition is satisfied
if (operation.isConditionSatisfied(this.classicalRegisters)) {
this._applyTernaryGate(gate, qubit1, qubit2, qubit3);
}
return this;
}
// Four qubit gates
applyFourQubitGate(gateName, qubit1, qubit2, qubit3, qubit4, condition = null) {
let gate;
switch (gateName.toUpperCase()) {
case "CCCX":
case "C3X":
gate = Gate.CCCX();
break;
default:
throw new Error(`Unknown four-qubit gate: ${gateName}`);
}
const operation = new CircuitOperation(gate, [qubit1, qubit2, qubit3, qubit4], [], condition);
this.operations.push(operation);
// Apply gate only if condition is satisfied
if (operation.isConditionSatisfied(this.classicalRegisters)) {
this._applyQuaternaryGate(gate, qubit1, qubit2, qubit3, qubit4);
}
return this;
}
// Specific gate methods with optional conditions
x(qubit, condition = null) {
return this.applyGate("X", qubit, [], condition);
}
y(qubit, condition = null) {
return this.applyGate("Y", qubit, [], condition);
}
z(qubit, condition = null) {
return this.applyGate("Z", qubit, [], condition);
}
h(qubit, condition = null) {
return this.applyGate("H", qubit, [], condition);
}
s(qubit, condition = null) {
return this.applyGate("S", qubit, [], condition);
}
sdg(qubit, condition = null) {
return this.applyGate("SDG", qubit, [], condition);
}
t(qubit, condition = null) {
return this.applyGate("T", qubit, [], condition);
}
tdg(qubit, condition = null) {
return this.applyGate("TDG", qubit, [], condition);
}
sx(qubit, condition = null) {
return this.applyGate("SX", qubit, [], condition);
}
sxdg(qubit, condition = null) {
return this.applyGate("SXDG", qubit, [], condition);
}
// Parametric gates with optional conditions
u(theta, phi, lambda, qubit, condition = null) {
return this.applyGate("U", qubit, [theta, phi, lambda], condition);
}
u1(lambda, qubit, condition = null) {
return this.applyGate("U1", qubit, [lambda], condition);
}
u2(phi, lambda, qubit, condition = null) {
return this.applyGate("U2", qubit, [phi, lambda], condition);
}
u3(theta, phi, lambda, qubit, condition = null) {
return this.applyGate("U3", qubit, [theta, phi, lambda], condition);
}
rx(theta, qubit, condition = null) {
return this.applyGate("RX", qubit, [theta], condition);
}
ry(theta, qubit, condition = null) {
return this.applyGate("RY", qubit, [theta], condition);
}
rz(phi, qubit, condition = null) {
return this.applyGate("RZ", qubit, [phi], condition);
}
p(lambda, qubit, condition = null) {
return this.applyGate("P", qubit, [lambda], condition);
}
// Two-qubit gates with optional conditions
cnot(control, target, condition = null) {
return this.applyTwoQubitGate("CNOT", control, target, [], condition);
}
cx(control, target, condition = null) {
return this.cnot(control, target, condition);
}
cz(control, target, condition = null) {
return this.applyTwoQubitGate("CZ", control, target, [], condition);
}
cy(control, target, condition = null) {
return this.applyTwoQubitGate("CY", control, target, [], condition);
}
ch(control, target, condition = null) {
return this.applyTwoQubitGate("CH", control, target, [], condition);
}
cs(control, target, condition = null) {
return this.applyTwoQubitGate("CS", control, target, [], condition);
}
csdg(control, target, condition = null) {
return this.applyTwoQubitGate("CSDG", control, target, [], condition);
}
ct(control, target, condition = null) {
return this.applyTwoQubitGate("CT", control, target, [], condition);
}
ctdg(control, target, condition = null) {
return this.applyTwoQubitGate("CTDG", control, target, [], condition);
}
csx(control, target, condition = null) {
return this.applyTwoQubitGate("CSX", control, target, [], condition);
}
csxdg(control, target, condition = null) {
return this.applyTwoQubitGate("CSXDG", control, target, [], condition);
}
// Controlled parametric gates
cu(theta, phi, lambda, control, target, condition = null) {
return this.applyTwoQubitGate("CU", control, target, [theta, phi, lambda], condition);
}
cu1(lambda, control, target, condition = null) {
return this.applyTwoQubitGate("CU1", control, target, [lambda], condition);
}
cu2(phi, lambda, control, target, condition = null) {
return this.applyTwoQubitGate("CU2", control, target, [phi, lambda], condition);
}
cu3(theta, phi, lambda, control, target, condition = null) {
return this.applyTwoQubitGate("CU3", control, target, [theta, phi, lambda], condition);
}
crx(theta, control, target, condition = null) {
return this.applyTwoQubitGate("CRX", control, target, [theta], condition);
}
cry(theta, control, target, condition = null) {
return this.applyTwoQubitGate("CRY", control, target, [theta], condition);
}
crz(phi, control, target, condition = null) {
return this.applyTwoQubitGate("CRZ", control, target, [phi], condition);
}
cp(lambda, control, target, condition = null) {
return this.applyTwoQubitGate("CP", control, target, [lambda], condition);
}
swap(qubit1, qubit2, condition = null) {
return this.applyTwoQubitGate("SWAP", qubit1, qubit2, [], condition);
}
rxx(theta, qubit1, qubit2, condition = null) {
return this.applyTwoQubitGate("RXX", qubit1, qubit2, [theta], condition);
}
ryy(theta, qubit1, qubit2, condition = null) {
return this.applyTwoQubitGate("RYY", qubit1, qubit2, [theta], condition);
}
rzz(theta, qubit1, qubit2, condition = null) {
return this.applyTwoQubitGate("RZZ", qubit1, qubit2, [theta], condition);
}
// Three-qubit gates with optional conditions
ccx(control1, control2, target, condition = null) {
return this.applyThreeQubitGate("CCX", control1, control2, target, condition);
}
toffoli(control1, control2, target, condition = null) {
return this.ccx(control1, control2, target, condition);
}
rccx(control1, control2, target, condition = null) {
return this.applyThreeQubitGate("RCCX", control1, control2, target, condition);
}
fredkin(control, target1, target2, condition = null) {
return this.applyThreeQubitGate("FREDKIN", control, target1, target2, condition);
}
cswap(control, target1, target2, condition = null) {
return this.fredkin(control, target1, target2, condition);
}
// Four-qubit gates with optional conditions
cccx(control1, control2, control3, target, condition = null) {
return this.applyFourQubitGate("CCCX", control1, control2, control3, target, condition);
}
c3x(control1, control2, control3, target, condition = null) {
return this.cccx(control1, control2, control3, target, condition);
}
// Gate matrix expansion methods (keeping existing implementation)
_expandGateMatrix(gateMatrix, targetQubit) {
const n = this.numQubits;
const dim = Math.pow(2, n);
let result = zeros(dim, dim);
const gate = Array.isArray(gateMatrix) ? matrix(gateMatrix) : gateMatrix;
for (let i = 0; i < dim; i++) {
for (let j = 0; j < dim; j++) {
const binaryI = i.toString(2).padStart(n, "0");
const binaryJ = j.toString(2).padStart(n, "0");
let match = true;
for (let k = 0; k < n; k++) {
if (k !== targetQubit && binaryI[n - 1 - k] !== binaryJ[n - 1 - k]) {
match = false;
break;
}
}
if (match) {
const targetStateI = parseInt(binaryI[n - 1 - targetQubit]);
const targetStateJ = parseInt(binaryJ[n - 1 - targetQubit]);
const gateElement = gate.get([targetStateI, targetStateJ]);
result.set([i, j], gateElement);
}
}
}
return result;
}
_expandTwoQubitGateMatrix(gateMatrix, control, target) {
const n = this.numQubits;
const dim = Math.pow(2, n);
let result = zeros(dim, dim);
const gate = Array.isArray(gateMatrix) ? matrix(gateMatrix) : gateMatrix;
for (let i = 0; i < dim; i++) {
for (let j = 0; j < dim; j++) {
const binaryI = i.toString(2).padStart(n, "0");
const binaryJ = j.toString(2).padStart(n, "0");
let match = true;
for (let k = 0; k < n; k++) {
if (k !== control && k !== target && binaryI[n - 1 - k] !== binaryJ[n - 1 - k]) {
match = false;
break;
}
}
if (match) {
const controlStateI = parseInt(binaryI[n - 1 - control]);
const targetStateI = parseInt(binaryI[n - 1 - target]);
const controlStateJ = parseInt(binaryJ[n - 1 - control]);
const targetStateJ = parseInt(binaryJ[n - 1 - target]);
const twoQubitStateI = controlStateI * 2 + targetStateI;
const twoQubitStateJ = controlStateJ * 2 + targetStateJ;
// FIXED: Swap the indices
const gateElement = gate.get([twoQubitStateI, twoQubitStateJ]);
result.set([i, j], gateElement);
}
}
}
return result;
}
_expandThreeQubitGateMatrix(gateMatrix, qubit1, qubit2, qubit3) {
const n = this.numQubits;
const dim = Math.pow(2, n);
let result = zeros(dim, dim);
const gate = Array.isArray(gateMatrix) ? matrix(gateMatrix) : gateMatrix;
for (let i = 0; i < dim; i++) {
for (let j = 0; j < dim; j++) {
const binaryI = i.toString(2).padStart(n, "0");
const binaryJ = j.toString(2).padStart(n, "0");
let match = true;
for (let k = 0; k < n; k++) {
if (k !== qubit1 && k !== qubit2 && k !== qubit3 && binaryI[n - 1 - k] !== binaryJ[n - 1 - k]) {
match = false;
break;
}
}
if (match) {
const state1I = parseInt(binaryI[n - 1 - qubit1]);
const state2I = parseInt(binaryI[n - 1 - qubit2]);
const state3I = parseInt(binaryI[n - 1 - qubit3]);
const state1J = parseInt(binaryJ[n - 1 - qubit1]);
const state2J = parseInt(binaryJ[n - 1 - qubit2]);
const state3J = parseInt(binaryJ[n - 1 - qubit3]);
const threeQubitStateI = state1I * 4 + state2I * 2 + state3I;
const threeQubitStateJ = state1J * 4 + state2J * 2 + state3J;
// FIXED: Swap the indices
const gateElement = gate.get([threeQubitStateI, threeQubitStateJ]);
result.set([i, j], gateElement);
}
}
}
return result;
}
_expandFourQubitGateMatrix(gateMatrix, qubit1, qubit2, qubit3, qubit4) {
const n = this.numQubits;
const dim = Math.pow(2, n);
let result = zeros(dim, dim);
const gate = Array.isArray(gateMatrix) ? matrix(gateMatrix) : gateMatrix;
for (let i = 0; i < dim; i++) {
for (let j = 0; j < dim; j++) {
const binaryI = i.toString(2).padStart(n, "0");
const binaryJ = j.toString(2).padStart(n, "0");
// Check if all other qubits are the same
let match = true;
for (let k = 0; k < n; k++) {
if (k !== qubit1 && k !== qubit2 && k !== qubit3 && k !== qubit4 && binaryI[n - 1 - k] !== binaryJ[n - 1 - k]) {
match = false;
break;
}
}
if (match) {
// Extract four qubit states
const state1I = parseInt(binaryI[n - 1 - qubit1]);
const state2I = parseInt(binaryI[n - 1 - qubit2]);
const state3I = parseInt(binaryI[n - 1 - qubit3]);
const state4I = parseInt(binaryI[n - 1 - qubit4]);
const state1J = parseInt(binaryJ[n - 1 - qubit1]);
const state2J = parseInt(binaryJ[n - 1 - qubit2]);
const state3J = parseInt(binaryJ[n - 1 - qubit3]);
const state4J = parseInt(binaryJ[n - 1 - qubit4]);
// Create 4-qubit computational basis indices
const fourQubitStateI = state1I * 8 + state2I * 4 + state3I * 2 + state4I;
const fourQubitStateJ = state1J * 8 + state2J * 4 + state3J * 2 + state4J;
// FIXED: Swap the indices
const gateElement = gate.get([fourQubitStateI, fourQubitStateJ]);
result.set([i, j], gateElement);
}
}
}
return result;
}
_applyUnaryGate(gate, qubit) {
const gateMatrix = this._expandGateMatrix(gate.matrix, qubit);
this.stateVector = multiply(gateMatrix, this.stateVector);
}
_applyBinaryGate(gate, qubit1, qubit2) {
const gateMatrix = this._expandTwoQubitGateMatrix(gate.matrix, qubit1, qubit2);
this.stateVector = multiply(gateMatrix, this.stateVector);
}
_applyTernaryGate(gate, qubit1, qubit2, qubit3) {
const gateMatrix = this._expandThreeQubitGateMatrix(gate.matrix, qubit1, qubit2, qubit3);
this.stateVector = multiply(gateMatrix, this.stateVector);
}
_applyQuaternaryGate(gate, qubit1, qubit2, qubit3, qubit4) {
const gateMatrix = this._expandFourQubitGateMatrix(gate.matrix, qubit1, qubit2, qubit3, qubit4);
this.stateVector = multiply(gateMatrix, this.stateVector);
}
// Analysis methods
getStateVector() {
return this.stateVector;
}
getStateProbabilities() {
const stateArray = this.stateVector.toArray();
const probabilities = [];
for (let i = 0; i < stateArray.length; i++) {
const amplitude = stateArray[i][0];
const probability = abs(amplitude) ** 2;
const binaryState = i.toString(2).padStart(this.numQubits, "0");
probabilities.push({
state: `|${binaryState}>`,
amplitude: ComplexNumber.fromMathJS(amplitude),
probability: probability
});
}
return probabilities;
}
getQubitProbabilities() {
const stateArray = this.stateVector.toArray();
const n = this.numQubits;
const qubitProbabilities = Array.from({
length: n
}, () => ({
0: 0,
1: 0
}));
for (let i = 0; i < stateArray.length; i++) {
const amplitude = stateArray[i][0];
const probability = abs(amplitude) ** 2;
// Convert to binary - MSB is leftmost
const binaryState = i.toString(2).padStart(n, "0");
// Map correctly: qubit j corresponds to bit position (n-1-j) in binary string
for (let qubitIndex = 0; qubitIndex < n; qubitIndex++) {
const bitValue = parseInt(binaryState[n - 1 - qubitIndex]);
qubitProbabilities[qubitIndex][bitValue] += probability;
}
}
return qubitProbabilities;
}
// Density matrix operations
getDensityMatrix() {
const ket = this.stateVector;
const bra = transpose(conj(ket));
return multiply(ket, bra);
}
_calculateNorm(vector) {
const vectorArray = vector.toArray();
let norm = 0;
for (const row of vectorArray) {
norm += abs(row[0]) ** 2;
}
return Math.sqrt(norm);
}
// Execute the circuit
execute() {
this.stateVector = this._initializeStateVector();
// Reset all classical registers
for (const register of this.classicalRegisters.values()) {
register.bits.fill(0);
}
for (const operation of this.operations) {
if (operation.isConditionSatisfied(this.classicalRegisters)) {
if (operation.type === "gate") {
if (operation.qubits.length === 1) {
this._applyUnaryGate(operation.gate, operation.qubits[0]);
} else if (operation.qubits.length === 2) {
this._applyBinaryGate(operation.gate, operation.qubits[0], operation.qubits[1]);
} else if (operation.qubits.length === 3) {
this._applyTernaryGate(operation.gate, operation.qubits[0], operation.qubits[1], operation.qubits[2]);
} else if (operation.qubits.length === 4) {
this._applyQuaternaryGate(operation.gate, operation.qubits[0], operation.qubits[1], operation.qubits[2], operation.qubits[3]);
}
} else if (operation.type === "measurement") {
const qubit = operation.qubits[0];
const classicalOp = operation.classicalOperations[0];
const result = this._performMeasurement(qubit);
const register = this.classicalRegisters.get(classicalOp.registerName);
if (register) {
register.setValue(classicalOp.bitIndex, result);
}
if (!this.config.measurementDeferred) {
this._updateStateVectorAfterMeasurement(qubit, result);
}
} else if (operation.type === "reset") {
this._deterministicReset(operation.qubits[0]);
}
}
}
return this;
}
// Deterministic reset operation
_deterministicReset(qubit) {
// Reset qubit to |0⟩ state deterministically
const probs = this.getQubitProbabilities();
const prob1 = probs[qubit][1];
if (prob1 > 1e-10) {
// If qubit has probability of being in |1⟩
// Apply X gate with probability weighting to reset to |0⟩
const resetOperator = this._createResetOperator(qubit);
this.stateVector = multiply(resetOperator, this.stateVector);
// Normalize the state
const norm = this._calculateNorm(this.stateVector);
this.stateVector = divide(this.stateVector, norm);
}
}
_createResetOperator(qubit) {
// Create a reset operator that projects qubit to |0⟩ state
const dim = Math.pow(2, this.numQubits);
const resetOp = zeros(dim, dim);
for (let i = 0; i < dim; i++) {
const binary = i.toString(2).padStart(this.numQubits, "0");
if (binary[this.numQubits - 1 - qubit] === "0") {
resetOp.set([i, i], c(1));
// Also include the |1⟩ component projected to |0⟩
const flippedBinary = binary.substring(0, this.numQubits - 1 - qubit) + "1" + binary.substring(this.numQubits - qubit);
if (flippedBinary.length === this.numQubits) {
const flippedIndex = parseInt(flippedBinary, 2);
resetOp.set([i, flippedIndex], c(1));
}
}
}
return resetOp;
}
// Partial trace operations (FIXED)
_partialTrace(rho, qubitIndex) {
const size = Math.pow(2, this.numQubits);
const reducedMatrix = zeros(2, 2);
for (let i = 0; i < size; i++) {
for (let j = 0; j < size; j++) {
const binaryI = i.toString(2).padStart(this.numQubits, "0");
const binaryJ = j.toString(2).padStart(this.numQubits, "0");
const otherBitsI = binaryI.slice(0, this.numQubits - 1 - qubitIndex) + binaryI.slice(this.numQubits - qubitIndex);
const otherBitsJ = binaryJ.slice(0, this.numQubits - 1 - qubitIndex) + binaryJ.slice(this.numQubits - qubitIndex);
if (otherBitsI === otherBitsJ) {
const value = rho.get([i, j]);
const row = binaryI[this.numQubits - 1 - qubitIndex] === "0" ? 0 : 1;
const col = binaryJ[this.numQubits - 1 - qubitIndex] === "0" ? 0 : 1;
reducedMatrix.set([row, col], add(reducedMatrix.get([row, col]), value));
}
}
}
return reducedMatrix;
}
// Partial trace over multiple qubits
_partialTraceMultipleQubits(rho, qubitsToKeep) {
let reducedRho = rho;
const qubitsToTrace = [];
for (let i = 0; i < this.numQubits; i++) {
if (!qubitsToKeep.includes(i)) {
qubitsToTrace.push(i);
}
}
// Trace out qubits in reverse order to maintain indexing
qubitsToTrace.sort((a, b) => b - a);
for (const qubit of qubitsToTrace) {
reducedRho = this._partialTrace(reducedRho, qubit);
}
return reducedRho;
}
// Deterministic execution with detailed tracking
executeDeterministic() {
this.stateVector = this._initializeStateVector();
// Reset all classical registers
for (const register of this.classicalRegisters.values()) {
register.bits.fill(0);
}
const executionResults = {
finalStateVector: null,
finalProbabilities: null,
measurementProbabilities: {},
gateApplications: [],
operationHistory: [],
classicalRegisters: new Map()
};
for (let i = 0; i < this.operations.length; i++) {
const operation = this.operations[i];
const conditionSatisfied = operation.isConditionSatisfied(this.classicalRegisters);
const operationResult = {
operation: operation,
conditionSatisfied: conditionSatisfied,
stateBefore: this._cloneMatrix(this.stateVector),
stateAfter: null,
probabilities: null,
classicalStatesBefore: this._cloneClassicalRegisters(),
classicalStatesAfter: null
};
if (!conditionSatisfied) {