Evalf := proc(x)
         local e;
             e := evalf(x); if e = -1.*infinity then -infinity else e fi
         end:
macro(evalf=Evalf);
macro(min=`intpak/min`, max=`intpak/max`, ilog10=`intpak/ilog10`);
intpak[init] := proc()
alias(ulp=Interval_ulp,
ru=Interval_Round_Up,rd=Interval_Round_Down,
width=Interval_width,
`&exp`=Interval_exp,
`&ln`=Interval_ln,
`&+`=Interval_add,
`&-`=Interval_subtract,
`&*`=Interval_times,
inv=Interval_reciprocal,
`&/`=Interval_divide,
`&sqrt`=Interval_sqrt,
`&sqr`=Interval_sqr,
`&intpower`=Interval_Integerpower,
`&**`= Interval_power,
midpoint=Interval_midpoint,
`&intersect`=Interval_intersect,
`&union`=Interval_union,
`&sin`=Interval_sin,
`&cos`=Interval_cos,
`&tan`=Interval_tan,
`&arcsin`=Interval_arcsin,
`&arccos`=Interval_arccos,
`&arctan`=Interval_arctan,
`&cosh`=Interval_cosh,
`&sinh`=Interval_sinh,
`&tanh`=Interval_tanh);
end:
intpak[init]():
################################################################################
#                                                                              #
#                  INTERVAL ARITHMETIC PACKAGE                                 #
#                                                                              #
#                by Amanda E. Connell and Robert M. Corless                    #
#                                                                              #
#                   The University of Western Ontario                          #
#                                                                              #
#                         August 13, 1992                                      #
#                                                                              #
# Revised slightly June 25, 1993.  Added convert/interval and inapply.         #
#                                                                              #
#                                                                              #
# Revised March 16, 1993.                                                      #
#    -- included fix to &intpower bug courtesy Steve Merrill.                  #
#                                                                              #
# Revised February 1, 1993, RMC                                                #
#    -- fixed &sqr bug                                                         #
#    -- fixed trig/ru bugs                                                     #
#    -- modified all routines to return unevaluated if called with             #
#       symbolic arguments.                                                    #
#                                                                              #
# Revised August 17, 1992, AEC                                                 #
#    -  The subroutines were packaged, together with helpfiles.                #
#                                                                              #
# Revised August 5, 1992, AEC                                                  #
#    -  Comments were amended in the code for all the subroutines              #
#    -  Procedure names were changed for consistency.                          #
#                                                                              #
# Written May 5- July 31 1992, AEC and RMC                                     #
#                                                                              #
################################################################################
`help/text/Interval_definitions`  := TEXT(
`HELP FOR: Interval Arithmetic Definitions`,
`             `,
`SYNOPSIS:`,
` - interval/type : an interval is defined in this test procedure as a `,
`   list with 2 floating point, infinite or FAIL elements, where `,
`   second element >= first element, or a list with 0 elements.`,
`             `,
` - min: a procedure which finds the minimum argument from a list of `,
`   n arguments, including numeric, infinite or FAIL arguments`,
`   example:`,
`   > min(-infinity,213432,infinity,0);`,
`                                   - infinity`,
`             `,
` - max: a procedure which finds the maximum argument from a list of`,
`   n arguments, including numeric, infinite or FAIL arguments`,
`   example:`,
`   > max(24365,879,3245,-infinity);`,
`                                    24365`,
`             `,
` - construct: a procedure which constructs an interval, with the option `,
`   to round the interval out of one endpoint (to make a degenerate `,
`   interval) or out of two endpoints`,
`             `,
`   examples:  `,
`   > Digits := 18;`,
`   > construct(-infinity,-infinity,'rounded'); `,
`            [- infinity, - infinity]         `,
`   > construct(0.0,4,'rounded');               `,
`            [0,4.00000000000000001]          `,
`   > construct(0.0,4.0);                     `,
`            [0, 4.0]                         `,
`   > construct(2.0);                         `,
`            [2.0,2.0]                        `,
`                 `,
` - is_in: this procedure tests to see if an interval, or numeric is `,
`   contained within another interval or numeric`,
`   examples:      `,
`   > is_in(infinity,[-infinity,infinity]);   `,
`             true                            `,
`   > is_in(2.0,2.0);                         `,
`             true                            `,
`   > is_in([2.0,2.0],2.0);                   `,
`             true                            `,
`   > is_in([1.9,2.1],[1.0,3.0]);             `,
`             true                            `,
`             `,
`REFERENCES:`,
` - B.I.A.S- Basic Interval Arithmetic Standard by George Corliss`,
`           `,
`SEE ALSO:`
) :
`help/text/construct`:=`help/text/Interval_definitions`:
`help/text/min`:=`help/text/Interval_definitions`:
`help/text/max`:=`help/text/Interval_definitions`:
`help/text/is_in`:=`help/text/Interval_definitions`:
# ------------------------------------------------------------------------------
`help/text/Interval_logarithmic`:= TEXT (
`HELP FOR: Interval logarithmic operators: &log and &exp`,
`             `,
`SYNOPSIS:`,
` - &log calculates the range the ln function takes over an interval, or`,
`   scalar argument`,
`             `,
` - &exp calculates the range the exponential function takes over an interval`,
`   or scalar argument`,
`             `,
`EXAMPLES:`,
`> Digits := 18;`,
`> &exp([0,infinity]);`,
`                       [.99999999999999999, infinity]`,
`> &exp(1.0);`,
`                    [2.71828182845904523, 2.71828182845904525]`,
`> &exp(0);`,
`                     [.99999999999999999, 1.00000000000000001]`,
`> &ln[0,0];`,
`  (note, due to an artifact of & operators the parentheses can be`,
`   sometimes omitted.  It is not known if this will be useful.)`,
`                            [- infinity, - infinity]`,
`> &ln[-infinity,0];`,
`                               [FAIL, - infinity]`,
`> &ln([0,10.]);`,
`                       [- infinity,2.30258509299404569]`,
`> Digits := 10;`,
`> &ln[.5,2.0];`,
`                          [-.6931471807, .6931471807]`,
`REFERENCES:`,
` - B.I.A.S.- Basic Interval Arithmetic Standard by George Corliss`,
` - Methods and Applications of Interval Analysis, by R.E.Moore`,
`             `,
`SEE ALSO: Interval_defintions, Interval_arithmetic, Interval_set, `,
`    Interval_trig, Interval_hyp`
):
`help/text/&ln`:=`help/text/Interval_logarithmic`:
`help/text/&exp`:=`help/text/Interval_logarithmic`:
# ------------------------------------------------------------------------------
`help/text/Interval_arithmetic` :=  TEXT(
`HELP FOR: Interval arithmetic operations`,
`             `,
`SYNOPSIS:  `,
` - All the arithmetic routines accept intervals, or scalars (which are then`,
`   constructed into intervals) infinity and FAIL arithmetic is performed`,
`   within these functions.`,
`             `,
` - inapply(expression,vars)`,
`   This procedure converts an ordinary Maple expression containing`,
`   arithmetic operators or the elementary functions sin, cos, tan,`,
`   and their inverses, exp, log, sinh, cosh, or tanh, and returns`,
`   an operator which evaluates that expression using rounded interval`,
`   arithmetic.  It uses the auxiliary subroutine ``convert/interval```,
`   which may also be called directly or by convert(expr,interval).`,
`   This call results in an expression involving the interval operators.`,
`             `,
` - &+,&-,&*,&/ `,
`   These operations are as defined in "Methods and Applications of Interval`,
`   Analysis" by R.E.Moore`,
`   An expression can be composed using interval arithmetic operators, the`,
`   Maple arithmetic operators preceded by & `,
`   &/ or inv procedures will return [-infinity,infinity] if 0 is contained`,
`   in the argument of the function.  `,
`             `,
` - &sqrt, &sqr compute the interval range of the sqrt or sqr function over`,
`   a given interval argument`,
`             `,
` - &** (or &^), &intpower.`,
`   &** computes one interval (or numeric) raised to the power of a floating`,
`   point interval or numeric, using a&**b=exp(b*ln(a)). There is an option`,
`   to return 0**0=[1.0,1.0], which is when Interval_option_zero=true, the `,
`   alternative is Interval_option_zero=false, 0**0=[FAIL,FAIL]`,
`   integerpower takes an interval (or numeric) raised to the power of`,
`   an integer. The Interval_option_zero is still applicable.`,
` - midpoint, width`,
`   These calculate the interval value of the midpoint and width of an `,
`   interval, respectively.`,
`             `,
`EXAMPLES:`,
`>inapply(1 + x + x^2, x);`,
`                        x -> 1 &+ (x &+ (x &intpower 2))`,
`> (-infinity)&+(infinity);`,
`                                  [FAIL, FAIL]`,
`> [.0,1.0]&+[2.0,2.0];`,
`                           [1.999999999, 3.000000001]`,
`> 1&+2.0;`,
`                           [2.999999999, 3.000000001]`,
`> [.0,1.0]&-[2.0,2.0];`,
`                          [-2.000000001, -.999999999]`,
`> [2.0,3.0]&*[2.0,2.0];`,
`                           [3.999999999, 6.000000001]`,
`> (-12341)&*(-infinity);`,
`                              [infinity, infinity]`,
`> inv([-3.0,3.0]);`,
`                            [- infinity, infinity]`,
`> inv([-infinity,-4.0]);`,
`                               [-.2500000001, 0]`,
`> [-1.0,3.0]&/[1.0,2.0];`,
`                          [-1.000000002, 3.000000004]`,
`> [2.0,4.0]&/[-2.0,4.0];`,
`                            [- infinity, infinity]`,
`> &sqrt[0,infinity];`,
`                                 [0, infinity]`,
`> &sqr[-infinity,0];`,
`                                 [0, infinity]`,
`> midpoint([-infinity,43262362365.]);`,
`                            [- infinity, - infinity]`,
`> midpoint([6.0,8.0]);`,
`                           [6.999999998, 7.000000002]`,
`> width([-infinity,-infinity]);`,
`                                      FAIL`,
`> width([-infinity,0]);`,
`                                    infinity`,
`> width(34.0);`,
`                                       0`,
`> width([23.0,4256.0]);`,
`                                     4233.0`,
`> [-infinity,infinity]&**(0);`,
`                           [.9999999989, 1.000000002]`,
`> [1.0,2.0]&**[3.0,5.0];`,
`                           [.999999999, 32.00000001]`,
`>  [-3.0,2.0]&intpower(2);`,
`                                [0, 9.000000001]`,
`>  [-infinity,5.0]&intpower(3);`,
`                           [- infinity, 125.0000001]`,
`>  [-2.0,-1.0]&intpower(-3);`,
`                          [-1.000000001, -.1249999999]`,
`            `,
`REFERENCES:`,
` - B.I.A.S.- Basic Interval Arithmetic Standard by George Corliss`,
` - Methods and Applications of Interval Analysis, by R.E.Moore`,
`             `,
`SEE ALSO: Interval_defintions, Interval_logarithmic, Interval_set, `,
`    Interval_trig, Interval_hyp`
):
`help/text/interval` := `help/text/Interval_arithmetic`:
`help/text/intpak` := `help/text/Interval_arithmetic`:
`help/text/&+`:=`help/text/Interval_arithmetic`:
`help/text/&-`:=`help/text/Interval_arithmetic`:
`help/text/&*`:=`help/text/Interval_arithmetic`:
`help/text/&/`:=`help/text/Interval_arithmetic`:
`help/text/inv`:=`help/text/Interval_arithmetic`:
`help/text/&sqr`:=`help/text/Interval_arithmetic`:
`help/text/&sqrt`:=`help/text/Interval_arithmetic`:
`help/text/&**`:=`help/text/Interval_arithmetic`:
`help/text/&intpower`:=`help/text/Interval_arithmetic`:
`help/text/midpoint`:=`help/text/Interval_arithmetic`:
`help/text/width`:=`help/text/Interval_arithmetic`:
# ------------------------------------------------------------------------------
`help/text/Interval_set`:= TEXT(
`HELP FOR: Interval set operations`,
`            `,
`SYNOPSIS:`,
` - &union. This returns the union of two interval or scalar arguments. If `,
`   the intersection of the two intervals is the empty interval ([]) then the`,
`   two interval arguments are returned.`,
`            `,
` - &intersect. This returns the intersection of two interval or scalar`,
`   arguments.`,
`            `,
`EXAMPLES:`,
`> &union([-infinity,infinity],[2.0,34.0]);`,
`                             [- infinity, infinity]`,
`> &union([8.0,12.0],9.0);`,
`                                  [8.0, 12.0]`,
`> &union([-infinity,12341.0],23523.0);`,
`                   [- infinity, 12341.0], [23523.0, 23523.0]`,
`> &intersect([8.0,12.0],9.0);`,
`                                   [9.0, 9.0]`,
`> &intersect([-infinity,12341.0],23523.0);`,
`                                       []`,
`             `,
`REFERENCES:`,
` - B.I.A.S.- Basic Interval Arithmetic Standard by George Corliss`,
` - Methods and Applications of Interval Analysis, by R.E.Moore`,
`             `,
`SEE ALSO: Interval_definitions, Interval_arithmetic, Interval_logarithmic`,
`          Interval_trig, Interval_hyp`
):
`help/text/&intersect`:=`help/text/Interval_set`:
`help/text/&union`:=`help/text/Interval_set`:
# ------------------------------------------------------------------------------
`help/text/Interval_trig`:=TEXT(
`HELP FOR: Interval trigonometric functions`,
`             `,
`SYNOPSIS:`,
` - &sin. This function scales the two endpoints of an interval argument, and`,
`   finds the maximum and minimum that the sin function takes on over that`,
`   scaled interval. If the width of the interval is greater than 2*Pi then`,
`   [-1.,1.] is returned.`,
`             `,
` - &cos. This also scales the two endpoints and finds the maximum and minimum`,
`   value that the cos function takes on over an interval argument.`,
`             `,
` - &tan. This scales the endpoints of the interval argument and returns the `,
`   maximum and minimum values that tan takes on over the interval.`,
`             `,
` - &arcsin. This uses Maple's own arcsin procedure to compute the rounded`,
`   interval range that of the arcsin function over a given interval argument.`,
`             `,
` - &arccos. This computes the widest, rounded interval range that arccos takes`,
`   for a given interval argument`,
`             `,
` - &arctan. This computes the widest interval range that arctan takes on `,
`   for a given interval argument. This function can accept one interval or`,
`   scalar argument and returns an interval between -Pi/2 and Pi/2, or it`,
`   can accept arguments of the form (y,x) where the result can be given from `,
`   -Pi to Pi, depending on the value of the second parameter, x.`,
`            `,
`EXAMPLES:`,
`> &cos[evalf(-1.2*Pi),evalf(.2*Pi)];`,
`                                   [-1., 1.]`,
`> &cos[evalf(-Pi/2),evalf(Pi/2)];`,
`                                            -8`,
`                            [-.1205103382*10  , 1.]`,
`> &cos[evalf(-7*Pi/2),evalf(-3*Pi)];`,
`                                                -8`,
`                            [-1., .3794896620*10  ]`,
`> &sin[evalf(Pi/3),evalf(Pi/2)];`,
`                               [.8660254031, 1.]`,
`> &sin[evalf(-1.2*Pi),evalf(Pi)];`,
`                                   [-1., 1.]`,
`> &tan(evalf(Pi/2));`,
`                             [- infinity, infinity]`,
`> &tan[evalf(301*Pi),evalf(302*Pi)];`,
`                             [- infinity, infinity]`,
`> &tan[(evalf(-Pi/2)),0];`,
`                             [- infinity, infinity]`,
`> &arctan([1.0,9.0],1.0);`,
`                           [.7853981633, 1.460139107]`,
`> &arctan(1.0,3.0);`,
`                           [.3217505543, .3217505545]`,
`> &arctan(-12.0);`,
`                          [-1.487655096, -1.487655094]`,
`> &arctan(infinity);`,
`                          [1.570796326, 1.570796328]`,
`> &arcsin([1.0,2.0]);`,
`Error, (in &arcsin) the arguments must be in the range [-1.,1.]`,
`> &arcsin([-1.0,1.0]);`,
`                          [-1.570796328, 1.570796328]`,
`> &arccos[-.290,.290];`,
`                           [1.276569488, 1.865023166]`,
`             `,
`REFERENCES:`,
` - B.I.A.S.- Basic Interval Arithmetic Standard by George Corliss`,
`             `,
`SEE ALSO: Interval_defintions, Interval_arithmetic, Interval_logarithmic`,
`     Interval_set, Interval_hyp`
):
`help/text/&tan`:=`help/text/Interval_trig`:
`help/text/&sin`:=`help/text/Interval_trig`:
`help/text/&cos`:=`help/text/Interval_trig`:
`help/text/&arctan`:=`help/text/Interval_trig`:
`help/text/&arccos`:=`help/text/Interval_trig`:
`help/text/&arcsin`:=`help/text/Interval_trig`:
# ------------------------------------------------------------------------------
`help/text/Interval_hyp`:= TEXT(
`HELP FOR: Hyperbolic interval functions`,
`             `,
`SYNOPSIS:`,
` - All the hyperbolic routines accept floating point interval or scalar`,
`   arguments. The routines use Maple's own tanh, sinh and cosh functions.`,
`            `,
` - The rounded interval result is returned, the result returned for cosh`,
`   always has lower endpoint>=1. The result returned for &tanh is in the`,
`   range [-1.,1.].`,
`            `,
`EXAMPLES:`,
`> &cosh[1.0,29.0];`,
`                                                    13`,
`                        [1.543080634, .1965667150*10  ]`,
`> &cosh(infinity);`,
`                              [infinity, infinity]`,
`> &cosh[-19.0,234.0];`,
`                                               102`,
`                            [1., .2108039624*10   ]`,
`> &sinh(34.0);`,
`                                     15                15`,
`                      [.2917308712*10  , .2917308714*10  ]`,
`> &sinh[-infinity,infinity];`,
`                             [- infinity, infinity]`,
`> &tanh([-infinity,infinity]);`,
`                                   [-1., 1.]`,
`> &tanh([-1.,1.]);`,
`                          [-.7615941561, .7615941561]`,
`> &tanh([-234.0,354984.0]);`,
`                                   [-1., 1.]`,
`REFERENCES:`,
` - B.I.A.S.- Basic Interval Arithmetic Standard by George Corliss`,
` - Methods and Applications of Interval Analysis, by R.E.Moore`,
`               `,
`SEE ALSO: Interval_defintions, Interval_arithmetic, Interval_set,`,
`      Interval_trig,Interval_logarithmic`
):
`help/text/&cosh`:=`help/text/Interval_hyp`:
`help/text/&sinh`:=`help/text/Interval_hyp`:
`help/text/&tanh`:=`help/text/Interval_hyp`:
# ------------------------------------------------------------------------------
################################################################################
#                                                                              #
#                   INT-TEST.MPL by R. Corless and A. Connell                  #
#                                                                              #
#                              June 1, 1992                                    #
#                                                                              #
# This file contains the basic interval defintions, as given in the Basic      #
# Interval Arithmetic Standard (B.I.A.S), eg rounding out procedure,           #
# the construct procedure and maximum and minimum procedures for infinite and  #
# FAIL arithmetic, the testing procedures.                                     #                 #
#                                                                              #
# Revised August 4, 1992, AEC                                                  #
#    - comments were amended in the code                                       #
#                                                                              #
################################################################################
# This procedure tests for evalf(-infinity), to eliminate problems that occur.
#is_neginfinity:=proc(x)
# if evalf(x)+infinity=0 then true else false fi:
#end:
#-----------------------------------------------------------------------------
# The following short subroutine is used for the case in which Maple evaluates
# -infinity to floating point precision to -1.infinity.
#simp_neginfinity:=proc(x)
#  if x+infinity=0  then -infinity else x fi:
#end:
#-----------------------------------------------------------------------------
# This type is included for ease of writing and clarity of code.
`type/num_or_FAIL`:=proc(a)
local bool,Constants:
Constants:={constants}:
bool:=type(a,numeric) or a=-infinity or a=infinity or a=FAIL
 or member(a,Constants):
