intpakX.mws

intpakX v1.0

written by  Grimmer, Markus, Department of Mathematics, University of Wuppertal, Germany, http://www.math.uni-wuppertal.de/wrswt
<© 1999-2002 Scientific Computing/Software Engineering Research Group, University of Wuppertal, Germany>

intpakX
by Krämer, Walter, Geulig, Ilse and Grimmer, Markus, Department of Mathematics, University of Wuppertal, Germany, http://www.math.uni-wuppertal.de/wrswt
<© 1999-2002 Scientific Computing/Software Engineering Research Group, University of Wuppertal, Germany>
intpak
by Corless, R. and Connell, A., University of Western Ontario, Canada
<© 1992-1993 R. Corless and A. Connell>

>    restart;

###########################################################################

intpakX v1.0 - Interval Arithmetic in Maple

This is a new, integrated version of the Maple package intpakX for interval computations.
It integrates and updates the package

- intpak by R. Corless and A. Connell
and its extension
- intpakX by I. Geulig and W. Kraemer

intpakX v1.0 was written/updated by M. Grimmer.

intpakX v1.0 provides basic data types and operations for interval arithmetic as well as additional
features for further interval computation.
Through this package, the features of the above mentioned packages are available in a
combined version as a Maple 7 module.
A couple of updates have been made to provide a version working with Maple 7 properly.  

For information how to create a Maple package from this document, see the end of this worksheet.


intpakX v1.0 (c) Scientific Computing/Software Engineering Research Group,
Department of Mathematics, University of Wuppertal, Germany


Contact:
kraemer@math.uni-wuppertal.de
markus.grimmer@math.uni-wuppertal.de
http://www.math.uni-wuppertal.de/wrswt

Disclaimer: see end of module

###########################################################################

###########################################################################
Module header
###########################################################################

>    intpakX:=module()
export init,Evalf,min,intpakX_min,max,intpakX_max,ilog10,intpakX_ilog10,
  Interval_ulp,ulp,
  Interval_Round_Up,Interval_Round_Down,ru,rd,
  intpakX_greater,is_in,construct,expinfinity,
  Interval_exp,infinityln,`&exp`,`&ln`,
  Interval_ln,addinfinity,Interval_add,`&+`,subtractinfinity,
  Interval_subtract,`&-`,timesinfinity,Interval_times,`&*`,
  Interval_reciprocal,inv,Interval_divide,`&/`,sqrtinfinity,Interval_sqrt,`&sqrt`,
  sqrinfinity,Interval_sqr,`&sqr`,
  Interval_option_zero,powerinfinity,Interval_Integerpower,`&intpower`,
  Interval_power,`&**`,Interval_midpoint,midpoint,
  Interval_width,width,Interval_intersect,`&intersect`,
  Interval_union,`&union`,Interval_trig_ru,Interval_trig_rd,
  Interval_scale,Interval_range_values,Interval_sin,Interval_cos,Interval_tan,
  Interval_arcsin,Interval_arccos,Interval_arctan,Interval_hyp_rd,Interval_hyp_ru,
  Interval_cosh,Interval_sinh,Interval_tanh,`&sin`,`&cos`,`&tan`,`&arcsin`,
  `&arccos`,`&arctan`,`&sinh`,`&cosh`,`&tanh`,
  ext_int_div,rel_diam,mid,compute_naive_interval_range,compute_mean_value_range,
  compute_monotonic_range,compute_combined_range,compute_taylor_form_range,`&Convex_Hull`,
  subdivide_equidistant,subdivide_adaptive,interval_list_plot,compute_range,
  max_abs_error,cni_range3d,
  subdivide_equi3d,interval_list_plot3d,compute_range3d,newton,compute_all_zeros,newton_plot,
  newton_with_plot,compute_all_zeros_with_plot,
  `&cabs`,complex_disc_plot,complex_polynom_plot,`&cadd`,`&csub`,`&cmult`,`&cdiv`,x0_start,
  `&cmult_opt`,`&cdiv_opt`,horner_eval_cent,horner_eval_opt,centred_form_eval,cexp;
option package;

###########################################################################

Name definitions (see below for body of corresponding procedures)

###########################################################################

>    min:=intpakX_min;
max:=intpakX_max;
ilog10:=intpakX_ilog10;
width:=Interval_width;
ulp:=Interval_ulp;
ru:=Interval_Round_Up;
rd:=Interval_Round_Down;
`&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;

###########################################################################

Initialization

The init procedure contains type definitions for the various (procedural) interval types.

In Maple, type defintions must be global; they seemingly cannot be module exports.

###########################################################################

>    init:=proc()

>    global Interval_fnlist,`type/num_or_FAIL`,`type/interval_comp`,`type/interval`,
       `type/complex_disc`,`type/complex_interval`,`convert/interval`,inapply;

>   

>        Interval_fnlist:=[sqrt=`&sqrt`,ln=`&ln`,exp=`&exp`,sin=`&sin`,cos=`&cos`,

>        tan=`&tan`,arcsin=`&arcsin`,arccos=`&arccos`,arctan=`&arctan`,sinh=`&sinh`,

>        cosh=`&cosh`];

   -  - in proc init  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  

   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:

   -  - in proc init  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  
  

   Simplified version of type interval_comp (cf. intpak/intpakX).
   Pi, gamma, Catalan, false, true are not allowed as interval borders.

>        `type/interval_comp`:=proc(x)

>             local bool;

>             bool:=type(x,float) or x=FAIL or x=-infinity or x=infinity or x=0;

>             bool;

>        end:
 

   -  - in proc init  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  
   PROCEDURE - TYPE/INTERVAL

   This procedure defines the procedural type interval.
   It 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.

    `type/interval`:=proc(x)

>           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 intpakX_greater(x[2],x[1]) 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:

   -  - in proc init  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  
   PROCEDURE - TYPE/COMPLEX_DISC

   This procedure implements (i.e. tests an argument to be of) the procedural type complex disc
   for use in complex interval arithmetic.
   

>        `type/complex_disc`:=proc(z)

>             local bool;

>             bool:=false;

>             if type(z,list) then

>                if nops(z)=3 then

>                   if type(z[3],numeric) then

>                      if z[3] >= 0 then

>                         bool:= type(z[1],numeric) and

>                                type(z[2],numeric);

>                      fi;

>                   fi;

>                fi;

>             fi;

>             bool;

>        end:

   -  - in proc init  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  
   PROCEDURE - TYPE/COMPLEX_INTERVAL

   This procedure implements (i.e. tests an argument to be of) the procedural type complex interval
   (~rectangular interval)
   for use in complex interval arithmetic.
   

>        `type/complex_interval`:=proc(z)

>           local bool;

>           bool:=false;

>           if type(z,list(interval)) then

>              if nops(z)=2 then

>                 if z[1]=[] then

>                    ERROR(`First Element of List must be a real interval.`);

>                 elif z[2]=[] then

>                    ERROR(`Second Element of List must be a real interval.`);

>                 else

>                    bool:=type(z[1][1],numeric) and type(z[1][2],numeric) and

>                       type(z[2][1],numeric) and type(z[2][2],numeric);

>                 fi;

>              fi;

>           fi;

>           bool;

>        end:
    

   -  - in proc init  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  
   PROCEDURE `CONVERT/INTERVAL`

   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.

>       `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

>               if type(op(2,e),`*`) and op(1,op(2,e)) = (-1) then

>                 `convert/interval`(op(1,e)) &- `convert/interval`(op(1,e)-e);

>               else

>                 `convert/interval`(op(1,e)) &+ `convert/interval`(e-op(1,e));

>               fi;

>           elif type(e,`*`) then

>                if op(1,e)=1.0 then

>                  `convert/interval`(subs(op(1,e)=1,e));

>                else

>                  `convert/interval`(op(1,e)) &*

>        (`convert/interval`(e/op(1,e)));

>                fi;

>        ### WARNING: note that `I` is no longer of type `^`

>           elif type(e,`^`) then

>                if type(op(2,e),posint) then

>                   `convert/interval`(op(1,e)) &intpower op(2,e);

>                elif type(op(2,e),integer) then

>                   inv(`convert/interval`(op(1,e)) &intpower (-op(2,e)));

>                elif op(2,e)=(1/2) then

>                   &sqrt(`convert/interval`(op(1,e)));

>                else (`convert/interval`(op(1,e)) &** `convert/interval`(op(2,e)))

>                fi;

>           elif type(e,function) then

>                ope:=[op(e)];

>                mope:=op(map(`convert/interval`,ope));

>                fn:=subs(Interval_fnlist,op(0,e));

>                fn(mope):

>          else e

>             

>           fi:

>        end:    

   -  - in proc init  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  
   PROCEDURE INAPPLY

  Converts the argument to an interval function.

>        inapply := proc(); unapply(convert(args[1],'interval'),args[2..nargs]); end:

   -  - end proc init global type definitions  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  

>        with(plots):

>        with(geometry):

>   
macro(evalf=Evalf);

>    RETURN();

>    end:

>    init();

#### end initialization

###########################################################################

>    Evalf := proc(x)

>             local e;

>                 e := evalf(x);

>                 if e = -1.*infinity then -infinity
             elif e = 1.*infinity then infinity
             else e fi

>             end:

>   

###########################################################################

BASIC INTERVAL DEFINITIONS

-----------------------------------------------------------------------------

Definition of `type/num_or_FAIL`:

## see init procedure!

-----------------------------------------------------------------------------

Definition of `type/interval_comp`:

## see init procedure!

-----------------------------------------------------------------------------

>    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:

-----------------------------------------------------------------------------

Definition of `type/interval`:

## moved to init procedure!

-----------------------------------------------------------------------------

OPERATOR &GREATER/INTERVAL_GREATER

Checks if (Arg1>=Arg2) applies.

>    intpakX_greater:=proc(a,b)

>    local a_rational, b_rational;

>   

>    if (a=FAIL) or (b=FAIL) then FAIL;

>    elif not(type(a,numeric) or member(a,{infinity,-infinity})) then

>         ERROR(`first argument must be a numeric, FAIL, infinity or

>    -infinity`);

>    elif not(type(b,numeric) or member(b,{infinity,-infinity})) then

>       ERROR(`second argument must be a numeric, FAIL, infinity or

>    -infinity`);

>    elif (a=infinity) then true;

>    elif (b=-infinity) then true;

>    elif (a = -infinity) then false;

>    elif (b=infinity) then false;

>    elif a > b then true

>    elif type(a,rational) and type(b,rational) then

>         if a >= b then true else false fi;

>    elif type(a,rational) and type(b,float) then

>         b_rational:=op(1,b)*(10^(op(2,b)));

>         if a >= b_rational then true else false fi;

>    elif type(a,float) and type(b,rational) then

>         a_rational:=op(1,a)*(10^(op(2,a)));

>         if a_rational >= b then true else false fi;      

>    elif type(a,float) and type(b,float) then

>         a_rational:=op(1,a)*(10^(op(2,a)));

>         b_rational:=op(1,b)*(10^(op(2,b)));

>         if a_rational >= b_rational then true else false fi;

>    fi;

>    end:

-----------------------------------------------------------------------------

 PROCEDURE - IS_IN

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.

The operator &greater/Interval_greater is used here.

>    is_in:=proc(x,a)

>          

>        if type(a,interval) then

>           if x=FAIL then FAIL

>           elif x=infinity then member(infinity,{a[1],a[2]})

>           elif x=-infinity then member(-infinity,{a[1],a[2]})

>           elif not(type(x,{numeric,interval})) then

>                ERROR(`first argument must be a numeric or an interval`)

