Program Listing for File functions.h

Return to documentation for file (symengine/symengine/functions.h)

#ifndef SYMENGINE_FUNCTIONS_H
#define SYMENGINE_FUNCTIONS_H

#include <symengine/basic.h>
#include <symengine/symengine_casts.h>
#include <symengine/constants.h>

namespace SymEngine
{

class Function : public Basic
{
};

class OneArgFunction : public Function
{
private:
    RCP<const Basic> arg_;
public:
    OneArgFunction(const RCP<const Basic> &arg) : arg_{arg} {};
    inline hash_t __hash__() const
    {
        hash_t seed = this->get_type_code();
        hash_combine<Basic>(seed, *arg_);
        return seed;
    }
    inline RCP<const Basic> get_arg() const
    {
        return arg_;
    }
    virtual inline vec_basic get_args() const
    {
        return {arg_};
    }
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const = 0;

    inline RCP<const Basic> create(const vec_basic &b) const
    {
        SYMENGINE_ASSERT(b.size() == 1);
        return create(b[0]);
    }

    virtual inline bool __eq__(const Basic &o) const
    {
        return is_same_type(*this, o)
               and eq(*get_arg(),
                      *down_cast<const OneArgFunction &>(o).get_arg());
    }
    virtual inline int compare(const Basic &o) const
    {
        SYMENGINE_ASSERT(is_same_type(*this, o))
        return get_arg()->__cmp__(
            *(down_cast<const OneArgFunction &>(o).get_arg()));
    }
};

template <class BaseClass>
class TwoArgBasic : public BaseClass
{
private:
    RCP<const Basic> a_;
    RCP<const Basic> b_;
public:
    TwoArgBasic(const RCP<const Basic> &a, const RCP<const Basic> &b)
        : a_{a}, b_{b} {};
    inline hash_t __hash__() const
    {
        hash_t seed = this->get_type_code();
        hash_combine<Basic>(seed, *a_);
        hash_combine<Basic>(seed, *b_);
        return seed;
    }
    inline RCP<const Basic> get_arg1() const
    {
        return a_;
    }
    inline RCP<const Basic> get_arg2() const
    {
        return b_;
    }
    virtual inline vec_basic get_args() const
    {
        return {a_, b_};
    }
    virtual RCP<const Basic> create(const RCP<const Basic> &a,
                                    const RCP<const Basic> &b) const = 0;

    inline RCP<const Basic> create(const vec_basic &b) const
    {
        SYMENGINE_ASSERT(b.size() == 2);
        return create(b[0], b[1]);
    }

