/*                            */
/*  Limit operator rule base  */
/*                            */ 


/*  Exponentiation rules  */

/*  Special limit #1:  0 ^ 0;  #2:  1 ^ Infinity;  #3:  Infinity ^ 0  */
200 # Lim(_var, _tar, _dir, _x ^ _y)_
( [
    Local(lx,ly); lx := Lim(var, tar, dir, x); ly := Lim(var, tar, dir, y);
    ((IsZero(lx) And IsZero(ly)) Or ((lx = 1) And IsInfinity(ly)) Or (IsInfinity(lx) And IsZero(ly)));
] )
<-- Exp(Lim(var, tar, dir, y * Ln(x)));

/*  Default rule  */
210 # Lim(_var, _tar, _dir, _x ^ _y)
<-- Lim(var, tar, dir, x)^Lim(var, tar, dir, y);


/*  Division rules  */

/*  Special limit #4:  0 / 0;  #5:  Infinity / Infinity  */
300 # Lim(_var, _tar, _dir, _x / _y)_
( [
    Local(lx,ly,infx,infy); 
     lx := Lim(var, tar, dir, x); 
     ly := Lim(var, tar, dir, y);
     infx := (IsInfinity(lx) Or (IsZero(Re(lx)) And IsInfinity(Im(lx))));
     infy := (IsInfinity(ly) Or (IsZero(Re(ly)) And IsInfinity(Im(ly))));
    ((IsZero(lx) And IsZero(ly)) Or 
     (infx And infy) 
     );
] )
<-- Lim(var, tar, dir, ApplyPure("D", {var, x})/ApplyPure("D", {var, y}));

/*  Special limit #6: null denominator  */
/*  Probably there are still some problems.  */

Dir(Right) <-- 1;
Dir(Left) <-- -1;

/*  To get the sign of the denominator on one side:  */
Sign(_var, _tar, _dir, _exp, _n)
<-- [
  Local(der, coef); der := ApplyPure("D", {var, exp});
  coef := Eval(ApplyPure("Subst", {var, tar, der}));
  If ( coef = 0,
       Sign(var, tar, dir, der, n+1),
       (Sign(coef)*Dir(dir)) ^ n
     );
];
  
/*  To avoid infinite recursion (with 1/Exp(-x) for instance)  */
310 # Lim(_var, _tar, _dir, _x / _y)_
(IsInfinity(tar) And IsZero(Lim(var, tar, dir, y)))
<-- Sign(Lim(var, tar, dir, x))*Sign(Lim(var, tar, dir, ApplyPure("D", {var, y})))*tar;

320 # Lim(_var, _tar, _dir, _x / _y)_IsZero(Lim(var, tar, dir, y))
<-- Sign(Lim(var, tar, dir, x))*Sign(var, tar, dir, y, 1)*Infinity;


/*  Default rule  */
330 # Lim(_var, _tar, _dir, _x / _y)
<-- Lim(var, tar, dir, x)/Lim(var, tar, dir, y); ];


/*  Multiplication rules  */

/*  To avoid some infinite recursions  */
400 # Lim(_var, _tar, _dir, _x * Exp(_y))_
(IsInfinity(Lim(var, tar, dir, x)) And (Lim(var, tar, dir, y) = -Infinity))
<-- Lim(var, tar, dir, x/Exp(-y));
400 # Lim(_var, _tar, _dir, Exp(_x) * _y)_
((Lim(var, tar, dir, x) = -Infinity) And IsInfinity(Lim(var, tar, dir, y)))
<-- Lim(var, tar, dir, y/Exp(-x));
400 # Lim(_var, _tar, _dir, Ln(_x) * _y)_
(IsZero(Lim(var, tar, dir, x)) And IsZero(Lim(var, tar, dir, y)))
<-- Lim(var, tar, dir, y*Ln(x));

/*  Special limit #7:  0 * Infinity  */
410 # Lim(_var, _tar, _dir, _x * _y)_
((IsZero(Lim(var, tar, dir, x)) And IsInfinity(Lim(var, tar, dir, y)))
  Or (IsInfinity(Lim(var, tar, dir, x)) And IsZero(Lim(var, tar, dir, y))))
<-- Lim(var, tar, dir, Simplify(ApplyPure("D", {var, y})/ApplyPure("D",
{var, 1/x})));

/*  Default rule  */
420 # Lim(_var, _tar, _dir, _x * _y)
<-- Lim(var, tar, dir, x) * Lim(var, tar, dir, y);


/*  Substraction rules  */

/*  Special limit #8:  Infinity - Infinity  */
500 # Lim(_var, _tar, _dir, _x - _y)_
( [
    Local(lx,ly); lx := Lim(var, tar, dir, x); ly := Lim(var, tar, dir, y);
    ((lx = Infinity) And (ly = Infinity)) Or ((lx = -Infinity) And (ly = -Infinity));
] )
<-- Lim(var, tar, dir, x*(1-y/x));

/*  Default rule  */
510 # Lim(_var, _tar, _dir, _x - _y)
<-- Lim(var, tar, dir, x)-Lim(var, tar, dir, y);

/*  Unary minus  */
520 # Lim(_var, _tar, _dir, - _x)
<-- - Lim(var, tar, dir, x);


/*  Addition rules  */

/*  Special limit #9:  Infinity + (-Infinity)  */
600 # Lim(_var, _tar, _dir, _x + _y)_
( [
    Local(lx,ly); lx := Lim(var, tar, dir, x); ly := Lim(var, tar, dir, y);
    ((lx = Infinity) And (ly = -Infinity)) Or ((lx = -Infinity) And (ly = Infinity));
] )
<-- Lim(var, tar, dir, x*(1+y/x));

/*  Default rule  */
610 # Lim(_var, _tar, _dir, _x + _y)
<-- Lim(var, tar, dir, x)+Lim(var, tar, dir, y);

/*  Global default rule : evaluate expression  */

700 # Lim(_var, _tar, _dir, exp_IsFunction)
<-- Eval(MapArgs(exp,"LimitArgs"));

LimitArgs(_arg) <-- Lim(var,tar,dir,arg);
UnFence("LimitArgs",1); /* Allow LimitArgs to have access to the local variables of the caller. */

701 # Lim(_var, _tar, _dir, _exp)
<-- Eval(ApplyPure("Subst", {var, tar, exp}));

  
/*  Limit without direction  */
  
10 # Lim(_var, tar_IsInfinity, _exp) <-- Lim(var, tar, None, exp);

20 # Lim(_var, _tar, _exp)
<-- [
  Local(l); l := Lim(var, tar, Left, exp);
  If ( l = Lim(var, tar, Right, exp),
       l,
       Undefined
     );
];




/* User-callable function */

(Limit(_var,_lim)(_fie)) <-- Lim(var,lim,fie);
(Limit(_var,_lim,_direction)(_fie)) <-- Lim(var,lim,direction,fie);
UnFence("Limit",3);





