gt:         gla = new SignedNumberRelations();
context: package org.matheclipse.core.eval.util;
  
  import java.util.HashMap;
  import java.util.Map;
  import org.matheclipse.core.builtin.IOFunctions;
  import org.matheclipse.core.eval.EvalEngine;
  import org.matheclipse.core.expression.F;
  import org.matheclipse.core.expression.S;
  import org.matheclipse.core.interfaces.IAST;
  import org.matheclipse.core.interfaces.IBuiltInSymbol;
  import org.matheclipse.core.interfaces.IDistribution;
  import org.matheclipse.core.interfaces.IEvaluator;
  import org.matheclipse.core.interfaces.IExpr;
  import org.matheclipse.core.interfaces.ISignedNumber;
  import org.matheclipse.core.interfaces.ISymbol;
  
  public class Assumptions extends AbstractAssumptions {
  
    private static class SignedNumberRelations {
  
      static final int GREATER_ID = 0;
      static final int GREATEREQUAL_ID = 1;
      static final int LESS_ID = 2;
      static final int LESSEQUAL_ID = 3;
      static final int EQUALS_ID = 4;
  
      private final ISignedNumber[] values;
  
      public SignedNumberRelations() {
        this.values = new ISignedNumber[5];
      }
  
      public final void addEquals(ISignedNumber expr) {
        values[EQUALS_ID] = expr;
      }
  
      public final void addGreater(ISignedNumber expr) {
        values[GREATER_ID] = expr;
      }
  
      public final void addGreaterEqual(ISignedNumber expr) {
        values[GREATEREQUAL_ID] = expr;
      }
  
      public final void addLess(ISignedNumber expr) {
        values[LESS_ID] = expr;
      }
  
      public final void addLessEqual(ISignedNumber expr) {
        values[LESSEQUAL_ID] = expr;
      }
  
      public final ISignedNumber getEquals() {
        return values[EQUALS_ID];
      }
  
      /**
       * The key has to be greater than the returned value from the values map, if <code>value!=null
       * </code>
       *
       * @return
       */
      public final ISignedNumber getGreater() {
        return values[GREATER_ID];
      }
  
      /**
       * The key has to be greater equal the returned value from the values map, if <code>value!=null
       * </code>
       *
       * @return
       */
      public final ISignedNumber getGreaterEqual() {
        return values[GREATEREQUAL_ID];
      }
  
      /**
       * The key has to be less than the returned value from the values map, if <code>value!=null
       * </code>
       *
       * @return
       */
      public final ISignedNumber getLess() {
        return values[LESS_ID];
      }
  
      /**
       * The key has to be less equal the returned value from the values map, if <code>value!=null
       * </code>
       *
       * @return
       */
      public final ISignedNumber getLessEqual() {
        return values[LESSEQUAL_ID];
      }
  
      public final boolean isLessOrGreaterRelation() {
        for (int i = 0; i <= LESSEQUAL_ID; i++) {
          if (values != null) {
            return true;
          }
        }
        return false;
      }
    }
  
    /**
     * Add a distribution.
     *
     * @param element a <code>Distributed(x, &lt;distribution&gt;)</code> expression
     * @param assumptions
     * @return
     */
    private static boolean addDistribution(IAST element, Assumptions assumptions) {
      if (element.arg2().isAST()) {
        IAST dist = (IAST) element.arg2();
  
        ISymbol head = (ISymbol) dist.head();
        if (head instanceof IBuiltInSymbol) {
          IEvaluator evaluator = ((IBuiltInSymbol) head).getEvaluator();
          if (evaluator instanceof IDistribution) {
            IExpr arg1 = element.arg1();
            if (arg1.isAST(S.Alternatives)) {
              ((IAST) arg1).forEach(x -> assumptions.distributionsMap.put(x, dist));
            } else {
              assumptions.distributionsMap.put(arg1, dist);
            }
            return true;
          }
        }
      }
      return false;
    }
  
    /**
     * Add a domain. Domain can be <code>
     * Algebraics, Booleans, Complexes, Integers, Primes, Rationals, Reals</code>
     *
     * @param element a <code>Element(x, &lt;domain&gt;)</code> expression
     * @param assumptions
     * @return
     */
    private static boolean addElement(IAST element, Assumptions assumptions) {
      if (element.size() >= 3) {
        IExpr arg1 = element.arg1();
        if (arg1.isAlternatives()) {
          IAST list = ((IAST) arg1).apply(S.List);
          list = list.mapThread(element, 1);
          for (int i = 1; i < list.size(); i++) {
            final IExpr arg = list.get(i);
            if (!arg.isAST()) {
              return false;
            }
            if (!addElement((IAST) arg, assumptions)) {
              return false;
            }
          }
          return true;
        }
        if (element.arg2().isSymbol()) {
          ISymbol domain = (ISymbol) element.arg2();
          if (S.isDomain(domain)) {
            if (arg1.isAST(S.Alternatives)) {
              ((IAST) arg1).forEach(x -> assumptions.elementsMap.put(x, domain));
            } else {
              assumptions.elementsMap.put(arg1, domain);
            }
            return true;
          }
        } else if (element.arg2().isAST(S.Arrays, 2, 3)) {
          IAST arrays = (IAST) element.arg2();
          ISymbol domain = S.Complexes;
          if (arrays.size() > 2 && arrays.arg2().isSymbol()) {
            domain = (ISymbol) arrays.arg2();
            if (S.isDomain(domain)) {
              // pass
            } else {
              return false;
            }
          }
          if (arrays.arg1().isList() && arrays.arg1().argSize() >= 2) {
            assumptions.tensorsMap.put(arg1, F.Arrays(arrays.arg1(), domain));
            return true;
          } else {
            // The list `1` of dimensions must have length `2`.
            IOFunctions.printMessage(S.Arrays, "rankl", F.list(arrays.arg1(), F.C2),
                EvalEngine.get());
          }
        } else if (element.arg2().isAST(S.Matrices, 2, 4)) {
          IAST matrices = (IAST) element.arg2();
          ISymbol domain = S.Complexes;
          if (matrices.size() > 2 && matrices.arg2().isSymbol()) {
            domain = (ISymbol) matrices.arg2();
            if (S.isDomain(domain)) {
              // pass
            } else {
              return false;
            }
          }
          if (matrices.arg1().isList() && matrices.arg1().argSize() == 2) {
            assumptions.tensorsMap.put(arg1, F.Matrices(matrices.arg1(), domain));
            return true;
          } else {
            // The list `1` of dimensions must have length `2`.
            IOFunctions.printMessage(S.Matrices, "rankl", F.list(matrices.arg1(), F.C2),
                EvalEngine.get());
          }
        } else if (element.arg2().isAST(S.Vectors, 2, 3)) {
          IAST vectors = (IAST) element.arg2();
          ISymbol domain = S.Complexes;
          if (vectors.size() > 2 && vectors.arg2().isSymbol()) {
            domain = (ISymbol) vectors.arg2();
            if (S.isDomain(domain)) {
              // pass
            } else {
              return false;
            }
          }
          if (!vectors.arg1().isList()) {
            assumptions.tensorsMap.put(arg1, F.Vectors(vectors.arg1(), domain));
            return true;
          } else {
            // The list `1` of dimensions must have length `2`.
            IOFunctions.printMessage(S.Vectors, "rankl", F.list(vectors.arg1(), F.C2),
                EvalEngine.get());
          }
        }
      }
      return false;
    }
  
    private static boolean addEqual(IAST equalsAST, Assumptions assumptions) {
      // arg1 == arg2
      if (equalsAST.arg2().isReal()) {
        ISignedNumber num = (ISignedNumber) equalsAST.arg2();
        IExpr key = equalsAST.arg1();
        SignedNumberRelations gla = assumptions.valueMap.get(key);
        if (gla == null) {
          gla = new SignedNumberRelations();
        }
        gla.addEquals(num);
        assumptions.valueMap.put(key, gla);
        return true;
      }
      if (equalsAST.arg1().isReal()) {
        ISignedNumber num = (ISignedNumber) equalsAST.arg1();
        IExpr key = equalsAST.arg2();
        SignedNumberRelations gla = assumptions.valueMap.get(key);
        if (gla == null) {
          gla = new SignedNumberRelations();
        }
        gla.addEquals(num);
        assumptions.valueMap.put(key, gla);
        return true;
      }
      return false;
    }
  
    private static boolean addGreater(IAST greaterAST, Assumptions assumptions) {
      if (greaterAST.isAST3()) {
        // arg1 > arg2 > arg3
        IExpr arg1 = greaterAST.arg1();
        IExpr arg2 = greaterAST.arg2();
        IExpr arg3 = greaterAST.arg3();
        if (arg1.isReal() && arg3.isReal() && !arg2.isNumber()) {
          if (((ISignedNumber) arg1).isGT(((ISignedNumber) arg3))) {
            ISignedNumber num1 = (ISignedNumber) arg1;
            ISignedNumber num3 = (ISignedNumber) arg3;
            IExpr key = arg2;
            SignedNumberRelations gla = assumptions.valueMap.get(key);
            if (gla == null) {
              gla = new SignedNumberRelations();
            }
            gla.addLess(num1);
            gla.addGreater(num3);
            assumptions.valueMap.put(key, gla);
            return true;
          }
        }
        return false;
      }
  
      // arg1 > arg2
      ISignedNumber num = null;
      if (greaterAST.arg2().isReal()) {
        num = (ISignedNumber) greaterAST.arg2();
      } else {
        num = greaterAST.arg2().evalReal();
      }
      if (num != null) {
        IExpr key = greaterAST.arg1();
        SignedNumberRelations gla = assumptions.valueMap.get(key);
        if (gla == null) {
          gla = new SignedNumberRelations();
        }
        gla.addGreater(num);
        assumptions.valueMap.put(key, gla);
        return true;
      }
  
      num = null;
      if (greaterAST.arg1().isReal()) {
        num = (ISignedNumber) greaterAST.arg1();
      } else {
        num = greaterAST.arg1().evalReal();
      }
      if (num != null) {
        IExpr key = greaterAST.arg2();
        SignedNumberRelations gla = assumptions.valueMap.get(key);
        if (gla == null) {
          gla = new SignedNumberRelations();
        }
        gla.addLess(num);
        assumptions.valueMap.put(key, gla);
        return true;
      }
      return false;
    }
  
    private static boolean addGreaterEqual(IAST greaterEqualAST, Assumptions assumptions) {
      if (greaterEqualAST.isAST3()) {
        // arg1 >= arg2 >= arg3
        IExpr arg1 = greaterEqualAST.arg1();
        IExpr arg2 = greaterEqualAST.arg2();
        IExpr arg3 = greaterEqualAST.arg3();
        if (arg1.isReal() && arg3.isReal() && !arg2.isNumber()) {
          if (!((ISignedNumber) arg1).isLT(((ISignedNumber) arg3))) {
            ISignedNumber num1 = (ISignedNumber) arg1;
            ISignedNumber num3 = (ISignedNumber) arg3;
            IExpr key = arg2;
            SignedNumberRelations gla = assumptions.valueMap.get(key);
            if (gla == null) {
              gla = new SignedNumberRelations();
            }
            gla.addLessEqual(num1);
            gla.addGreaterEqual(num3);
            assumptions.valueMap.put(key, gla);
            return true;
          }
        }
        return false;
      }
  
      // arg1 >= arg2
      ISignedNumber num = null;
      if (greaterEqualAST.arg2().isReal()) {
        num = (ISignedNumber) greaterEqualAST.arg2();
      } else {
        num = greaterEqualAST.arg2().evalReal();
      }
      if (num != null) {
        IExpr key = greaterEqualAST.arg1();
        SignedNumberRelations gla = assumptions.valueMap.get(key);
        if (gla == null) {
          gla = new SignedNumberRelations();
        }
        gla.addGreaterEqual(num);
        assumptions.valueMap.put(key, gla);
        return true;
      }
  
      num = null;
      if (greaterEqualAST.arg1().isReal()) {
        num = (ISignedNumber) greaterEqualAST.arg1();
      } else {
        num = greaterEqualAST.arg1().evalReal();
      }
      if (num != null) {
        IExpr key = greaterEqualAST.arg2();
        SignedNumberRelations gla = assumptions.valueMap.get(key);
        if (gla == null) {
          gla = new SignedNumberRelations();
        }
        gla.addLessEqual(num);
        assumptions.valueMap.put(key, gla);
        return true;
      }
      return false;
    }
  
    private static boolean addLess(IAST lessAST, Assumptions assumptions) {
      if (lessAST.isAST3()) {
        // arg1 < arg2 < arg3;
        IExpr arg1 = lessAST.arg1();
        IExpr arg2 = lessAST.arg2();
        IExpr arg3 = lessAST.arg3();
        if (arg1.isReal() && arg3.isReal() && !arg2.isNumber()) {
          if (((ISignedNumber) arg1).isLT(((ISignedNumber) arg3))) {
            ISignedNumber num1 = (ISignedNumber) arg1;
            ISignedNumber num3 = (ISignedNumber) arg3;
            IExpr key = arg2;
            SignedNumberRelations gla = assumptions.valueMap.get(key);
            if (gla == null) {
              gla = new SignedNumberRelations();
            }
            gla.addGreater(num1);
            gla.addLess(num3);
            assumptions.valueMap.put(key, gla);
            return true;
          }
        }
        return false;
      }
  
      // arg1 < arg2
      ISignedNumber num = null;
      if (lessAST.arg2().isReal()) {
        num = (ISignedNumber) lessAST.arg2();
      } else {
        num = lessAST.arg2().evalReal();
      }
      if (num != null) {
        IExpr key = lessAST.arg1();
        SignedNumberRelations gla = assumptions.valueMap.get(key);
        if (gla == null) {
          gla = new SignedNumberRelations();
        }
        gla.addLess(num);
        assumptions.valueMap.put(key, gla);
        return true;
      }
      num = null;
      if (lessAST.arg1().isReal()) {
        num = (ISignedNumber) lessAST.arg1();
      } else {
        num = lessAST.arg1().evalReal();
      }
      if (num != null) {
        IExpr key = lessAST.arg2();
        SignedNumberRelations gla = assumptions.valueMap.get(key);
        if (gla == null) {
          gla = new SignedNumberRelations();
        }
        gla.addGreater(num);
        assumptions.valueMap.put(key, gla);
        return true;
      }
      return false;
    }
  
    private static boolean addLessEqual(IAST lessEqualAST, Assumptions assumptions) {
  
      if (lessEqualAST.isAST3()) {
        // arg1 <= arg2 <= arg3
        IExpr arg1 = lessEqualAST.arg1();
        IExpr arg2 = lessEqualAST.arg2();
        IExpr arg3 = lessEqualAST.arg3();
        if (arg1.isReal() && arg3.isReal() && !arg2.isNumber()) {
          if (((ISignedNumber) arg1).isLE(((ISignedNumber) arg3))) {
            ISignedNumber num1 = (ISignedNumber) arg1;
            ISignedNumber num3 = (ISignedNumber) arg3;
            IExpr key = arg2;
            SignedNumberRelations gla = assumptions.valueMap.get(key);
            if (gla == null) {
              gla = new SignedNumberRelations();
            }
            gla.addGreaterEqual(num1);
            gla.addLessEqual(num3);
            assumptions.valueMap.put(key, gla);
            return true;
          }
        }
        return false;
      }
  
      // arg1 <= arg2;
      ISignedNumber num = null;
      if (lessEqualAST.arg2().isReal()) {
        num = (ISignedNumber) lessEqualAST.arg2();
      } else {
        num = lessEqualAST.arg2().evalReal();
      }
      if (num != null) {
        IExpr key = lessEqualAST.arg1();
        SignedNumberRelations gla = assumptions.valueMap.get(key);
        if (gla == null) {
          gla = new SignedNumberRelations();
        }
        gla.addLessEqual(num);
        assumptions.valueMap.put(key, gla);
        return true;
      }
      num = null;
      if (lessEqualAST.arg1().isReal()) {
        num = (ISignedNumber) lessEqualAST.arg1();
      } else {
        num = lessEqualAST.arg1().evalReal();
      }
      if (num != null) {
        IExpr key = lessEqualAST.arg2();
        SignedNumberRelations gla = assumptions.valueMap.get(key);
        if (gla == null) {
  