/* Standard analytic functions */
2 # Sin(x_IsNumber)_InNumericMode() <-- SinNum(x);
4 # Sin(ArcSin(_x))           <-- x;
4 # Sin(ArcCos(_x)) <-- Sqrt(1-x^2);
4 # Sin(ArcTan(_x)) <-- x/Sqrt(1+x^2);
5 # Sin(- _x)_(Not IsConstant(x))                 <-- -Sin(x);
6 # (Sin(x_IsConstant))_(IsNegativeNumber(N(Eval(x))))   <-- -Sin(-x);

// must prevent it from looping
6 # Sin(x_IsInfinity)       <-- Undefined;
6 # Sin(Undefined) <-- Undefined;

110 # Sin(Complex(_r,_i)) <--
    (Exp(I*Complex(r,i)) - Exp(- I*Complex(r,i))) / (I*2) ;

1 # SinMap( _n )_(Not(IsRationalOrNumber(n))) <-- UnList({Atom("Sin"),n*Pi});
2 # SinMap( _n )_(n<0) <-- -SinMap(-n);
2 # SinMap( _n )_(n>2) <-- SinMap(Mod(n,2));
3 # SinMap( _n )_(n>1) <-- SinMap(n-2);
4 # SinMap( _n )_(n>1/2) <-- SinMap(1-n);

5 # SinMap( n_IsInteger ) <-- 0;
5 # SinMap( 1/6 ) <-- 1/2;
5 # SinMap( 1/4 ) <-- Sqrt(2)/2;
5 # SinMap( 1/3 ) <-- Sqrt(3)/2;
5 # SinMap( 1/2 ) <-- 1;
5 # SinMap( 1/10) <-- (Sqrt(5)-1)/4;

10 # SinMap(_n) <-- UnList({Atom("Sin"),n*Pi});

200 # Sin(v_CanBeUni(Pi))_(Not(InNumericMode()) And Degree(v,Pi) < 2 And Coef(v,Pi,0) = 0) <--
[
  SinMap(Coef(v,Pi,1));
];

2 # Cos(x_IsNumber)_InNumericMode() <-- CosNum(x);
4 # Cos(ArcCos(_x))           <-- x;
4 # Cos(ArcSin(_x)) <-- Sqrt(1-x^2);
4 # Cos(ArcTan(_x)) <-- 1/Sqrt(1+x^2);
5 # Cos(- _x)_(Not IsConstant(x))                 <-- Cos(x);
6 # (Cos(x_IsConstant))_(IsNegativeNumber(N(Eval(x))))   <-- Cos(-x);
// must prevent it from looping

110 # Cos(Complex(_r,_i)) <--
    (Exp(I*Complex(r,i)) + Exp(- I*Complex(r,i))) / (2) ;

1 # CosMap( _n )_(Not(IsRationalOrNumber(n))) <-- UnList({Atom("Cos"),n*Pi});
2 # CosMap( _n )_(n<0) <-- CosMap(-n);
2 # CosMap( _n )_(n>2) <-- CosMap(Mod(n,2));
3 # CosMap( _n )_(n>1) <-- CosMap(2-n);
4 # CosMap( _n )_(n>1/2) <-- -CosMap(1-n);

5 # CosMap( 0 ) <-- 1;
5 # CosMap( 1/6 ) <-- Sqrt(3)/2;
5 # CosMap( 1/4 ) <-- Sqrt(2)/2;
5 # CosMap( 1/3 ) <-- 1/2;
5 # CosMap( 1/2 ) <-- 0;
5 # CosMap( 2/5 ) <-- (Sqrt(5)-1)/4;

6 # Cos(x_IsInfinity) <-- Undefined;
6 # Cos(Undefined) <-- Undefined;
10 # CosMap(_n) <-- UnList({Atom("Cos"),n*Pi});

200 # Cos(v_CanBeUni(Pi))_(Not(InNumericMode()) And Degree(v,Pi) < 2 And Coef(v,Pi,0) = 0) <--
      CosMap(Coef(v,Pi,1));

400 # Cos(x_IsRationalOrNumber) <--
    [
     Local(ll);
     ll:= MathFloor(N(Eval(x/Pi)));
     If(IsEven(ll),x:=(x - Pi*ll),x:=(-x + Pi*(ll+1)));
     UnList({Cos,x});
     ];

400 # Cos(x_IsRationalOrNumber) <--
    [
     Local(ll);
     ll:= MathFloor(N(Eval(Abs(x)/Pi)));
     If(IsEven(ll),x:=(Abs(x) - Pi*ll),x:=(-Abs(x) + Pi*(ll+1)));
     UnList({Cos,x});
     ];