>           elif a=[] and x<>[] then false

>           elif a[1]=FAIL or a[2]=FAIL then FAIL

>           elif type(x,numeric) then

>              intpakX_greater(x,a[1]) and  intpakX_greater(a[2],x)

>           elif type(x,interval) then

>             if x=[] then false #????????????

>             elif x[1]=FAIL or x[2]=FAIL then FAIL

>             else intpakX_greater(x[1],a[1]) and intpakX_greater(a[2],x[2])

>             fi;

>           fi;

>        elif a=infinity then evalb(x=infinity)

>        elif a=-infinity then evalb(x=-infinity)

>        elif a=FAIL then FAIL

>        elif type(a,numeric) then

>             if x=FAIL then FAIL

>             elif x=infinity or x=-infinity then false

>             elif type(x,numeric) then

>                  intpakX_greater(a,x) and intpakX_greater(x,a);

>             elif type(x,interval) then

>                  if x=[] then false

>                  else  intpakX_greater(x[1],a) and intpakX_greater(a,x[2])

>                  fi;

>             else ERROR(`first argument must be a numeric or an interval`)

>             fi;

>        else ERROR(`second argument must be an interval or a numeric`)

>        fi;

>    end:

-----------------------------------------------------------------------------

PROCEDURE - CONSTRUCT

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.

>    construct:=proc()

>    local p,q,Constants;

>       if member(false,{args}) then

>          ERROR(`false and true ar not accepted as arguments`);

>       fi;

>   

>       if member(FAIL,{args}) then RETURN([FAIL,FAIL]) fi;

>       Constants:={Pi,gamma,Catalan};

>   

>       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(intpakX_min(p,q)),ru(intpakX_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:=(args[1]);

>            q:=(args[2]);

>            if member(p,Constants) and member(q,Constants)

>            then construct(p,q,rounded);

>            elif member(p,Constants) then

>                 if Evalf(p) < q then

>                    if intpakX_greater(Evalf(q),q) then

>                       [rd(Evalf(p)),Evalf(q)]

>                    else [rd(Evalf(p)),ru(Evalf(q))]

>                    fi;

>                 elif Evalf(p) > q then

>                    if intpakX_greater(q,Evalf(q)) then

>                       [Evalf(q),ru(Evalf(p))]

>                    else [rd(Evalf(q)),ru(Evalf(p))]

>                    fi;

>                 else construct(p,q,rounded);

>                 fi;

>            elif member(q,Constants) then

>                 if Evalf(q) < p then

>                    if intpakX_greater(Evalf(p),p) then

>                       [rd(Evalf(q)),Evalf(p)]

>                    else [rd(Evalf(q)),ru(Evalf(p))]

>                    fi;

>                 elif Evalf(q) > p then

>                    if intpakX_greater(p,Evalf(p)) then

>                       [Evalf(p),ru(Evalf(q))]

>                    else [rd(Evalf(p)),ru(Evalf(q))]

>                    fi;

>                 else construct(p,q,rounded);

>                 fi;

>            elif intpakX_greater(q,p) then

>                 if intpakX_greater(Evalf(q),q) and

>                    intpakX_greater(p,Evalf(p)) then

>                     [Evalf(p),Evalf(q)];

>                 elif intpakX_greater(Evalf(q),q) then

>                    [rd(Evalf(p)),Evalf(q)];

>                 elif intpakX_greater(p,Evalf(p)) then

>                     [Evalf(p),ru(Evalf(q))];

>                 else [rd(Evalf(p)),ru(Evalf(q))];

>                 fi;

>            else

>                 if intpakX_greater(Evalf(p),p) and

>                    intpakX_greater(q,Evalf(q)) then

>                     [Evalf(q),Evalf(p)];

>                 elif intpakX_greater(Evalf(p),p) then

>                    [rd(Evalf(q)),Evalf(p)];

>                 elif intpakX_greater(q,Evalf(q)) then

>                     [Evalf(q),ru(Evalf(p))];

>                 else [rd(Evalf(q)),ru(Evalf(p))];

>                 fi;

>   

>            fi

>          else ERROR(`incorrect arguments entered`)

>          fi

>   

>       elif nargs=1 then

>          if type(args[1],num_or_FAIL) then

>             p:=args[1];

>             if member(p,Constants) then

>               [rd(Evalf(p)),ru(Evalf(p))];

>             elif is_in(p,Evalf(p)) then

>               [Evalf(p),Evalf(p)];

>             elif intpakX_greater(p,Evalf(p)) then

>               [Evalf(p),ru(Evalf(p))];

>             else [rd(Evalf(p)),Evalf(p)];

>             fi;

>          else ERROR(`incorrect arguments entered`)

>          fi

>       else ERROR(`maximum of three arguments accepted`)

>       fi

>    end:    

###########################################################################

Logarithm and Exponential Functions:

PROCEDURE &EXP/INTERVAL_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

         Return unevaluated.

>        '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:

---------------------------------------------------------------------------

###########################################################################

BASIC INTERVAL ARITHMETIC OPERATIONS

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/INTERVAL_RECIPROCAL

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


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.

>    Interval_divide := proc(a,b):

>     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

>     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:

>    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 / INTERVAL_INTEGERPOWER

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 &** / INTERVAL_POWER

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.

The procedure has been enhanced to accept numbers of type fraction as exponents.

>    Interval_power:=proc(x,n)

>    local logx,prod,result,oldDigits;

>       if type(x,interval) and (type(n,interval)
      or type(n,interval_comp) or type(n,fraction)) 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 + intpakX_ilog10(x[2]);

>           elif not type(x[2],numeric) then

>                Digits:=Digits + 2 + intpakX_ilog10(x[1])

>           else

>             Digits:=intpakX_max(intpakX_ilog10(x[1]),intpakX_ilog10(x[2])) + Digits + 2

>           fi;

>           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]

>           elif type(n,fraction) then

>                if n=(1/2) then &sqrt(x)

>                else

>                    logx:=&ln(x);

>                    prod:=construct(n,rounded) &* logx;

>                    result:=&exp(prod);

>                    Digits:=oldDigits;

>                    construct(result[1],result[2],rounded)

>                fi

>            else

>                 logx:=&ln(x);

>                 prod:=n &* logx;

>                 result:= &exp(prod);

>                 Digits:=oldDigits;

>                 construct(result[1],result[2],rounded)

>             fi

>        elif type(x,num_or_FAIL) then construct(x) &** n

>        elif type(n,integer) then x &intpower n

>        else 'x &** n'

>        fi

>    end:

>   

------------------------------------------------------------------------------

PROCEDURE MIDPOINT / INTERVAL_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

>     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:

###########################################################################

Union and Intersect

------------------------------------------------------------------------------

PROCEDURE &INTERSECT / INTERVAL_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 / INTERVAL_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:

###############################################################################

TRIGONOMETRIC FUNCTIONS
(sin, cos, tan and corresponding arc and hyperbolic procedures)


----------------------------------------------------------------------------

Auxiliary functions

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.

>    intpakX_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 / INTERVAL_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 / INTERVAL_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 / INTERVAL_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 / INTERVAL_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 / INTERVAL_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 / INTERVAL_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:

-------------------------------------------------------------------------------

Auxiliary procedures for sinh, cosh, tanh

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 / INTERVAL_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 / INTERVAL_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 / INTERVAL_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

-----------------------------------------------------------------------------

Definitions of `convert/interval` and inapply:

--> moved to init procedure!

-----------------------------------------------------------------------------

###############################################################################

Minimum and Maximum

-----------------------------------------------------------------------------

PROCEDURE MIN / INTPAKXI_MIN

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

>    intpakX_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 MAX / INTPAKXI_MAX

Note if FAIL is one of the n arguments given FAIL is returned.

>    intpakX_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:

###########################################################################

EXTENSIONS (from intpakX by I. Geulig and W. Kraemer)

###########################################################################

03/2002: If there is any code or output in German left in this part, please contact me at

markus.grimmer@math.uni-wuppertal.de

-----------------------------------------------------------------------------

PROCEDURE EXT_INT_DIV

Extended Interval Division.

>    ext_int_div:=proc(x,y)

>       

>       if (type(x,interval) and type(y,interval)) then

>         if not( type(x[1],numeric) and type(x[2],numeric) ) then

>               ERROR(`first arg must be a finite interval or a numeric`);

>         fi;

>   

>         if not( type(y[1],numeric) and type(y[2],numeric) ) then

>               ERROR(`second arg must be a finite interval or a numeric`);

>         fi;

>   

>         if is_in(0,y) then

>            if is_in(0,x) then          

>               [-infinity,infinity]

>            elif (y[1]=0) and (y[2]=0) then []

>            elif (x[2]<0) and (y[1]<y[2]) and (y[2]=0) then

>               [rd(x[2]/y[1]),infinity]

>            elif (x[2]<0) and (y[1]<0) and (0<y[2]) then

>               [-infinity,ru(x[2]/y[2])] &union [rd(x[2]/y[1]),infinity]

>            elif (x[2]<0) and (0=y[1]) and (y[1]<y[2]) then

>               [-infinity,ru(x[2]/y[2])]

>            elif (0<x[1]) and (y[1]<y[2]) and (y[2]=0) then

>               [-infinity,ru(x[1]/y[1])]

>            elif (0<x[1]) and (y[1]<0) and (0<y[2]) then

>               [-infinity,ru(x[1]/y[1])] &union [rd(x[1]/y[2]),infinity]

>            elif (0<x[1]) and (0=y[1]) and (y[1]<y[2]) then

>               [rd(x[1]/y[2]),infinity];

>            fi;

>   

>         else (x &/ y)

>         fi;

>   

>      elif type(x,num_or_FAIL) and type(y,interval) then

>           ext_int_div(construct(x),y);

>      elif type(x,interval) and type(y,num_or_FAIL) then

>           ext_int_div(x,construct(y));

>      elif type(x,num_or_FAIL) and type(y,num_or_FAIL) then

>           ext_int_div(construct(x),construct(y));

>      else (x &/ y)

>      fi;

>    end:

-----------------------------------------------------------------------------

PROCEDURE REL_DIAM

Relative Diameter of an interval.

>    rel_diam:=proc(x::interval)

>              if x[1]=FAIL or x[2]=FAIL then

>                ERROR(`Interval must be real.`);

>              else

>                if (-infinity < x[1]) and (x[2] < infinity) then

>                   if is_in(0,x) then

>                      width(x);

>                   else

>                      width(x) / (min(abs(x[1]),abs(x[2])));

>                   fi:

>                else

>                   ERROR(`Interval must be real.`);

>                fi:

>              fi:

>            end:

-----------------------------------------------------------------------------

PROCEDURE MID

Midpoint of a real interval. The procedure returns a number which is guaranteed to be in the input interval.

>    mid:=proc(z)

>       local m;

>       if type(z,interval) then

>         if z=[] or z[1]=FAIL or z[2]=FAIL or

>           is_in(infinity,z) or is_in(-infinity,z) then

>            ERROR(` Parameter must be real Interval! `);

>         else

>            if width(z)=0 then

>               m:=z[1];

>            else

>               m:=z[1] + 0.5 * width(z);

>               if not( (z[1] < m) and (m < z[2])) then

>                  m:=z[2];

>               fi;

>            fi;

>          fi;

>       elif type(z,numeric) then

>            m:=z;

>       else

>            RETURN('mid(z)');

>       fi;

>       RETURN(m);

>    end:

###########################################################################

RANGE ENCLOSURE WITH GRAPHICAL REPRESENTATION


###########################################################################

FUNCTIONS OF ONE REAL VARIABLE