    virtual inline bool __eq__(const Basic &o) const
    {
        return is_same_type(*this, o)
               and eq(*get_arg1(),
                      *down_cast<const TwoArgBasic &>(o).get_arg1())
               and eq(*get_arg2(),
                      *down_cast<const TwoArgBasic &>(o).get_arg2());
    }
    virtual inline int compare(const Basic &o) const
    {
        SYMENGINE_ASSERT(is_same_type(*this, o))
        const TwoArgBasic &t = down_cast<const TwoArgBasic &>(o);
        if (neq(*get_arg1(), *(t.get_arg1()))) {
            return get_arg1()->__cmp__(
                *(down_cast<const TwoArgBasic &>(o).get_arg1()));
        } else {
            return get_arg2()->__cmp__(
                *(down_cast<const TwoArgBasic &>(o).get_arg2()));
        }
    }
};

typedef TwoArgBasic<Function> TwoArgFunction;

class MultiArgFunction : public Function
{
private:
    vec_basic arg_;

public:
    MultiArgFunction(const vec_basic &arg) : arg_{arg} {};
    inline hash_t __hash__() const
    {
        hash_t seed = this->get_type_code();
        for (const auto &a : arg_)
            hash_combine<Basic>(seed, *a);
        return seed;
    }
    virtual inline vec_basic get_args() const
    {
        return arg_;
    }
    inline const vec_basic &get_vec() const
    {
        return arg_;
    }
    virtual RCP<const Basic> create(const vec_basic &v) const = 0;
    virtual inline bool __eq__(const Basic &o) const
    {
        return is_same_type(*this, o)
               and unified_eq(get_vec(),
                              down_cast<const MultiArgFunction &>(o).get_vec());
    }
    virtual inline int compare(const Basic &o) const
    {
        SYMENGINE_ASSERT(is_same_type(*this, o))
        return unified_compare(
            get_vec(), down_cast<const MultiArgFunction &>(o).get_vec());
    }
};

class Sign : public OneArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_SIGN)
    Sign(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> sign(const RCP<const Basic> &arg);

class Floor : public OneArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_FLOOR)
    Floor(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> floor(const RCP<const Basic> &arg);

class Ceiling : public OneArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_CEILING)
    Ceiling(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> ceiling(const RCP<const Basic> &arg);

class Truncate : public OneArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_TRUNCATE)
    Truncate(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> truncate(const RCP<const Basic> &arg);

class Conjugate : public OneArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_CONJUGATE)
    Conjugate(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> conjugate(const RCP<const Basic> &arg);

class TrigBase : public OneArgFunction
{
public:
    TrigBase(RCP<const Basic> arg) : OneArgFunction(arg){};
};

class TrigFunction : public TrigBase
{
public:
    TrigFunction(RCP<const Basic> arg) : TrigBase(arg){};
};

class InverseTrigFunction : public TrigBase
{
public:
    InverseTrigFunction(RCP<const Basic> arg) : TrigBase(arg){};
};

bool get_pi_shift(const RCP<const Basic> &arg, const Ptr<RCP<const Number>> &n,
                  const Ptr<RCP<const Basic>> &m);

bool could_extract_minus(const Basic &arg);

bool handle_minus(const RCP<const Basic> &arg,
                  const Ptr<RCP<const Basic>> &rarg);

bool inverse_lookup(umap_basic_basic &d, const RCP<const Basic> &t,
                    const Ptr<RCP<const Basic>> &index);

// \return true of conjugate has to be returned finally else false
bool trig_simplify(const RCP<const Basic> &arg, unsigned period, bool odd,
                   bool conj_odd, // input
                   const Ptr<RCP<const Basic>> &rarg, int &index,
                   int &sign); // output

RCP<const Basic> sqrt(const RCP<const Basic> &arg);

RCP<const Basic> cbrt(const RCP<const Basic> &arg);

class Sin : public TrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_SIN)
    Sin(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> sin(const RCP<const Basic> &arg);

class Cos : public TrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_COS)
    Cos(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> cos(const RCP<const Basic> &arg);

class Tan : public TrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_TAN)
    Tan(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};
RCP<const Basic> tan(const RCP<const Basic> &arg);

class Cot : public TrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_COT)
    Cot(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};
RCP<const Basic> cot(const RCP<const Basic> &arg);

class Csc : public TrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_CSC)
    Csc(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};
RCP<const Basic> csc(const RCP<const Basic> &arg);

class Sec : public TrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_SEC)
    Sec(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};
RCP<const Basic> sec(const RCP<const Basic> &arg);