2 # Tan(x_IsNumber)_InNumericMode() <-- TanNum(x);
4 # Tan(ArcTan(_x))           <-- x;
4 # Tan(ArcSin(_x)) <-- x/Sqrt(1-x^2);
4 # Tan(ArcCos(_x)) <-- Sqrt(1-x^2)/x;
5 # Tan(- _x)_(Not IsConstant(x))                  <-- -Tan(x);
6 # (Tan(x_IsConstant))_(IsNegativeNumber(N(Eval(x))))   <-- -Tan(-x);

// must prevent it from looping
6 # Tan(Infinity) <-- Undefined;
6 # Tan(Undefined) <-- Undefined;

110 # Tan(Complex(_r,_i)) <-- Sin(Complex(r,i))/Cos(Complex(r,i));

1 # TanMap( _n )_(Not(IsRationalOrNumber(n))) <-- UnList({Atom("Tan"),n*Pi});
2 # TanMap( _n )_(n<0) <-- -TanMap(-n);
2 # TanMap( _n )_(n>1) <-- TanMap(Mod(n,1));
4 # TanMap( _n )_(n>1/2) <-- -TanMap(1-n);

5 # TanMap( 0 ) <-- 0;
5 # TanMap( 1/6 ) <-- 1/3*Sqrt(3);
5 # TanMap( 1/4 ) <-- 1;
5 # TanMap( 1/3 ) <-- Sqrt(3);
5 # TanMap( 1/2 ) <-- Infinity;

10 # TanMap(_n) <-- UnList({Atom("Tan"),n*Pi});

200 # Tan(v_CanBeUni(Pi))_(Not(InNumericMode()) And Degree(v,Pi) < 2 And Coef(v,Pi,0) = 0) <--
      TanMap(Coef(v,Pi,1));


100 # Sin(_x)/Tan(_x) <-- Cos(x);
100 # Sin(_x)/Cos(_x) <-- Tan(x);
100 # Cos(_x)*Tan(_x) <-- Sin(x);
100 # Cos(_x)/Sin(_x) <-- (1/Tan(x));
100 # Tan(_x)/Sin(_x) <-- (1/Cos(x));
100 # Tan(_x)*Cos(_x) <-- Sin(x);
100 # 1/Cot(_x)     <-- Tan(x);
100 # 1/Sec(_x)     <-- Cos(x);
100 # 1/Csc(_x)     <-- Sin(x);
100 # Sec(_x)       <-- 1/Cos(x);
100 # Csc(_x)       <-- 1/Sin(x);
100 # Cot(_x)       <-- 1/Tan(x);


2 # Exp(x_IsNumber)_InNumericMode() <-- ExpNum(x);
4 # Exp(Ln(_x))           <-- x;
110 # Exp(Complex(_r,_i)) <--  Exp(r)*(Cos(i) + I*Sin(i));
200 # Exp(0) <-- 1;
200 # Exp(-Infinity) <-- 0;
200 # Exp(Infinity) <-- Infinity;
200 # Exp(Undefined) <-- Undefined;

2 # Ln(0)                    <-- -Infinity;
2 # Ln(1)                    <-- 0;
2 # Ln(Infinity)                    <-- Infinity;
2 # Ln(Undefined)                   <-- Undefined;

/* 2 # Ln(-Infinity)                    <-- 0; */
2 # Ln(x_IsNegativeNumber)_InNumericMode() <-- Complex(Ln(-x), Pi);
3 # Ln(x_IsNumber)_(InNumericMode() And x>=1) <-- Internal'LnNum(x);
4 # Ln(Exp(_x))              <-- x;

3 # Ln(Complex(_r,_i)) <-- Complex(Ln(Abs(Complex(r,i))), Arg(Complex(r,i)));
4 # Ln(x_IsNegativeNumber) <-- Complex(Ln(-x), Pi);
5 # Ln(x_IsNumber)_(InNumericMode() And x<1) <-- - Internal'LnNum(MathDivide(1, x));


2 # ArcSin(x_IsNumber)_(InNumericMode() And Abs(x)<=1) <-- ArcSinNum(x);
/// complex ArcSin
3 # ArcSin(x_IsNumber)_InNumericMode() <-- Sign(x)*(Pi/2+I*ArcCosh(x));
// TODO: can we do this one correctly?
//4 # ArcSin(Sin(_x))           <-- x;
110 # ArcSin(Complex(_r,_i)) <--
    (- I) * Ln((I*Complex(r,i)) + ((1-(Complex(r,i)^2))^(1/2)));