-----------------------------------------------------------------------------

PROCEDURE COMPUTE_NAIVE_INTERVAL_RANGE

Range enclosure using interval evaluation.

>    compute_naive_interval_range:=proc(f,T)

>         local F;

>         F:=inapply(f(t),t);

>         RETURN(F(T));

>    end:


-----------------------------------------------------------------------------

PROCEDURE COMPUTE_MEAN_VALUE_RANGE

Range enclosure using mean value form.

compute_mean_value_range:=proc(f,t_0,T)

>       local dF, F_Bound, MeanValueForm;

>       dF:=inapply(diff(f(t),t),t);

>       F_Bound:=dF(T);

>       MeanValueForm:=inapply(f(t),t)(t_0) &+    (F_Bound &* (T &- t_0));

>       RETURN(MeanValueForm);

>    end:

-----------------------------------------------------------------------------

PROCEDURE COMPUTE_MONOTONIC_RANGE

Range Enclodure of a monotone twice continuously differentiable function.
If monotony cannot be proven, FAIL will be returned.

>    compute_monotonic_range:=proc(f,T::interval)

>       local df,dfBound,fLeft,fRight,c;

>         df:=D(f);

>         dfBound:=compute_naive_interval_range(df,T);

>         fLeft:=compute_naive_interval_range(f,construct(T[1]));

>         fRight:=compute_naive_interval_range(f,construct(T[2]));

>   

>         if dfBound[2] <= 0. then

>           # Function is monotonously decreasing

>             RETURN([fRight[1],fLeft[2]]);

>         elif 0. <= dfBound[1] then

>           # Function is monotonously increasing

>             RETURN([fLeft[1],fRight[2]]);

>         fi;

>   

>         c:=T[1] + 0.5 * (T[2]-T[1]);

>         dfBound:=dfBound &intersect compute_mean_value_range(df,c,T);

>   

>         if dfBound[2] <= 0. then

>           # Function is monotonously decreasing

>             RETURN([fRight[1],fLeft[2]]);

>         elif 0. <= dfBound[1] then

>           # Function is monotonously increasing

>             RETURN([fLeft[1],fRight[2]]);

>         fi;

>   

>    # Monotony couldn't be proven

>   

>         RETURN(FAIL)

>    end:

>   

-----------------------------------------------------------------------------

PROCEDURE COMBINED_RANGE

Range enclosure combining the above three methods

>    compute_combined_range:=proc(f,T)

>       local fBound,c;

>       fBound:=compute_monotonic_range(f,T);

>   

>        if not(fBound = FAIL) then

>          RETURN(fBound)

>       fi;

>   

>       c:=T[1] + 0.5*(T[2]-T[1]);

>       fBound:=compute_naive_interval_range(f,T)

>         &intersect compute_mean_value_range(f,c,T);

>       

>       RETURN(fBound);

>    end:

>   

-----------------------------------------------------------------------------

PROCEDURE COMPUTE_TAYLOR_FORM_RANGE

Range enclosure using second order Taylor form

>    compute_taylor_form_range:=proc(f,t_0,T)

>       local dF2, tf_bound, taylor_form;

>       dF2:=inapply(diff(f(t),t$2),t);

>       tf_bound:=dF2(T);

>       taylor_form:=inapply(f(t),t)(t_0) &+

>                    (inapply(diff(f(t),t),t)(t_0) &* (T &- t_0)) &+

>                    ((tf_bound &/ 2) &* ((T &- t_0) &intpower 2));

>       RETURN(taylor_form);

>    end:

-----------------------------------------------------------------------------

PROCEDURES &CONVEX_HULL

Computes convex hull of two intervals.

>    `&Convex_Hull`:=proc(x::interval,y::interval)

>       RETURN([min(x[1],y[1]),max(x[2],y[2])]);

>    end:

-----------------------------------------------------------------------------

PROCEDURE SUBDIVIDE_EQUIDISTANT, SUBDIVIDE_ADAPTIVE

Methods for interval subdivision during the computation of range enclosures.

>    subdivide_equidistant:=proc(f::{function,procedure},

>                                list_of_intervals::evaln,

>                                list_of_ranges::evaln)

>          local N, n, i, iter_counter, T, T1, T2, F1, F2, temp, t_mid,

>                temp_list_of_intervals, temp_list_of_ranges;

>   

>          N:=3;

>   

>          if not(type(eval(list_of_intervals),listlist)) then

>             lprint(`Second Parameter must be list of intervals!`);

>             T:=readstat(`Enter Start interval: `);

>             list_of_intervals:=[construct(T[1],T[2])];

>          fi;

>       

>          n:=nops(eval(list_of_intervals));

>         

>          temp_list_of_intervals:=[];

>          temp_list_of_ranges:=[];

>          

>          for i from 1 to n do

>            T:=list_of_intervals[i];

>   

>          # Bisection of current interval

>               

>            t_mid:=T[1] + 0.5*(T[2]-T[1]);

>            T1:=construct(T[1],t_mid);

>            T2:=construct(t_mid,T[2]);

>   

>          
      # Optional 4th parameter: Iteration counter iter_counter

>            if (nargs >= 4) and (type(args[4],nonnegint)) then

>               iter_counter:=args[4];

>            else

>               iter_counter:=1;

>            fi;

>   

>           if iter_counter <= N then

>              F1:=compute_naive_interval_range(f,T1);

>              F2:=compute_naive_interval_range(f,T2);

>           else

>             F1:=compute_combined_range(f,T1);

>             F2:=compute_combined_range(f,T2);

>           fi;

>                                                  

>           temp_list_of_intervals:=[op(temp_list_of_intervals),T1,T2];

>           temp_list_of_ranges:=[op(temp_list_of_ranges),F1,F2];

>          od:

>   

>          list_of_intervals:=[op(temp_list_of_intervals)];

>          list_of_ranges:=[op(temp_list_of_ranges)];

>          

>          temp:=list_of_ranges[1];

>          for i from 2 to nops(eval(list_of_ranges)) do

>              temp:=&Convex_Hull(temp,list_of_ranges[i]);

>          od;

>          

>          RETURN(temp);

>    end:

     -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -

>    subdivide_adaptive:=proc(f::{function,procedure},

>                             list_of_intervals::evaln,

>                             list_of_ranges::evaln)

>          local N, n, iter_counter, temp_max, temp_min,i, T, T1, T2,

>                F1, F2, temp, t_mid, temp_list_of_intervals,            

>                temp_list_of_ranges, eps;

>   

>          N:=3;

>   

>          if not(type(eval(list_of_intervals),listlist)) then

>             lprint(`Second parameter must be list of intervals!`);

>             T:=readstat(`Enter start interval: `);

>             T:=construct(T[1],T[2]);

>             list_of_intervals:=[T];

>             list_of_ranges:=[compute_naive_interval_range(f,T)];

>          fi;

>   

>          n:=nops(eval(list_of_intervals));

>   

>          if nops(eval(list_of_ranges)) < n then

>             ERROR(`Second list is too short!`);

>          fi;

>   

>          temp_min:=min(seq(list_of_ranges[i][1],i=1..n));

>          temp_max:=max(seq(list_of_ranges[i][2],i=1..n));

>                

>          eps:=0.1*width(construct(temp_min,temp_max));

>     

>          temp_list_of_intervals:=[];

>          temp_list_of_ranges:=[];

>          

>          for i from 1 to n do

>            T:=list_of_intervals[i];

>   
     # If T satisfies the selection criterion, T will be subdivided into halves

>   

>            if (list_of_ranges[i][1] <= temp_min + eps) or

>               (list_of_ranges[i][2] >= temp_max -eps ) then

>   

>               # Bisection of current interval

>               

>               t_mid:=T[1] + 0.5*(T[2] - T[1]);

>               T1:=construct(T[1],t_mid);

>               T2:=construct(t_mid,T[2]);

>   

>            if (nargs >= 4) and (type(args[4],nonnegint)) then

>               iter_counter:=args[4];

>            else

>               iter_counter:=1;

>            fi;

>   

>               if iter_counter <= N then

>                  F1:=compute_naive_interval_range(f,T1);

>                  F2:=compute_naive_interval_range(f,T2);

>               else

>                  F1:=compute_combined_range(f,T1);

>                  F2:=compute_combined_range(f,T2);

>               fi;           

>               

>               temp_list_of_intervals:=[op(temp_list_of_intervals),

>                                       T1,T2];

>               temp_list_of_ranges:=[op(temp_list_of_ranges),F1,F2];

>            else

>               temp_list_of_intervals:=[op(temp_list_of_intervals),T];

>               temp_list_of_ranges:=[op(temp_list_of_ranges),

>                                       list_of_ranges[i]];

>           

>            fi;

>          od:

>   

>          list_of_intervals:=[op(temp_list_of_intervals)];

>          list_of_ranges:=[op(temp_list_of_ranges)];

>          

>          temp:=list_of_ranges[1];

>          for i from 2 to nops(eval(list_of_ranges)) do

>              temp:=&Convex_Hull(temp,list_of_ranges[i]);

>          od;

>          

>          RETURN(temp);

>    end:

-----------------------------------------------------------------------------

PROCEDURE INTERVAL_LIST_PLOT

>    interval_list_plot:=proc(interval_list::list(list(numeric)),

>                             range_list::list(list(numeric)))

>         local n, i, T, F, c, opts, p;

>   

>         if nops(interval_list) > nops(range_list) then

>           ERROR(`Second list is too short!`);

>         fi;

>   

>         opts:=[args[3..nargs]];

>         n:=nops(interval_list);

>         for i from 1 to n do

>            T:=interval_list[i];

>            F:=range_list[i];

>            c:=plottools[rectangle]([T[1],F[2]],[T[2],F[1]]);

>            p[i]:=display(c,op(opts));

>         od;

>          

>      RETURN(display([seq(p[i],i=1..n)]));

>    end:

-----------------------------------------------------------------------------

PROCEDURE COMPUTE_RANGE

>    compute_range:=proc(f::{function,procedure},xstart,iterationsteps::nonnegint)

>        global list_of_intervals, list_of_ranges, max_iter_counter, q,

>               r, iter_counter;

>        local T, F, S, xrange, i, m, nx, h, arg_list, conv_linear,

>              conv_quadratic, div_adaptive, c_list, j,x;

>   

>        # Initialization of global variables

>   

>        x:='x';

>        

>        

>        if type(simplify(f(x)),numeric) or (simplify(diff(f(x),x)) = 0) then

>           lprint(`Function is constant = `, simplify(f(x)));

>           RETURN();

>        fi;

>   

>        if type(xstart,{interval,numeric..numeric}) then

>           T:=construct(op(1,xstart),op(2,xstart));

>        elif type(xstart,{identical('X'),identical('x')} = {interval,numeric..numeric}) then

>           T:=construct(op(1,rhs(xstart)),op(2,rhs(xstart)));

>        else

>           ERROR(`Second argument must be an interval or a range.`);

>        fi;

>   

>        if not(type(compute_naive_interval_range(f,T),interval)) then

>           ERROR(`First argument must be function in one real variable with real values.`);

>        fi;

>   

>        list_of_intervals:=[T];

>           

>        max_iter_counter:=iterationsteps;

>        nx:=1;

>        conv_linear:=false;

>        conv_quadratic:=false;

>        div_adaptive:=false;

>        

>        arg_list:=[args[4..nargs]];

>   

>        for i from 1 to  nops(arg_list) do

>          if type(arg_list[i],identical('Nx') = nonnegint) then

>             nx:=rhs(arg_list[i]);

>          elif arg_list[i] = 'linear' then

