import _ from 'lodash' ; import Operator from './Operator' ; import Frame from './Frame' ; import { generateOperators } from './Elements' ; import { weightedRandomInt , startingPolarization , startingDirection } from './helpers' ; import { IAbsorption , IGrid , ICell , IIndicator , IXYOperator , IParticle , Elem } from './interfaces' ; returns export function generateLaserIndicator ( cells ) { const lasers = cells . filter ( ( cell ) => cell . element === Elem . Laser ) ; if ( lasers . length !== 1 ) { throw new Error ( `Cannot initialize QuantumSimulation. ${ lasers . length } != 1 lasers.` ) ; } const laserIndicator = { x : lasers [ 0 ] . x , y : lasers [ 0 ] . y , direction : startingDirection ( lasers [ 0 ] . rotation ) , polarization : startingPolarization ( lasers [ 0 ] . polarization ) , } ; return laserIndicator ; } /**
 * SIMULATION CLASS
 * Loads a grid
 * Convert its elements into operators and merge them into a global operator.
 * Generate simulation frames and absorptions.
 */ export default class Simulation { readonly sizeX : number ; readonly sizeY : number ; public operators : IXYOperator [ ] ; public globalOperator : Operator ; public frames : Frame [ ] ; public constructor ( sizeX , sizeY , operators ) { this . sizeX = sizeX ; this . sizeY = sizeY ; this . operators = operators ; this . globalOperator = Frame . singlePhotonInteraction ( this . sizeX , this . sizeY , this . operators ) ; this . frames = [ ] ; } public static fromGrid ( grid ) { return new Simulation ( grid . cols , grid . rows , generateOperators ( grid . cells ) ) ; } param indicator public initializeFromIndicator ( indicator ) { this . frames = [ ] ; const frame = new Frame ( this ) ; frame . addPhotonFromIndicator ( indicator . x , indicator . y , indicator . direction , indicator . polarization ) ; this . frames . push ( frame ) ; } returns public get lastFrame ( ) : Frame { return this . frames [ this . frames . length - 1 ] ; } returns public nextFrame ( ) { if ( this . frames . length === 0 ) { throw new Error ( `Cannot do nextFrame when there are no frames. initializeFromLaser or something else.` ) ; } const frame = new Frame ( this , this . lastFrame . vector ) ; frame . propagateAndInteract ( ) ; return frame ; } param n param stopThreshold param logging public generateFrames ( n = 20 , stopThreshold = 1e-6 , logging = false ) { for ( let i = 0 ; i < n ; i += 1 ) { const nextFrame = this . nextFrame ( ) ; this . frames . push ( nextFrame ) ; if ( this . lastFrame . probability < stopThreshold ) { break ; } } if ( logging ) { console . debug ( 'POST-SIMULATION LOG:' ) ; console . debug ( 'probabilityPerFrame' , this . probabilityPerFrame ) ; console . debug ( 'totalAbsorptionPerFrame' , this . totalAbsorptionPerFrame ) ; console . debug ( 'totalAbsorptionPerTile' , this . totalAbsorptionPerTile ) ; console . debug ( 'An example of realization:' ) ; } } returns public get probabilityPerFrame ( ) : number [ ] { return this . frames . map ( ( frame ) : number => frame . probability ) ; } /**
     * Quantum state probability of absorption for each frame.
     */ public get totalAbsorptionPerFrame ( ) : number [ ] { return this . frames . map ( ( frame ) : number => frame . totalProbabilityLoss ) ; } returns public get allParticles ( ) : IParticle [ ] { const result = [ ] ; this . frames . forEach ( ( frame ) : void => { frame . particles . forEach ( ( particle ) : void => { result . push ( particle ) ; } ) ; } ) ; return result ; } todo returns public get totalAbsorptionPerTile ( ) : IAbsorption [ ] { return _ ( this . frames ) . flatMap ( ( frame ) : IAbsorption [ ] => frame . absorptions ) . groupBy ( ( absorption ) : string => `(${ absorption . x }.${ absorption . y })` ) . values ( ) . map ( ( absorptions ) : IAbsorption => ( { x : absorptions [ 0 ] . x , y : absorptions [ 0 ] . y , probability : _ . sumBy ( absorptions , 'probability' ) , } ) ) . value ( ) ; } remark todo todo todo public sampleRandomRealization ( ) { const lastId = weightedRandomInt ( this . totalAbsorptionPerFrame , false ) ; const lastFrameAbs = this . frames [ lastId ] . absorptions ; const absorptionId = weightedRandomInt ( lastFrameAbs . map ( ( d ) : number => d . probability ) , true ) ; const absorption = lastFrameAbs [ absorptionId ] ; const states = this . frames . slice ( 0 , lastId ) . map ( ( frame ) : Frame => frame . normalize ( ) ) ; return { statePerFrame : states , probability : absorption . probability , step : lastId , x : absorption . x , y : absorption . y , } ; } }