nl_tokens: integral ( f ( x ) ^g ( x ) * f ( x ) ^h ( x ) x ) = integral ( f ( x ) ^ ( g ( x ) + h ( x )) x )
pl_tokens: function ( expr , context , subIntegral ) { if ( expr . type === "OperatorNode" && expr . op === '*' ) { var argsAsPower = expr . args . map ( getExprInPowerForm ) ; // Collect common bases (this is O(n^2) worst case) var reducedArgs = argsAsPower . reduce ( function ( acc , exprPower ) { for ( var i = 0 ; i < <mask> . length ; i ++ ) { if ( acc [ i ] . base . equals ( exprPower . base ) ) { acc [ i ] . power = new OperatorNode ( '+' , 'add' , [ acc [ i ] . power , exprPower . power ] ) ; return acc ; } } // Did not share a common base with any other factor so far acc . push ( exprPower ) ; return acc ; } , [ ] ) ; if ( reducedArgs . length < expr . args . length ) { // We combined some things var reducedExpr = powerFactorsToNode ( reducedArgs ) ; return subIntegral ( reducedExpr , context , "combining powers" ) ; } } function getExprInPowerForm ( expr ) { if ( expr . type === "OperatorNode" && expr . op === '^' ) { return { base : expr . args [ 0 ] , power : expr . args [ 1 ] } ; } else { return { base : expr , power : new ConstantNode ( 1 ) } ; } } function powerFactorsToNode ( factors ) { if ( factors . length === 1 ) { return powerToNode ( factors [ 0 ] ) ; } else { return new OperatorNode ( '*' , 'multiply' , factors . map ( powerToNode ) ) ; } function powerToNode ( powerExpr ) { return new OperatorNode ( '^' , 'pow' , [ powerExpr . base , powerExpr . power ] ) ; } } }