>             conv_linear:=true;

>          elif (arg_list[i] = 'quadratic') or (arg_list[i] = 'quadratisch') then

>             conv_quadratic:=true;

>          elif (arg_list[i] = 'adaptive') or (arg_list[i] = 'adaptiv') then

>             div_adaptive:=true;

>          elif type(arg_list[i],identical('colorlist') = list) then

>             c_list:=rhs(arg_list[i]);

>          fi;

>         od;

>   

>         if conv_quadratic then

>           F:=compute_combined_range(f,T);

>           lprint(`Start range enclosure =  `,F);

>           list_of_ranges:=[F];

>           r[0]:=F;

>         else

>            F:=compute_naive_interval_range(f,T);

>            lprint(`Start range enclosure =  `,F);

>            list_of_ranges:=[F];

>            r[0]:=F;

>         fi;

>   

>    # Subdivision of Start interval in Nx subparts,

>    # given the optional parameter Nx

>   

>        if nx > 1 then

>           h:=width(T)/nx;

>           list_of_intervals:=[seq([T[1] + (i-1)*h, T[1] + i*h],i=1..nx)];

>           

>           if conv_quadratic then

>             list_of_ranges:=[seq(compute_combined_range(f,S),S=list_of_intervals)];

>           else

>             list_of_ranges:=[seq(compute_naive_interval_range(f,S),S=list_of_intervals)];

>           fi;

>   

>           r[0]:=[min(seq(list_of_ranges[i][1],i=1..nx)),              

>                  max(seq(list_of_ranges[i][2],i=1..nx))];

>           printf(`%s %d %s = \n[%.10g,%.10g]\n`,

>                  `Range enclosure after subdivision into `,nx,

>                  ` intervals`,r[0][1],r[0][2]);

>   

>        fi;

>   

>        xrange:=T[1]..T[2];

>   

>        # Colour list for graphical representation

>   

>        if c_list = 'c_list' then

>           c_list:=[blue,red];

>        fi;

>      

>        q[0]:=interval_list_plot(list_of_intervals,list_of_ranges,color=c_list[1],

>               style=line,thickness=2);

>        x:='x';

>        q[max_iter_counter+1]:=plot(f(x),x=xrange,color=black,

>                                    numpoints=500,linestyle=1);

>   

>        # Iteration

>   

>        iter_counter:=0;

>   

>        for i from 1 to  max_iter_counter do

>            iter_counter:=iter_counter + 1;

>            

>            if conv_linear then

>               if div_adaptive then

>                 r[i]:=subdivide_adaptive(f,list_of_intervals,list_of_ranges);

>               else

>                 r[i]:=subdivide_equidistant(f,list_of_intervals,list_of_ranges);

>               fi;

>            elif conv_quadratic then

>               if div_adaptive then

>                 r[i]:=subdivide_adaptive(f,list_of_intervals,list_of_ranges,100);

>               else

>                 r[i]:=subdivide_equidistant(f,list_of_intervals,list_of_ranges,100);

>               fi;

>            else

>               if div_adaptive then

>                 r[i]:=subdivide_adaptive(f,list_of_intervals,list_of_ranges,i);

>               else

>                 r[i]:=subdivide_equidistant(f,list_of_intervals,list_of_ranges,i);

>               fi;

>            fi;

>   

>            j:= (i mod nops(c_list)) + 1;

>            if i < max_iter_counter then

>              q[i]:=interval_list_plot(list_of_intervals,list_of_ranges,color=c_list[j],

>                          style=line,thickness=2);

>            else

>              q[i]:=interval_list_plot(list_of_intervals,list_of_ranges,color=yellow,style=patch);

>            fi;

>        od;

>        

>        m:=max_iter_counter;

>        printf(`%s %s %s %d = %s[%.10g,%.10g]\n`,

>           Range_enclosure ,after,step,m,` `,r[m][1],r[m][2]);

>   

>    # Graphical representation of the last three steps of the iteration

>   

>        if m <= 1 then

>          display([seq(q[i],i=0..(m+1))],axes=framed,
           title=`Iterative range enclosure of f`,titlefont=[TIMES,BOLD,12]);

>        else

>          display([seq(q[i],i=(m-2)..m),q[m+1]],axes=framed,
           title=`Iterative range enclosure of f`,titlefont=[TIMES,BOLD,12]);

>        fi;

>    end:
 

-----------------------------------------------------------------------------

PROCEDURE MAX_ABS_ERROR

>    max_abs_error:=proc(list_of_ranges::list(interval))

>      local index_of_max, index_of_min,temp_max,temp_min, n, i, new_list;

>      index_of_max:=1;

>      index_of_min:=1;

>      n:=nops(list_of_ranges);

>      if n=0 or (n=1 and list_of_ranges[1]=[]) then

>         ERROR(`Input parameter must contain at least one real interval. `);

>      fi;

>   

>      temp_max:=list_of_ranges[1][2];

>      temp_min:=list_of_ranges[1][1];

>   

>      for i from 1 to n do

>         if list_of_ranges[i][2] > temp_max then

>            temp_max:=list_of_ranges[i][2];

>            index_of_max:=i;

>         fi;

>         if list_of_ranges[i][1] < temp_min then

>            temp_min:=list_of_ranges[i][1];

>            index_of_min:=i;

>         fi;

>       od;

>       temp_max:=list_of_ranges[index_of_max][1];

>       temp_min:=list_of_ranges[index_of_min][2];

>       

>       if temp_min > temp_max then

>         RETURN(max(seq(width(list_of_ranges[i]),i=1..n)));

>       else

>         new_list:=[];

>         for i from 1 to n do

>            if is_in(list_of_ranges[i],[temp_min,temp_max]) then

>               next;

>            else

>               new_list:=[op(new_list),list_of_ranges[i]];

>            fi;

>          od;

>          n:=nops(new_list);

>          lprint(`Number of intervals: `,n);

>          RETURN(max(seq(width(new_list[i]),i=1..nops(new_list))));

>        fi;

>    end:  

>   

###########################################################################

FUNCTIONS OF TWO  REAL VARIABLES

-----------------------------------------------------------------------------

PROCEDURE CNI_RANGE3D

Interval evaluation of a function f: R^2 -> R.

>    cni_range3d:=proc(f,T,S)

>      local F;

>      F:=inapply(f(t,s),t,s);

>      RETURN(F(T,S));

>    end:

The procedure subdivide_equi3d computes a range enclosure for a function of two real variables by
subdivision of the intervals in list_of_intervals2d in two intervals each. If k is odd, subdivision is
performed in x direction, if k is even, subdivision is performed in y direction.

An element of the global variable list_of_intervals2d should be a two dimensional interval, defined as
a list of two intervals, i.e. XY:=[[x1,x2],[y1,y2]].
The variable list_of_ranges contains the range enclosures
for the corresponding (sub-)intervals in list_of_intervals2d.

>    subdivide_equi3d:=proc(f,

>                           list_of_intervals2d::evaln,

>                           list_of_ranges::evaln,

>                           k::nonnegint)

>       local n, i, temp_loi, temp_lor, TS, T, S, T1, T2, S1, S2, F1, F2,

>             F3, F4, t_mid, s_mid, temp;

>   

>      if not(type(eval(list_of_intervals2d),listlist)) then

>        TS:=readstat(`Enter two-dimensional start interval [[x1,x2],[y1,y2]]:`);

>        T:=construct(TS[1][1],TS[1][2]);

>        S:=construct(TS[2][1],TS[2][2]);

>        list_of_intervals2d:=[[T,S]];

>        list_of_ranges:=[cni_range3d(f,T,S)];

>      fi;

>   

>      n:=nops(eval(list_of_ranges));

>      temp_loi:=[];

>      temp_lor:=[];

>      for i from 1 to n do

>        TS:=list_of_intervals2d[i];

>        T:=TS[1];

>        S:=TS[2];

>        if type(k,odd) then

>          t_mid:=T[1] + 0.5*(T[2] - T[1]);

>          T1:=construct(T[1],t_mid);

>          T2:=construct(t_mid,T[2]);

>          F1:=cni_range3d(f,T1,S);

>          F2:=cni_range3d(f,T2,S);

>          temp_loi:=[op(temp_loi),[T1,S],[T2,S]];

>          temp_lor:=[op(temp_lor),F1,F2];

>        else

>          s_mid:=S[1] + 0.5*(S[2] - S[1]);

>          S1:=construct(S[1],s_mid);

>          S2:=construct(s_mid,S[2]);

>          F1:=cni_range3d(f,T,S1);

>          F2:=cni_range3d(f,T,S2);

>          temp_loi:=[op(temp_loi),[T,S1],[T,S2]];

>          temp_lor:=[op(temp_lor),F1,F2];

>        fi;

>      od;

>   

>      list_of_intervals2d:=[op(temp_loi)];

>      list_of_ranges:=[op(temp_lor)];

>   

>      temp:=list_of_ranges[1];

>      for i from 2 to nops(eval(list_of_ranges)) do

>          temp:=&Convex_Hull(temp,list_of_ranges[i]);

>      od;

>   

>      RETURN(temp);

>    end:

>   

-----------------------------------------------------------------------------

PROCEDURE INTERVAL_LIST_PLOT3D

Graphical representation of a single iteration step

>    interval_list_plot3d:=proc(interval_list,range_list)

>         local n, i, j, TS, T, S, F, c, c_list, p, opts, c_out;

>     

>     opts:=[args[3..nargs]];

>   

>     for i from 1 to  nops(opts) do

>        if type(opts[i],identical('colorlist') = list) then

>             c_list:=rhs(opts[i]);

>        elif type(opts[i],identical('cutout') = rational) then

>             c_out:=rhs(opts[i]);

>        fi;

>     od;

>   

>     if c_list = 'c_list' then    

>     c_list:=[blue,red,green,magenta];

>     fi;

>   

>     if c_out = 'c_out' then

>        c_out := 8/10;

>     fi;

>   

>     n:=nops(range_list);

>   

>     for i from 1 to n do

>              TS:=interval_list[i];

>              T:=TS[1];

>              S:=TS[2];

>   

>              F:=range_list[i];

>              c:=plottools[cuboid]([T[1],S[1],F[1]],[T[2],S[2],F[2]]);

>   

>            # Different colours are applied for individual intervals  

>              p[i]:=display(plottools[cutout](c,c_out),

>                  color=c_list[(i mod nops(c_list)) + 1]);

>            # p[i]:=display([c],color=c_list[(i mod nops(c_list)) + 1]);

>     od;

>                

>        RETURN(display([seq(p[i],i=1..n)]));

>    end:

>   

-----------------------------------------------------------------------------

PROCEDURE COMPUTE_RANGE3D

>    compute_range3d:=proc(f::{function,procedure},X,Y,iterationsteps::nonnegint)

>     global list_of_intervals2d,list_of_ranges,q, r;

>     local TS, T, S, iter_counter, max_iter_counter, i, j, m, nx, ny, hx,

>    hy, lx, ly, opts, c_list,c_out,n,opts_new,x,y;

>   

>     x:='x';

>     y:='y';

>        

>     if type(simplify(f(x,y)),numeric) then

>           lprint(`Funktion ist konstant = `, simplify(f(x,y)));

>           RETURN();

>     fi;

>   

>     if type(X,{interval,numeric..numeric}) then

>          T:=construct(op(1,X),op(2,X));

>     elif type(X,{identical('X'),identical('x')} =

>    {interval,numeric..numeric})  then

>          T:=construct(op(1,rhs(X)),op(2,rhs(X)));

>     else ERROR(`Second argument must be an interval or a range`);