class ASin : public InverseTrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_ASIN)
    ASin(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> asin(const RCP<const Basic> &arg);

class ACos : public InverseTrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_ACOS)
    ACos(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> acos(const RCP<const Basic> &arg);

class ASec : public InverseTrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_ASEC)
    ASec(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> asec(const RCP<const Basic> &arg);

class ACsc : public InverseTrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_ACSC)
    ACsc(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> acsc(const RCP<const Basic> &arg);

class ATan : public InverseTrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_ATAN)
    ATan(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> atan(const RCP<const Basic> &arg);

class ACot : public InverseTrigFunction
{

public:
    IMPLEMENT_TYPEID(SYMENGINE_ACOT)
    ACot(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> acot(const RCP<const Basic> &arg);

class ATan2 : public TwoArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_ATAN2)
    ATan2(const RCP<const Basic> &num, const RCP<const Basic> &den);
    bool is_canonical(const RCP<const Basic> &num,
                      const RCP<const Basic> &den) const;
    inline RCP<const Basic> get_num() const
    {
        return get_arg1();
    }
    inline RCP<const Basic> get_den() const
    {
        return get_arg2();
    }
    virtual RCP<const Basic> create(const RCP<const Basic> &a,
                                    const RCP<const Basic> &b) const;
};

RCP<const Basic> atan2(const RCP<const Basic> &num,
                       const RCP<const Basic> &den);

class Log : public OneArgFunction
{
    // Logarithms are taken with the natural base, `e`. To get
    // a logarithm of a different base `b`, use `log(x, b)`,
    // which is essentially short-hand for `log(x)/log(b)`.
public:
    IMPLEMENT_TYPEID(SYMENGINE_LOG)
    Log(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> log(const RCP<const Basic> &arg);
RCP<const Basic> log(const RCP<const Basic> &arg, const RCP<const Basic> &b);

class LambertW : public OneArgFunction
{
    // Lambert W function, defined as the inverse function of
    // x*exp(x). This function represents the principal branch
    // of this inverse function, which is multivalued.
    // For more information, see:
    // http://en.wikipedia.org/wiki/Lambert_W_function
public:
    IMPLEMENT_TYPEID(SYMENGINE_LAMBERTW)
    LambertW(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> lambertw(const RCP<const Basic> &arg);

class Zeta : public TwoArgFunction
{
    // Hurwitz zeta function (or Riemann zeta function).
    //
    // For `\operatorname{Re}(a) > 0` and `\operatorname{Re}(s) > 1`, this
    // function is defined as
    //
    // .. math:: \zeta(s, a) = \sum_{n=0}^\infty \frac{1}{(n + a)^s},
    //
    // where the standard choice of argument for :math:`n + a` is used.
    // If no value is passed for :math:`a`, by this function assumes a default
    // value
    // of :math:`a = 1`, yielding the Riemann zeta function.
public:
    using TwoArgFunction::create;
    IMPLEMENT_TYPEID(SYMENGINE_ZETA)
    Zeta(const RCP<const Basic> &s, const RCP<const Basic> &a);
    Zeta(const RCP<const Basic> &s);
    inline RCP<const Basic> get_s() const
    {
        return get_arg1();
    }
    inline RCP<const Basic> get_a() const
    {
        return get_arg2();
    }
    bool is_canonical(const RCP<const Basic> &s,
                      const RCP<const Basic> &a) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &a,
                                    const RCP<const Basic> &b) const;
};

RCP<const Basic> zeta(const RCP<const Basic> &s, const RCP<const Basic> &a);
RCP<const Basic> zeta(const RCP<const Basic> &s);

class Dirichlet_eta : public OneArgFunction
{
    // See http://en.wikipedia.org/wiki/Dirichlet_eta_function
public:
    IMPLEMENT_TYPEID(SYMENGINE_DIRICHLET_ETA)
    Dirichlet_eta(const RCP<const Basic> &s);
    inline RCP<const Basic> get_s() const
    {
        return get_arg();
    }
    bool is_canonical(const RCP<const Basic> &s) const;
    RCP<const Basic> rewrite_as_zeta() const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
    using OneArgFunction::create;
};

RCP<const Basic> dirichlet_eta(const RCP<const Basic> &s);

class FunctionSymbol : public MultiArgFunction
{
protected:
    std::string name_;

public:
    IMPLEMENT_TYPEID(SYMENGINE_FUNCTIONSYMBOL)
    FunctionSymbol(std::string name, const vec_basic &arg);
    FunctionSymbol(std::string name, const RCP<const Basic> &arg);
    virtual hash_t __hash__() const;
    virtual bool __eq__(const Basic &o) const;
    virtual int compare(const Basic &o) const;
    inline const std::string &get_name() const
    {
        return name_;
    }
    bool is_canonical(const vec_basic &arg) const;
    virtual RCP<const Basic> create(const vec_basic &x) const;
};

RCP<const Basic> function_symbol(std::string name, const RCP<const Basic> &arg);
RCP<const Basic> function_symbol(std::string name, const vec_basic &arg);

class FunctionWrapper : public FunctionSymbol
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_FUNCTIONWRAPPER)
    FunctionWrapper(std::string name, const vec_basic &arg);
    FunctionWrapper(std::string name, const RCP<const Basic> &arg);
    virtual RCP<const Basic> create(const vec_basic &v) const = 0;
    virtual RCP<const Number> eval(long bits) const = 0;
    virtual RCP<const Basic> diff_impl(const RCP<const Symbol> &s) const = 0;
};

class Derivative : public Basic
{
private:
    RCP<const Basic> arg_;
    // The symbols are declared as Basic (and checked by is_canonical() below),
    // to avoid issues with converting vector<RCP<Symbol>> to
    // vector<RCP<Basic>>, see [1], [2]. The problem is that even though Symbol
    // inherits from Basic, vector<RCP<Symbol>> does not inherit from
    // vector<RCP<Basic>>, so the compiler can't cast the derived type to the
    // base type when calling functions like unified_eq() that are only
    // defined for the base type vector<RCP<Basic>>.
    // [1]
    // http://stackoverflow.com/questions/14964909/how-to-cast-a-vector-of-shared-ptrs-of-a-derived-class-to-a-vector-of-share-ptrs
    // [2]
    // http://stackoverflow.com/questions/114819/getting-a-vectorderived-into-a-function-that-expects-a-vectorbase
    multiset_basic x_;

public:
    IMPLEMENT_TYPEID(SYMENGINE_DERIVATIVE)
    Derivative(const RCP<const Basic> &arg, const multiset_basic &x);

    static RCP<const Derivative> create(const RCP<const Basic> &arg,
                                        const multiset_basic &x)
    {
        return make_rcp<const Derivative>(arg, x);
    }

    virtual hash_t __hash__() const;
    virtual bool __eq__(const Basic &o) const;
    virtual int compare(const Basic &o) const;
    inline RCP<const Basic> get_arg() const
    {
        return arg_;
    }
    inline const multiset_basic &get_symbols() const
    {
        return x_;
    }
    virtual vec_basic get_args() const
    {
        vec_basic args = {arg_};
        args.insert(args.end(), x_.begin(), x_.end());
        return args;
    }
    bool is_canonical(const RCP<const Basic> &arg,
                      const multiset_basic &x) const;
};

class Subs : public Basic
{
private:
    RCP<const Basic> arg_;
    map_basic_basic dict_;

public:
    IMPLEMENT_TYPEID(SYMENGINE_SUBS)
    Subs(const RCP<const Basic> &arg, const map_basic_basic &x);

    static RCP<const Subs> create(const RCP<const Basic> &arg,
                                  const map_basic_basic &x)
    {
        return make_rcp<const Subs>(arg, x);
    }

    virtual hash_t __hash__() const;
    virtual bool __eq__(const Basic &o) const;
    virtual int compare(const Basic &o) const;
    inline const RCP<const Basic> &get_arg() const
    {
        return arg_;
    }
    inline const map_basic_basic &get_dict() const
    {
        return dict_;
    };
    virtual vec_basic get_variables() const;
    virtual vec_basic get_point() const;
    virtual vec_basic get_args() const;

    bool is_canonical(const RCP<const Basic> &arg,
                      const map_basic_basic &x) const;
};

class HyperbolicBase : public OneArgFunction
{
public:
    HyperbolicBase(RCP<const Basic> arg) : OneArgFunction{arg} {};
};

class HyperbolicFunction : public HyperbolicBase
{
public:
    HyperbolicFunction(RCP<const Basic> arg) : HyperbolicBase{arg} {};
};

class InverseHyperbolicFunction : public HyperbolicBase
{
public:
    InverseHyperbolicFunction(RCP<const Basic> arg) : HyperbolicBase{arg} {};
};

class Sinh : public HyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_SINH)
    Sinh(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> sinh(const RCP<const Basic> &arg);

class Csch : public HyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_CSCH)
    Csch(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> csch(const RCP<const Basic> &arg);

class Cosh : public HyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_COSH)
    Cosh(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> cosh(const RCP<const Basic> &arg);

class Sech : public HyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_SECH)
    Sech(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> sech(const RCP<const Basic> &arg);

class Tanh : public HyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_TANH)
    Tanh(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> tanh(const RCP<const Basic> &arg);

class Coth : public HyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_COTH)
    Coth(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> coth(const RCP<const Basic> &arg);

class ASinh : public InverseHyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_ASINH)
    ASinh(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> asinh(const RCP<const Basic> &arg);

class ACsch : public InverseHyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_ACSCH)
    ACsch(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> acsch(const RCP<const Basic> &arg);

class ACosh : public InverseHyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_ACOSH)
    ACosh(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> acosh(const RCP<const Basic> &arg);

class ATanh : public InverseHyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_ATANH)
    ATanh(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> atanh(const RCP<const Basic> &arg);

class ACoth : public InverseHyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_ACOTH)
    ACoth(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> acoth(const RCP<const Basic> &arg);

class ASech : public InverseHyperbolicFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_ASECH)
    ASech(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> asech(const RCP<const Basic> &arg);

class KroneckerDelta : public TwoArgFunction
{
public:
    using TwoArgFunction::create;
    IMPLEMENT_TYPEID(SYMENGINE_KRONECKERDELTA)
    KroneckerDelta(const RCP<const Basic> &i, const RCP<const Basic> &j);
    bool is_canonical(const RCP<const Basic> &i,
                      const RCP<const Basic> &j) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &a,
                                    const RCP<const Basic> &b) const;
};

RCP<const Basic> kronecker_delta(const RCP<const Basic> &i,
                                 const RCP<const Basic> &j);

class LeviCivita : public MultiArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_LEVICIVITA)
    LeviCivita(const vec_basic &&arg);
    bool is_canonical(const vec_basic &arg) const;
    virtual RCP<const Basic> create(const vec_basic &arg) const;
};

