UNPKG

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
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) {