code: package it.unibz.inf.ontop.model.term.functionsymbol.db.impl;
  
  import com.google.common.collect.ImmutableList;
  import it.unibz.inf.ontop.exception.MinorOntopInternalBugException;
  import it.unibz.inf.ontop.iq.node.VariableNullability;
  import it.unibz.inf.ontop.model.term.*;
  import it.unibz.inf.ontop.model.term.functionsymbol.db.DBNotFunctionSymbol;
  import it.unibz.inf.ontop.model.term.functionsymbol.db.TrueOrNullFunctionSymbol;
  import it.unibz.inf.ontop.model.type.DBTermType;
  import it.unibz.inf.ontop.utils.ImmutableCollectors;
  
  import javax.annotation.Nonnull;
  import java.util.Optional;
  import java.util.function.Function;
  
  public class DefaultDBNotFunctionSymbol extends DBBooleanFunctionSymbolImpl implements DBNotFunctionSymbol {
  
      private final String prefix;
  
      protected DefaultDBNotFunctionSymbol(@Nonnull String nameInDialect, DBTermType dbBooleanTermType) {
          super(nameInDialect, ImmutableList.of(dbBooleanTermType), dbBooleanTermType);
          prefix = String.format("%s ", nameInDialect);
      }
  
      @Override
      public boolean blocksNegation() {
          return false;
      }
  
      @Override
      public ImmutableExpression negate(ImmutableList<? extends ImmutableTerm> subTerms, TermFactory termFactory) {
          return (ImmutableExpression) subTerms.get(0);
      }
  
      @Override
      public String getNativeDBString(ImmutableList<? extends ImmutableTerm> terms, Function<ImmutableTerm, String> termConverter,
                                      TermFactory termFactory) {
          return inBrackets(prefix + termConverter.apply(terms.get(0)));
      }
  
      @Override
      public boolean isAlwaysInjectiveInTheAbsenceOfNonInjectiveFunctionalTerms() {
          return true;
      }
  
      @Override
      public boolean canBePostProcessed(ImmutableList<? extends ImmutableTerm> arguments) {
          return true;
      }
  
      @Override
      protected ImmutableTerm buildTermAfterEvaluation(ImmutableList<ImmutableTerm> newTerms,
                                                       TermFactory termFactory, VariableNullability variableNullability) {
  
          ImmutableTerm newTerm = newTerms.get(0);
          if (newTerm instanceof Constant)
              return newTerm.isNull()
                      ? newTerm
                      : termFactory.getDBBooleanConstant(newTerm.equals(termFactory.getDBBooleanConstant(false)));
  
          if (newTerm instanceof ImmutableExpression) {
              ImmutableExpression newExpression = ((ImmutableExpression) newTerm);
              ImmutableExpression negatedTerm = newExpression.negate(termFactory);
              return newExpression.getFunctionSymbol().blocksNegation()
                      // Avoids infinite loop
                      ? negatedTerm
                      : negatedTerm.simplify(variableNullability);
          }
          else if (newTerm instanceof Variable)
              // TODO: shall we use NOT(IS_TRUE(...) instead)?
              return termFactory.getStrictEquality(newTerm, termFactory.getDBBooleanConstant(false));
          else
              throw new MinorOntopInternalBugException("NOT was expecting an expression as parameter");
      }
  
      @Override
      protected boolean tolerateNulls() {
          return false;
      }
  
      /**
       * Requires its arguments to be expressions
       */
      @Override
      protected ImmutableList<? extends ImmutableTerm> transformIntoRegularArguments(
              ImmutableList<? extends NonFunctionalTerm> arguments, TermFactory termFactory) {
          return arguments.stream()
                  .map(termFactory::getIsTrue)
                  .collect(ImmutableCollectors.toList());
      }
  
      @Override
      public ImmutableTerm simplify2VL(ImmutableList<? extends ImmutableTerm> terms, TermFactory termFactory,
                                       VariableNullability variableNullability) {
          ImmutableTerm simplifedTerm = simplify(terms, termFactory, variableNullability);
  
          if (simplifedTerm.isNull())
              return termFactory.getDBBooleanConstant(false);
  
          Optional<ImmutableExpression> optionalNewNotExpression = Optional.of(simplifedTerm)
                  .filter(t -> t instanceof ImmutableExpression)
                  .map(e -> (ImmutableExpression) e)
                  .filter(e -> e.getFunctionSymbol().equals(this));
  
          return optionalNewNotExpression
                  .map(n -> Optional.of(n)
                          .map(e -> e.getTerm(0))
                          .filter(t -> t instanceof ImmutableExpression)
                          /*
                           * NOT(TRUE_OR_NULL(...)) is false under 2VL.
                           */
                          .filter(t -> ((ImmutableExpression) t).getFunctionSymbol() instanceof TrueOrNullFunctionSymbol)
                          .map(t -> (ImmutableTerm) termFactory.getDBBooleanConstant(false))
                          .orElse(simplifedTerm))
                  .orElseGet(() -> Optional.of(simplifedTerm)
                          .filter(t -> t instanceof ImmutableExpression)
                          .map(t -> (ImmutableExpression) t)
                          // Makes sure the 2VL is evaluated for the simplified expression
                          .map(t -> t.evaluate2VL(variableNullability).getTerm())
                          .orElse(simplifedTerm));
      }
  }
  