>     fi;

>   

>     if type(Y,{interval,numeric..numeric}) then

>          S:=construct(op(1,Y),op(2,Y));

>     elif type(Y,{identical('Y'),identical('y')} =

>    {interval,numeric..numeric})  then

>          S:=construct(op(1,rhs(Y)),op(2,rhs(Y)));

>     else ERROR(`Third argument must be an interval or a range`);

>     fi;

>   

>     if not(type(cni_range3d(f,T,S),interval)) then

>        ERROR(`First argument must be real function of two real variables!`);

>     fi;

>   

>     lprint(`Start range enclosure = `,cni_range3d(f,T,S));

>   

>     # Initialization of global variables

>   

>     max_iter_counter:=iterationsteps;

>     nx:=1;

>     ny:=1;

>     

>     opts:=[args[5..nargs]];

>   

>     n:=nops(opts);

>     opts_new:=[];

>     for i from 1 to  n do

>        if type(opts[i],identical('Nx') = nonnegint) then

>             nx:=rhs(opts[i]);

>        elif type(opts[i],identical('Ny') = nonnegint) then

>             ny:=rhs(opts[i]);

>        elif type(opts[i],identical('colorlist') = list) then

>             c_list:=rhs(opts[i]);

>        elif type(opts[i],identical('cutout') = numeric) then

>             c_out:=rhs(opts[i]);

>        else opts_new:=[op(opts_new),opts[i]]

>        fi;

>     od;

>     

>    q[max_iter_counter+1]:=plot3d(f(x,y),x=T[1]..T[2],y=S[1]..S[2]);

>   

>     # Subdivision of the start interval into in nx*ny subparts,

>     # given an optional parameter [nx, ny].

>   

>     if nx > 1 then

>        hx:=width(T)/nx;

>        lx:=[seq([T[1] + (i-1)*hx, T[1] + i*hx],i=1..nx)];

>     else

>        lx:=[T];

>     fi;

>     if ny > 1 then

>        hy:=width(S)/ny;

>        ly:=[seq([S[1] + (i-1)*hy, S[1] + i*hy],i=1..ny)];

>      else

>        ly:=[S];

>      fi;

>        list_of_intervals2d:=[seq(seq([lx[i],ly[j]],j=1..ny),i=1..nx)];

>       

>    list_of_ranges:=[seq(cni_range3d(f,TS[1],TS[2]),TS=list_of_intervals2d)];

>   

>        r[0]:=[min(seq(list_of_ranges[i][1],i=1..(nx*ny))),

>               max(seq(list_of_ranges[i][2],i=1..(nx*ny)))];

>    if nx >1 or ny > 1 then    

>      printf(`%s %d %s = \n[%.10g,%.10g]\n`, `Range enclosure after subdivision into`,nx*ny,  `intervals`,r[0][1],r[0][2]);

>     fi;

>   

>    if c_list = 'c_list' then

>       c_list:=[blue,red,green,magenta];

>    fi;

>   

>    if c_out = 'c_out' or not(type(c_out,rational) and (0 <= c_out) and

>    (c_out <= 1)) then

>       c_out:=8/10;

>    fi;

>   

>    q[0]:=interval_list_plot3d(list_of_intervals2d,list_of_ranges,colorlist=c_list,cutout=c_out);

>       

>      iter_counter:=0;

>   

>     for i from 1 to max_iter_counter do

>        iter_counter:=iter_counter + 1;

>       

>    r[i]:=subdivide_equi3d(f,list_of_intervals2d,list_of_ranges,iter_counter);

>        # lprint(`Range enclosure after Iteration step`,i,` = `,r[i]);

    printf(`%s %s %s %s %d = %s[%.10g,%.10g]\n`,

>           Range,enclosure,after,step,i,` `,r[i][1],r[i][2]);

>   
 q[i]:=interval_list_plot3d(list_of_intervals2d,list_of_ranges,colorlist=c_list,cutout=c_out);

>    od;

>   

>      m:=max_iter_counter;

>      display([q[m],q[m+1]],op(opts_new),axes=framed);

>   

>   

>    end:   

>   

###########################################################################

EXTENDED INTERVAL NEWTON METHOD

>   

-----------------------------------------------------------------------------

PROCEDURE NEWTON

Newton-Iteration

>    newton:=proc(f,df,xold::interval,eps::float,xunique::boolean)

>      global zeros,infos,N,iter_counter;  

>      local c,ynew,xnew,i,unique,j,insert;

>           

>        if not(type(xold[1],numeric) and type(xold[2],numeric)) then

>           RETURN(`Start_interval_must_be_real!`);

>        fi:

>   

>        # Cancel Iteration if no zero exists in start interval

>   

>        if not(is_in(0.,f(xold))) then

>                  RETURN();

>        fi:

>   

>        # Increase number of iteration steps by 1

>   

>        iter_counter:=iter_counter + 1;

>   

>        # Extended interval Newton step

>   

>        c:=midpoint(xold);

>   

>        # c:=mid(xold);

>         

>        ynew:=ext_int_div(f(c),df(xold));

>   

>        if (nops([ynew]) >= 2) then

>           xnew[1]:=(c &- op(1,[ynew])) &intersect xold;

>           xnew[2]:=(c &- op(2,[ynew])) &intersect xold;

>           unique:=false;

>        else

>           ynew:=(c &- ynew);

>           xnew[1]:=ynew &intersect xold;

>           

>           if xnew[1] = [] then RETURN() fi;

>   

>         # Strict inclusion implies existence and uniqueness

>         # of zero in xold

>   

>           unique:=xunique or

>                   ((xold[1] < xnew[1][1]) and (xnew[1][2] < xold[2]));

>           xnew[2]:=[];

>        fi:

>   

>        

>        # Bisection, if no reduction of interval is achieved

>   

>        if (xnew[1] = xold) or (xnew[2] = xold) then

>           c:=c[2];

>          

>           if (xold[1] < c) and (c < xold[2]) then

>             xnew[1]:=[xold[1],c];

>             xnew[2]:=[c,xold[2]];

>           else

>             N:=N+1;

>             zeros[N]:=xold;

>             infos[N]:=unique;

>             RETURN();

>          fi;

>   

>        fi:

>   

>        # Output of computed enclosures or further iteration steps

>   

>        for i from 1 to 2 do

>           if (xnew[i] <> []) then

>              if (rel_diam(xnew[i]) < eps) then

>                 if (is_in(0.,f(xnew[i]))) then

>                    if unique=false then

>                       insert:=true;

>   

>        # Combine enclosure intervals with equal end points

>   

>                       for j from 1 to N do

>                          if ((xnew[i] &intersect zeros[j]) <> []) and

>                             (infos[j] = false) then

>                               zeros[j]:=zeros[j] &union xnew[i];

>                               insert:=false;

>                               break;

>                          fi;

>                        od;

>   

>                        if insert then

>                          N:=N + 1;

>                          zeros[N]:=xnew[i];

>                          infos[N]:=unique;

>                        fi;

>                    else       

>                       N:=N + 1;

>                       zeros[N]:=xnew[i];

>                       infos[N]:=unique;

>                    fi;

>                 fi:

>              else

>                 newton(f,df,xnew[i],eps,unique);

>              fi:

>            fi:

>         od:

>        RETURN();    

>    end:

-----------------------------------------------------------------------------
PROCEDURE COMPUTE_ALL_ZEROS

>   

>    compute_all_zeros:=proc(g::{function,procedure},xstart::interval,eps)

>        global zeros,infos,N,iter_counter;

>        local f,df,xold,unique,i,x,x1,x2,n;

>   

>        # Convert g and g' to interval functions

>   

>        x:='x';

>        

>        if type(simplify(g(x)),numeric) or (simplify(diff(g(x),x)) = 0) then

>           lprint(`Function is constant = `, simplify(g(x)));

>           RETURN();

>        fi;

>   

>        f:=inapply(g(x),x);

>        df:=inapply(diff(g(x),x),x);

>   

>        if not(type(f(xstart),interval)) then

>          ERROR(`First argument must be real function of one real variable.`);

>        fi;  

>         

>        if not(type(xstart[1],numeric) and type(xstart[2],numeric)) then

>           ERROR(`Start_interval_must_be_real.`);

>        fi:

>         

>        x1:=xstart[1];

>        x2:=xstart[2];

>   

>       

>        # Determine precision of computation

>   

>        if (nargs > 3) and type(args[4],nonnegint) then

>           Digits:=max(args[4],10,Digits);

>        fi;

>     

>        while not(is_in(Evalf(x1),x1) and is_in(Evalf(x2),x2))

>              and (Digits <= 100) do

>           Digits:=eval(Digits) + 5;

>        od;

>           

>        Digits:= max(ceil(abs(Evalf(log10(eps)))) + 5,

>                                    Digits);

>        lprint(`Digits = `,Digits);

>   

>        lprint(`       `);

>        

>        if width(xstart)=0 then

>           xold:=[rd(x1),ru(x2)];

>           Digits:=Digits+2;

>        else xold:=xstart;

>        fi;

>      

>        # Initialization

>   

>        zeros:=table();

>        infos:=table();

>        N:=0;

>        iter_counter:=0;

>        unique:=false;

>   

>        # Perform Iteration

>   

>        newton(f,df,xold,Evalf(eps),unique);

>   

>        # Output

>   

>        if N = 0 then

>           lprint(`No zero contained in start interval.`);

>           RETURN();

>        fi;

>        

>         for i from 1 to N do

>            print(eval(zeros[i]));

>            if infos[i]=true then

>               print(`contains exactly one zero.`);

>            else

>               print(`potential enclosure of zero`);

>            fi;

>         od;

>        lprint(`       `);

>        lprint(`Number of enclosures of zeros: `,N);

>        lprint(`Number of Iterations steps: `,iter_counter);

>    end:

>   

>   

-----------------------------------------------------------------------------

PROCEDURE NEWTON_PLOT

Graphical representation of one interval newton step.

>    newton_plot:=proc(g,f,xold::interval,ynew::list,xnew::list)

>       local

>    xrange,yrange,p,hy,h1,h2,i,intxold,intxnew,n,punkt,punkt1,punkt2,punkt3,cx,x,c;

>   

>       lprint(`xold=`,xold);

>       lprint(`xnew1=`,xnew[1]);

>   

>       if (xnew[2] <> []) then

>          lprint(`xnew2=`,xnew[2]);

>       fi;

>   

>       

>       xrange:=(xold[1]-(width(xold)/10.))..(xold[2]+(width(xold)/10.));

>       

>      

>    yrange:=(f(xold)[1]-width(f(xold))/10.)..(f(xold)[2]+width(f(xold))/10.);

>   

>       x:='x';

>       p[1]:=plot(g(x),x=xrange,color=black,numpoints=200):

>       hy:=width(f(xold));

>       h1:=hy/25.;

>       h2:=hy/50.;

>   

>    # Representation of old interval - yellow

                      

>    intxold:=plottools[rectangle]([xold[1],0.],[xold[2],-h2]);

>             p[2]:=PLOT(intxold,COLOR(RGB,1,1,0));

>       

>             # Boundaries of old interval

>            

>    p[3]:=plot([[xold[1],-h1],[xold[1],h1]],color=black,thickness=4):

>   

>            

>    p[4]:=plot([[xold[2],-h1],[xold[2],h1]],color=black,thickness=4):

>   

>             # Labelling for old interval

>   

>             p[5]:=textplot([midpoint(xold)[1],-h1,'xold'],align=BELOW);

>             

>             # Representation of computed new intervals

>   

>             n:=6;

>   

>             for i from 1 to 2 do