RCP<const Basic> levi_civita(const vec_basic &arg);

class Erf : public OneArgFunction
{
    /*   The Gauss error function. This function is defined as:
     *
     *   .. math::
     *      \mathrm{erf}(x) = \frac{2}{\sqrt{\pi}} \int_0^x e^{-t^2}
     *\mathrm{d}t.
     **/
public:
    IMPLEMENT_TYPEID(SYMENGINE_ERF)
    Erf(const RCP<const Basic> &arg) : OneArgFunction(arg)
    {
        SYMENGINE_ASSIGN_TYPEID()
        SYMENGINE_ASSERT(is_canonical(arg))
    }
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> erf(const RCP<const Basic> &arg);

class Erfc : public OneArgFunction
{
    /*   The complementary error function. This function is defined as:
     *
     *   .. math::
     *      \mathrm{erfc}(x) = 1 - \frac{2}{\sqrt{\pi}} \int_0^x e^{-t^2}
     *       \mathrm{d}t.
     **/
public:
    IMPLEMENT_TYPEID(SYMENGINE_ERFC)
    Erfc(const RCP<const Basic> &arg) : OneArgFunction(arg)
    {
        SYMENGINE_ASSIGN_TYPEID()
        SYMENGINE_ASSERT(is_canonical(arg))
    }
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> erfc(const RCP<const Basic> &arg);

class Gamma : public OneArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_GAMMA)
    Gamma(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> gamma(const RCP<const Basic> &arg);

class LowerGamma : public TwoArgFunction
{
public:
    using TwoArgFunction::create;
    IMPLEMENT_TYPEID(SYMENGINE_LOWERGAMMA)
    LowerGamma(const RCP<const Basic> &s, const RCP<const Basic> &x);
    bool is_canonical(const RCP<const Basic> &s,
                      const RCP<const Basic> &x) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &a,
                                    const RCP<const Basic> &b) const;
};

RCP<const Basic> lowergamma(const RCP<const Basic> &s,
                            const RCP<const Basic> &x);

class UpperGamma : public TwoArgFunction
{
public:
    using TwoArgFunction::create;
    IMPLEMENT_TYPEID(SYMENGINE_UPPERGAMMA)
    UpperGamma(const RCP<const Basic> &s, const RCP<const Basic> &x);
    bool is_canonical(const RCP<const Basic> &s,
                      const RCP<const Basic> &x) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &a,
                                    const RCP<const Basic> &b) const;
};

