code: private IQTree liftBindingAfterPropagatingCondition(ImmutableList<IQTree> initialChildren,
                                                          VariableGenerator variableGenerator,
                                                          IQProperties currentIQProperties) {
          final ImmutableSet<Variable> projectedVariables = getProjectedVariables(initialChildren);
  
          // Non-final
          ImmutableList<IQTree> currentChildren = initialChildren;
          ImmutableSubstitution<ImmutableTerm> currentSubstitution = substitutionFactory.getSubstitution();
          Optional<ImmutableExpression> currentJoiningCondition = getOptionalFilterCondition();
          boolean hasConverged = false;
  
          try {
  
              int i = 0;
              while ((!hasConverged) && (i++ < MAX_ITERATIONS)) {
                  LiftingStepResults results = liftChildBinding(currentChildren, currentJoiningCondition, variableGenerator);
                  hasConverged = results.hasConverged;
                  currentChildren = results.children;
                  currentSubstitution = results.substitution.composeWith(currentSubstitution);
                  currentJoiningCondition = results.joiningCondition;
              }
  
              if (i >= MAX_ITERATIONS)
                  throw new MinorOntopInternalBugException("InnerJoin.liftBinding() did not converge after " + MAX_ITERATIONS);
  
              IQTree joinIQ = createJoinOrFilterOrTrue(currentChildren, currentJoiningCondition, currentIQProperties);
  
              AscendingSubstitutionNormalization ascendingNormalization =
                      normalizeAscendingSubstitution(currentSubstitution, projectedVariables);
  
              IQTree newJoinIQ = ascendingNormalization.normalizeChild(joinIQ);
  
              ImmutableSet<Variable> childrenVariables = getProjectedVariables(currentChildren);
  
              /*
               * NB: creates a construction if a substitution needs to be propagated and/or if some variables
               * have to be projected away
               */
              return ascendingNormalization.generateTopConstructionNode()
                      .map(Optional::of)
                      .orElseGet(() -> Optional.of(projectedVariables)
                              .filter(vars -> !vars.equals(childrenVariables))
                              .map(iqFactory::createConstructionNode))
                      .map(constructionNode -> (IQTree) iqFactory.createUnaryIQTree(constructionNode, newJoinIQ,
                              currentIQProperties.declareLifted()))
                      .orElse(newJoinIQ);
  
          } catch (EmptyIQException e) {
              return iqFactory.createEmptyNode(projectedVariables);
          }
      }
docs: TODO: explain