ts-quantum
Version:
TypeScript library for quantum mechanics calculations and utilities
257 lines • 10.4 kB
JavaScript
;
/**
* Multi-Spin State Implementation
*
* Prototype for handling sequential coupling of multiple angular momentum states.
* Addresses the limitations identified in T66 research for multi-spin coupling.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.MultiSpinState = void 0;
const core_1 = require("./core");
const composition_1 = require("./composition");
const stateAnalysis_1 = require("./stateAnalysis");
/**
* Multi-spin angular momentum state that tracks coupling history
* and maintains knowledge of all J components present
*/
class MultiSpinState {
constructor(spins, mValues, currentState, couplingHistory = [], availableJ = new Set()) {
this.spins = [...spins];
this.mValues = [...mValues];
this.currentState = currentState;
this.couplingHistory = [...couplingHistory];
this.availableJ = new Set(availableJ);
}
/**
* Creates a MultiSpinState from a single spin state
* @param j Angular momentum quantum number
* @param m Magnetic quantum number
* @returns New MultiSpinState with single spin
*/
static fromSingleSpin(j, m) {
const state = (0, core_1.createJmState)(j, m);
const availableJ = new Set([j]);
return new MultiSpinState([j], // spins
[m], // mValues
state, // currentState
[], // couplingHistory
availableJ // availableJ
);
}
/**
* Creates a MultiSpinState from existing coupled state (for analysis)
* @param state Existing StateVector
* @param spins Array of individual j values that were coupled
* @param mValues Array of individual m values
* @returns New MultiSpinState for analysis
*/
static fromCoupledState(state, spins, mValues) {
// For now, we can't determine available J values from arbitrary state
// This would require the state decomposition functionality
const availableJ = new Set();
return new MultiSpinState(spins, mValues, state, [], availableJ);
}
/**
* Adds another spin to this multi-spin state using proper state decomposition
* @param j Angular momentum of spin to add
* @param m Magnetic quantum number of spin to add
* @returns New MultiSpinState with additional spin coupled
*/
addSpin(j, m) {
// Create the new spin state
const newSpinState = (0, core_1.createJmState)(j, m);
if (this.spins.length === 1) {
// Simple case: first coupling, we know the effective J
const effectiveJ = this.spins[0];
const coupledState = (0, composition_1.addAngularMomenta)(this.currentState, effectiveJ, newSpinState, j);
// Calculate new available J values
const jMin = Math.abs(effectiveJ - j);
const jMax = effectiveJ + j;
const newAvailableJ = new Set();
for (let newJ = jMin; newJ <= jMax; newJ += 0.5) {
newAvailableJ.add(newJ);
}
// Create coupling step record
const couplingStep = {
addedSpin: j,
addedM: m,
previousJ: Array.from(this.availableJ),
resultingJ: Array.from(newAvailableJ),
timestamp: Date.now()
};
// Get actual available J values from the metadata
const metadata = coupledState.getAngularMomentumMetadata();
const actualAvailableJ = metadata ? new Set(metadata.jComponents.keys()) : newAvailableJ;
return new MultiSpinState([...this.spins, j], [...this.mValues, m], coupledState, [...this.couplingHistory, couplingStep], actualAvailableJ);
}
else {
// Complex case: need to handle composite state with multiple j-components
// This is the key innovation that solves the T66 problem
// Analyze the current composite state
const analysis = (0, stateAnalysis_1.analyzeAngularState)(this.currentState);
if (!analysis.isAngularMomentum) {
throw new Error('Cannot add spin to non-angular momentum state');
}
// For now, use the dominant J component (can be enhanced later)
const dominantJ = analysis.dominantJ;
if (dominantJ === null) {
throw new Error('Cannot determine dominant J component');
}
// Extract the dominant J component as a pure state
const extracted = (0, stateAnalysis_1.extractJComponent)(this.currentState, dominantJ);
if (!extracted) {
throw new Error(`Cannot extract J=${dominantJ} component from composite state`);
}
// Couple the extracted pure state with the new spin
const coupledState = (0, composition_1.addAngularMomenta)(extracted.state, dominantJ, newSpinState, j);
// Calculate new available J values based on the dominant component
const jMin = Math.abs(dominantJ - j);
const jMax = dominantJ + j;
const newAvailableJ = new Set();
for (let newJ = jMin; newJ <= jMax; newJ += 0.5) {
newAvailableJ.add(newJ);
}
// Create coupling step record
const couplingStep = {
addedSpin: j,
addedM: m,
previousJ: Array.from(this.availableJ),
resultingJ: Array.from(newAvailableJ),
timestamp: Date.now()
};
// Get actual available J values from the metadata
const metadata = coupledState.getAngularMomentumMetadata();
const actualAvailableJ = metadata ? new Set(metadata.jComponents.keys()) : newAvailableJ;
return new MultiSpinState([...this.spins, j], [...this.mValues, m], coupledState, [...this.couplingHistory, couplingStep], actualAvailableJ);
}
}
/**
* Extracts a specific J component from the current state
* @param targetJ The J value to extract
* @returns StateVector for that J component, or null if not present
*/
extractJComponent(targetJ) {
if (!this.availableJ.has(targetJ)) {
return null;
}
// Use the metadata-based state analysis implementation (no j1,j2 parameters needed)
const extracted = (0, stateAnalysis_1.extractJComponent)(this.currentState, targetJ);
return extracted ? extracted.state : null;
}
/**
* Simple heuristic to determine dominant J value
* Real implementation would analyze state amplitudes
*/
getDominantJ() {
if (this.availableJ.size === 0) {
throw new Error('No available J values to determine dominant J');
}
// For prototype: return the maximum J value
return Math.max(...Array.from(this.availableJ));
}
/**
* Gets all currently available J values and their information
* @returns Map of J values to basic information
*/
getJComponents() {
const result = new Map();
for (const j of this.availableJ) {
result.set(j, { available: true, estimated: true });
}
return result;
}
/**
* Gets the valid intertwiner values for spin network vertices
* These are the J values that could appear at a vertex with these incident spins
* @returns Array of valid J values
*/
getValidIntertwiners() {
// For a vertex with n incident edges, the valid J values are determined
// by successive application of triangle inequalities
return Array.from(this.availableJ).sort((a, b) => a - b);
}
/**
* Gets all individual spins in this multi-spin state
* @returns Array of individual j values
*/
getIndividualSpins() {
return [...this.spins];
}
/**
* Gets all individual magnetic quantum numbers
* @returns Array of individual m values
*/
getIndividualMs() {
return [...this.mValues];
}
/**
* Gets the coupling history showing how this state was built
* @returns Array of coupling steps
*/
getCouplingHistory() {
return [...this.couplingHistory];
}
/**
* Gets the current coupled state vector
* @returns Current StateVector
*/
getCurrentState() {
return this.currentState;
}
/**
* Gets the total dimension of the current state
* @returns Dimension of current state vector
*/
getDimension() {
return this.currentState.dimension;
}
/**
* Gets the number of individual spins in this state
* @returns Number of spins
*/
getSpinCount() {
return this.spins.length;
}
/**
* Gets the norm of the current state
* @returns Norm of current state vector
*/
norm() {
return this.currentState.norm();
}
/**
* Checks if the state is normalized
* @param tolerance Numerical tolerance
* @returns True if state is normalized
*/
isNormalized(tolerance = 1e-10) {
return Math.abs(this.norm() - 1.0) < tolerance;
}
/**
* Returns a string representation of the multi-spin state
* @returns Human-readable description
*/
toString() {
const spinInfo = this.spins.map((j, i) => `j${i + 1}=${j}`).join(', ');
const mInfo = this.mValues.map((m, i) => `m${i + 1}=${m}`).join(', ');
const jInfo = Array.from(this.availableJ).sort().join(', ');
return `MultiSpinState(${this.spins.length} spins: ${spinInfo}; ${mInfo}; available J=[${jInfo}]; dim=${this.getDimension()})`;
}
/**
* Returns detailed information about the state
* @returns Detailed string representation
*/
toDetailedString() {
let result = this.toString() + '\n';
result += `State: ${this.currentState.toString()}\n`;
if (this.couplingHistory.length > 0) {
result += 'Coupling History:\n';
this.couplingHistory.forEach((step, i) => {
result += ` ${i + 1}. Added j=${step.addedSpin}, m=${step.addedM}: [${step.previousJ.join(',')}] → [${step.resultingJ.join(',')}]\n`;
});
}
return result;
}
}
exports.MultiSpinState = MultiSpinState;
//# sourceMappingURL=multiSpinState.js.map