Expr Expr::max(const Expr& Other) const {
  if (Other == GetBottomValue())
    return *this;
  else if (*this == GetBottomValue())
    return Other;

  if (ExIsLessThan(Expr_, Other.getExpr()))
    return Expr_;
  else if (ExIsLessThan(Other.getExpr(), Expr_))
    return Expr_;
  else if (GiNaC::is_a<GiNaC::numeric>(Expr_))
    return Other.getExpr();
  else if (GiNaC::is_a<GiNaC::numeric>(Other.getExpr()))
    return Other.getExpr();

  return Expr(GiNaC::max(Expr_, Other.getExpr()));
}
Expr Expr::min(const Expr& Other) const {
  if (Other == GetBottomValue())
    return *this;
  else if (*this == GetBottomValue())
    return Other;
  if (ExIsLessThan(Expr_, Other.getExpr()))
    return Expr_;
  else if (ExIsLessThan(Other.getExpr(), Expr_))
    return Other.getExpr();
  else if (GiNaC::is_a<GiNaC::numeric>(Expr_))
    return Expr_;
  else if (GiNaC::is_a<GiNaC::numeric>(Other.getExpr()))
    return Other.getExpr();
    
  GiNaC::ex Res = GiNaC::min(Expr_, Other.getExpr());
  EXPR_DEBUG(dbgs() << "min(): " << *this << " :: " << Other
                    << " = " << Res << "\n");
  return Expr(Res);
}
Expr Expr::operator/(const Expr& Other) const {
  return Expr_/Other.getExpr();
}
bool Expr::ne(const Expr& Other) const {
  return !Expr_.is_equal(Other.getExpr());
}
bool Expr::le(const Expr& Other) const {
  return ExIsLessThan(Expr_, Other.getExpr() = 1);
}
bool Expr::ge(const Expr& Other) const {
  return ExIsGreaterThan(Expr_, Other.getExpr() + 1);
}
Expr ExprMap::operator[](const Expr& Ex) {
  return Expr(Map_[Ex.getExpr()]);
}
bool Expr::lt(const Expr& Other, std::map<Expr, Range> Assume) const {
  //for (auto& P : Assume)
  //  assert(GiNaC::is_a<GiNaC::symbol>(P.first.getExpr()) &&
  //         "Assumptions must map symbols to range");
  return ExIsLessThan(Expr_, Other.getExpr()); 
}
bool Expr::match(Expr Ex) const {
  return Expr_.match(Ex.getExpr());
}
bool Expr::has(Expr Ex) const {
  return Expr_.has(Ex.getExpr());
}
bool Expr::match(Expr Ex, ExprMap& Map) const {
  return Expr_.match(Ex.getExpr(), Map.getMap());
}
Expr Expr::subs(Expr This, Expr That) const {
  return Expr_.subs(This.getExpr() == That.getExpr());
}
Expr Expr::max(Expr Other) const {
  if (isValid() && Other.isValid())
    return GiNaC::max(Expr_, Other.getExpr()).eval();
  return InvalidExpr();
}
Expr Expr::operator^(const Expr& Other) const {
  if (isValid() && Other.isValid())
    return pow(Expr_, Other.getExpr());
  return InvalidExpr();
}
Expr Expr::operator/(const Expr& Other) const {
  if (isValid() && Other.isValid())
    return Expr_/Other.getExpr();
  return InvalidExpr();
}