>                if xnew[i] <> [] then

>                           

>    intxnew:=plottools[rectangle]([xnew[i][1],h2],[xnew[i][2],0.]);

>                 p[n]:=PLOT(intxnew,COLOR(RGB,0,1,0));

>                 n:=n+1:

>                

>    p[n]:=plot([[xnew[i][1],-h1],[xnew[i][1],h1]],thickness=4):

>                 n:=n+1:

>                

>    p[n]:=plot([[xnew[i][2],-h1],[xnew[i][2],h1]],thickness=4):

>                 n:=n+1:

>                 if i=1 then

>                  

>    p[n]:=textplot([midpoint(xnew[i])[1],h1,'xnew1'],align=ABOVE);

>                 elif i=2 then

>                  

>    p[n]:=textplot([midpoint(xnew[i])[1],h1,'xnew2'],align=ABOVE);

>                 fi:

>                 n:=n+1;

>               fi:

>             od:

>   

>     # representation of tangent - red.

>      

>             c:=midpoint(xold)[2];

>             punkt[1]:=[c,g(c)];

>             

>     # Determination of intersection points

>       

>             if nops(ynew)=2 then

>               if is_in(-infinity,ynew[1]) then

>                  punkt[2]:=[ynew[1][2],0];

>                  punkt[3]:=[ynew[2][1],0];

>               else

>                  punkt[2]:=[ynew[1][1],0];

>                  punkt[3]:=[ynew[2][2],0];

>               fi;

>             else

>               if ynew[1] = [-infinity,infinity] then

>                 

>    p:=display([seq(p[i],i=1..n-1)],axes=framed,xtickmarks=5,

>                    

>    view=[xrange,yrange],font=[TIMES,ITALIC,10],axesfont=[TIMES,ROMAN,10],

>                     scaling=unconstrained);

>            

>                  RETURN(p);

>   

>               elif is_in(-infinity,ynew[1])  then

>                  punkt[2]:=[ynew[1][2],0];

>                  punkt[3]:=[0.,g(c)];

>               elif is_in(infinity,ynew[1]) then

>                  punkt[2]:=[ynew[1][1],0];

>                  punkt[3]:=[0.,g(c)];

>               else

>                  punkt[2]:=[ynew[1][1],0];

>                  punkt[3]:=[ynew[1][2],0];

>               fi;

>             fi;

>             

>             point(punkt1,punkt[1]):

>             point(punkt2,punkt[2]):

>             point(punkt3,punkt[3]);

>             line(g1,[punkt1,punkt2]);

>             line(g2,[punkt1,punkt3]);

>             

>             p[n]:=draw([g1],view=[xrange,yrange],color=red,linestyle=3);

>   

>             n:=n+1;

>   

>             p[n]:=draw([g2],view=[xrange,yrange],color=red,linestyle=3);

>              

>     # Representation of all graphical elements

>     

>    p:=display([seq(p[i],i=1..n)],axes=framed,xtickmarks=5,view=[xrange,yrange],

>     font=[TIMES,ITALIC,10],axesfont=[TIMES,ROMAN,10],scaling=unconstrained);

>            

>         RETURN(p);

>    end:

>   

>   

-----------------------------------------------------------------------------

PROCEDURE NEWTON_WITH_PLOT


Newton-Iteration with graphical representation

>    newton_with_plot:=proc(g,f,df,xold::interval,eps::float,xunique::boolean)

>        local c,ynew,xnew,i,j,insert,unique;

>        global zeros,infos,N,iter_counter,max_iter_counter,p,dx;

>   

>        if not(type(xold[1],numeric) and type(xold[2],numeric)) then

>           RETURN(`Start interval_must_be_real.`);

>        fi:

>        

>        if not(is_in(0.,f(xold))) then

>                  RETURN();

>        fi:

>   

>        # Increase number of iteration steps by 1

>   

>        iter_counter:=iter_counter + 1;

>        

>        # Extended interval Newton Step

>   

>        c:=midpoint(xold);

>        

>        ynew:=[ext_int_div(f(c),df(xold))];

>        if (nops(ynew) >= 2) then

>           ynew[1]:=c &- ynew[1];

>           xnew[1]:=ynew[1] &intersect xold;

>   

>           ynew[2]:=c &- ynew[2];

>           xnew[2]:=ynew[2] &intersect xold;

>           

>           unique:=false;

>        else

>           ynew[1]:=c &- ynew[1];

>           xnew[1]:=ynew[1] &intersect xold;

>   

>           if xnew[1] = [] then RETURN() fi;

>          

>         # Strict inclusion implies existence and uniqueness

>         # of zero in xold

>   
       unique:=xunique or

>                   ((xold[1] < xnew[1][1]) and (xnew[1][1] < xold[2]));   

>       

>           xnew[2]:=[];

>        fi:

>       

>        # Bisection, if no reduction of interval is achieved

>        if (xnew[1] = xold) or (xnew[2] = xold) then

>           c:=c[2];

>           if (xold[1] < c) and (c < xold[2]) then

>             xnew[1]:=[xold[1],c];

>             xnew[2]:=[c,xold[2]];

>           else

>             N:=N+1;

>             zeros[N]:=xold;

>             infos[N]:=unique;

>             RETURN();

>          fi;

>   

>        fi:

>        

>        # Representation of Newton step

>   

>        xnew:=[xnew[1],xnew[2]];

>   

>        lprint(`Iteration step `, iter_counter);

>        p[iter_counter]:=newton_plot(g,f,xold,ynew,xnew);

>        print(p[iter_counter]);

>   

>        # Output of computed enclosures or further iteration steps

>   

>        for i from 1 to 2 do

>           if (xnew[i] <> []) then

>              if (rel_diam(xnew[i]) < eps) or (iter_counter=max_iter_counter) then

>                 if (is_in(0.,f(xnew[i]))) then

>                    if unique=false then

>                       insert:=true;

>   

>           # Combine enclosure intervals with equal end points

>   

>                       for j from 1 to N do

>                          if ((xnew[i] &intersect zeros[j]) <> []) and

>                             (infos[j] = false) then

>                               zeros[j]:=zeros[j] &union xnew[i];

>                               insert:=false;

>                               break;

>                          fi;

>                        od;

>   

>                        if insert then

>                          N:=N + 1;

>                          zeros[N]:=xnew[i];

>                          infos[N]:=unique;

>                        fi;

>                    else       

>                       N:=N + 1;

>                       zeros[N]:=xnew[i];

>                       infos[N]:=unique;

>                    fi;

>                 fi:

>              else

>                 newton_with_plot(g,f,df,xnew[i],eps,unique);

>              fi:

>            fi:

>         od:

>        RETURN();

>    end:

>   

-----------------------------------------------------------------------------

PROCEDURE COMPUTE_ALL_ZEROS_WITH_PLOT

Enclosure of the zeros of a continuously differentiable function g with graphical representation

>    compute_all_zeros_with_plot:=proc(g::{function,procedure},xstart::interval,eps)

>        global zeros,infos,N,iter_counter,max_iter_counter;

>        local f,df,xold,unique,i,x,x1,x2;

>   

>        x:='x';

>   

>        if type(simplify(g(x)),numeric) or (simplify(diff(g(x),x)) = 0) then

>           lprint(`Function is constant = `, simplify(g(x)));

>           RETURN();

>        fi;

>   

>        # Conversion of g and g' into interval functions

>   

>        if (nargs > 4) and type(args[5],nonnegint) then

>          max_iter_counter:=args[5];

>        else

>          max_iter_counter:=readstat("Enter maximal number of iteration steps: ");

>   

>        fi;

>   

>        f:=inapply(g(x),x);

>        df:=inapply(diff(g(x),x),x);

>   

>        if not(type(f(xstart),interval)) then

>          ERROR(`First argument must be real function in one real variable.`);

>        fi;

>     

>        x1:=xstart[1];

>        x2:=xstart[2];

>   

>        # Determine precsion of computation

>   

>        if (nargs > 3) and type(args[4],nonnegint) then

>           Digits:=max(args[4],10,Digits);

>        fi;

>   

>        while not(is_in(Evalf(x1),x1) and is_in(Evalf(x2),x2))

>              and (Digits <= 100) do

>           Digits:=eval(Digits) + 5;

>        od;

>   

>        Digits:= max(ceil(abs(Evalf(log10(eps)))) + 5,Digits);

>   

>        lprint(`Digits = `,Digits);

>        lprint(`      `);

>       

>        if width(xstart)=0 then

>           xold:=[rd(x1),ru(x2)];

>           Digits:=Digits+2;

>        else xold:=xstart;

>        fi;

>   

>        # Initialization

>   

>        zeros:=table();

>        infos:=table();

>        N:=0;

>        iter_counter:=0;

>        unique:=false;

>   

>        # Perform iteration

>   

>         newton_with_plot(g,f,df,xold,Evalf(eps),unique);

>   

>        # Output

>   

>        if N = 0 then

>           lprint(`No zero contained in start interval.`);

>           RETURN();

>        fi;

>   

>        for i from 1 to N do

>            print(eval(zeros[i]));

>            if infos[i]=true then

>               print(` contains exactly one zero.`);

>            else

>               print(` potential enclosure of zero`);

>            fi;

>        od;

>        lprint(`         `);

>        lprint(`Number of enclosures of zeros: `,N);

>        lprint(`Number of iteration steps: `,iter_counter);

>    end:

>   

###########################################################################

COMPLEX DISC ARITHMETIC

###########################################################################

Type definitions and aouxiliary procedures

Type definitions --> see init procedure

-----------------------------------------------------------------------------

Definition of `type/complex_disc`:

--> moved to init procedure!

-----------------------------------------------------------------------------

Definition of `type/complex_interval`:

--> moved to init procedure!

-----------------------------------------------------------------------------

PROCEDURE `&CABS`

This procedure computes a real interval enclosing the abolute value of a complex number
or a complex rectangular interval.

>    `&cabs`:=proc(z)

>           local w;

>           if type(z,complex_interval) then

>              w:=&sqrt( (&sqr(z[1])) &+ (&sqr(z[2])) );

>           elif type(z,complex) then

>              w:=&sqrt( (&sqr(Re(z))) &+ (&sqr(Im(z))) );

>           else

>              '&cabs(z)';

>           fi;

>    end:

>   

-----------------------------------------------------------------------------

PROCEDURE COMPLEX_DISC_PLOT

Graphical representation of a complex disc

>    complex_disc_plot:=proc(z::complex_disc)

>       local opts, x, y, r;

>       opts:=[args[2..nargs]];

>       x:=z[1];

>       y:=z[2];

>       r:=z[3];

>       plot([x + r*cos(t), y +r*sin(t), t=0..2*Pi],op(opts));

>    end:

>    complex_polynom_plot:=proc(p::polynom(complex,z),u::complex_disc)

>      local opts, x, y, r;

>   

>      opts:=[args[3..nargs]];

>      x:=u[1];

>      y:=u[2];

>      r:=u[3];

>      complexplot(subs(z=x + I*y + r * (cos(t) + I*sin(t)),p),t=0..2*Pi,op(opts));

>    end:

>   

###########################################################################

BASIC ARITHMETIC OPERATIONS

-----------------------------------------------------------------------------

PROCEDURE `&CADD`

Centered addition of two Complex discs

>    `&cadd`:=proc(u::{complex,complex_disc},v::{complex,complex_disc})

>       local cx, cy, c, r;

>       

>       if type(u,complex_disc) and type(v,complex_disc) then

>          cx:= u[1] &+ v[1];

>          cy:= u[2] &+ v[2];

