The partial trace operation is a fundamental operation in quantum mechanics that allows us to obtain the reduced density matrix of a subsystem by "tracing out" other subsystems. This document outlines the consolidated implementation approach for the quantum package.
The partial trace implementation should be consolidated in a single location:
// Primary implementation: packages/quantum/src/operators/operator.ts
// In MatrixOperator class
All other implementations should be removed or refactored to use this primary implementation.
The partial trace operation $\text{Tr}B(\rho{AB})$ for a composite system $\rho_{AB}$ is defined as:
$\text{Tr}B(\rho{AB}) = \sum_i (I_A \otimes \langle i_B|)\rho_{AB}(I_A \otimes |i_B\rangle)$
where:
partialTrace(dims: number[], traceOutIndices: number[]): IOperator {
// Validate dimensions
const totalDim = dims.reduce((a, b) => a * b, 1);
if (totalDim !== this.dimension) {
throw new Error('Product of subsystem dimensions must equal total dimension');
}
// Validate trace indices
if (!traceOutIndices.every(i => i >= 0 && i < dims.length)) {
throw new Error('Invalid trace out indices');
}
// Calculate remaining dimension
const remainingDim = dims
.filter((_, i) => !traceOutIndices.includes(i))
.reduce((a, b) => a * b, 1);
// Initialize result matrix
const resultMatrix = Array(remainingDim).fill(null)
.map(() => Array(remainingDim).fill(null)
.map(() => math.complex(0, 0)));
// Perform partial trace using coordinate mapping
const traceRange = Array(this.dimension).fill(0).map((_, i) => i);
for (let i = 0; i < remainingDim; i++) {
for (let j = 0; j < remainingDim; j++) {
for (const k of traceRange) {
// Map indices to multi-dimensional coordinates
const iCoords = indexToCoords(i, dims.filter((_, idx) =>
!traceOutIndices.includes(idx)));
const jCoords = indexToCoords(j, dims.filter((_, idx) =>
!traceOutIndices.includes(idx)));
const kCoords = indexToCoords(k, dims.filter((_, idx) =>
traceOutIndices.includes(idx)));
// Combine coordinates
const fullICoords = combineCoords(iCoords, kCoords, traceOutIndices);
const fullJCoords = combineCoords(jCoords, kCoords, traceOutIndices);
// Map back to flat indices
const fullI = coordsToIndex(fullICoords, dims);
const fullJ = coordsToIndex(fullJCoords, dims);
// Add to result
resultMatrix[i][j] = math.add(
resultMatrix[i][j],
this.matrix[fullI][fullJ]
) as Complex;
}
}
}
return new MatrixOperator(resultMatrix);
}
function indexToCoords(index: number, dims: number[]): number[] {
const coords: number[] = [];
let remainder = index;
for (let i = dims.length - 1; i >= 0; i--) {
coords.unshift(remainder % dims[i]);
remainder = Math.floor(remainder / dims[i]);
}
return coords;
}
function coordsToIndex(coords: number[], dims: number[]): number {
let index = 0;
let factor = 1;
for (let i = coords.length - 1; i >= 0; i--) {
index += coords[i] * factor;
factor *= dims[i];
}
return index;
}
function combineCoords(coords1: number[], coords2: number[],
traceIndices: number[]): number[] {
const result: number[] = [];
let i1 = 0;
let i2 = 0;
for (let i = 0; i < coords1.length + coords2.length; i++) {
if (traceIndices.includes(i)) {
result.push(coords2[i2++]);
} else {
result.push(coords1[i1++]);
}
}
return result;
}
All validation should be consolidated into the validatePartialTrace function in utils/validation.ts:
export function validatePartialTrace(
dims: number[],
totalDim: number,
traceOutIndices: number[]
): void {
// Validate total dimension
const dimProduct = dims.reduce((a, b) => a * b, 1);
if (dimProduct !== totalDim) {
throw new Error(
'Product of subsystem dimensions must equal total dimension'
);
}
// Validate trace indices
if (!traceOutIndices.every(i => i >= 0 && i < dims.length)) {
throw new Error('Invalid trace out indices');
}
// Validate remaining dimension is non-zero
const remainingDim = dims
.filter((_, i) => !traceOutIndices.includes(i))
.reduce((a, b) => a * b, 1);
if (remainingDim === 0) {
throw new Error('Cannot trace out all subsystems');
}
}
// Create a 4x4 density matrix (2-qubit system)
const matrix = new MatrixOperator(/* ... */);
// Trace out second qubit
const reducedDensity = matrix.partialTrace([2, 2], [1]);
// Create an 8x8 density matrix (3-qubit system)
const matrix = new MatrixOperator(/* ... */);
// Trace out first and third qubits
const reducedDensity = matrix.partialTrace([2, 2, 2], [0, 2]);
Unit Tests:
Integration Tests: