quaco.js
Version:
A lightweight modular Quantum Computing Simulator in JavaScript. Supports qubits, quantum gates, entanglement, circuits, algorithms, and visualization.
103 lines (88 loc) • 3.58 kB
JavaScript
// src/QuantumRegister.js
import { Complex } from './utils/Complex.js';
import { QuantumGate } from './QuantumGate.js';
import { MathUtils } from './utils/MathUtils.js';
/**
* Represents a register of multiple qubits (n qubits).
* Full quantum state is a 2^n dimensional vector.
*/
export class QuantumRegister {
constructor(numQubits) {
this.numQubits = numQubits;
// Initialize state vector |00...0⟩
const size = 1 << numQubits; // 2^numQubits
this.state = Array(size).fill(new Complex(0, 0));
this.state[0] = new Complex(1, 0); // Start in |00...0⟩
}
/**
* Applies a single-qubit gate to the specified qubit index.
* @param {Complex[][]} gateMatrix - 2x2 matrix
* @param {number} qubitIndex - index of target qubit (0 = least significant)
*/
applyGate(gateMatrix, qubitIndex) {
const newState = new Array(this.state.length).fill(new Complex(0, 0));
for (let i = 0; i < this.state.length; i++) {
// Check bit at qubitIndex
const bit = (i >> qubitIndex) & 1;
for (let j = 0; j < 2; j++) {
// Flip bit at qubitIndex to j (0 or 1)
const flipped = (i & (~(1 << qubitIndex))) | (j << qubitIndex);
const gateElement = gateMatrix[j][bit];
newState[flipped] = newState[flipped].add(
gateElement.mul(this.state[i])
);
}
}
this.state = MathUtils.normalize(newState);
}
/**
* Applies a 2-qubit gate (like CNOT) to control and target qubits.
* Only CNOT is supported in this version.
* @param {number} controlQubit
* @param {number} targetQubit
*/
applyCNOT(controlQubit, targetQubit) {
const newState = new Array(this.state.length).fill(new Complex(0, 0));
for (let i = 0; i < this.state.length; i++) {
const controlBit = (i >> controlQubit) & 1;
let flipped = i;
if (controlBit === 1) {
// Flip target qubit
flipped = i ^ (1 << targetQubit);
}
newState[flipped] = newState[flipped].add(this.state[i]);
}
this.state = MathUtils.normalize(newState);
}
/**
* Measures the entire register, collapsing to one classical outcome.
* @returns {string} bitstring, e.g., "001"
*/
measure() {
const probabilities = this.state.map(amplitude => amplitude.abs2());
const rand = Math.random();
let cumulative = 0;
for (let i = 0; i < probabilities.length; i++) {
cumulative += probabilities[i];
if (rand < cumulative) {
// Collapse to basis state |i⟩
this.state = Array(this.state.length).fill(new Complex(0, 0));
this.state[i] = new Complex(1, 0);
return i.toString(2).padStart(this.numQubits, '0'); // binary string
}
}
}
/**
* Prints the quantum register state.
*/
printState() {
console.log("Quantum Register State:");
for (let i = 0; i < this.state.length; i++) {
const amplitude = this.state[i];
if (!MathUtils.almostEqual(amplitude.abs2(), 0)) {
const basis = `|${i.toString(2).padStart(this.numQubits, '0')}⟩`;
console.log(`${amplitude.toString()} ${basis}`);
}
}
}
}