ts-quantum
Version:
TypeScript library for quantum mechanics calculations and utilities
436 lines • 16.7 kB
JavaScript
;
/**
* Density matrix implementation for mixed quantum states and operations
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.negativity = exports.concurrence = exports.traceFidelity = exports.createPhaseFlipChannel = exports.createBitFlipChannel = exports.createPhaseDampingChannel = exports.createAmplitudeDampingChannel = exports.createDepolarizingChannel = exports.KrausChannel = exports.DensityMatrixOperator = void 0;
const operator_1 = require("../operators/operator");
const matrixOperations_1 = require("../utils/matrixOperations");
const math = __importStar(require("mathjs"));
const matrixOperations_2 = require("../utils/matrixOperations");
/**
* Implementation of density matrix operations
*/
class DensityMatrixOperator {
constructor(matrix) {
this.objectType = 'operator'; // Inherits from IOperator
this.type = 'hermitian';
// Validate matrix dimensions
if (!matrix || matrix.length === 0) {
throw new Error('Empty matrix provided');
}
const dim = matrix.length;
if (!matrix.every(row => row.length === dim)) {
throw new Error('Matrix must be square');
}
// Normalize matrix and create operator
const normalizedMatrix = (0, matrixOperations_2.normalizeMatrix)(matrix);
this.operator = new operator_1.MatrixOperator(normalizedMatrix, 'hermitian');
this.dimension = dim;
// Validate trace = 1
const tr = this.trace();
// console.log("Trace: ", tr);
// console.log("Trace real part: ", tr.re);
// console.log("Trace imaginary part: ", tr.im);
if (Math.abs(tr.re - 1) > 1e-10 || Math.abs(tr.im) > 1e-10) {
throw new Error('Density matrix must have trace 1');
}
// Validate positive semidefinite (simplified check via purity ≤ 1)
if (this.purity() > 1 + 1e-10) {
throw new Error('Density matrix must be positive semidefinite');
}
}
/**
* Applies density matrix to state vector
*/
apply(state) {
return this.operator.apply(state);
}
/**
* Composes with another operator
*/
compose(other) {
return this.operator.compose(other);
}
/**
* Returns adjoint (same as original for density matrix)
*/
adjoint() {
return this; // Density matrices are Hermitian
}
/**
* Returns matrix representation
*/
toMatrix() {
return this.operator.toMatrix();
}
/**
* Calculates trace of density matrix
*/
trace() {
const matrix = this.toMatrix();
return matrix.reduce((sum, row, i) => math.add(sum, row[i]), math.complex(0, 0));
}
/**
* Calculates purity Tr(ρ²)
*/
purity() {
// Calculate Tr(ρ²) by squaring the matrix and taking trace
const matrix = this.toMatrix();
const matSquared = (0, matrixOperations_1.multiplyMatrices)(matrix, matrix);
// Sum diagonal elements
let trace = math.complex(0, 0);
for (let i = 0; i < this.dimension; i++) {
trace = math.add(trace, matSquared[i][i]);
}
// The purity should be real for a valid density matrix
return trace.re;
}
/**
* Calculates von Neumann entropy -Tr(ρ ln ρ)
*/
vonNeumannEntropy() {
const { values } = this.eigenDecompose();
let entropy = 0;
for (const value of values) {
if (value.re > 1e-10) { // Only consider non-zero eigenvalues
entropy -= value.re * Math.log(value.re);
}
}
return entropy;
}
/**
* Performs partial trace over specified subsystems
*/
partialTrace(dims, traceOutIndices) {
return this.operator.partialTrace(dims, traceOutIndices);
}
/**
* Scales density matrix by a complex number
*/
scale(scalar) {
return this.operator.scale(scalar);
}
/**
* Adds this density matrix with another operator
*/
add(other) {
return this.operator.add(other);
}
/**
* Returns eigenvalues and eigenvectors
*/
eigenDecompose() {
return this.operator.eigenDecompose();
}
/**
* Creates density matrix from pure state
*/
static fromPureState(state) {
const dim = state.dimension;
const matrix = Array(dim).fill(null).map(() => Array(dim).fill(null).map(() => math.complex(0, 0)));
// Compute |ψ⟩⟨ψ|
for (let i = 0; i < dim; i++) {
for (let j = 0; j < dim; j++) {
matrix[i][j] = math.multiply(state.amplitudes[i], math.conj(state.amplitudes[j]));
}
}
return new DensityMatrixOperator(matrix);
}
/**
* Creates density matrix from mixed state
*/
static mixedState(states, probabilities) {
if (states.length !== probabilities.length) {
throw new Error('Number of states must match number of probabilities');
}
if (Math.abs(probabilities.reduce((a, b) => a + b, 0) - 1) > 1e-10) {
throw new Error('Probabilities must sum to 1');
}
const dim = states[0].dimension;
if (!states.every(s => s.dimension === dim)) {
throw new Error('All states must have same dimension');
}
// Compute Σᵢ pᵢ|ψᵢ⟩⟨ψᵢ|
const matrix = Array(dim).fill(null).map(() => Array(dim).fill(null).map(() => math.complex(0, 0)));
for (let k = 0; k < states.length; k++) {
const state = states[k];
const prob = probabilities[k];
for (let i = 0; i < dim; i++) {
for (let j = 0; j < dim; j++) {
const term = math.multiply(math.multiply(state.amplitudes[i], math.conj(state.amplitudes[j])), math.complex(prob, 0));
matrix[i][j] = math.add(matrix[i][j], term);
}
}
}
return new DensityMatrixOperator(matrix);
}
/**
* Returns tensor product with another operator
*/
tensorProduct(other) {
return this.operator.tensorProduct(other);
}
/**
* Calculates the operator norm
*/
norm() {
return this.operator.norm();
}
/**
* Tests whether the density matrix is identically zero
*/
isZero(tolerance) {
return this.operator.isZero(tolerance);
}
}
exports.DensityMatrixOperator = DensityMatrixOperator;
/**
* Implementation of quantum channels using Kraus operators
*/
class KrausChannel {
constructor(krausOperators) {
this.krausOperators = krausOperators;
// Validate non-empty array of operators
if (!krausOperators || krausOperators.length === 0) {
throw new Error('At least one Kraus operator is required');
}
// Validate completeness relation Σᵢ Eᵢ†Eᵢ = I
const dim = krausOperators[0].dimension;
if (!krausOperators.every(op => op.dimension === dim)) {
throw new Error('All Kraus operators must have same dimension');
}
// Check completeness relation
const sum = krausOperators.reduce((sum, Ei) => {
const EiDagger = Ei.adjoint();
return addOperators(sum, EiDagger.compose(Ei));
}, createZeroOperator(dim));
const identity = createIdentityOperator(dim);
const diff = subtractOperators(sum, identity);
if (!diff.isZero()) {
throw new Error('Kraus operators must satisfy completeness relation');
}
}
getOperators() {
return [...this.krausOperators];
}
apply(state) {
const dim = this.krausOperators[0].dimension;
const result = Array(dim).fill(null).map(() => Array(dim).fill(null).map(() => math.complex(0, 0)));
// Apply channel: ρ' = Σᵢ EᵢρEᵢ†
for (const Ei of this.krausOperators) {
const EiDagger = Ei.adjoint();
const term = Ei.compose(state).compose(EiDagger);
const termMatrix = term.toMatrix();
for (let i = 0; i < dim; i++) {
for (let j = 0; j < dim; j++) {
result[i][j] = math.add(result[i][j], termMatrix[i][j]);
}
}
}
return new DensityMatrixOperator(result);
}
}
exports.KrausChannel = KrausChannel;
// Helper functions for quantum channel creation
/**
* Creates a depolarizing channel
* For qubits: ρ → (1-p)ρ + p/3(XρX + YρY + ZρZ)
*/
function createDepolarizingChannel(dimension, p) {
if (p < 0 || p > 1) {
throw new Error('Probability must be between 0 and 1');
}
if (dimension !== 2) {
throw new Error('Depolarizing channel currently only implemented for qubits (dimension=2)');
}
// Kraus operators for depolarizing channel
const krausOperators = [];
// E0 = √(1-p) * I
const E0Matrix = [
[math.complex(Math.sqrt(1 - p), 0), math.complex(0, 0)],
[math.complex(0, 0), math.complex(Math.sqrt(1 - p), 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E0Matrix));
// E1 = √(p/3) * X
const sqrt_p_3 = Math.sqrt(p / 3);
const E1Matrix = [
[math.complex(0, 0), math.complex(sqrt_p_3, 0)],
[math.complex(sqrt_p_3, 0), math.complex(0, 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E1Matrix));
// E2 = √(p/3) * Y
const E2Matrix = [
[math.complex(0, 0), math.complex(0, -sqrt_p_3)],
[math.complex(0, sqrt_p_3), math.complex(0, 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E2Matrix));
// E3 = √(p/3) * Z
const E3Matrix = [
[math.complex(sqrt_p_3, 0), math.complex(0, 0)],
[math.complex(0, 0), math.complex(-sqrt_p_3, 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E3Matrix));
return new KrausChannel(krausOperators);
}
exports.createDepolarizingChannel = createDepolarizingChannel;
/**
* Creates an amplitude damping channel
* Models energy decay: |1⟩ → |0⟩ with probability γ
*/
function createAmplitudeDampingChannel(gamma) {
if (gamma < 0 || gamma > 1) {
throw new Error('Damping parameter must be between 0 and 1');
}
// Kraus operators for amplitude damping
const krausOperators = [];
// E0 = |0⟩⟨0| + √(1-γ)|1⟩⟨1|
const E0Matrix = [
[math.complex(1, 0), math.complex(0, 0)],
[math.complex(0, 0), math.complex(Math.sqrt(1 - gamma), 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E0Matrix));
// E1 = √γ|0⟩⟨1|
const E1Matrix = [
[math.complex(0, 0), math.complex(Math.sqrt(gamma), 0)],
[math.complex(0, 0), math.complex(0, 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E1Matrix));
return new KrausChannel(krausOperators);
}
exports.createAmplitudeDampingChannel = createAmplitudeDampingChannel;
/**
* Creates a phase damping channel
* Models pure dephasing without energy loss
*/
function createPhaseDampingChannel(gamma) {
if (gamma < 0 || gamma > 1) {
throw new Error('Damping parameter must be between 0 and 1');
}
// Kraus operators for phase damping
const krausOperators = [];
// E0 = |0⟩⟨0| + √(1-γ)|1⟩⟨1|
const E0Matrix = [
[math.complex(1, 0), math.complex(0, 0)],
[math.complex(0, 0), math.complex(Math.sqrt(1 - gamma), 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E0Matrix));
// E1 = √γ|1⟩⟨1|
const E1Matrix = [
[math.complex(0, 0), math.complex(0, 0)],
[math.complex(0, 0), math.complex(Math.sqrt(gamma), 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E1Matrix));
return new KrausChannel(krausOperators);
}
exports.createPhaseDampingChannel = createPhaseDampingChannel;
/**
* Creates a bit flip channel
* Applies X gate with probability p: ρ → (1-p)ρ + pXρX
*/
function createBitFlipChannel(p) {
if (p < 0 || p > 1) {
throw new Error('Probability must be between 0 and 1');
}
// Kraus operators for bit flip channel
const krausOperators = [];
// E0 = √(1-p) * I
const E0Matrix = [
[math.complex(Math.sqrt(1 - p), 0), math.complex(0, 0)],
[math.complex(0, 0), math.complex(Math.sqrt(1 - p), 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E0Matrix));
// E1 = √p * X
const sqrtP = Math.sqrt(p);
const E1Matrix = [
[math.complex(0, 0), math.complex(sqrtP, 0)],
[math.complex(sqrtP, 0), math.complex(0, 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E1Matrix));
return new KrausChannel(krausOperators);
}
exports.createBitFlipChannel = createBitFlipChannel;
/**
* Creates a phase flip channel
* Applies Z gate with probability p: ρ → (1-p)ρ + pZρZ
*/
function createPhaseFlipChannel(p) {
if (p < 0 || p > 1) {
throw new Error('Probability must be between 0 and 1');
}
// Kraus operators for phase flip channel
const krausOperators = [];
// E0 = √(1-p) * I
const E0Matrix = [
[math.complex(Math.sqrt(1 - p), 0), math.complex(0, 0)],
[math.complex(0, 0), math.complex(Math.sqrt(1 - p), 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E0Matrix));
// E1 = √p * Z
const sqrtP = Math.sqrt(p);
const E1Matrix = [
[math.complex(sqrtP, 0), math.complex(0, 0)],
[math.complex(0, 0), math.complex(-sqrtP, 0)]
];
krausOperators.push(new operator_1.MatrixOperator(E1Matrix));
return new KrausChannel(krausOperators);
}
exports.createPhaseFlipChannel = createPhaseFlipChannel;
// Helper functions for quantum operations
function addOperators(a, b) {
if (a.dimension !== b.dimension) {
throw new Error('Operator dimensions do not match');
}
const matrixA = a.toMatrix();
const matrixB = b.toMatrix();
const sumMatrix = matrixA.map((row, i) => row.map((elem, j) => math.add(elem, matrixB[i][j])));
return new operator_1.MatrixOperator(sumMatrix);
}
function subtractOperators(a, b) {
if (a.dimension !== b.dimension) {
throw new Error('Operator dimensions do not match');
}
const matrixA = a.toMatrix();
const matrixB = b.toMatrix();
const diffMatrix = matrixA.map((row, i) => row.map((elem, j) => math.subtract(elem, matrixB[i][j])));
return new operator_1.MatrixOperator(diffMatrix);
}
function createIdentityOperator(dimension) {
const matrix = Array(dimension).fill(null).map((_, i) => Array(dimension).fill(null).map((_, j) => i === j ? math.complex(1, 0) : math.complex(0, 0)));
return new operator_1.MatrixOperator(matrix, 'unitary');
}
function createZeroOperator(dimension) {
const matrix = Array(dimension).fill(null).map(() => Array(dimension).fill(null).map(() => math.complex(0, 0)));
return new operator_1.MatrixOperator(matrix);
}
// Note: Entanglement measures have been moved to information.ts
// This allows better organization of quantum information metrics
// Re-export entanglement measures from information.ts
var information_1 = require("../utils/information");
Object.defineProperty(exports, "traceFidelity", { enumerable: true, get: function () { return information_1.traceFidelity; } });
Object.defineProperty(exports, "concurrence", { enumerable: true, get: function () { return information_1.concurrence; } });
Object.defineProperty(exports, "negativity", { enumerable: true, get: function () { return information_1.negativity; } });
//# sourceMappingURL=densityMatrix.js.map