RCP<const Basic> uppergamma(const RCP<const Basic> &s,
                            const RCP<const Basic> &x);

class LogGamma : public OneArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_LOGGAMMA)
    LogGamma(const RCP<const Basic> &arg) : OneArgFunction(arg)
    {
        SYMENGINE_ASSIGN_TYPEID()
        SYMENGINE_ASSERT(is_canonical(arg))
    }
    bool is_canonical(const RCP<const Basic> &arg) const;
    RCP<const Basic> rewrite_as_gamma() const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> loggamma(const RCP<const Basic> &arg);

class Beta : public TwoArgFunction
{
public:
    using TwoArgFunction::create;
    IMPLEMENT_TYPEID(SYMENGINE_BETA)
    Beta(const RCP<const Basic> &x, const RCP<const Basic> &y)
        : TwoArgFunction(x, y)
    {
        SYMENGINE_ASSIGN_TYPEID()
        SYMENGINE_ASSERT(is_canonical(x, y))
    }
    static RCP<const Beta> from_two_basic(const RCP<const Basic> &x,
                                          const RCP<const Basic> &y);
    bool is_canonical(const RCP<const Basic> &s, const RCP<const Basic> &x);
    RCP<const Basic> rewrite_as_gamma() const;
    virtual RCP<const Basic> create(const RCP<const Basic> &a,
                                    const RCP<const Basic> &b) const;
};