>          c:=[mid(cx),mid(cy)];

>          if u[3]=0 then

>             r:=v[3];

>          elif v[3]=0 then

>             r:=u[3];

>          else

>             r:= u[3] &+ v[3];

>             r:=r[2];

>          fi;

>       

>          r:= ru(Evalf(r) + width(cx));

>          r:= ru(Evalf(r) + width(cy));

>          RETURN([op(c),r]);

>       elif type(u,complex) and type(v,complex_disc) then

>            [Re(u),Im(u),0] &cadd v;

>       elif type(u,complex_disc) and type(v,complex) then

>            u &cadd [Re(v),Im(v),0];

>       else

>            [Re(u),Im(u),0] &cadd [Re(v),Im(v),0];

>       fi;

>   

>    end:


-----------------------------------------------------------------------------

PROCEDURE `&CSUB`

Centered subtraction of two Complex discs

>    `&csub`:=proc(u::{complex,complex_disc},v::{complex,complex_disc})

>       local cx, cy, c, r;

>       if type(u,complex_disc) and type(v,complex_disc) then

>          cx:=u[1] &- v[1];

>          cy:=u[2] &- v[2];

>          c:=[mid(cx),mid(cy)];

>          if u[3] = 0 then

>             r:=v[3];

>          elif v[3]=0 then

>             r:=u[3];

>          else

>             r:= u[3] &+ v[3];

>             r:=r[2];

>          fi;

>       

>          r:= ru(Evalf(r) + width(cx));

>          r:= ru(Evalf(r) + width(cy));

>          RETURN([op(c),r]);

>       elif type(u,complex) and type(v,complex_disc) then

>          [Re(u),Im(u),0] &csub v;

>       elif type(u,complex_disc) and type(v,complex) then

>          u &csub [Re(v),Im(v),0];

>       else

>          [Re(u),Im(u),0] &csub [Re(v),Im(v),0];

>       fi;

>    end:

-----------------------------------------------------------------------------

PROCEDURE `&CMULT`

Centered multiplication of two Complex discs

>    `&cmult`:=proc(u::{complex,complex_disc},v::{complex,complex_disc})

>       local cx, cy, c, r, r1, r2, r3;

>       

>       if type(u,complex_disc) and type(v,complex_disc) then

>          cx:=(u[1] &* v[1]) &- (u[2] &* v[2]);

>          cy:=(u[1] &* v[2]) &+ (u[2] &* v[1]);

>          c:=[mid(cx),mid(cy)];

>          if u[3]=0 then

>             r:=(&cabs(u[1]+I*u[2])) &* v[3];

>          elif v[3]=0 then

>             r:=(&cabs(v[1]+I*v[2])) &* u[3];

>          else

>             r1:= (&cabs(u[1]+I*u[2])) &* v[3];

>             r2:= (&cabs(v[1]+I*v[2])) &* u[3];

>             r3:= u[3] &* v[3];

>             r:= r1 &+ r2 &+ r3;

>          fi;

>             r:=r[2];

>             r:= ru(Evalf(r) + width(cx));

>             r:= ru(Evalf(r) + width(cy));

>             RETURN([op(c),r]);

>        elif type(u,complex) and type(v,complex_disc) then

>             [Re(u),Im(u),0] &cmult v;

>        elif type(u,complex_disc) and type(v,complex) then

>             u &cmult [Re(v),Im(v),0];

>        else

>             [Re(u),Im(u),0] &cmult [Re(v),Im(v),0];

>        fi;

>    end:

-----------------------------------------------------------------------------

PROCEDURE `&CDIV`

Centered division of two Complex discs

>    `&cdiv`:=proc(u::{complex,complex_disc},v::{complex,complex_disc})

>        local c, cx, cy, r, nenner, a;

>        

>        if type(u,complex_disc) and type(v,complex_disc) then

>           a:=&cabs(v[1]+I*v[2]);

>           if (a[1] <= v[3]) then

>              ERROR(`Denominator contains zero! `):

>           elif (u[1] = 1) and (u[2]=0) and (u[3]=0) then

>                nenner:= (&sqr(&cabs((v[1]+I*v[2])))) &- (&sqr(v[3]));

>                if is_in(0,nenner) then

>                   ERROR(`Formula denominator contains zero! `):

>                else           

>                   cx:=v[1] &/ nenner;

>                   cy:=((-1)*v[2]) &/ nenner;

>                   r:=v[3] &/ nenner;

>                   c:=[mid(cx),mid(cy)];

>                fi;

>           else

>                RETURN( u &cmult ( [1,0,0] &cdiv v));

>                

>           fi;

>           r:=r[2];

>           r:= ru(Evalf(r) + width(cx));

>           r:= ru(Evalf(r) + width(cy));

>           RETURN([op(c),r]);

>        elif type(u,complex) and type(v,complex_disc) then

>             [Re(u),Im(u),0] &cdiv v;

>        elif type(u,complex_disc) and type(v,complex) then

>             u &cdiv [Re(v),Im(v),0];

>        elif type(u,complex) and type(v,complex) then

>             [Re(u),Im(u),0] &cdiv [Re(v),Im(v),0];

>        fi;

>    end:


-----------------------------------------------------------------------------

PROCEDURE X0_START

x0_start:=proc(s1::interval,s2::interval)

>              local f, F, xu, xo, s3, s, t;

>              s:='s';

>              t:='t';

>              f:=(s,t)->(sqrt((1+s^2)*(1+t^2))*s*t - s^2*t^2) / (1+s^2+t^2);

>              F:=inapply(f(s,t),s,t);

>              xu:=F(s1,s2);

>              xu:=xu[1];

>              s3:=s1 &* s2;

>              xo:=min(s1[2],s2[2],s3[2]);

>              if xu <= xo then

>                RETURN([xu,xo]);

>              else

>                 ERROR(`Kann Startintervall nicht bestimmen`);

>              fi;

>   

>    end:

-----------------------------------------------------------------------------

PROCEDURE `&CMULT_OPT`

Surface optimal multiplication of two complex discs.

>    `&cmult_opt`:=proc(u::{complex,complex_disc},v::{complex,complex_disc})

>          local  c,cx, cy, r, x0, s1, s2, r1, r2, r3, z1, z2, z1z2, r1r2,

>    r1z2, r2z1, P, dP,t, i, xold, m;

>          

>       if type(u,complex_disc) and type(v,complex_disc) then

>          if (u[1]=0 and u[2]=0 and u[3]=0) or

>             (v[1]=0 and v[2]=0 and v[3]=0) then

>               RETURN([0,0,0]);

>             # if one of the discs is zero, zero is returned

>             
         # u and/or w are circles with radius 0 ("a point")

>   

>          elif u[3]=0 then

>               # Determine midpoint

>               cx:=(u[1] &* v[1]) &- (u[2] &* v[2]);

>               cy:=(u[1] &* v[2]) &+ (u[2] &* v[1]);

>               c:=[mid(cx),mid(cy)];

>   

>               # Determine radius

>   

>               if v[3]=0 then

>                  r:=[0,0];

>               else

>                  r:= (&cabs(u[1]+I*u[2])) &* v[3];

>               fi;

>               

>               r:=r[2];

>               r:=ru(Evalf(r) + width(cx));

>               r:=ru(Evalf(r) + width(cy));

>               RETURN([op(c),r]);

>          elif v[3]=0 then

>               # Determine midpoint

>               cx:=(u[1] &* v[1]) &- (u[2] &* v[2]);

>               cy:=(u[1] &* v[2]) &+ (u[2] &* v[1]);

>               c:=[mid(cx),mid(cy)];

>   

>               # Determine radius

>               r:=(&cabs(v[1]+I*v[2])) &* u[3];

>       

>               r:=r[2];

>               r:=ru(Evalf(r) + width(cx));

>               r:=ru(Evalf(r) + width(cy));

>               RETURN([op(c),r]);

>   

>   

>          # One factor is circle with midpoint 0.

>   

>          elif (u[1]=0) and (u[2]=0) then

>               c:=[0,0];

>               if (v[1]=0) and (v[2]=0) then

>                  r:= u[3] &* v[3];

>               else

>                  r:= u[3] &* ((&cabs(v[1]+I*v[2])) &+ v[3]);

>               fi;

>               

>               r:=r[2];

>               RETURN([0,0,r]);

>           elif (v[1]=0) and (v[2]=0) then

>                c:=[0,0];

>                r:=v[3] &* ((&cabs(u[1]+I*u[2])) &+ u[3]);

>                r:=r[2];

>                RETURN([0,0,r]);

>           else

>   

>                s1:= u[3] &/ (&cabs(u[1]+I*u[2]));

>                s2:= v[3] &/ (&cabs(v[1]+I*v[2]));

>                z1:=u[1] + I*u[2];

>                z2:=v[1] + I*v[2];

>   

>                x0:=x0_start(s1,s2);

>                #lprint(x0);

>                z1z2:=&intpower(&cabs(z1),2) &* &intpower(&cabs(z2),2);

>                r1r2:=&intpower(u[3],2) &* &intpower(v[3],2);

>   

>                r1z2:=&intpower(u[3],2) &* &intpower(&cabs(z2),2);

>                r2z1:=&intpower(v[3],2) &* &intpower(&cabs(z1),2);

>   

>              # Determine x0 using Newton method,

>              # start interval = x0start

>   

>                t:='t';

>                P:=(2 &* z1z2 &* (&intpower(t,3))) &+

>               ((z1z2 &+ r1z2 &+ r2z1) &* (&intpower(t,2))) &- r1r2;

>                #lprint(eval(subs(t=x0,P)));

>                dP:=(6 &* z1z2 &* (&intpower(t,2))) &+ (2 &* (z1z2 &+ r1z2 &+ r2z1) &* t);

>                #lprint(`dP=`,eval(subs(t=x0,dP)));

>             

>                for i from 1 to 10 do

>                  #lprint(x0);

>                  xold:=x0;

>                  m:=midpoint(xold);

>                  x0:=(m &-

>                       (eval(subs(t=m,P)) &/ eval(subs(t=xold,dP))) );

>                  x0:=x0 &intersect xold;

>                  if x0=xold then break; fi;

>                od;

>                #lprint(`x0=`,x0);

>                

>                # Determine midpoint

>                cx:=((u[1] &* v[1]) &- (u[2] &* v[2])) &* (1 &+ x0);

>                cy:=((u[1] &* v[2]) &+ (u[2] &* v[1])) &* (1 &+ x0);

>                c:=[mid(cx),mid(cy)];

>                #lprint(`c=`,c);

>                

>                # Determine radius

>   

>                r1:=3 &* z1z2 &* &intpower(x0,2);

>                r2:=2 &* (z1z2 &+ r1z2 &+ r2z1) &* x0;

>                r3:=r1z2 &+ r2z1 &+ r1r2;

>                r:=&sqrt(r1 &+ r2 &+ r3);

>                r:=r[2];

>                r:=ru(Evalf(r) + width(cx));

>                r:=ru(Evalf(r) + width(cy));

>                RETURN([op(c),r]);

>              fi;

>       elif type(u,complex) and type(v,complex_disc) then

>            [Re(u),Im(u),0] &cmult_opt v;

>       elif type(u,complex_disc) and type(v,complex) then

>            u &cmult_opt [Re(v),Im(v),0];

>       else

>            [Re(u),Im(u),0] &cmult_opt [Re(v),Im(v),0];

>       fi;

>    end:    

-----------------------------------------------------------------------------

PROCEDURE `&CDIV_OPT`

Surface optimal division of two complex discs.

>    `&cdiv_opt`:=proc(u::{complex,complex_disc},v::{complex,complex_disc})

