import _ from 'lodash' ; const identityMap = new Map < string , symbol > ( ) ; /**
 * Dimension class, e.g.
 * - "polarization" with coordinates ["H", "V"]
 * - "direction" with coordinates [">", "^", "<", "v"]
 * Vide: http://nlp.seas.harvard.edu/NamedTensor and http://nlp.seas.harvard.edu/NamedTensor2
 */ export default class Dimension { /** A symbol used for Dimension comparison */ private readonly identity : symbol ; name : string ; size : number ; coordNames : string [ ] ; param name param size param coordNames constructor ( name , size , coordNames ) { if ( size !== coordNames . length ) { throw new Error ( `Coordinates [${ coordNames }] array is of length ${ coordNames . length }, not ${ size }.` ) ; } this . name = name ; this . coordNames = coordNames ; this . size = size ; const hashKey = this . hashKey ( ) ; let identity = identityMap . get ( hashKey ) ; if ( identity == null ) { identity = Symbol ( name ) ; identityMap . set ( hashKey , identity ) ; } this . identity = identity ; } remark returns private hashKey ( ) { return `${ this . name }-${ this . size }-${ this . coordNames . length }-${ this . coordNames . map ( ( n , i ) => `#${ i }-${ n }` ) . join ( '-' ) }` ; } param basis returns static polarization ( basis = [ 'H' , 'V' ] ) { return new Dimension ( 'polarization' , 2 , basis ) ; } returns static direction ( ) { return new Dimension ( 'direction' , 4 , [ '>' , '^' , '<' , 'v' ] ) ; } param basis returns static spin ( basis = [ 'u' , 'd' ] ) { return new Dimension ( 'spin' , 2 , basis ) ; } param size param name static position ( size , name = 'x' ) { const coordNames = _ . range ( size ) . map ( ( i ) => i . toString ( ) ) ; return new Dimension ( name , size , coordNames ) ; } note Equivalent to  Dimension . position (2, 'qubit')
     *  param basis returns static qubit ( basis = [ '0' , '1' ] ) { return new Dimension ( 'qubit' , 2 , basis ) ; } param n returns static qubits ( n ) { return _ . range ( n ) . map ( ( ) => Dimension . qubit ( ) ) ; } param coordNames reassignCoordNames ( coordNames ) { return new Dimension ( this . name , this . size , coordNames ) ; } returns toString ( ) { return `#Dimension [${ this . name }] of size [${ this . size . toString ( ) }] has coordinates named: [${ this . coordNames }]` ; } returns get coordString ( ) : string { return this . coordNames . join ( '' ) ; } param dim2 returns isEqual ( dim2 ) { return this . identity === dim2 . identity ; } param coordName returns coordNameToIndex ( coordName ) { const idx = this . coordNames . indexOf ( coordName ) ; if ( idx < 0 ) { throw new Error ( `${ coordName } is not in [${ this . coordNames }]` ) ; } else { return idx ; } } param dims static concatDimNames ( dims ) { let names = '' ; dims . forEach ( ( dim ) => { names += dim . coordString ; } ) ; return names ; } param dims1 param dims2 static checkDimensions ( dims1 , dims2 ) { if ( dims1 . length !== dims2 . length ) { console . error ( `Dimensions with unequal number of components ${ dims1 . length } !== ${ dims2 . length }.\n
        Dimensions 1:\n${ dims1 . join ( '\n' ) }\n
        Dimensions 2:\n${ dims2 . join ( '\n' ) }` ) ; throw new Error ( 'Dimensions array size mismatch...' ) ; } for ( let i = 0 ; i < dims1 . length ; i ++ ) { if ( ! dims1 [ i ] . isEqual ( dims2 [ i ] ) ) { console . error ( `Dimensions have the same number of components, but the component ${ i } is\n${ dims1 [ i ] }\nvs\n${ dims2 [ i ] }.\n
          Dimensions 1:\n${ dims1 . join ( '\n' ) }\n
          Dimensions 2:\n${ dims2 . join ( '\n' ) }` ) ; throw new Error ( 'Dimensions array order mismatch...' ) ; } } } param s param dimensions returns static stringToCoordIndices ( s , dimensions ) { if ( dimensions . length !== s . length ) { throw `dimensions.length (${ dimensions . length }) !== string.length (${ s . length })` ; } return _ . range ( dimensions . length ) . map ( ( i ) => dimensions [ i ] . coordNameToIndex ( s [ i ] ) ) ; } }