bool:
end:
#-----------------------------------------------------------------------------
`type/interval_comp`:=proc(x)
  local bool,Constants:
  Constants:={constants}:
  bool:=type(x,float) or x=FAIL or (x)=-infinity or x=infinity or x=0 or
        member(x,Constants):
  bool:
end:
#-----------------------------------------------------------------------------
Interval_ulp := proc(x):
  if x=0 then (0) else
    Float(1,length(op(1,x))+op(2,x)-Digits)
  fi:
end:
#-----------------------------------------------------------------------------
Interval_Round_Up := proc(x):
  if x=-infinity then x
  elif x=infinity then infinity
  elif x=FAIL then FAIL
  else x + ulp(x)
  fi:
  end:
#-----------------------------------------------------------------------------
Interval_Round_Down := proc(x):
   if x=-infinity then x
   elif x=infinity then infinity
   elif x=FAIL then FAIL
   else x - ulp(x)
   fi:
   end:
#-----------------------------------------------------------------------------
#  PROCEDURE - TYPE/INTERVAL
`type/interval`:= proc(x)
# This procedure tests an argument to see if it is an interval. An interval
# is defined here to be a list with either zero elements,+/- infinity,FAIL
# or a list with two floating point members.
 local bool:
 bool:=false:
 if type(x,list) then
   if nops(x)=2 then
     if type(x[1],'interval_comp') and type(x[2],'interval_comp')
      then if max(x[1],x[2])=x[2] then bool:=true
           elif x[1]=FAIL or x[2]=FAIL then bool:=true
           else ERROR (`enter the lowest endpoint first`)
           fi:
     fi:
   elif nops(x)=0 then bool:=true
   fi:
 fi:
 bool:
 end:
#-----------------------------------------------------------------------------
#    PROCEDURE - CONSTRUCT
construct:=proc()
  local p,q:
  #  This procedure can accept a single argument, to construct a degenerate
  # interval, two arguments, to construct an interval form the low/high
  # endpoints. The option `rounded` can be entered as the last argument in
  # each case to construct a rounded interval.
  # Special type checking is performed to find (evalf(-infinity)). Where it
  # occurs as an argument, evalf(-infinity) is always rounded to -infinity, to
  # eliminate evalf(-infinity) from being an interval endpoint.
  # Suitable arguments are numeric, FAIL, +-infinity and constants.
   if nargs=3 then
    if args[3]='rounded' and type(args[1],'num_or_FAIL') and
        type(args[2],'num_or_FAIL')
    then p:=evalf(args[1]):
         q:=evalf(args[2]):
    [rd(min(p,q)),ru(max(p,q))]
    else ERROR(`first, second args must be numeric, third arg must be "rounded"`)
    fi:
 elif nargs=2 then
    if args[2]='rounded' and type(args[1],'num_or_FAIL') then
     [rd(evalf(args[1])),ru(evalf(args[1]))]
    elif type(args[1],'num_or_FAIL') and type(args[2],'num_or_FAIL') then
     p:=evalf(args[1]):
     q:=evalf(args[2]):
     if p=-infinity and q=-infinity
        then [rd(p),ru(q)]
     elif p=-infinity then [min(rd(p),q),max(ru(p),q)]
     elif q=-infinity then [min(p,rd(q)),max(p,ru(q))]
     else [min(p,q),max(p,q)]
     fi:
    else ERROR(`incorrect arguments entered`)
    fi:
 elif nargs=1 then
    if type(args[1],'num_or_FAIL') then
      if args[1]=-infinity then construct(-infinity,'rounded')
      else [evalf(args[1]),evalf(args[1])]
      fi:
    else ERROR (`only numeric, or infinite arguments are accepted`)
    fi:
 else ERROR (`maximum of three arguments accepted`)
 fi:
 end:
#-----------------------------------------------------------------------------
#  PROCEDURE - TEST-IN
is_in:=proc(x,a)
#
# This procedure takes two parameters. It tests to see whether the interval,
# or numeric x is contained in the interval a. If a is a float then
# the procedure constructs an interval to test.
#
if type(a,'interval') then
   if x=FAIL then (FAIL)
   elif not(type(x,'interval') or type(x,'num_or_FAIL'))
      then ERROR(`first argument must be a numeric or an interval`)
   elif a=[] then (false)
   elif a[1]=FAIL or a[2]=FAIL then (FAIL)
   elif(type(x,'num_or_FAIL')) then
      if evalf(max(x,a[1]))=evalf(x) and evalf(max(x,a[2]))=evalf(a[2])
      then (true) else (false) fi:
   elif type(x,'interval') then
     if x=[] then (false)
     elif x[1]=FAIL or x[2]=FAIL then (FAIL)
     elif evalf(max(x[1],a[1]))=evalf(x[1]) and
           evalf(max(x[2],a[2]))=evalf(a[2])
        then (true)
     else(false)
     fi:
   fi:
 elif type(a,'num_or_FAIL') then
   is_in(x,construct(a))
 else ERROR(`second arg must be an interval or a numeric`)
 fi:
 end:
#-----------------------------------------------------------------------------
################################################################################
#                                                                              #
#                 INT-LOG.MPL by R. Corless and A. Connell                     #
#                                                                              #
#                              May 29, 1992                                    #
#                                                                              #
#  This file contains the &log, &exp procedures for intervals, as defined in   #
#  the Basic Interval Arithmetic Standard. (B.I.A.S.) and Moore, Methods and   #
#  Applications of Interval Arithmetic.                                        #
#                                                                              #
#  Revised August 5, 1992, AEC                                                 #
#     - comments were added to the code.                                       #
#     - procedure names were changed.                                          #
#                                                                              #
################################################################################
#   PROCEDURE &EXP
#  expinfinity is only called from &exp. It deals with FAIL and +/- infinity.
#  Like most of the other subroutines &exp takes floating point intervals
#  or numerics (which are converted into intervals).
expinfinity:=proc(x):
  if x=FAIL then FAIL
  elif x=infinity then infinity
  elif x=-infinity then 0
  else evalf(exp(x))
  fi:
end:
Interval_exp:=proc(x):
  if type(x,'interval') then
    if x=[] then []
    elif x[1]=FAIL or x[2]=FAIL then [FAIL,FAIL]
    else [rd(expinfinity(x[1])),ru(expinfinity(x[2]))]
    fi:
  elif type(x,'num_or_FAIL') then
    Interval_exp(construct(x))
  else 
    # Want to return unevaluated here.
    'Interval_exp(x)'
#    ERROR(`floating point interval or scalar arguments are required`)
  fi:
end:
# ---------------------------------------------------------------------------
#     PROCEDURE  &LN
infinityln:=proc(x)
  if x=FAIL then FAIL
  elif x=infinity then infinity
  elif x=0 then -infinity
  elif (min(x,0)=x ) then FAIL
  # The above line returns FAIL, as opposed to Maple`s ln function which
  # returns an ERROR message stating that a singularity has been encountered.
  else ln(x)
  fi:
end:
Interval_ln:=proc(x)
  if type(x,'interval') then
    if x=[] then []
    else [rd(infinityln(x[1])),ru(infinityln(x[2]))]
    fi:
  elif type(x,'num_or_FAIL') then Interval_ln(construct(x))
  else
    # Return unevaluated
    'Interval_ln(x)' 
    # ERROR (`floating point intervals or scalars required`)
  fi:
end:
# ---------------------------------------------------------------------------
################################################################################
#                                                                              #
#                 INTERVAL.MPL  by R. Corless and A. Connell                   #
#                                                                              #
#                             June 1, 1992                                     #
#                                                                              #
#   This contains the basic interval arithmetic standard (B.I.A.S.)            #
# arithmetic interval operations. The operations appear as given in Moore,     #
# Methods and Applications of Interval Analysis, Chapter 2, p 9-17.            #
#                                                                              #
# Revised August 4, 1992, AEC                                                  #
#    - function names were changed in the code.                                #
#    - comments were amended in the code                                       #
#                                                                              #
################################################################################
# All the interval arithmetic subroutines perform type checking.
# They accept scalars (of type numeric) or intervals (floating point).
# Floating point and integer scalars are made into intervals.
#--------------------------------------------------------------------------------
# The ***infinity subroutines correct any problems that may occur with
# infinite and FAIL results
#-------------------------------------------------------------------------------
#    PROCEDURE  &+
addinfinity:=proc(x,y)
  if (x=infinity and y=(-infinity)) or (x=(-infinity) and y=infinity)
   then FAIL
  elif x=FAIL or y=FAIL then FAIL
  elif x=infinity or y=infinity then infinity
  elif x=-infinity or y=-infinity then -infinity
  else x+y
  fi:
 end:
Interval_add:=proc(a,b)
 if type(a,'interval') and type(b,'interval') then
    if a=[] or b=[] then []
    else [rd(addinfinity(a[1],b[1])),ru(addinfinity(a[2],b[2]))]
    fi:
 elif type(a,'interval') and type(b,'num_or_FAIL') then Interval_add(a,construct(b))
 elif type(a,'num_or_FAIL') and type(b,'interval') then Interval_add(construct(a),b)
 elif type(a,'num_or_FAIL') and type(b,'num_or_FAIL')
    then Interval_add(construct(a),construct(b))
 else 
  # Return unevaluated
  'Interval_add'(a,b)
  # ERROR(`floating point interval and scalar arguments required`)
 fi:
end:
# -------------------------------------------------------------------------------
#    PROCEDURE &-
subtractinfinity:=proc(x,y)
  if (x=infinity and y=(infinity)) or (x=(-infinity) and y=(-infinity))
   then FAIL
  elif x=FAIL or y=FAIL then FAIL
  elif x=infinity  then infinity
  elif y=infinity then -infinity
  elif x=-infinity then -infinity
  elif y=-infinity then infinity
  else x-y
  fi:
 end:
Interval_subtract := proc(a,b)
if type(a,'interval') and type(b,'interval') then
  if a=[] or b=[] then [] else
    [rd(subtractinfinity(a[1],b[2])),ru(subtractinfinity(a[2],b[1]))]
  fi:
elif type(a,'interval') and type(b,'num_or_FAIL')
   then Interval_subtract(a,construct(b))
elif type(a,'num_or_FAIL') and type(b,'interval')
   then Interval_subtract(construct(a),b)
elif type(a,'num_or_FAIL') and type(b,'num_or_FAIL')
   then Interval_subtract(construct(a),construct(b))
else
  # Return unevaluated
  'Interval_subtract(a,b)'  
  #  ERROR(`floating point interval and scalar arguments are required`)
fi:
end:
# -------------------------------------------------------------------------------
#    PROCEDURE  &*
timesinfinity:=proc(a,b)
if a=0 or b=0 then 0
elif a=FAIL or b=FAIL then FAIL
elif (a=-infinity and min(b,0)=0) or (b=-infinity and min(a,0)=0)then -infinity
elif (a=-infinity and min(b,0)=b) or (b=-infinity and min(a,0)=a) then infinity
elif (a=infinity and min(b,0)=0) or (b=infinity and min(a,0)=0) then infinity
elif (a=infinity and min(b,0)=b) or (b=infinity and min(a,0)=a)then -infinity
# the min function is called so that infinity*(-infinity) will give -infinity
# if either of the arguments in Interval_times are FAIL the result will
# be [FAIL,FAIL].
# The above code is long but takes into account every possibility.
else a*b
fi:
end:
Interval_times := proc(a,b)
   local xy,xY,Xy,XY:
   if type(a,'interval') and type(b,'interval') then
     if a=[] or b=[] then [] else
       xy := timesinfinity(a[1],b[1]):
       xY := timesinfinity(a[1],b[2]):
       Xy := timesinfinity(a[2],b[1]):
       XY := timesinfinity(a[2],b[2]):
       [ rd(min(xy,xY,Xy,XY)),ru(max(xy,xY,Xy,XY))]
     fi:
   elif type(a,'interval') and type(b,'num_or_FAIL') then
       Interval_times(a,construct(b))
   elif type(a,'num_or_FAIL') and type(b,'interval') then
       Interval_times(construct(a),b)
   elif type(a,'num_or_FAIL') and type(b,'num_or_FAIL') then
       Interval_times(construct(a),construct(b))
   else
    # Return unevaluated
    'Interval_times(a,b)'
    # ERROR(`floating point interval and scalar arguments are required`)
  fi:
end:
#---------------------------------------------------------------------
#    PROCEDURE   inv
# This procedure returns 1/infinity =0.
# If zero is contained in the denominator(interval) the procedure returns
# [-infinity,infinity]
Interval_reciprocal := proc(x):
if type(x,'interval') then
   if x=[] then []
   elif x[1]=FAIL or x[2]=FAIL then [FAIL,FAIL]
   elif is_in(0.0,x) then [-infinity,infinity]
   elif abs(x[1])=infinity and abs(x[2])=infinity then [0,0]
   elif abs(x[1])=infinity then [rd(1./x[2]),0]
   elif abs(x[2])=infinity then [0,ru(1./x[1])]
   else  [rd(1./x[2]),ru(1./x[1])]
   fi:
elif type(x,'num_or_FAIL') then
   Interval_reciprocal(construct(x))
else
  # Return unevaluated
  'Interval_reciprocal(x)' 
  # ERROR(`a floating point interval or scalar argument is required`)
fi:
end:
# ----------------------------------------------------------------------
#    PROCEDURE   &/
Interval_divide := proc(a,b):
# This procedure also performs type checking. A check is also done
# to see if 0.0 is contained in the denominator. [-infinity,infinity] is
# returned.
 if type(a,'interval') and type(b,'interval') then
  if a=[] or b=[] then []
  elif is_in(0.0,b) then [-infinity,infinity]
  elif (abs(b[1])=infinity or abs(b[2])=infinity) and (abs(a[1])=infinity
         or abs(a[2])=infinity) then [FAIL,FAIL]
  else a &* inv(b)
  fi:
 elif type(a,'interval') and type(b,'num_or_FAIL') then
  Interval_divide(a,construct(b))
 elif type(a,'num_or_FAIL') and type(b,'interval') then
   Interval_divide(construct(a),b)
 elif type(a,'num_or_FAIL') and type(b,'num_or_FAIL')  then
   Interval_divide(construct(a),construct(b))
 else
   # Return unevaluated
   'Interval_divide(a,b)'
   # ERROR(`floating point interval and scalar arguments are required`)
 fi:
 end:
# ---------------------------------------------------------------------
#    PROCEDURE  &SQRT
# An error message is returned if a negative argument is entered.
sqrtinfinity:=proc(x)
if x=FAIL then FAIL
elif x=0 then 0
elif x=infinity then infinity
elif min(x,0)=x then ERROR (`cannot compute the sqrt of a negative number`)
else sqrt(x)
fi:
end:
Interval_sqrt := proc(x)
if type(x,'interval') then
    if x=[] then [] else
     [rd(sqrtinfinity(x[1])),ru(sqrtinfinity(x[2]))]
    fi:
elif type(x,'num_or_FAIL') then Interval_sqrt(construct(x))
else 
  # Return unevaluated
  'Interval_sqrt(x)'
  # ERROR(`floating point interval or scalar argument is required`)
fi:
end:
# ----------------------------------------------------------------------
#    PROCEDURE &SQR
sqrinfinity:=proc(x)
if x=FAIL then FAIL
elif abs(x)=infinity then infinity
else x**2
fi:
end:
Interval_sqr:=proc(x)
local a,b:
if type(x,'interval') then
#
# Revised due to bug report by G. F. Corliss 2/1/93
#
 if x=[] then [] 
 elif is_in(0,x) then
   [0,ru(max(sqrinfinity(x[1]),sqrinfinity(x[2])))]
 else
   a := min(abs(x[1]),abs(x[2])):
   b := max(abs(x[1]),abs(x[2])):
   [rd(sqrinfinity(a)),ru(sqrinfinity(b))]
 fi:
#
# Old code:
#   
#   if x=[] then [] else
#      a:=max(sqrinfinity(x[1]),0):
#      b:=sqrinfinity(x[2]):
#      [rd(min(a,b)),ru(max(a,b))]:
# This max/min is to ensure that the result is of type interval.
# For example &sqr[-infinity,0] gives [0,infinity] and not the other
# way around.
#  fi:
elif type(x,'num_or_FAIL') then Interval_sqr(construct(x))
else 
  # Return unevaluated
  'Interval_sqr(x)'
  # ERROR (`a floating point interval or scalar argument is required`)
fi:
end:
# ------------------------------------------------------------------------
Interval_option_zero:=false:
# if option zero is true then 0**0=1
# if Interval_option_zero is false then 0**0=FAIL.
# This global variable can be changed by the user depending on which they
# prefer. The disadvantage with the false case is that even if only one of
# the endpoints is zero raised to zero, the resulting interval will
# be [FAIL,FAIL].
# ------------------------------------------------------------------------
#    PROCEDURE &INTPOWER
# Integerpower: This takes interval or num_or_FAIL arguments, x, and raises
# them to an integer power.
# Powerinfinity is a subroutine used to evaluate such cases as
# infinity**2 etc.
#
powerinfinity:=proc(x,n)
if n=0 then 1.
elif n=infinity and min(x,0)=x then FAIL
elif n=infinity then infinity
elif n=-infinity then 0
elif x=0 then 0
# This is included to prevent error messages for such cases as 0**(-3)
elif x=infinity then if n>0 then infinity else 0 fi:
elif x=-infinity then
  if type(n/2,integer) and n>0 then infinity else (-infinity) fi:
elif x=FAIL then FAIL
else x**n
fi:
end:
#
Interval_Integerpower:=proc(x,n)
local a,b:
if type (x,'interval') and type(n,integer) then
  if x=[] then []
  else
    a:=powerinfinity(x[1],n):
    b:=powerinfinity(x[2],n):
# The following is a check for monotonicity. If n is even and n>0 then
# if zero is in the interval it represents the lowest endpoint in the
# returned interval, and the the max endpoint is the max of x[1] and x[2]
# to the power n.
# Otherwise the function is monotonic, n>0 and the endpoints are evaluated
# directly for the maximum, and minimum values the function takes on the
# interval,x.
# If n<0 and 0 is contained in the interval, x, then [-infinity,infinity]
# is returned. Otherwise the value of the two endpoints raised to the negative
# power n are returned.
    if n<0 and type(n/2,integer) and is_in(0,x) then [rd(min(a,b)),infinity]
    elif n<0 and (not type(n/2,integer)) and is_in(0,x) then [-infinity,infinity]
    elif (n<0) then [rd(min(a,b)),ru(max(a,b))]
    elif n>0 and type(n/2,integer) and is_in(0,x) then
      [0,ru(max(a,b))]
    else [rd(min(a,b)),ru(max(a,b))]
# The else case covers n=0, n>0 and odd (ie monotonic).
    fi:
  fi:
elif type(x,'num_or_FAIL') then Interval_Integerpower(construct(x),n)
else 
  # Return unevaluated
  'Interval_Integerpower(x,n)'
  # ERROR
  # (`arg[1] must be a float interval or numeric, arg[2] must be an integer`)
fi:
end:
# ------------------------------------------------------------------------
#    PROCEDURE &**
# This procedure calculates an interval raised to the power of another interval.
# Digits is extended to reduce rounding error.
# Note the conditions on the ops of x, that they be numeric, so that the
# ilog10 function can be applied.
Interval_power:=proc(x,n)
local logx,prod,result,oldDigits:
 if type(x,'interval') and (type(n,'interval') or type(n,'interval_comp')) then
   oldDigits:=Digits:
   if x=[] then []
   elif n=[] then []
   elif not (type(x[1],numeric) and type(x[2],numeric))
     then Digits:=Digits
   elif not(type(x[1],numeric)) then
     Digits:=Digits+2+ilog10(x[2])
   elif not type(x[2],numeric) then
     Digits:=Digits+2+ilog10(x[1])
   else
     Digits:=max(Digits+2+ilog10(x[1]),Digits+2+ilog10(x[2])):
   fi:
# The following test refers to the cases of 0**+/-infinity and 0**0.
# In both cases the interval [FAIL,FAIL] is returned.
# There is an option to return 0**0=[1.0,1.0] which is on when
# Interval_option_zero=true. The case where 0 is in an interval is not
# tested for. This should theoretically return [FAIL,FAIL] too,
# but it would create problems along the way if it was implemented.
   if type(n,'interval') and (abs(n[1])=infinity or abs(n[2])=infinity)
    and (x[1]=0 or x[2]=0) then [FAIL,FAIL]
   elif type(n,'interval_comp') and (abs(n)=infinity)
     and (x[1]=0 or x[2]=0)  then [FAIL,FAIL]
   elif type(n,'interval') and (n[1]=0 or n[2]=0) and (x[1]=0 or x[2]=0)
     and not Interval_option_zero then [FAIL,FAIL]
   elif type(n,'interval_comp') and (n=0) and (x[1]=0 or x[2]=0)
     and not Interval_option_zero then [FAIL,FAIL]
   else logx:=(&ln(x)):
     prod:=(n&*logx):
     result:=&exp(prod):
     Digits:=oldDigits:
     construct(result[1],result[2],'rounded'):
   fi:
# The result is truncated to Digits precision, from oldDigits precision,
# and then a rounded interval is constructed.
elif type(x,'num_or_FAIL') then Interval_power(construct(x),n)
# although the &ln, &*, and &exp are able to take non-interval arguments
# of type/num_or_FAIL, the call to ilog10 in the above code means that
# only interval arguments can be accepted. Therefore if type/num_or_FAIL
# are entered, they must be constructed into intervals before being evaluated.
elif type (n,integer) then &intpower(x,n)
else
  # Return unevaluated
  'Interval_power(x,n)' 
  # ERROR (`floating point intervals, or scalars required`)
fi:
end:
#------------------------------------------------------------------------------
#    PROCEDURE midpoint
Interval_midpoint:=proc(x):
if type(x,'interval') then
  if x=[] then FAIL
  elif x[1]=FAIL or x[2]=FAIL then FAIL
  else (addinfinity(x[1],x[2]))&/2.:
  fi:
elif type (x,'num_or_FAIL') then Interval_midpoint(construct(x))
else
  # Return unevaluated
  'Interval_midpoint(x)'
  # ERROR(`floating interval or scalar argument required`)
fi:
end:
# ------------------------------------------------------------------------
#    PROCEDURE width
 Interval_width:=proc(x):
 if type(x,'interval') then
   if x=[] then []
   elif x[1]=FAIL or x[2]=FAIL then [FAIL,FAIL]
   else subtractinfinity(x[2],x[1])
   fi:
 elif type(x,'num_or_FAIL') then
   if not (x=infinity or x=-infinity)  then 0
   else Interval_width(construct(x)) fi:
   else 
    # Return unevaluated
    'Interval_width(x)'
    # ERROR(`floating interval or scalar argument required`)
 fi:
 end:
#------------------------------------------------------------------------------
################################################################################
#                                                                              #
#                     INT-SET.MPL by R. Corless and A. Connell                 #
#                                                                              #
#                            May 29, 1992                                      #
#                                                                              #
#  This file contains &union and &intersect.                                   #
#                                                                              #
################################################################################
#    PROCEDURE &INTERSECT
Interval_intersect:=proc(a,b)
if type(a,'interval') and type(b,'interval') then
  if a=[] or b=[] then []
  elif a[1]=FAIL or a[2]=FAIL or b[1]=FAIL or b[2]=FAIL then [FAIL,FAIL]
  elif (max(a[1],b[2])=a[1] and not a[1]=b[2])
  or (max(b[1],a[2])=b[1] and not b[1]=a[2])  then []
  else [(max(a[1],b[1])),(min(a[2],b[2]))]
  fi:
elif type(a,'num_or_FAIL') and type(b,'interval') then
   Interval_intersect(construct(a),b)
elif type(a,'interval') and type(b,'num_or_FAIL') then
   Interval_intersect(a,construct(b))
elif type(a,'num_or_FAIL') and type(b,'num_or_FAIL') then
   Interval_intersect(construct(a),construct(b))
else 
  # Return unevaluated
  'Interval_intersect(a,b)'
  # ERROR(`floating point interval or scalar arguments required`)
fi:
end:
#-------------------------------------------------------------------------
#    PROCEDURE &UNION
# This accepts floating point interval or scalar arguments. If the intersection
# of the two arguments is the empty interval then the union of the two arguments
# are the arguments themselves.
Interval_union:=proc(a,b)
if type(a,'interval') and type(b,'interval') then
  if a=[] then b
  elif b=[] then a
  elif a[1]=FAIL or a[2]=FAIL or b[1]=FAIL or b[2]=FAIL then [FAIL,FAIL]
  elif &intersect(a,b)=[] then RETURN(a,b)
  else [(min(a[1],b[1])),(max(a[2],b[2]))]
  fi:
elif type(a,'num_or_FAIL') and type(b,'interval') then
   Interval_union(construct(a),b)
elif type(a,'interval') and type(b,'num_or_FAIL') then
   Interval_union(a, construct(b))
elif type(a, 'num_or_FAIL') and type(b,'num_or_FAIL') then
   Interval_union(construct(a), construct(b))
else 
  # Return unevaluated
  'Interval_union(a,b)'
  # ERROR(`floating point interval or scalar arguments required`)
fi:
end:
#-------------------------------------------------------------------------
###############################################################################
#                                                                             #
#           INT-TRIG.MPL by R. Corless and A. Connell                         #
#                                                                             #
#                        July 13, 1992                                        #
#                                                                             #
# This file contains the &cos, &sin and &tan procedures which calculate the   #
# range of values the cos, sin, and tan functions take on  over a given       #
# interval (floating point) or scalar (integer or float) argument.            #
# This file contains the &arccos, &arcsin, and &arctan procedures. These      #
# functions calculate the range of values the corresponding functions take    #
# on over the given argument range. Maple's own arctan, arcsin and arccos     #
# functions are used.                                                         #
#                                                                             #
#                                                                             #
# Revised July 31, 1992, AEC                                                  #
#    - comments were amended in the code.                                     #
#    - variable names were changed                                            #
#                                                                             #
###############################################################################
# The following two procedures are called from &cos and &sin to ensure
# that the maximum and minimum the result can take are 1. and -1.
# There is no rounding out of 1. and -1.
Interval_trig_ru:=proc(x) if x= 1. then  1. else ru(x) fi; end:
Interval_trig_rd:=proc(x) if x=-1. then -1. else rd(x) fi; end:
# ----------------------------------------------------------------------------
# The following was written by Dr Dave Hare for the next version of Maple.
ilog10:=proc(x) if x=0 then 0 else length(op(1,x))+op(2,x)-1;  fi;  end:
#-----------------------------------------------------------------------------
# The following code is similar to Dr Dave Hare's code for scaling in
# Maple's sin function, except the arguments are scaled down
# as follows:
#
#      k:=xx/2*Pi    and    x:=xx-2*Pi*k , where x is returned.
#
# In order that the shape of the interval be preserved, the arguments
# are divided by 2*Pi.
#
# The two endpoints of the interval argument, xx, are scaled to the
# same degree, to the minimum k value.
# After scaling the interval 'result' is rounded out.

Interval_scale:=proc(xx)
 local k,x,d,k1,k2, mag_x1,mag_x2,mag_x,result:
 mag_x1:=ilog10(xx[1]):
 mag_x2:=ilog10(xx[2]):
 mag_x:=max(mag_x1,mag_x2):
 if mag_x1 >=0 then
    d:=max(Digits, 2+mag_x):
    k1:=round(evalf(xx[1]/(2*Pi),d)):
 fi:
 if mag_x2>=0 then
     d:=max(Digits,2+mag_x):
     k2:=round(evalf(xx[2]/(2*Pi),d)):
 fi:
 if mag_x1>=0  and mag_x2>=0 then
    k:=min(k1,k2):
    x[1]:=rd(evalf((xx[1])-2*Pi*k,Digits+d+mag_x)):
    x[2]:=ru(evalf((xx[2])-2*Pi*k,Digits+d+mag_x)):
    result:= [x[1],x[2]]:
 else result:= [xx[1],xx[2]] fi:
 result
 end:
# ------------------------------------------------------------------
  Interval_range_values:=proc(x,y1,y2)
  local k1,k2,p1,p2,int:
# The following code is used to test for maxima and minima in the &sin
# and &cos subroutines.
# (In order for this testing to work for &cos, Pi/2 must first be added to the
# arguments. This is done in &cos.)
#
# First the number of the 2Pi interval, k, in which the endpoint occurs
# is assigned. The 2Pi intervals either side of x=zero have value k=0.
# In the positive x axis k>=0 , in the negative x axis k<=0. It is then
# possible to compare the k1 and k2 values. Testing is done for both the
# positive and negative cases if abs(k2-k1)=1. If x[2]-x[1]>=2*Pi then
# obviously there is a maximum and a minimum in the interval and [-1.,1.]
# is returned.
#
    k1:=trunc(evalf(x[1]/(2.*Pi))):
    k2:=trunc(evalf(x[2]/(2.*Pi))):
#
# The interval(x) is scaled down to `int`. Int is then tested for containment
# of 1/4 and 3/4, those fractions of the 2*Pi interval at which the maxima and
# minima occur.
    p1:=frac(evalf(x[1]/(2.*Pi))):
    p2:=frac(evalf(x[2]/(2.*Pi))):
    int:=construct(p1,p2):
    if abs(x[1]-x[2])>=evalf(2*Pi) then [-1.,1.]
    elif abs(k2-k1)=1 then
      if evalf(x[1])>=0 and evalf(x[2])>=0 then
        if p1<=(1/4) then [-1.,1.]
        elif p1>=(1/4) and p1<=(3/4) and p2>=1/4 then [-1.,1. ]
        elif p1>=(1/4) and p1<=3/4 and p2<=(1/4) then [-1.,Interval_trig_ru(max(y1,y2))]
        elif p1>=3/4 and p2>=1/4 and p2<=3/4 then [Interval_trig_rd(min(y1,y2)),1.]
        elif p1>=3/4 and p2>=3/4 then [-1.,1.]
        elif p1>=3/4 and p2<=1/4 then [rd(min(y1,y2)),ru(max(y1,y2))]
        fi:
# The case for all negative endpoints
      elif evalf(x[1])<=0 and evalf(x[2])<=0 then
        if p1<=-3/4 then [-1.,1.]
        elif p1>-3/4 and p1<=-1/4 and p2>=-3/4 then [-1.,1.]
        elif p1>-3/4 and p1<=-1/4 and p2<=-3/4 then [-1.,ru(max(y1,y2))]
        elif p1>-1/4 and p2>=-3/4 and p2<=-1/4 then [rd(min(y1,y2)),1.]
        elif p1>-1/4 and p2>=-1/4 then [-1.,1.]
        elif p1>-1/4 and p2<=-3/4 then [rd(min(y1,y2)),ru(max(y1,y2))]
        fi:
      fi:
# This is the case for k values the same, on the positive x axis.
    elif x[1]>=0 and x[2]>=0 then
      if is_in(1/4,int) and is_in(3/4,int) then [-1.,1.]
      elif is_in(1/4,int) then [Interval_trig_rd(min(y1,y2)),1.]
      elif is_in(3/4,int) then [-1.,Interval_trig_ru(max(y1,y2))]
      else [Interval_trig_rd(min(y1,y2)),Interval_trig_ru(max(y1,y2))]
      fi:
# This is the case for k values the same, on the negative x axis.
    elif x[1]<=0 and x[2]<=0 then
      if is_in(-3/4,int) and is_in(-1/4,int) then [-1.,1.]
      elif is_in(-3/4,int) then [Interval_trig_rd(min(y1,y2)),1.]
      elif is_in(-1/4,int) then [-1.,Interval_trig_ru(max(y1,y2))]
      else [Interval_trig_rd(min(y1,y2)),Interval_trig_ru(max(y1,y2))]
      fi:
# This is the case for k values the same, 0, either side of x=0.
    elif x[1]<=0 and x[2]>=0 then
      if is_in(-3/4,int) or is_in(3/4,int) then [-1.,1.]
      elif is_in(-1/4,int) and is_in(1/4,int) then [-1.,1.]
      elif is_in(-1/4,int) then [-1.,Interval_trig_ru(max(y1,y2))]
      elif is_in(1/4,int) then [Interval_trig_rd(min(y1,y2)),1.]
      else [Interval_trig_rd(min(y1,y2)),Interval_trig_ru(max(y1,y2))]
       fi:
    fi:
    end:
# --------------------------------------------------------------------------
#    PROCEDURE &SIN
# This function accepts floating-point interval arguments, or floating point
# or integer scalar arguments.
#
Interval_sin:=proc(s)
local x,y1,y2:
if type (s,'interval') then
  if s=[] then []
  elif s[1]=-infinity or s[2]=-infinity or s[1]=infinity
        or s[2]=infinity then  [-1.,1.]
  elif s[1]=FAIL or s[2]=FAIL then [FAIL,FAIL]
#
# The following test ensures that if the argument entered at either of the
# endpoints has error in its last digit, then if the ulp of the last digit is
# greater than 2*Pi, [-1.,1.] is returned.
  elif (ulp(s[1])/10.>=evalf(2*Pi) or ulp(s[2])/10.>=evalf(2*Pi)) and
      not s[1]=s[2] then [-1.,1.]
  else
    x:=Interval_scale(s):
    y1:=evalf(sin(x[1])):
    y2:=evalf(sin(x[2])):
    Interval_range_values(x,y1,y2):
  fi:
elif type(s,'num_or_FAIL') then Interval_sin(construct(s))
else 
  # Return unevaluated
  'Interval_sin(s)'
  # ERROR(` floating point intervals or scalars required`)
fi:
end:
# ---------------------------------------------------------------------------
#    PROCEDURE &COS
# This function uses identical testing code from &sin to test for maximas
# and minimas by adding Pi/2 to the argument of the cos function.
# This saves repetition of code that has already been written and tested.
#
# The actual values of cos at the endpoints are calculated before the Pi/2 is
# added. 
#
# This function accepts floating point interval arguments, or floating point
# or integer scalar arguments.
#
Interval_cos:=proc(s)
local y1,y2,r,t,x:
if type (s,'interval') then
  if s=[] then []
  elif s[1]=-infinity or s[2]=-infinity or s[1]=infinity
        or s[2]=infinity then  [-1.,1.]
  elif s[1]=FAIL or s[2]=FAIL then [FAIL,FAIL]
# The same test as in &sin occurs here.
  elif (ulp(s[1])>=evalf(2*Pi) or ulp(s[2])>=evalf(2*Pi)) and
   not s[1]=s[2]
  then [-1.,1.]
  else
    r:=Interval_scale(s):
# Digits are increased for accuracy.
    t:=[evalf(s[1]+evalf(.5*Pi,Digits+3),Digits+3),evalf(s[2]
            +evalf(.5*Pi,Digits+3),Digits+3)]:
    x:=Interval_scale(t):
    y1:=evalf(cos(r[1])):
    y2:=evalf(cos(r[2])):
    Interval_range_values(x,y1,y2):
  fi:
elif type(s,'num_or_FAIL') then Interval_cos(construct(s))
else 
  # Return unevaluated
  'Interval_cos(s)'
  # ERROR(` floating point intervals or scalars required`)
fi:
end:
# --------------------------------------------------------------------------
#    PROCEDURE &TAN
# This function accepts floating-point interval arguments, or floating point
# or integer scalar arguments.
#
# For ease of testing, like &cos, Pi/2 is added, with increased Digits.
# In the same way as for &cos and &sin, the interval is scaled down to a 2*Pi
# interval and the k1 and k2 values are calculated.
# The testing for this function is simpler than the &sin and &cos due
# to the monotonicity of tan over the regions on which it is defined.
#
Interval_tan:=proc(s)
local int,k1,k2,p1,p2,y1,y2,r,t,x:
if type (s,'interval') then
  if s=[] then []
  elif s[1]=-infinity or s[2]=-infinity or s[1]=infinity
        or s[2]=infinity then  [-infinity,infinity]
  elif s[1]=FAIL or s[2]=FAIL then [FAIL,FAIL]
# The following test ensures that if the argument entered at either of the
# two endpoints (providing it's not a degenerate interval) has ulp greater than
# Pi then [-infinity,infinity] is returned.
  elif (ulp(s[1])>=evalf(Pi) or ulp(s[2])>=evalf(Pi)) and
      not s[1]=s[2] then [-infinity,infinity]
  else
    r:=Interval_scale(s):
    t:=[evalf(s[1]+evalf(.5*Pi),Digits+3),evalf(s[2]
            +evalf(.5*Pi),Digits+3)]:
    x:=Interval_scale(t):
    y1:=evalf(tan(r[1])):
    y2:=evalf(tan(r[2])):
#
# First the number of the 2Pi interval, k, in which
# the endpoint occurs is assigned. The 2Pi intervals either side of x=zero
# have value k=0. In the positive x axis k>=0 , in the negative x axis k<=0.
# It is then possible to compare the k1 and k2 values.
#
    k1:=trunc(evalf(x[1]/(2.*Pi))):
    k2:=trunc(evalf(x[2]/(2.*Pi))):
#
# The fraction of the 2*Pi interval is then assigned.
# The interval(x) is scaled down to `int`. Int is then tested for containment
# of 1/2, that fraction of the 2*Pi interval at which the singularity is
# encountered. 
    p1:=frac(evalf(x[1]/(2.*Pi))):
    p2:=frac(evalf(x[2]/(2.*Pi))):
    int:=construct(p1,p2):
# If x[2]-x[1]>=Pi then obviously there is a singularity encountered in the
# interval and [-infinity,infinity] is returned.
    if abs(x[1]-x[2])>=evalf(Pi) then [-infinity,infinity]
    elif abs(k2-k1)=1 then [-infinity,infinity]
# After scaling, x=0 is a singularity.
    elif k1=0 and k2=0 and x[1]<=0 and x[2]>=0 then [-infinity,infinity]
    elif k1=k2 and x[1]>=0 and x[2]>=0 then
# If one of the endpoints is a singularity , for example [-Pi/2,0], then
# [-infinity,infinity] is returned.
      if is_in(.5,int) or is_in (-.5,int) or is_in(0,int)
        then [-infinity,infinity]
      else [Interval_trig_rd(min(y1,y2)),Interval_trig_ru(max(y1,y2))]
      fi:
    elif k1=k2 and x[1]<=0 and x[2]<=0 then
      if is_in(.5,int)  or is_in(-.5,int) or is_in (0,int)
         then [-infinity,infinity]
      else [Interval_trig_rd(min(y1,y2)), Interval_trig_ru(max(y1,y2))]
      fi:
    fi:
  fi:
elif type(s,'num_or_FAIL') then Interval_tan(construct(s))
else 
  # Return unevaluated
  'Interval_tan(s)'
  # ERROR(` floating point intervals or scalars required`)
fi:
end:
#-------------------------------------------------------------------------------
#    PROCEDURE &ARCSIN
# The following simple function returns the rounded interval of the
# inverse sin function. The Maple V arcsin function carries one guard digit.
# Here simply rounding the interval out ensures that the solution(s)
# is/are always contained in the interval.
# The results returned are in the interval [-Pi/2,Pi/2].
Interval_arcsin:=proc(x):
if type (x,'interval') then
    if x=[] then []
    elif x[1]=FAIL or [2]=FAIL then [FAIL,FAIL]
# The testing for the correct argument range is complicated by the possiblity
# of infinite arguments.
    elif (max(abs(x[1]),abs(1.))=abs(x[1]) and not (x[1]=1. or x[1]=-1.))
      or (max(abs(x[2]), abs(1.))=abs(x[2]) and not (x[2]=1. or x[2]=-1.)) then
         ERROR ( `the arguments must be in the range [-1.,1.]`)
    else [rd(evalf(arcsin(x[1]))),ru(evalf(arcsin(x[2])))]:
    fi:
elif type(x,'num_or_FAIL') then
Interval_arcsin(construct(x))
else 
  # Return unevaluated
  'Interval_arcsin(x)'
  # ERROR(` floating point intervals or scalars required`)
fi:
end:
# ----------------------------------------------------------------------------
#    PROCEDURE &ARCCOS
# The following simple function returns the rounded interval of the
# arccos function. The Maple V arccos function carries one guard digit.
# Here simply rounding the interval out ensures that the solution(s)
# is/are always contained in the interval.
# The results returned are in the interval [0, Pi].
Interval_arccos:=proc(x):
if type (x,'interval') then
    if x=[] then []
    elif x[1]=FAIL or [2]=FAIL then [FAIL,FAIL]
# The testing for the correct argument range is complicated by the possiblity
# of infinite arguments.
    elif (max(abs(x[1]),abs(1.))=abs(x[1]) and not (x[1]=1. or x[1]=-1.))
      or (max(abs(x[2]), abs(1.))=abs(x[2]) and not (x[2]=1. or x[2]=-1.)) then
       ERROR ( `the arguments must be in the range [-1.,1.]`)
    else [rd(evalf(arccos(x[2]))),ru(evalf(arccos(x[1])))]:
    fi:
elif type(x,'num_or_FAIL') then
Interval_arccos(construct(x))
else 
  # Return unevaluated
  'Interval_arccos(x)'
  # ERROR(` floating point intervals or scalars required`)
fi:
end:
# ------------------------------------------------------------------------------
#    PROCEDURE &ARCTAN
# The following procedure calculates the range of the arctan function,
# given the x coordinate and the y coordinate of a point.
# The default value for x is 1, and the answer returned is in the
# [-Pi/2,Pi/2] interval. The arctan of the high and low endpoints of the
# interval arguments are calculated. The rounded, widest possible interval
# is returned.
Interval_arctan:=proc(y,x)
local a,b,c,d:
if nargs=2 then
  if type(y,'interval') and (type(x,'interval') or x=[1,1]) then
# The integer interval is needed for cases where only one argument is given
# and [1,1] is the default value for the second argument. It is important for
# cases involving infinity that the 1 be an integer as Maple's arctan function
# returns cannot calculate such examples as arctan(infinity,1.0).
# This may be amended in the next version  of Maple, as a result of suggestions
# to the writers of maple.
    if x[1]=FAIL or x[2]=FAIL or y[1]=FAIL or y[2]=FAIL then [FAIL,FAIL]
    else
       a:=evalf(arctan(y[1],x[1])):
       b:=evalf(arctan(y[1],x[2])):
       c:=evalf(arctan(y[2],x[1])):
       d:=evalf(arctan(y[2],x[2])):
       [rd(min(a,b,c,d)),ru(max(a,b,c,d))]
    fi:
  elif type(y,'interval') and type(x,'num_or_FAIL') then
    Interval_arctan(y,construct(x))
  elif (type(x,'interval') or x=[1,1]) and type(y,'num_or_FAIL') then
    Interval_arctan(construct(y),x)
  elif type(x,'num_or_FAIL') and type(y,'num_or_FAIL') then
    Interval_arctan(construct(y),construct(x))
  fi:
elif nargs=1 then Interval_arctan(y,[1,1])
else 
  # Return unevaluated
  'Interval_arctan(y,x)'
  # ERROR(`up to two floating point interval or scalar arguments accepted`)
fi:
end:
#-------------------------------------------------------------------------------
################################################################################
#                                                                              #
#                 INT-HYP.MPL by R. Corless and A. Connell                     #
#                                                                              #
#                             July 14, 1992                                    #
#                                                                              #
#  This file contains the &cosh, &sinh, &tanh functions for intervals, as      #
#  defined in the Basic Interval Arithmetic Standard. (B.I.A.S.).              #
#  Maple V's existing functions are used. Special rounding is done to ensure   #
#  that results returned are in the correct interval.                          #
#                                                                              #
#  Revised August 4, 1992, AEC                                                 #
#     - comments were added to the code                                        #
#                                                                              #
################################################################################
# The following rounding procedure ensure that the results of the hyperbolic
# functions are always in the correct range. e.g. -1.<= tanh(x) <=1.
# 1.<=cosh(x).
Interval_hyp_rd:=proc(x); if x=-1. then x else rd(x) fi; end:
Interval_hyp_ru:=proc(x); if x= 1. then x else ru(x) fi; end:
# ------------------------------------------------------------------------------
#    PROCEDURE &COSH
# The following simple function returns the rounded interval result
# of the cosh function over an interval range. Maple's cosh function is
# called. A check is done for the inclusion of 0, a minimum.
Interval_cosh:=proc(x):
if type(x,'interval') then
    if x=[] then []
    elif x[1]=FAIL or x[2]=FAIL then [FAIL,FAIL]
    elif is_in(0,x) then [1.,ru(evalf(max(cosh(x[1]),cosh(x[2]))))]
    else [Interval_hyp_rd(evalf(cosh(x[1]))),ru(evalf(cosh(x[2])))]
# The absolute minimum of the cosh function is 1., so the lower endpoint is not
# rounded below 1.
    fi:
elif type (x,'num_or_FAIL') then Interval_cosh(construct(x))
else 
  # Return unevaluated
  'Interval_cosh(x)'
  # ERROR (`floating point interval or scalar argument required`)
fi:
end:
# ------------------------------------------------------------------------------
#    PROCEDURE &SINH
# The following simple function returns the rounded interval result
# of the sinh function over an interval range. Maple's sinh function
# is called.
Interval_sinh:=proc(x):
if type(x,'interval') then
   if x=[] then []
   elif x[1]=FAIL or x[2]=FAIL then [FAIL,FAIL]
   else [rd(sinh(x[1])),ru(sinh(x[2]))]
   fi:
elif  type(x,'num_or_FAIL') then Interval_sinh(construct(x))
else 
  # Return unevaluated
  'Interval_sinh(x)'
  # ERROR (`floating point interval or scalar argument required`)
fi:
end:
# ------------------------------------------------------------------------------
#    PROCEDURE &TANH
# The following simple function returns the rounded interval result
# of the tanh function over an interval range. Maple's tanh function
# is called. Results are in the range [-1.,1.].
Interval_tanh:=proc(x):
if type(x,'interval') then
   if x=[] then []
   elif x[1]=FAIL or x[2]=FAIL then [FAIL,FAIL]
   else [Interval_hyp_rd(evalf(tanh(x[1]))),Interval_hyp_ru(evalf(tanh(x[2])))]
   fi:
elif  type(x,'num_or_FAIL') then Interval_tanh(construct(x))
else 
  # Return unevaluated
  'Interval_tanh(x)'
  # ERROR (`floating point interval or scalar argument required`)
fi:
end:
# ------------------------------------------------------------------------------
#   PROCEDURES `CONVERT/INTERVAL` AND INAPPLY
#
# A utility program to convert Maple expressions to interval
# arithmetic.  convert(1+x + x^2,'interval') returns (1 &+ x) &+ (x &^ 2),
# whereas inapply(1+x+x^2,x) yields the operator x -> (1 &+ x) etc.
#
macro(ci=`convert/interval`):
Interval_fnlist := [sin=`&sin`,
                cos=`&cos`,
                tan=`&tan`,
                arcsin=`&arcsin`,
                arccos=`&arccos`,
                arctan=`&arctan`,
                exp=`&exp`,
                ln=`&ln`,
                sqrt=`&sqrt`] :

`convert/interval` := proc(e)
  local ope,mope,fn:
  option system:

  if type(e,'interval') or type(e,'interval_comp') then e
  elif type(e,`+`) then
    ci(op(1,e)) &+ ci(e-op(1,e))
  elif type(e,`*`) then
    ci(op(1,e)) &* ci(e/op(1,e))
  elif type(e,`^`) then
    if type(op(2,e),posint) then
       ci(op(1,e)) &intpower op(2,e)
    elif type(op(2,e),integer) then
       inv( ci(op(1,e)) &intpower (-op(2,e)) )
    else
       ci(op(1,e)) &^ ci(op(2,e))
    fi
  elif type(e,function) then
    ope := [op(e)]:
    mope:= op(map(ci,ope)):
    fn := subs(Interval_fnlist,op(0,e)):
    fn(mope)
  else
    e
  fi
end:
inapply := proc(); unapply(convert(args[1],'interval'),args[2..nargs]); end:
#
#        F O R    M A P L E   V   R E L E A S E   I   O N L Y
#
# These three routines are needed for Maple V only, as the routines
# are built-in to Maple V Release 2.
#
# ------------------------------------------------------------------------
# This procedure was written by Dave Hare as a means of calculating how many
# Digits a number should be raised to in scaling.
#ilog10:=proc(x)
# if x=0 then 0
#   else length(op(1,x))+op(2,x)-1
# fi:
#end:
#-----------------------------------------------------------------------------
#  PROCEDURE - MINIMUM
# This is called from &*, and numerous other procedures. It finds the minimum
# of n arguments, of type(numeric) or infinity.
# Note if one the n arguments given is FAIL then FAIL is returned
min:=proc() local a,i,result:
  a:={args} minus {infinity}:
  if nops(a)=0 then RETURN(infinity)
  elif member(FAIL,a) then RETURN (FAIL)
  elif member(-infinity,a) then RETURN (-infinity)
  else
    result :=a[1];
    for i from 2 to nops(a) do
	if a[i]<result then result := a[i] fi;
    od:
    result
  fi:
end:
#-----------------------------------------------------------------------------
#   PROCEDURE - MAXIMUM
# Note if FAIL is one of the n arguments given FAIL is returned.
max:=proc() local a,i,result:
   a:={args} minus {-infinity}:
   if nops(a)=0 then RETURN(-infinity)
   elif member (FAIL,a) then RETURN(FAIL)
   elif member (infinity,a) then RETURN(infinity)
   else
     result:=a[1];
     for i from 2 to nops(a) do
         if a[i]>result then result:=a[i] fi:
     od:
    result
   fi:
 end:
#save `intpak.m`;
#quit