>          if type(u,complex_disc) and type(v,complex_disc) then

>             RETURN( u &cmult_opt ([1,0,0] &cdiv v));

>          elif type(u,complex) and type(v,complex_disc) then

>             [Re(u),Im(u),0] &cdiv_opt v;

>          elif type(u,complex_disc) and type(v,complex) then

>             u &cdiv_opt [Re(v),Im(v),0];

>          else

>             [Re(u),Im(u),0] &cdiv_opt [Re(v),Im(v),0]

>          fi;

>     end:

>   

###########################################################################

RANGE ENCLOSURES FOR COMPLEX POLYNOMIALS

-----------------------------------------------------------------------------

PROCEDURE HORNER_EVAL_CENT

Horner-Scheme with centered multiplication

>    horner_eval_cent:=proc(p::polynom(complex,z),u::{complex,complex_disc})

>             local n, Z, s, i, koeff, sx, sy;

>    ### WARNING: degree(0,x) now returns -infinity

>             n:=degree(p,z);

>   

>             

>             # p ist constant polynomial

>   

>             if n=0 or n=-infinity then

>                RETURN(p);

>             fi;

>   

>             if type(u,complex) then

>                Z:=[Re(u),Im(u),0];

>             else

>                Z:=u;

>             fi;

>             koeff:=coeff(p,z^n);

>             s:=[Re(koeff),Im(koeff),0];

>   

>             for i from (n-1) to 0 by -1 do

>                if i>0 then

>                  koeff:=coeff(p,z^i);

>                  if koeff=0 then

>                     s:=s &cmult Z;

>                  else

>                     s:=(s &cmult Z) &cadd [Re(koeff),Im(koeff),0];

>                  fi;

>                elif (i=0) then

>    ### WARNING: ldegree(0,x) now returns infinity

>                     if ldegree(p,z) = 0 then

>                        s:= (s &cmult Z) &cadd [Re(tcoeff(p)),Im(tcoeff(p)),0];

>                     else

>                        s:= s &cmult Z;

>                     fi;

>                fi;

>                

>             od;

>             

>             RETURN(s);

>    end:


-----------------------------------------------------------------------------

PROCEDURE HORNER_EVAL_OPT

Horner-Scheme with surface optimal multiplication

>    horner_eval_opt:=proc(p::polynom(complex,z),u::{complex,complex_disc})

>             local n, Z, s, i, koeff;

>    ### WARNING: degree(0,x) now returns -infinity

>             n:=degree(p,z);

>   

>             if n=0 or n=-infinity then

>                RETURN(p);

>             fi;

>             

>             if type(u,complex) then

>                Z:=[Re(u),Im(u),0];

>             else

>                Z:=u;

>             fi;

>   

>             koeff:=coeff(p,z^n);

>             s:=[Re(koeff),Im(koeff),0];

>             for i from (n-1) to 0 by -1 do

>                if i>0 then

>                  koeff:=coeff(p,z^i);

>                  if koeff=0 then

>                     s:=s &cmult_opt Z;

>                  else

>                     s:=(s &cmult_opt Z) &cadd [Re(koeff),Im(koeff),0];

>                  fi;

>                elif (i=0) then

>    ### WARNING: ldegree(0,x) now returns infinity

>                     if ldegree(p,z) = 0 then

>                        s:= (s &cmult_opt Z) &cadd [Re(tcoeff(p)),Im(tcoeff(p)),0];

>                     else

>                        s:= s &cmult_opt Z;

>                     fi;

>                fi;

>                

>             od;

>             RETURN(s);

>    end:

-----------------------------------------------------------------------------

PROCEDURE CENTRED_FORM_EVAL

Centered form using centered multiplication

>    centred_form_eval:=proc(p::polynom(complex,z),

>    u::{complex_disc,complex})

>      local c, cx, cy, r, r1, r2, cu, pc, pcx, pcy, i, poly, n, Z;

>     

>           if type(u,complex) then

>              Z:=[Re(u),Im(u),0];

>              cu:=u;

>           else

>              Z:=u;

>              cu:=u[1]+I*u[2];

>           fi;

>    ### WARNING: degree(0,x) now returns -infinity

>           n:=degree(p);

>   

>           if n=0 or n=-infinity then

>              RETURN(p);

>           fi;

>   

>           # Determine midpont of p(Z)

>   

>           pc:=horner_eval_cent(p,cu);

>           cx:=[op(1,pc[1] &- pc[3]),op(2,pc[1] &+ pc[3])];

>           cy:=[op(1,pc[2] &- pc[3]),op(2,pc[2] &+ pc[3])];

>           c:=[mid(cx),mid(cy)];

>   

>                

>           # Determine radius of p(Z)

>   

>           r:=0;

>           for i from 1 to n do

>              poly:=diff(p,z$i);

>              pc:=horner_eval_cent(poly,cu);

>                    

>              if type(pc,complex_disc) then

>                 pcx:=[op(1,pc[1] &- pc[3]),op(2,pc[1] &+ pc[3])];

>                 pcy:=[op(1,pc[2] &- pc[3]),op(2,pc[2] &+ pc[3])];

>                 r1:= &cabs( [pcx,pcy] );

>              else

>                 r1:=&cabs( pc);

>              fi;

>                     

>              if i>1 then

>                 r2:= (&intpower(Z[3],i));

>              else

>                 r2:= Z[3];

>              fi;

>   

>              r:= r &+ ((r1 &* r2) &/ (i!));

>           od;

>           r:=r[2];

>           r:=ru(Evalf(r) + width(cx));

>           r:= ru(Evalf(r) + width(cy));

>           RETURN([op(c),r]);

>    end:

>   

###########################################################################

EXPONENTIAL FUNCTION FOR COMPLEX DISCS

-----------------------------------------------------------------------------
PROCEDURE CEXP

>    cexp:=proc(u::{complex,complex_disc})

>       local cx, cy, c, r, r1, r2;

>       

>       if type(u,complex_disc) then

>          

>          # Bestimmung des Mittelpunktes

>   

>          cx:=(&exp(u[1])) &* (&cos(u[2]));

>          cy:=(&exp(u[1])) &* (&sin(u[2]));

>          c:=[mid(cx),mid(cy)];

>   

>          # Bestimmung des Radius

>   

>                

>          r1:=&cabs( [cx,cy] );

>          r2:=(&exp(u[3])) &- 1;

>          r:=r1 &* r2;

>   

>          r:=r[2];

>          r:=ru(Evalf(r) + width(cx));

>          r:=ru(Evalf(r) + width(cy));

>   

>          RETURN([op(c),r]);

>       else

>          cexp([Re(u),Im(u),0]);

>       fi;

>    end :

###########################################################################

>    end module:

###########################################################################

end package intpakX

###########################################################################

intpakX v1.0 (c) Scientific Computing/Software Engineering Research Group,
Department of Mathematics, University of Wuppertal, Germany

Contact:
kraemer@math.uni-wuppertal.de
markus.grimmer@math.uni-wuppertal.de
http://www.math.uni-wuppertal.de/wrswt

###########################################################################

Disclaimer:

While every effort has been made to validate the solutions in this package,

Waterloo Maple Inc. and the contributors are not responsible for any errors

contained and are not liable for any damages resulting from the use of this

material.

###########################################################################

Warning, the name changecoords has been redefined

###########################################################################

You can create a Maple library with the following commands:

i) Tell Maple where to put the library:

>    libname:="C:/mylib/interval", libname;
You can use the directory name of your choice in the above line. An empty directory is recommended.

libname :=

ii) Create the new library:

>    march('create',libname[1],100);

iii) Save the library

>    savelib('intpakX');

###########################################################################
Now you can load the library as follows:

>    restart;

>    libname:="C:/mylib/interval", libname;

libname :=

>    with(intpakX);

Warning, the name changecoords has been redefined

Warning, the assigned name midpoint now has a global binding

Warning, the protected names ilog10, max and min have been redefined and unprotected

[`&*`, `&**`, `&+`, `&-`, `&/`, `&Convex_Hull`, `&arccos`, `&arcsin`, `&arctan`, `&cabs`, `&cadd`, `&cdiv`, `&cdiv_opt`, `&cmult`, `&cmult_opt`, `&cos`, `&cosh`, `&csub`, `&exp`, `&intersect`, `&intpow...
[`&*`, `&**`, `&+`, `&-`, `&/`, `&Convex_Hull`, `&arccos`, `&arcsin`, `&arctan`, `&cabs`, `&cadd`, `&cdiv`, `&cdiv_opt`, `&cmult`, `&cmult_opt`, `&cos`, `&cosh`, `&csub`, `&exp`, `&intersect`, `&intpow...
[`&*`, `&**`, `&+`, `&-`, `&/`, `&Convex_Hull`, `&arccos`, `&arcsin`, `&arctan`, `&cabs`, `&cadd`, `&cdiv`, `&cdiv_opt`, `&cmult`, `&cmult_opt`, `&cos`, `&cosh`, `&csub`, `&exp`, `&intersect`, `&intpow...
[`&*`, `&**`, `&+`, `&-`, `&/`, `&Convex_Hull`, `&arccos`, `&arcsin`, `&arctan`, `&cabs`, `&cadd`, `&cdiv`, `&cdiv_opt`, `&cmult`, `&cmult_opt`, `&cos`, `&cosh`, `&csub`, `&exp`, `&intersect`, `&intpow...
[`&*`, `&**`, `&+`, `&-`, `&/`, `&Convex_Hull`, `&arccos`, `&arcsin`, `&arctan`, `&cabs`, `&cadd`, `&cdiv`, `&cdiv_opt`, `&cmult`, `&cmult_opt`, `&cos`, `&cosh`, `&csub`, `&exp`, `&intersect`, `&intpow...
[`&*`, `&**`, `&+`, `&-`, `&/`, `&Convex_Hull`, `&arccos`, `&arcsin`, `&arctan`, `&cabs`, `&cadd`, `&cdiv`, `&cdiv_opt`, `&cmult`, `&cmult_opt`, `&cos`, `&cosh`, `&csub`, `&exp`, `&intersect`, `&intpow...
[`&*`, `&**`, `&+`, `&-`, `&/`, `&Convex_Hull`, `&arccos`, `&arcsin`, `&arctan`, `&cabs`, `&cadd`, `&cdiv`, `&cdiv_opt`, `&cmult`, `&cmult_opt`, `&cos`, `&cosh`, `&csub`, `&exp`, `&intersect`, `&intpow...
[`&*`, `&**`, `&+`, `&-`, `&/`, `&Convex_Hull`, `&arccos`, `&arcsin`, `&arctan`, `&cabs`, `&cadd`, `&cdiv`, `&cdiv_opt`, `&cmult`, `&cmult_opt`, `&cos`, `&cosh`, `&csub`, `&exp`, `&intersect`, `&intpow...
[`&*`, `&**`, `&+`, `&-`, `&/`, `&Convex_Hull`, `&arccos`, `&arcsin`, `&arctan`, `&cabs`, `&cadd`, `&cdiv`, `&cdiv_opt`, `&cmult`, `&cmult_opt`, `&cos`, `&cosh`, `&csub`, `&exp`, `&intersect`, `&intpow...
[`&*`, `&**`, `&+`, `&-`, `&/`, `&Convex_Hull`, `&arccos`, `&arcsin`, `&arctan`, `&cabs`, `&cadd`, `&cdiv`, `&cdiv_opt`, `&cmult`, `&cmult_opt`, `&cos`, `&cosh`, `&csub`, `&exp`, `&intersect`, `&intpow...

>