private IQTree liftBinding(ConstructionNode childConstructionNode, UnaryIQTree liftedChildIQ,
                               IQProperties currentIQProperties, VariableGenerator variableGenerator) {
        IQTree grandChildIQTree = liftedChildIQ.getChild();

        IQProperties liftedProperties = currentIQProperties.declareLifted();

        ImmutableExpression unoptimizedExpression = childConstructionNode.getSubstitution()
                .applyToBooleanExpression(getFilterCondition());

        try {
            ExpressionAndSubstitution expressionAndSubstitution = simplifyCondition(Optional.of(unoptimizedExpression),
                    ImmutableSet.of());

            Optional<FilterNode> newFilterNode = expressionAndSubstitution.optionalExpression
                    .map(iqFactory::createFilterNode);

            if (expressionAndSubstitution.substitution.isEmpty()) {
                IQTree filterLevelTree = newFilterNode
                        .map(n -> (IQTree) iqFactory.createUnaryIQTree(n, grandChildIQTree, liftedProperties))
                        .orElse(grandChildIQTree);
                return iqFactory.createUnaryIQTree(childConstructionNode, filterLevelTree, liftedProperties);
            }
            else {
                IQTree newGrandChild = grandChildIQTree.applyDescendingSubstitution(
                        expressionAndSubstitution.substitution, expressionAndSubstitution.optionalExpression);

                IQTree filterLevelTree = newFilterNode
                        .map(n -> (IQTree) iqFactory.createUnaryIQTree(n, newGrandChild, currentIQProperties))
                        .orElse(newGrandChild);

                IQTree filterParentTree = iqFactory.createUnaryIQTree(
                        iqFactory.createConstructionNode(grandChildIQTree.getVariables(),
                                (ImmutableSubstitution<ImmutableTerm>)(ImmutableSubstitution<?>)
                                        expressionAndSubstitution.substitution),
                        filterLevelTree);

                // Recursive
                return iqFactory.createUnaryIQTree(childConstructionNode, filterParentTree, currentIQProperties)
                        .liftBinding(variableGenerator);
            }

        } catch (UnsatisfiableConditionException e) {
            return iqFactory.createEmptyNode(childConstructionNode.getVariables());
        }
    }
private IQTree liftBinding ( ConstructionNode childConstructionNode , UnaryIQTree liftedChildIQ , IQProperties currentIQProperties , VariableGenerator variableGenerator ) { IQTree grandChildIQTree = liftedChildIQ . getChild ( ) ; IQProperties liftedProperties = currentIQProperties . declareLifted ( ) ; ImmutableExpression unoptimizedExpression = childConstructionNode . getSubstitution ( ) . applyToBooleanExpression ( getFilterCondition ( ) ) ; try { ExpressionAndSubstitution expressionAndSubstitution = simplifyCondition ( Optional . of ( unoptimizedExpression ) , ImmutableSet . of ( ) ) ; Optional < FilterNode > newFilterNode = expressionAndSubstitution . optionalExpression . map ( iqFactory :: createFilterNode ) ; if ( expressionAndSubstitution . substitution . isEmpty ( ) ) { IQTree filterLevelTree = newFilterNode . map ( n -> ( IQTree ) iqFactory . createUnaryIQTree ( n , grandChildIQTree , liftedProperties ) ) . orElse ( grandChildIQTree ) ; return iqFactory . createUnaryIQTree ( childConstructionNode , filterLevelTree , liftedProperties ) ; } else { IQTree newGrandChild = grandChildIQTree . applyDescendingSubstitution ( expressionAndSubstitution . substitution , expressionAndSubstitution . optionalExpression ) ; IQTree filterLevelTree = newFilterNode . map ( n -> ( IQTree ) iqFactory . createUnaryIQTree ( n , newGrandChild , currentIQProperties ) ) . orElse ( newGrandChild ) ; IQTree filterParentTree = iqFactory . createUnaryIQTree ( iqFactory . createConstructionNode ( grandChildIQTree . getVariables ( ) , ( ImmutableSubstitution < ImmutableTerm > ) ( ImmutableSubstitution < ? > ) expressionAndSubstitution . substitution ) , filterLevelTree ) ; return iqFactory . createUnaryIQTree ( childConstructionNode , filterParentTree , currentIQProperties ) . liftBinding ( variableGenerator ) ; } } catch ( UnsatisfiableConditionException e ) { return iqFactory . createEmptyNode ( childConstructionNode . getVariables ( ) ) ; } }
TODO: let the filter node simplify (interpret) expressions in the lifted substitution