RCP<const Basic> beta(const RCP<const Basic> &x, const RCP<const Basic> &y);

class PolyGamma : public TwoArgFunction
{
public:
    using TwoArgFunction::create;
    IMPLEMENT_TYPEID(SYMENGINE_POLYGAMMA)
    PolyGamma(const RCP<const Basic> &n, const RCP<const Basic> &x)
        : TwoArgFunction(n, x)
    {
        SYMENGINE_ASSIGN_TYPEID()
        SYMENGINE_ASSERT(is_canonical(n, x))
    }
    bool is_canonical(const RCP<const Basic> &n, const RCP<const Basic> &x);
    RCP<const Basic> rewrite_as_zeta() const;
    virtual RCP<const Basic> create(const RCP<const Basic> &a,
                                    const RCP<const Basic> &b) const;
};

RCP<const Basic> polygamma(const RCP<const Basic> &n,
                           const RCP<const Basic> &x);

RCP<const Basic> digamma(const RCP<const Basic> &x);

RCP<const Basic> trigamma(const RCP<const Basic> &x);

class Abs : public OneArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_ABS)
    Abs(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> abs(const RCP<const Basic> &arg);

class Max : public MultiArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_MAX)
    Max(const vec_basic &&arg);
    bool is_canonical(const vec_basic &arg) const;
    virtual RCP<const Basic> create(const vec_basic &arg) const;
};

RCP<const Basic> max(const vec_basic &arg);

class Min : public MultiArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_MIN)
    Min(const vec_basic &&arg);
    bool is_canonical(const vec_basic &arg) const;
    virtual RCP<const Basic> create(const vec_basic &arg) const;
};

RCP<const Basic> min(const vec_basic &arg);

RCP<const Basic> trig_to_sqrt(const RCP<const Basic> &arg);

class UnevaluatedExpr : public OneArgFunction
{
public:
    IMPLEMENT_TYPEID(SYMENGINE_UNEVALUATED_EXPR)
    UnevaluatedExpr(const RCP<const Basic> &arg);
    bool is_canonical(const RCP<const Basic> &arg) const;
    virtual RCP<const Basic> create(const RCP<const Basic> &arg) const;
};

RCP<const Basic> unevaluated_expr(const RCP<const Basic> &arg);

} // SymEngine

#endif