import { antilogAlpha , logAlpha } from '../alpha' ; type CoefficientExponentObject = { [ power ] : number ; } ; const fromNumberArrayToExponentObject = ( coefficients ) => { const exponentObject = { } ; coefficients . forEach ( ( coefficient , index ) => { if ( coefficient === 0 ) return ; exponentObject [ index ] = logAlpha ( coefficient ) ; } ) ; return exponentObject ; } ; const removeTrailingZeroes = ( coefficients ) => { const lastNonZeroIndex = coefficients . length - coefficients . slice ( ) . reverse ( ) . findIndex ( coef => coef !== 0 ) ; return coefficients . slice ( 0 , lastNonZeroIndex ) ; } ; const fromExponentObjectToNumberArray = ( exponents ) => { const maxPower = Math . max ( ... Object . keys ( exponents ) . map ( Number ) ) ; const coefficients = Array ( maxPower + 1 ) . fill ( 0 ) ; for ( const [ power , exponent ] of Object . entries ( exponents ) ) { coefficients [ Number ( power ) ] = antilogAlpha ( exponent ) ; } return removeTrailingZeroes ( coefficients ) ; } ; export class Polinomial { private coefficients : number [ ] ; private exponents : CoefficientExponentObject ; constructor ( coefficients ? , exponents ? ) { if ( coefficients ) { this . coefficients = removeTrailingZeroes ( coefficients ) ; this . exponents = fromNumberArrayToExponentObject ( coefficients ) ; } else if ( exponents ) { this . coefficients = fromExponentObjectToNumberArray ( exponents ) ; this . exponents = exponents ; } else { this . coefficients = [ ] ; this . exponents = { } ; } } static fromCoef ( coefficients ) { return new Polinomial ( coefficients , undefined ) ; } static fromCoefExponents ( exponents ) { return new Polinomial ( undefined , exponents ) ; } coefficientAtPower ( position ) { if ( position >= this . coefficients . length ) { return 0 ; } return this . coefficients [ position ] ; } /**
     * Returns the biggest power that has a non-zero coefficient
     */ greaterPower ( ) { return this . coefficients . length - 1 ; } map ( callback ) { return new Polinomial ( this . coefficients . map ( callback ) ) ; } mapExponent ( callback ) { const newExponentEntries = Object . entries ( this . exponents ) . map ( callback ) ; return new Polinomial ( undefined , Object . fromEntries ( newExponentEntries ) ) ; } sum ( target ) { return target . map ( ( coefficient , power ) => this . coefficientAtPower ( power ) ^ coefficient ) ; } multiply ( target ) { if ( Object . keys ( this . exponents ) . length === 0 ) { return this ; } if ( Object . keys ( target . toExponents ( ) ) . length === 0 ) { return target ; } const polinomials = Object . entries ( this . exponents ) . map ( ( [ lefthandSidePower , exponent ] ) => target . mapExponent ( ( [ righthandSidePower , targetExponent ] ) => [ Number ( lefthandSidePower ) + Number ( righthandSidePower ) , ( exponent + targetExponent + Math . floor ( ( exponent + targetExponent ) / 256 ) ) % 256 , ] ) ) ; return polinomials . reduce ( ( acc , curr ) => acc . sum ( curr ) ) ; } modulo ( target ) { const leadPower = this . greaterPower ( ) ; const targetPower = target . greaterPower ( ) ; const leadExponent = this . exponents [ leadPower ] ; const targetExponent = target . toExponents ( ) [ targetPower ] ; if ( leadPower < target . greaterPower ( ) ) { return this ; } return this . sum ( target . multiply ( Polinomial . fromCoefExponents ( { [ leadPower - targetPower ] : leadExponent - targetExponent } ) ) ) . modulo ( target ) ; } toCoef ( ) { return this . coefficients ; } toExponents ( ) { return this . exponents ; } }