150 # ArcSin(- _x)_(Not IsConstant(x))             <-- -ArcSin(x);
160 # (ArcSin(x_IsConstant))_(IsNegativeNumber(N(Eval(x)))) <-- -ArcSin(-x);

200 # ArcSin(0) <-- 0;
200 # ArcSin(1/2) <-- Pi/6;
200 # ArcSin(Sqrt(1/2)) <-- Pi/4;
200 # ArcSin(Sqrt(3/4)) <-- Pi/3;
200 # ArcSin(1) <-- Pi/2;
200 # ArcSin(_n)_(n = -1) <-- -Pi/2;
200 # ArcSin(_n)_(-n = Sqrt(3/4)) <-- -Pi/3;
200 # ArcSin(_n)_(-n = Sqrt(1/2)) <-- -Pi/4;
200 # ArcSin(_n)_(-n = 1/2) <-- -Pi/6;

2 # ArcCos(x_IsNumber)_InNumericMode() <-- Internal'Pi()/2-ArcSin(x);
// TODO: can we do this one correctly?
//4 # ArcCos(Cos(_x))           <-- x;
5 # (ArcTan(x_IsConstant))_(IsNegativeNumber(N(Eval(x))))   <-- -ArcTan(-x);
110 # ArcCos(Complex(_r,_i)) <--
    (- I)*Ln(Complex(r,i) + (Complex(r,i)^2 - 1)^(1/2));
   /* TODO check! */

200 # ArcCos(0) <-- Pi/2;
200 # ArcCos(1/2) <-- Pi/3;
200 # ArcCos(Sqrt(1/2)) <-- Pi/4;
200 # ArcCos(Sqrt(3/4)) <-- Pi/6;
200 # ArcCos(1) <-- 0;
200 # ArcCos(_n)_(n = -1) <-- Pi;
200 # ArcCos(_n)_(-n = Sqrt(3/4)) <-- 5/6*Pi;
200 # ArcCos(_n)_(-n = Sqrt(1/2)) <-- 3/4*Pi;
200 # ArcCos(_n)_(-n = 1/2) <-- 2/3*Pi;

//TODO fix! 4 # ArcTan(Tan(_x))           <-- x;
4 # ArcTan(-Tan(_x))           <-- -ArcTan(Tan(x));
110 # ArcTan(Complex(_r,_i)) <--
     (- I*0.5)*Ln(Complex(1,Complex(r,i))/ Complex(1, - Complex(r,i)));

150 # ArcTan(- _x)_(Not IsConstant(x))             <-- -ArcTan(x);
160 # (ArcTan(x_IsConstant))_(IsNegativeNumber(N(Eval(x)))) <-- -ArcTan(-x);

200 # ArcTan(Sqrt(3)) <-- Pi/3;
200 # ArcTan(-Sqrt(3)) <-- -Pi/3;
200 # ArcTan(1) <-- Pi/4;
200 # ArcTan(0) <-- 0;
200 # ArcTan(_n)_(n = -1) <-- -Pi/4;

200 # ArcTan(Infinity) <-- Pi/2;
200 # ArcTan(-Infinity) <-- -Pi/2;
200 # ArcTan(Undefined) <-- Undefined;
200 # ArcSin(Undefined) <-- Undefined;
200 # ArcCos(Undefined) <-- Undefined;

2 # Sinh(_x)_(InNumericMode() And (IsNumber(x) Or Type(x) = "Complex")) <-- N(Eval( (Exp(x)-Exp(-x))/2 ));
2 # Cosh(_x)_(InNumericMode() And (IsNumber(x) Or Type(x) = "Complex")) <-- N(Eval( (Exp(x)+Exp(-x))/2 ));
2 # Tanh(_x)_(InNumericMode() And (IsNumber(x) Or Type(x) = "Complex")) <-- N(Eval( Sinh(x)/Cosh(x) ));


10 # ArcSinh(_x)_(InNumericMode() And (IsNumber(x) Or Type(x) = "Complex")) <-- N(Eval( Ln(x+Sqrt(x^2+1)) ));
10 # ArcCosh(_x)_(InNumericMode() And (IsNumber(x) Or Type(x) = "Complex")) <-- N(Eval( Ln(x+Sqrt(x^2-1)) ));
10 # ArcTanh(_x)_(InNumericMode() And (IsNumber(x) Or Type(x) = "Complex")) <-- N(Eval( Ln((1+x)/(1-x))/2 ));

