class RecursiveLinearizingComposer extends RecursiveLinearizingComposerTree {

    public SimplePolynomialFunction compose( SimplePolynomialFunction inner ) {
        Preconditions.checkArgument(outerInputLength == inner.getOutputLength() , "Outer input length must equal inner output length" );
        List<SimplePolynomialFunction> pieces = evaluate( null , Arrays.asList( inner.getMonomials() ), Lists.newArrayList( inner.getMonomials() ), rowContributions( inner ) , indices( inner.getMonomials() ) );
        SimplePolynomialFunction result = null;
        for( SimplePolynomialFunction piece : pieces ) {
            if( result == null ) { 
                result = piece;
            } else {
                result = piece.xor( result );
            }
        }
        if( constantContribution!=null ) {
            result = result.xor( getConstantFunction( inner.getInputLength() ) );
        }
        return result;
    }

}

class RecursiveLinearizingComposerTest {

    private static final Logger logger;

    @Test 
    public void testRecurisveLinearizingComposer() {

        logger.debug("Starting recursive linearing composer tests.");
        BasePolynomialFunction f = (BasePolynomialFunction)SimplePolynomialFunctions.denseRandomMultivariateQuadratic( 128 , 128);
        BasePolynomialFunction inner = (BasePolynomialFunction) EnhancedBitMatrix.randomMatrix( 128 , 256 ) .multiply(  SimplePolynomialFunctions.identity( 256 ) );
        
        
        RecursiveLinearizingComposer composer = new RecursiveLinearizingComposer( f );
        Stopwatch watch = Stopwatch.createStarted();
        SimplePolynomialFunction composed = composer.compose( inner );
        logger.info( "Compose time: {} ms" , watch.elapsed( TimeUnit.MILLISECONDS ) );
        
        BitVector input =  BitVectors.randomVector( inner.getInputLength() );
        BitVector expected = f.apply( inner.apply( input ) );
        BitVector actual = composed.apply( input );
        
        Assert.assertEquals( expected , actual );
    }

}