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; } RecursiveLinearizingComposer(SimplePolynomialFunction outer ); @Override void bucket(Monomial m, BitVector contribution); SimplePolynomialFunction compose( SimplePolynomialFunction inner ); SimplePolynomialFunction getConstantFunction( int innerInputLength);  }
@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 ); }