200 # ArcSinh(Infinity) <-- Infinity;
200 # ArcSinh(-Infinity) <-- -Infinity;
200 # ArcSinh(Undefined) <-- Undefined;
200 # ArcCosh(Infinity) <-- Infinity;
200 # ArcCosh(-Infinity) <-- Infinity+I*Pi/2;
200 # ArcCosh(Undefined) <-- Undefined;
200 # ArcTanh(Infinity) <-- Infinity+I*Pi/2;
200 # ArcTanh(-Infinity) <-- -Infinity-I*Pi/2;  // this is a little silly b/c we don't support correct branch cuts yet
200 # ArcTanh(Undefined) <-- Undefined;

/* hyperbolic stuff */
100 # 1/Coth(_x)    <-- Tanh(x);
100 # 1/Sech(_x)    <-- Cosh(x);
100 # 1/Csch(_x)    <-- Sinh(x);
100 # Sech(_x)      <-- 1/Cosh(x);
100 # Csch(_x)      <-- 1/Sinh(x);
100 # Coth(_x)      <-- 1/Tanh(x);

5   # Cosh(- _x)    <-- Cosh(x);
5   # Sinh(- _x)    <-- -Sinh(x);

100 # Sinh(_x)^2-Cosh(_x)^2     <-- 1;
100 # Sinh(_x)+Cosh(_x)     <-- Exp(x);
100 # Sinh(_x)-Cosh(_x)     <-- Exp(-x);

// this is never activated
//100 # Sinh(I*_x)        <-- I*Sin(x);
//100 # Cosh(I*_x)        <-- Cos(x);

100 # Sinh(_x)/Cosh(_x) <-- Tanh(x);
100 # Sinh(_x)*Csch(_x) <-- 1;
100 # Cosh(_x)*Sech(_x) <-- 1;
100 # Tanh(_x)*Cosh(_x) <-- Sinh(x);
100 # Coth(_x)*Sinh(_x) <-- Cosh(x);

200 # Sinh(0)       <-- 0;
200 # Sinh(Infinity)    <-- Infinity;
200 # Sinh(-Infinity)   <-- -Infinity;
200 # Sinh(ArcSinh(_x)) <-- x;
200 # Sinh(ArcCosh(_x)) <-- Sqrt((x-1)/(x+1))*(x+1);
200 # Sinh(ArcTanh(_x)) <-- x/Sqrt(1-x^2);

200 # Cosh(0)       <-- 1;
200 # Cosh(Infinity)    <-- Infinity;
200 # Cosh(-Infinity)   <-- Infinity;
200 # Cosh(ArcCosh(_x)) <-- x;
200 # Cosh(ArcSinh(_x)) <-- Sqrt(1+x^2);
200 # Cosh(ArcTanh(_x)) <-- 1/Sqrt(1-x^2);

200 # Tanh(0)           <-- 0;
200 # Tanh(Infinity)    <-- 1;
200 # Tanh(-Infinity)   <-- -1;
200 # Tanh(ArcTanh(_x)) <-- x;
200 # Tanh(ArcSinh(_x)) <-- x/Sqrt(1+x^2);
200 # Tanh(ArcCosh(_x)) <-- Sqrt((x-1)/(x+1))*(x+1)/x;

200 # Sinh(Undefined) <-- Undefined;
200 # Cosh(Undefined) <-- Undefined;
200 # Tanh(Undefined) <-- Undefined;

UnProtect(Abs);
10 # Abs(Infinity)  <-- Infinity;
Protect(Abs);

/* Threading of standard analytic functions */
Sin(xlist_IsList) <-- MapSingle("Sin",xlist);
Cos(xlist_IsList) <-- MapSingle("Cos",xlist);
Tan(xlist_IsList) <-- MapSingle("Tan",xlist);
Sinh(xlist_IsList) <-- MapSingle("Sinh",xlist);
Cosh(xlist_IsList) <-- MapSingle("Cosh",xlist);
Tanh(xlist_IsList) <-- MapSingle("Tanh",xlist);


ArcSin(xlist_IsList) <-- MapSingle("ArcSin",xlist);
ArcCos(xlist_IsList) <-- MapSingle("ArcCos",xlist);
ArcTan(xlist_IsList) <-- MapSingle("ArcTan",xlist);
ArcSinh(xlist_IsList) <-- MapSingle("ArcSinh",xlist);
ArcCosh(xlist_IsList) <-- MapSingle("ArcCosh",xlist);
ArcTanh(xlist_IsList) <-- MapSingle("ArcTanh",xlist);


Exp(xlist_IsList) <-- MapSingle("Exp",xlist);
Ln(xlist_IsList) <-- MapSingle("Ln",xlist);

2 # ArcTan(x_IsNumber)_InNumericMode() <-- ArcTanNum(x);
