# TheoryBodies

body:
  real_fun_continuity_equiv: THEORY
  %------------------------------------------------------------------------------
  % There are two definitions of continuity of functions real -> real. One is
  % based on metric spaces and the other is a direct definition. In this theory,
  % we prove the equivalence of these definitions.
  %
  %     Authors: Anthony Narkawicz,  NASA Langley
  %
  %     Version 1.0         10/9/2009  Initial Version
  %------------------------------------------------------------------------------

  BEGIN

    IMPORTING real_metric_space, continuous_functions, continuity_ms_def

    f: VAR [real -> real]

    continuous_real : TYPE = {f | continuous?[real](f)}

    real_fun_continuity_equiv: LEMMA
    			     continuous?[real,real_dist,real,real_dist](f)
  			     IFF
  			     continuous?[real](f)


  END real_fun_continuity_equiv

addendum:
  %%% ================ Addendum: generated declarations ================

  % Assuming TCC generated (at line 17, column 8) for
      % continuity_ms_def[real, real_dist, real, real_dist]
      % generated from assumption continuity_ms_def.fullset_metric_space1
  real_fun_continuity_equiv_TCC1: OBLIGATION
    metric_space?[real, real_dist](fullset[real]);


body:
  weierstrass_approximation: THEORY

  %--------------------------------------------------------------------------
  % The Weierstrass Approximation Theorem
  % (Every continuous function on a closed interval can be uniformly
  % approximated by polynomials)
  % 
  % Version 1      April 2010
  %
  % Anthony Narkawicz       NASA
  %--------------------------------------------------------------------------

  BEGIN

    IMPORTING reals@bernstein_polynomials,
    	    real_fun_continuity_equiv,
  	    real_fun_on_compact_sets[real,real_dist],
  	    uniform_continuity[real,real_dist,real,real_dist],
  	    reals@sqrt


    x,y,t,Ma   : VAR real
    i,j,m,p,n  : VAR nat
    k,r,Np     : VAR posnat
    delta	     : VAR posreal
    a,b	     : VAR real

    f: VAR [real -> real]

     Weierstrass_approx_combin1: LEMMA
       p<=2 AND k > p IMPLIES
       sigma(0,k,LAMBDA (i:nat): IF i > k THEN 0 ELSE i^p*C(k,i)*(-1)^(k-i) ENDIF) = 0

     Weierstrass_approximation_0_1: LEMMA
      continuous?[real,real_dist,real,real_dist](f,closed_intv(0,1))
      IMPLIES
        FORALL (epsilon:posreal):
        EXISTS (a: sequence[real],n:nat):
        FORALL (x:(closed_intv(0,1))):
        abs(polynomial(a,n)(x) - f(x)) < epsilon

  END weierstrass_approximation

addendum:
  %%% ================ Addendum: generated declarations ================

  % Assuming TCC generated (at line 17, column 5) for
      % real_fun_on_compact_sets[real, real_dist]
      % generated from assumption real_fun_on_compact_sets.fullset_metric_space
  IMP_real_fun_on_compact_sets_TCC1: OBLIGATION
    metric_space?[real, real_dist](fullset[real]);

  % Subtype TCC generated (at line 32, column 13) for  k
      % expected type  T_high[nat]
  Weierstrass_approx_combin1_TCC1: OBLIGATION
    FORALL (k: posnat, p: nat):
      k > p AND p <= 2 IMPLIES k >= 0 OR (EXISTS (j: nat): k <= j);

  % Subtype TCC generated (at line 32, column 54) for  p
      % expected type  {i_1: int | i /= 0 OR i_1 >= 0}
  Weierstrass_approx_combin1_TCC2: OBLIGATION
    FORALL (k: posnat, p: nat):
      k > p AND p <= 2 IMPLIES
       (FORALL (i: nat): NOT i > k IMPLIES i /= 0 OR p >= 0);

  % Subtype TCC generated (at line 32, column 60) for  i
      % expected type  {i: nat | i <= k}
  Weierstrass_approx_combin1_TCC3: OBLIGATION
    FORALL (k: posnat, p: nat):
      k > p AND p <= 2 IMPLIES (FORALL (i: nat): NOT i > k IMPLIES i <= k);


body:
  continuous_lambda  [ T : TYPE FROM real ] : THEORY
  BEGIN

    IMPORTING continuous_functions[T],
              reals@min_max
    
    f,g : VAR continuous_fun

    pos_continuous?(f):bool = FORALL (x:T) : f(x) > 0
    pos_continuous_fun : TYPE = (pos_continuous?)

    nzf : VAR nz_continuous_fun
    pf  : VAR pos_continuous_fun
    x   : VAR T
    k   : VAR real
    nzk : VAR nzreal
    n   : VAR nat
    
    id_cont : LEMMA
      continuous?(LAMBDA(x):x)

    const_cont: LEMMA
      continuous?(LAMBDA(x):k)
     
    add_cont : LEMMA
      continuous?(LAMBDA(x):f(x)+g(x))

    sub_cont : LEMMA
      continuous?(LAMBDA(x):f(x)-g(x))

    neg_cont : LEMMA
      continuous?(LAMBDA(x):-f(x))

    mult_cont : LEMMA
      continuous?(LAMBDA(x):f(x)*g(x))

    div_cont : LEMMA
      continuous?(LAMBDA(x):f(x)/nzf(x))

    scal_mult_cont : LEMMA
      continuous?(LAMBDA(x):k*f(x))

    scal_div1_cont : LEMMA
      continuous?(LAMBDA(x):f(x)/nzk)

    scal_div2_cont : LEMMA
      continuous?(LAMBDA(x):k/nzf(x))

    pow_cont : LEMMA
      continuous?(LAMBDA(x):f(x)^n) 

    sq_cont : LEMMA
      continuous?(LAMBDA (x):sq(f(x)))

    IMPORTING sqrt_derivative,
              composition_continuous

    sqrt_cont : LEMMA
      continuous?(LAMBDA(x):sqrt(pf(x)))

    abs_cont : LEMMA
      continuous?(LAMBDA (x):abs(f(x)))

    max_cont : LEMMA
      continuous?(LAMBDA (x):max(f(x),g(x)))

    min_cont : LEMMA
      continuous?(LAMBDA (x):min(f(x),g(x)))

  END continuous_lambda

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 50, column 31) for  n
      % expected type  {i: int | f(x) /= 0 OR i >= 0}
  pow_cont_TCC1: OBLIGATION
    FORALL (f: continuous_fun[T], n: nat, x: T): f(x) /= 0 OR n >= 0;

  % Subtype TCC generated (at line 59, column 31) for  pf(x)
      % expected type  nnx: nonneg_real
  sqrt_cont_TCC1: OBLIGATION
    FORALL (pf: pos_continuous_fun, x: T): pf(x) >= 0;


body:
  cont_if_fun[ T : TYPE FROM real] : THEORY
  %------------------------------------------------------------------------------------
  %
  %    Continuity of a function defined using an IF-THEN-ELSE
  %
  %    G = IF <expr> THEN f1 ELSE f2 ENDIF
  %
  %    is continuous if f1 and f2 are continuous and they are equal at all of the
  %    place where the <expr> is discontinuous.
  %
  %    Author: Rick Butler                     NASA Langley
  %            Jan 22, 2009
  %--------------------------------------------------------------------------------------
  BEGIN

    ASSUMING

       connected_domain : ASSUMPTION
  	FORALL (x, y : T), (z : real) :
  	    x <= z AND z <= y IMPLIES T_pred(z)

    ENDASSUMING

    IMPORTING continuous_functions[T]

    f,f1,f2 : VAR [T -> real]

    P : VAR [T -> bool]

    a, b, c, d, x : VAR T

    discont_pts(P): set[T] = {x:T | NOT continuous_at?(P,x)}

    discont_pts_lem: LEMMA NOT discont_pts(P)(a) IMPLIES
                              EXISTS (delta: posreal): 
                                 (FORALL (x:T): abs(x-a) < delta IMPLIES P(x) = true) OR
                                 (FORALL (x:T): abs(x-a) < delta IMPLIES P(x) = false)

    if_fun(P: [T-> bool], f1:[T -> real], f2:[T -> real]): [T -> real] = 
         (LAMBDA (x:T): IF P(x) THEN f1(x) ELSE f2(x) ENDIF)

    if_fun_cont: LEMMA continuous?(f1) AND continuous?(f2) AND
                       (FORALL (x:T): discont_pts(P)(x) IMPLIES f1(x) = f2(x))
                      IMPLIES
                       continuous?(if_fun(P,f1,f2))

    discont_pts_simple: LEMMA continuous?(f1) AND continuous?(f2) AND
      P = (LAMBDA (t: T): f1(t) > 0 AND f2(t) > 0) AND
      discont_pts(P)(x) 
      IMPLIES f1(x) = 0 OR f2(x) = 0

    prod_fun_lem: LEMMA continuous?(f1) AND continuous?(f2) AND
      P = (LAMBDA (t: T): f1(t) > 0 AND f2(t) > 0) AND
      discont_pts(P)(x)
      IMPLIES
         f1(x)*f2(x) = -abs(f1(x)*f2(x))
      


  END cont_if_fun


body:
  linear_functions[T: TYPE FROM real]: THEORY
  BEGIN

     ASSUMING            %% ----- restrict T to single interval ------

      connected_domain : ASSUMPTION
  	FORALL (x, y : T), (z : real) :
  	    x <= z AND z <= y IMPLIES T_pred(z)

      not_one_element : ASSUMPTION
  	 FORALL (x : T) : EXISTS (y : T) : x /= y

     ENDASSUMING

     IMPORTING reals@real_fun_props

     a,b,c,x,y: VAR T
     m,k: VAR real

     f,g: VAR [T -> real]
   
     linear?(f): bool = (EXISTS m,k: f = (LAMBDA x: m*x + k))

     linear_on?(f,a,b): bool = 
             (EXISTS m,k: (FORALL x: a <= x AND x <= b IMPLIES f(x) = m*x + k))


     linear_add: LEMMA linear?(f) AND linear?(g) IMPLIES
                         linear?(f+g)

  END linear_functions


body:
  continuous_linear[T: TYPE FROM real]: THEORY
  %----------------------------------------------------------------------------
  %  Author:  Ricky W. Butler     NASA Langley Research Center
  %----------------------------------------------------------------------------
  BEGIN
     
     ASSUMING            %% ----- restrict T to single interval ------

      connected_domain : ASSUMPTION
  	FORALL (x, y : T), (z : real) :
  	    x <= z AND z <= y IMPLIES T_pred(z)

      not_one_element : ASSUMPTION
  	 FORALL (x : T) : EXISTS (y : T) : x /= y

     ENDASSUMING


     IMPORTING continuous_functions, linear_functions


     a,b,c,x,y: VAR T
     m,k: VAR real

     f,f1,f2: VAR [T -> real]

     linear_cont: LEMMA linear?(f) IMPLIES continuous?(f)

  %  linear_on?(f,a,b): bool = 
  %           (EXISTS m,k: (FORALL x: a <= x AND x <= b IMPLIES f(x) = m*x + k))

     continuous_in?(f,a,b): bool = (FORALL x: a < x AND x < b IMPLIES
                                         continuous?[T](f,x))

     cont_in_linear: LEMMA linear_on?(f,a,b) IMPLIES continuous_in?(f,a,b)


     unary_minus_dist: LEMMA -(a-x) = x - a


     AUTO_REWRITE+ unary_minus_dist


     piecewise: LEMMA   f1(b) = f2(b) AND a < b AND b < c AND
                        linear_on?(f1,a,b) AND
                        linear_on?(f2,b,c)
                     IMPLIES
              LET f = (LAMBDA x: IF x <= b THEN f1(x) ELSE f2(x) ENDIF) IN
                        continuous?(f,b)

     cont_piece: LEMMA (FORALL y: a < y AND y < b IMPLIES f1(y) = f2(y)) AND
                       a < x AND x < b AND
                       continuous?(f1,x) IMPLIES
                       continuous?(f2,x) 


  % -------- results for closed intervals:  [ bot(a), top(a) ] -----------

    top(a): real = IF bounded_above?(fullset[T]) THEN lub(fullset[T])
                   ELSE a ENDIF

    bot(a): real = IF bounded_below?(fullset[T]) THEN glb(fullset[T])
                   ELSE a ENDIF

    top_lem: LEMMA bounded_above?(fullset[T]) IMPLIES (FORALL x: x <= top(a)) 

    top_least: LEMMA (FORALL y: upper_bound?(y, fullset[T]) IMPLIES
                                              top(a) <= y)    


    bot_lem: LEMMA bounded_below?(fullset[T]) IMPLIES (FORALL x: bot(a) <= x) 

    bot_least: LEMMA (FORALL y: lower_bound?(y, fullset[T]) IMPLIES
                                                 y <= bot(a) )    

    cont_upto_lub: LEMMA T_pred(x) AND  a < x AND
                               bounded_above?(fullset[T]) AND 
                               T_pred(top(a)) AND
                               linear_on?(f, a, top(a))
                               IMPLIES
                                  continuous?(f, x )

    cont_downto_glb: LEMMA T_pred(x) AND  a > x AND
                               bounded_below?(fullset[T]) AND 
                               T_pred(bot(a)) AND
                               linear_on?(f, bot(a), a)
                               IMPLIES
                                  continuous?(f, x )

  %  -------- results for piecewise linear functions

     on_linear_part?(x,f): bool = EXISTS a,b: a < x AND x < b AND
                                           linear_on?(f,a,b)


     on_linear_top?(x,f): bool = bounded_above?(fullset[T]) AND
                                    (EXISTS a:  a < x AND T_pred(top(a)) AND
                                          linear_on?(f,a,top(x)))


     on_linear_bottom?(x,f): bool = bounded_below?(fullset[T]) AND
                                 (EXISTS a: a > x AND T_pred(bot(a)) AND
                                           linear_on?(f,bot(a),a))

     on_junction?(b,f): bool =  (EXISTS a,c: a < b AND b < c AND
                                   (EXISTS (m1,k1,m2,k2: real):
               (FORALL y: a <= y AND y <= b IMPLIES f(y) = m1*y + k1) AND
               (FORALL y: b <= y AND y <= c IMPLIES f(y) = m2*y + k2) AND
                                    m1*b+k1 = m2*b + k2))
                                

     piecewise_linear?(f): bool = (FORALL x: on_linear_part?(x,f) OR
                                             on_linear_top?(x,f) OR
                                             on_linear_bottom?(x,f) OR
                                             on_junction?(x,f))        

     cont_piecewise_linear: LEMMA piecewise_linear?(f) IMPLIES
                                    continuous?(f)                              

  END continuous_linear

addendum:
  %%% ================ Addendum: generated declarations ================

  % Assuming TCC generated (at line 19, column 35) for  linear_functions[T]
      % generated from assumption linear_functions.connected_domain
  linear_cont_TCC1: OBLIGATION
    FORALL (x, y: T), (z: real): x <= z AND z <= y IMPLIES T_pred(z);

  % Assuming TCC generated (at line 19, column 35) for  linear_functions[T]
      % generated from assumption linear_functions.not_one_element
  linear_cont_TCC2: OBLIGATION FORALL (x: T): EXISTS (y: T): x /= y;

  % Subtype TCC generated (at line 59, column 35) for
      % extend[real, T, bool, FALSE](fullset[T])
      % expected type  (nonempty?[real])
  top_TCC1: OBLIGATION
    FORALL (a: T): nonempty?[real](extend[real, T, bool, FALSE](fullset[T]));

  % Subtype TCC generated (at line 98, column 55) for  top(x)
      % expected type  T
  on_linear_top?_TCC1: OBLIGATION
    FORALL (x: T):
      bounded_above?(extend[real, T, bool, FALSE](fullset[T])) IMPLIES
       (FORALL (a): T_pred(top(a)) AND a < x IMPLIES T_pred(top(x)));


body:
  interm_value_thm: THEORY
  %-----------------------------------------------------------------
  %  API for Intermediate Value Theorem
  %-----------------------------------------------------------------
  BEGIN

    IMPORTING continuity_interval, reals@intervals_real

    a,b,x: VAR real

    interm_value1 : LEMMA a < b IMPLIES
                                FORALL (f: [closed_interval(a,b) -> real]):
                                continuous?(f) AND f(a) < x AND x < f(b)
  	                        IMPLIES EXISTS (c: closed_interval(a,b)): f(c) = x

    interm_value2 : LEMMA a < b IMPLIES
                                FORALL (f: [closed_interval(a,b) -> real]):
                                continuous?(f) AND f(a) <= x AND x <= f(b)
  	                        IMPLIES EXISTS (c: closed_interval(a,b)): f(c) = x

    interm_value3 : LEMMA a < b IMPLIES
                                FORALL (f: [closed_interval(a,b) -> real]):
                                continuous?(f) AND f(b) < x AND x < f(a)
  	                        IMPLIES EXISTS (c: closed_interval(a,b)): f(c) = x

    interm_value4 : LEMMA a < b IMPLIES
                                FORALL (f: [closed_interval(a,b) -> real]):
                                continuous?(f) AND f(b) <= x AND x <= f(a)
  	                        IMPLIES EXISTS (c: closed_interval(a,b)): f(c) = x

    interm_value5 : LEMMA a < b IMPLIES
                                FORALL (f: [closed_interval(a,b) -> real],p,q:closed_interval(a,b)):
                                continuous?(f) AND f(p) <= x AND x <= f(q)
  	                        IMPLIES EXISTS (c: closed_interval(a,b)): 
  				((p<=c AND c<=q) OR (q<=c AND c<=p)) AND f(c) = x


    f: VAR [real -> real]


    cont_intv : LEMMA a < b AND continuous?(f) 
                IMPLIES continuous?(LAMBDA (x: closed_interval(a, b)): f(x))


    cont_intv1: LEMMA a < b AND continuous?[closed_interval[real](a, b)](f) 
                IMPLIES continuous?(LAMBDA (x: closed_interval(a, b)): f(x))




    interm_val1 : LEMMA a < b IMPLIES
                                continuous?[closed_interval(a,b)](f) AND f(a) < x AND x < f(b)
  	                        IMPLIES EXISTS (c: closed_interval(a,b)): f(c) = x

    interm_val2 : LEMMA a < b IMPLIES
                                FORALL (f: [real -> real]):
                                continuous?[closed_interval(a,b)](f) AND f(a) <= x AND x <= f(b)
  	                        IMPLIES EXISTS (c: closed_interval(a,b)): f(c) = x

    interm_val3 : LEMMA a < b IMPLIES
                                FORALL (f: [real -> real]):
                                continuous?[closed_interval(a,b)](f) AND f(b) < x AND x < f(a)
  	                        IMPLIES EXISTS (c: closed_interval(a,b)): f(c) = x

    interm_val4 : LEMMA a < b IMPLIES
                                FORALL (f: [real -> real]):
                                continuous?[closed_interval(a,b)](f) AND f(b) <= x AND x <= f(a)
  	                        IMPLIES EXISTS (c: closed_interval(a,b)): f(c) = x

    % ----------------------------------------------------------------------------------

    xl,xu: VAR real

    zeros_interm: LEMMA  continuous?(f)
                       AND f(xl) = 0 AND f(xu) = 0 AND
                      (FORALL (x: open_interval(xl,xu)): f(x) /= 0)
                    IMPLIES
                      (FORALL (x: open_interval(xl,xu)): f(x) > 0) OR
                      (FORALL (x: open_interval(xl,xu)): f(x) < 0)

    % ----------------------------------------------------------------------------------

    IMPORTING reals@connected_set

    ab : VAR Connected

    IntermediateValue : THEOREM
      FORALL (f:[real->real]):
      continuous?(f) AND
      (FORALL (c:(ab)) : f(c) /= 0) IMPLIES 
      (FORALL (x,y:(ab)) : f(x)*f(y) > 0)       

  END interm_value_thm

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 13, column 51) for  a
      % expected type  closed_interval[real](a, b)
  interm_value1_TCC1: OBLIGATION
    FORALL (a, b: real):
      a < b IMPLIES
       (FORALL (f: [closed_interval[real](a, b) -> real]):
          continuous?(f) IMPLIES a <= a AND a <= b);

  % Subtype TCC generated (at line 13, column 68) for  b
      % expected type  closed_interval[real](a, b)
  interm_value1_TCC2: OBLIGATION
    FORALL (a, b, x: real):
      a < b IMPLIES
       (FORALL (f: [closed_interval[real](a, b) -> real]):
          f(a) < x AND continuous?(f) IMPLIES a <= b AND b <= b);

  % Subtype TCC generated (at line 18, column 70) for  b
      % expected type  closed_interval[real](a, b)
  interm_value2_TCC1: OBLIGATION
    FORALL (a, b, x: real):
      a < b IMPLIES
       (FORALL (f: [closed_interval[real](a, b) -> real]):
          f(a) <= x AND continuous?(f) IMPLIES a <= b AND b <= b);

  % Subtype TCC generated (at line 23, column 51) for  b
      % expected type  closed_interval[real](a, b)
  interm_value3_TCC1: OBLIGATION
    FORALL (a, b: real):
      a < b IMPLIES
       (FORALL (f: [closed_interval[real](a, b) -> real]):
          continuous?(f) IMPLIES a <= b AND b <= b);


body:
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %  Restriction of continuous functions  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  restriction_continuous2[T1, T2 : TYPE FROM real] : theory
  BEGIN

    ASSUMING

    sub_domain : ASSUMPTION
  	FORALL (x : T1) : EXISTS (y : T2) : x = y

    ENDASSUMING

    IMPORTING continuous_functions

    f : VAR [T2 -> real]

    sub_dom : LEMMA FORALL (u : T1) : T2_pred(u)

    restrict2(f) : [T1 -> real] = LAMBDA (u : T1) : f(u)

    CONVERSION restrict2

    restrict_continuous2 : LEMMA
  	continuous?(f) IMPLIES continuous?[T1](f) 

  END restriction_continuous2

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 21, column 52) for  u
      % expected type  T2
  restrict2_TCC1: OBLIGATION FORALL (u: T1): T2_pred(u);


body:
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %  Restriction of continuous functions  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  restriction_cont_fun[T1, T2 : TYPE FROM real] : theory
  BEGIN

    ASSUMING

    sub_domain : ASSUMPTION
  	FORALL (x : T1) : EXISTS (y : T2) : x = y

    ENDASSUMING

    IMPORTING continuous_functions

    f : VAR [T2 -> real]

    sub_dom : LEMMA FORALL (u : T1) : T2_pred(u)

    restrict2(f) : [T1 -> real] = LAMBDA (u : T1) : f(u)

    CONVERSION restrict2

    restrict_cont_fun : LEMMA
  	continuous?(f) IMPLIES continuous?[T1](f) 

  END restriction_cont_fun

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 21, column 52) for  u
      % expected type  T2
  restrict2_TCC1: OBLIGATION FORALL (u: T1): T2_pred(u);


body:
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %  Restriction of continuous functions  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  restriction_continuous[T1 : TYPE FROM real ] : THEORY
  BEGIN

    IMPORTING continuous_functions

    f : VAR [real -> real]

    restrict_continuous : LEMMA
  	continuous?(f) IMPLIES continuous?[T1](f)

  END restriction_continuous


body:
  top_continuity : THEORY
  %----------------------------------------------------------------------------
  %  Author:  Bruno Dutertre    Royal Holloway & Bedford New College
  %----------------------------------------------------------------------------
  BEGIN

    IMPORTING continuous_functions, composition_continuous,
  	    restriction_continuous, restriction_cont_fun,
              restriction_continuous2,
  	    continuous_functions_props,
              continuity_interval,
              interm_value_thm, 
              continuous_functions_more,
              unif_cont_fun,
              inverse_continuous_functions,
              continuous_linear,
              cont_if_fun,
              continuous_lambda,
              real_fun_continuity_equiv,
              weierstrass_approximation

  END top_continuity


body:
  top_limits : THEORY
  %----------------------------------------------------------------------------
  %  Author:  Bruno Dutertre    Royal Holloway & Bedford New College
  %----------------------------------------------------------------------------
  BEGIN

    IMPORTING lim_of_functions, lim_of_composition

  END top_limits


body:
  top: THEORY
  %----------------------------------------------------------------------------
  %
  %  Additional Set Theory (sets_aux)
  %  --------------------------------
  %
  %  Version 1.0    Powersets merged with finite_sets_aux    2/10/04
  %  Version 2.0    Jerry James libraries added              5/5/04
  %  Version 2.1    Updates for PVS 3.2; removed theories    11/3/04
  %                 now in the prelude or finite_sets
  %  Version 3.0    Merged in Alfons Geser's order theories  2/10/05
  %  Version 3.1    Added some theories from David Lester    4/12/05
  %  Version 3.2    Added cardinal and sets_lemmas_extra     5/11/05
  %  Version 3.3    Updated countable sets theories          9/15/09
  % 
  %  Authors:
  %      Bruno Dutertre <bruno@sdl.sri.com>    SRI International
  %      Jerry James    <jamesj@acm.org>       University of Kansas
  %      David Lester   <dlester@cs.man.ac.uk> Manchester University
  %----------------------------------------------------------------------------
  BEGIN

   %---- Bruno Dutertre theories on powersets
   IMPORTING
    fun_below_props,          % bijections with Cartesian products
    power_sets,               % cardinality and finiteness
    set_of_functions          % functions from finite set A to B

   %---- Jerry James theories on infinite cardinalities
   IMPORTING
    bits,                     % sets of bit numbers (used to show countability)
    card_comp,                % compare the cardinality of any two types
    card_comp_props,          % properties of the card_comp predicates
    card_comp_set,            % compare the cardinality of any two sets
    card_comp_set_props,      % properties of the card_comp_set predicates
    card_comp_set_transitive, % transitivity of the card_comp_set predicates
    card_comp_transitive,     % transitivity of the card_comp predicates
    card_finite,              % card_comp vs. card(S) from finite_sets
    card_power,               % card[T] < card[set[T]]
    card_power_set,           % card(S) < card(powerset(S))
    card_sets_lemmas,         % relationships of set operations to cardinality
    card_single,              % single type properties of card_comp_set preds
    card_function,            % surjection/injection image properties
    cardinal,                 % cardinality(S) for any set S
    countability,             % definition of (un)countable sets
    countable_image,          % countable image
    countable_props,          % properties of (un)countable sets
    countable_set,            % some countable sets of numbers (e.g., integers)
    countable_setofsets,      % operations on countable families of sets
    countable_types,          % countability of some prelude types
    infinite_card,            % card_comp implications for finiteness
    infinite_image,           % infinite images of a set under some function
    infinite_sets,            % cardinality of infinite set add and remove
    sets_lemmas_extra         % disjoint? is commutative

   %--- David Lester theories on infinite/countable sets
   IMPORTING
    countable_image,          % image of a countable set is countable
    card_function,            % finite/infinite properties of functions
    infinite_nat_def,         % infinite IFF injective map from the naturals


    indexed_sets_aux,      % Additional prelude indexed set lemmas
    countable_indexed_sets,% countable setsofsets vs indexed sets
    nat_indexed_sets,      % increasing/decresing indexed sets
    inverse_image_Union,   % inverse_image(f,Union(X))

    countability_aux,      %% RWB

    cantor_bernstein_schroeder  %% Proved by Anthony Narkawicz

   IMPORTING
   % Dragan Stosic's relational and functional choice facts based on Axiom of Choice
     top_choice_facts,
   % Dragan Stosic's refinement relations
     top_refinement_relations
   
  END top


body:
  %--------------------------------------------------------------%
  %   Author: Dragan Stosic                                      %
  %--------------------------------------------------------------%
  relation_extension[T, U: TYPE+]: THEORY
   BEGIN

   le_T: VAR equivalence[T]

   le_U: VAR equivalence[U]

   m, n: VAR [T, U]

   f: VAR [T -> U]

   g: VAR [U -> T]
    
   R: VAR equivalence[[T, U]]

   p_r1: VAR [[[T,U] -> T]]

   p_r2: VAR [[[T,U] -> U]]

   proj_tuple_1: [[[T,U] -> T]] = LAMBDA (m:[T,U]): m`1

   proj_tuple_2: [[[T,U] -> U]] = LAMBDA (m:[T,U]): m`2

   extended_equiv_class(R)(m): set[[T,U]] = { n | R(m, n) }

   extended_equiv_classT(R, p_r1, m, n) : set[T] = 
     { (t : T) | t= p_r1(m) AND  extended_equiv_class(R)(n)(m) }
   
   extended_equiv_classU(R, p_r2, m, n) : set[U] = 
     { (u : U) | u= p_r2(m) AND  extended_equiv_class(R)(n)(m) }
   
  % extended equivalence relation based on two equivalence 
  % relations : le_T , le_U

   rel_extension(le_T, le_U) : set[[[T, U], [T, U]]] =
     { (m, n) | le_T(m`1, n`1) AND le_U(m`2, n`2) }

   rel_extension_is_equivalence: JUDGEMENT
   rel_extension(le_T, le_U) HAS_TYPE equivalence[[T, U]]
                                                  
  % class representative for the rel_extension equivalence relation

   repEC_ext(le_T, le_U, m): [[T, U]] = repEC(rel_extension(le_T, le_U))(m)
      
  END relation_extension

addendum:
  %%% ================ Addendum: generated declarations ================

  % Judgement subtype TCC generated (at line 42, column 1) for
      % rel_extension(le_T, le_U)
      % expected type  equivalence[[T, U]]
  rel_extension_is_equivalence: OBLIGATION
    FORALL (le_T, le_U): equivalence?[[T, U]](rel_extension(le_T, le_U));


body:
  %--------------------------------------------------------------%
  %   Author: Dragan Stosic                                      %
  %--------------------------------------------------------------%

  relation_inverse_image[T, U: TYPE+]: THEORY
  BEGIN
    
    R: VAR pred[[U, U]]
   
    f: VAR [T -> U]

    t: VAR T

    image_inverse(R, f):pred[[T, T]] = { (t1,t2:T) | R(f(t1),f(t2)) }

  % The equivClass definition over the inverse image set
     equivClass(R, f, t):pred[T] = { t1:T | image_inverse(R, f)(t, t1) }
   
  % Curried form
    image_inverse(R)(f):pred[[T, T]] = image_inverse(R, f)

  % Curried form
    equivClass(R, f)(t):pred[T] =  equivClass(R, f, t)

    equivClass_is_nonempty: LEMMA equivalence?[U](R)
      IMPLIES nonempty?[T](equivClass(R,f)(t))

    equivClass_equal_is_nonempty: LEMMA nonempty?[T](equivClass(=, f)(t))

    inverse_image_of_equivalence: LEMMA equivalence?[U](R) 
      IMPLIES equivalence?[T](image_inverse(R, f))

    preserves_eqv_of_inv_image: LEMMA EXISTS R: equivalence?[T](image_inverse(R, f))  

    inverse_image_of_equality: LEMMA equivalence?[T](image_inverse(=, f))
    
    image_inverse_eq_is_eq_kernel: LEMMA 
      EquivalenceKernel[T, T, U](f) = image_inverse(=)(f)
       
    inv_img_surj_impl_codom_eq: LEMMA  
      FORALL (f:(surjective?[T, U])):
        equivalence?[T](image_inverse(R,f)) IMPLIES equivalence?[U](R)

    right_inv_inv_finv_image_impl_codom_eq: LEMMA  
      right_inverse?(inverse(f), f) IMPLIES
        equivalence?[T](image_inverse(R, f)) IMPLIES equivalence?[U](R)

    surjective_eqv_image_inv_rel_codomain: THEOREM 
      FORALL (f:(surjective?[T, U])):
        equivalence?[T](image_inverse(R)(f)) = equivalence?[U](R)

    right_inv_inv_finv_image_eq_codom_eq: LEMMA  
      right_inverse?(inverse(f), f) IMPLIES
        equivalence?[T](image_inverse(R, f)) =  equivalence?[U](R)

  END relation_inverse_image


body:
  %--------------------------------------------------------------%
  %   Author: Dragan Stosic                                      %
  %--------------------------------------------------------------%

  relation_inverse_extension[T, U: TYPE+]: THEORY
  BEGIN

   IMPORTING relation_inverse_image[T, U],
             relation_inverse_image[U, T],
             relation_extension[T, U]

   f: VAR [T -> U]

   g: VAR [U -> T]

   m, n :VAR [T, U]

   re_U: VAR equivalence[U]

   re_T: VAR equivalence[T]

   l_T(re_U, f):pred[[T, T]] = image_inverse(re_U, f)

   le_U_induces_equivalence :JUDGEMENT l_T(re_U, f) HAS_TYPE equivalence[T]
    
   l_U(re_T, g):pred[[U, U]] = image_inverse(re_T, g)

   le_T_induces_equivalence: JUDGEMENT l_U(re_T, g) HAS_TYPE equivalence[U]

  % etended equivalence relation based on inverse images of equivalence 
  % relations

   rel_inv_extension(re_T, re_U, f, g) : set[[[T, U], [T, U]]] =
     { (m, n) | l_T(re_U, f)(n`1,m`1) AND l_U(re_T, g)(n`2,m`2) }

   rel_inv_extension_is_equivalence: JUDGEMENT 
     rel_inv_extension(re_T, re_U, f, g) HAS_TYPE equivalence[[T, U]]

  % connection between two relations: 
  % rel_extension and rel_image_extension

   rel_extension_IFF_rel_ext : LEMMA 
     LET GFm=(g(m`2),f(m`1)), GFn=(g(n`2),f(n`1)) IN
       rel_extension(re_T, re_U)(GFm, GFn) = 
         rel_inv_extension(re_T, re_U, f, g)(n, m)

  % replaced: definition of the rel_inv_extension using the rel_extension 

   rel_inv_extension2(re_T, re_U, f, g):set[[[T, U], [T, U]]] = 
     { (n, m) | LET GFm=(g(m`2),f(m`1)), GFn=(g(n`2),f(n`1)) IN
        rel_extension(re_T, re_U)(GFm, GFn) 
     }

   rel_inv_extension2_is_equivalence: JUDGEMENT 
     rel_inv_extension2(re_T, re_U, f, g) HAS_TYPE equivalence[[T, U]]

  END relation_inverse_extension

addendum:
  %%% ================ Addendum: generated declarations ================

  % Judgement subtype TCC generated (at line 24, column 37) for  l_T(re_U, f)
      % expected type  equivalence[T]
  le_U_induces_equivalence: OBLIGATION
    FORALL (f, re_U): equivalence?[T](l_T(re_U, f));

  % Judgement subtype TCC generated (at line 28, column 37) for  l_U(re_T, g)
      % expected type  equivalence[U]
  le_T_induces_equivalence: OBLIGATION
    FORALL (g, re_T): equivalence?[U](l_U(re_T, g));

  % Judgement subtype TCC generated (at line 37, column 3) for
      % rel_inv_extension(re_T, re_U, f, g)
      % expected type  equivalence[[T, U]]
  rel_inv_extension_is_equivalence: OBLIGATION
    FORALL (f, g, re_T, re_U):
      equivalence?[[T, U]](rel_inv_extension(re_T, re_U, f, g));

  % Judgement subtype TCC generated (at line 55, column 3) for
      % rel_inv_extension2(re_T, re_U, f, g)
      % expected type  equivalence[[T, U]]
  rel_inv_extension2_is_equivalence: OBLIGATION
    FORALL (f, g, re_T, re_U):
      equivalence?[[T, U]](rel_inv_extension2(re_T, re_U, f, g));


body:
  %--------------------------------------------------------------%
  %   Author: Dragan Stosic                                      %
  %--------------------------------------------------------------%

  rr_rel[T, U: TYPE+]: THEORY
   BEGIN
    IMPORTING relation_extension[T, U],
              relation_inverse_extension[T, U]

   le_T: VAR equivalence[T]

   le_U: VAR equivalence[U]

   n: VAR [T, U]

   f: VAR [T -> U]

   g: VAR [U -> T]

  % Definition 1:
  % Relation [T, U]
  % Domain T partitioned with the le_T equivalence relation 
  % Codomain U  partitioned with the le_U equivalence relation 
  % Functions: f[ T -> U] and g [U -> T]

   RR(le_T, le_U, f, g):set[[T,U]] = 
     { (n) | LET Fn = (n`1,f(n`1)), 
                   Gn  = (g(n`2), n`2), 
                     GFn  = (g(n`2), f(n`1))  IN 
                       rel_extension(le_T, le_U)(Fn, Gn)     OR
                         rel_extension(le_T, le_U)(GFn, Fn)  OR
                           rel_extension(le_T, le_U)(GFn, Gn)  
     }

  % Definition 2:
  % Relation [T, U]
  % Domain T partitioned with the le_T equivalence relation 
  % Codomain U  partitioned with the le_U equivalence relation 
  % Functions: f[ T -> U] and g [U -> T]

  RR2(le_T, le_U, f, g):set[[T,U]] = 
     { (n) | LET Fn = (n`1,f(n`1)), 
                   Gn  = (g(n`2), n`2), 
                     GFn  = (g(n`2), f(n`1))  IN 
                       rel_inv_extension2(le_T, le_U, f, g)(Fn, Gn)     OR
                         rel_inv_extension2(le_T, le_U, f, g)(GFn, Fn)  OR
                           rel_inv_extension2(le_T, le_U, f, g)(GFn, Gn)  
     }

   g_conistent_with_RR: LEMMA 
     le_T( n`1, g(n`2) ) IMPLIES RR(le_T, le_U, f, g)(n)  
   
   f_conistent_with_RR: LEMMA 
     le_U( n`2, f(n`1) ) IMPLIES RR(le_T, le_U, f, g)(n)  


  % Connection between RR and RR2
   
   RR_functional_conditional_equal_RR2: LEMMA
      LET GFn=(g(n`2),f(n`1)) IN 
        RR(le_T, le_U, f, g)(GFn) IFF  RR2(le_T, le_U, f, g)(n)
   
  END rr_rel


body:
  % domain:              finite
  % codomain:            infinite
  % EquivClass domain:   finite
  % EquivClass codomain: infinite
  finite_to_infinite_finite_equival_infinite_equival_classes: THEORY
  BEGIN
    T11: TYPE+ = below(2)
    U11: TYPE+ = nat
    IMPORTING relations[T11], relations[U11],
               rr_rel[T11, U11];
   
    equivT(t0, t1: T11): bool = odd?(t0+1) = even?(t1)
    equivU(u0, u1: U11): bool = odd?(u0+1) = even?(u1) OR even?(u0) = even?(u1)  
    g11: [T11 -> U11] = LAMBDA (t: T11): IF (even?(t)) THEN 0 ELSE 1 ENDIF
    e11: [U11 -> T11] = LAMBDA (u: U11): IF (even?(u)) THEN 0 ELSE 1 ENDIF
    ref11: predicate[[T11, U11]] = (LAMBDA (p: [T11, U11]):
                                 IF (even?(p`2)) THEN p`1 = 0 ELSE p`1 = 1 ENDIF)

    relations_equality: LEMMA  ref11 = RR(equivT, equivU, g11, e11)

    relations_equality2: LEMMA  ref11 = RR2(equivT, equivU, g11, e11)

  END finite_to_infinite_finite_equival_infinite_equival_classes

addendum:
  %%% ================ Addendum: generated declarations ================

  % Existence TCC generated (at line 200, column 2) for  T11: TYPE+ = below(2)
  T11_TCC1: OBLIGATION EXISTS (x: {s: nat | s < 2}): TRUE;

  % Subtype TCC generated (at line 212, column 40) for  equivT
      % expected type  equivalence[T11]
  relations_equality_TCC1: OBLIGATION equivalence?[T11](equivT);

  % Subtype TCC generated (at line 212, column 48) for  equivU
      % expected type  equivalence[U11]
  relations_equality_TCC2: OBLIGATION equivalence?[U11](equivU);


body:
  % domain:              infinite
  % codomain:            infinite
  % EquivClass domain:   infinite
  % EquivClass codomain: finite
  infinite_to_infinite_infinite_equival_finite_equival_classes: THEORY 
  BEGIN
    IMPORTING ints@div
    T10: TYPE+ = nat
    U10: TYPE+ = nat
    IMPORTING relations[T10], relations[U10],
              rr_rel[T10, U10];

    equivT(t0, t1: T10): bool = t0 = t1
    equivU(u0, u1: U10): bool = div(u0,10) = div(u1,10)
    g10: [T10 -> U10] = LAMBDA (t: T10): 10*t
    e10: [U10 -> T10] = LAMBDA (u: U10): div(u,10)
    ref10: predicate[[T10, U10]] = LAMBDA (p: [T10, U10]): p`1=div(p`2,10)

    relations_equality: LEMMA  ref10 = RR(equivT, equivU, g10, e10)

    relations_equality2: LEMMA  ref10 = RR2(equivT, equivU, g10, e10)

  END infinite_to_infinite_infinite_equival_finite_equival_classes

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 188, column 40) for  equivT
      % expected type  equivalence[T10]
  relations_equality_TCC1: OBLIGATION equivalence?[T10](equivT);

  % Subtype TCC generated (at line 188, column 48) for  equivU
      % expected type  equivalence[U10]
  relations_equality_TCC2: OBLIGATION equivalence?[U10](equivU);


body:
  % domain:              infinite
  % codomain:            infinite
  % EquivClass domain:   infinite
  % EquivClass codomain: infinite
  infinite_to_infinite_infinite_equival_infinite_equival_classes: THEORY 
  BEGIN
    T9: TYPE = nat
    U9: TYPE = posnat
    IMPORTING relations[T9], relations[U9], 
              rr_rel[T9, U9]

    equivT(t0, t1: T9): bool = t0 = t1 
    equivU(u0, u1: U9): bool = u0 = u1 
    g9: [T9 -> U9] = LAMBDA (t: T9): t+1
    e9: [U9 -> T9] = LAMBDA (u: U9): u-1
    ref9: predicate[[T9, U9]] = LAMBDA (p: [T9, U9]): p`1+1= p`2

    relations_equality: LEMMA  ref9 = RR(equivT, equivU, g9, e9)

    relations_equality2: LEMMA  ref9 = RR2(equivT, equivU, g9, e9)

  END infinite_to_infinite_infinite_equival_infinite_equival_classes

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 161, column 35) for  u - 1
      % expected type  T9
  e9_TCC1: OBLIGATION FORALL (u: U9): u - 1 >= 0;

  % Subtype TCC generated (at line 164, column 39) for  equivT
      % expected type  equivalence[T9]
  relations_equality_TCC1: OBLIGATION equivalence?[T9](equivT);

  % Subtype TCC generated (at line 164, column 47) for  equivU
      % expected type  equivalence[U9]
  relations_equality_TCC2: OBLIGATION equivalence?[U9](equivU);


body:
  % domain:              infinite
  % codomain:            finite
  % EquivClass domain:   infinite
  % EquivClass codomain: finite
  infinite_to_finite_infinite_equival_finite_equival_classes: THEORY 
  BEGIN
    T8: TYPE+ = nat
    U8: TYPE+ = below(2)
    IMPORTING relations[T8], relations[U8],
              rr_rel[T8, U8]

    equivT(t0, t1: T8): bool = odd?(t0+1) = even?(t1) OR even?(t0) = even?(t1)
    equivU(u0, u1: U8): bool = odd?(u0+1) = even?(u1)  
    g8: [T8 -> U8] = LAMBDA (t: T8): IF (even?(t)) THEN 0 ELSE 1 ENDIF
    e8: [U8 -> T8] = LAMBDA (u: U8): IF ( even?(u)) THEN 0 ELSE 1 ENDIF
    ref8: predicate[[T8, U8]] = LAMBDA (p: [T8, U8]):
                                 IF ( even?(p`1)) THEN p`2 = 0 ELSE p`2 = 1 ENDIF

    relations_equality: LEMMA  ref8 = RR(equivT, equivU, g8, e8)
   
    relations_equality2: LEMMA  ref8 = RR2(equivT, equivU, g8, e8)

  END infinite_to_finite_infinite_equival_finite_equival_classes

addendum:
  %%% ================ Addendum: generated declarations ================

  % Existence TCC generated (at line 130, column 2) for  U8: TYPE+ = below(2)
  U8_TCC1: OBLIGATION EXISTS (x: {s: nat | s < 2}): TRUE;

  % Subtype TCC generated (at line 141, column 39) for  equivT
      % expected type  equivalence[T8]
  relations_equality_TCC1: OBLIGATION equivalence?[T8](equivT);

  % Subtype TCC generated (at line 141, column 47) for  equivU
      % expected type  equivalence[U8]
  relations_equality_TCC2: OBLIGATION equivalence?[U8](equivU);


body:
  % domain:              infinite
  % codomain:            finite
  % EquivClass domain:   finite
  % EquivClass codomain: finite
  infinite_to_finite_finite_equival_finite_equival_classes : THEORY 
  BEGIN
    T7: TYPE = nat
    U7: TYPE = {0,1}
    IMPORTING relations[T7], relations[U7],
              rr_rel[T7, U7]
   
    equivT(t0, t1: T7): bool = even?(t0) = even?(t1)
    equivU(u0, u1: U7): bool = u0 = u1   
    g7: [T7 -> U7] = LAMBDA (t: T7):  IF (even?(t)) THEN 0 ELSE 1 ENDIF
    e7: [U7 -> T7] = LAMBDA (u: U7): IF (u = 0) THEN 0 ELSE 1 ENDIF
    ref7: predicate[[T7, U7]] = LAMBDA (p: [T7, U7]):
                                 IF (even?(p`1)) THEN p`2 = 0 ELSE p`2 = 1 ENDIF
    
    relations_equality: LEMMA  ref7 = RR(equivT, equivU, g7, e7)

    relations_equality2: LEMMA  ref7 = RR2(equivT, equivU, g7, e7)

  END infinite_to_finite_finite_equival_finite_equival_classes

addendum:
  %%% ================ Addendum: generated declarations ================

  U7_ord_defaxiom: AXIOM U7_ord(0) = 0 AND U7_ord(1) = 1;

  U7_inclusive: AXIOM FORALL (U7_var: U7): zero?(U7_var) OR one?(U7_var);

  U7_induction: AXIOM
    FORALL (p: [U7 -> boolean]):
      p(0) AND p(1) IMPLIES (FORALL (U7_var: U7): p(U7_var));

  U7_well_founded: AXIOM strict_well_founded?[U7](<<);

  U7: TYPE

  zero?: [U7 -> boolean]

  one?: [U7 -> boolean]

  U7_ord: [U7 -> upto(1)]

  ord(x: U7): [U7 -> upto(1)] = CASES x OF 0: 0, 1: 1 ENDCASES

  subterm(x: U7, y: U7):  boolean = x = y;

  0: (zero?)

  1: (one?)

  <<:  (strict_well_founded?[U7]) = LAMBDA (x, y: U7): FALSE;

  % Subtype TCC generated (at line 117, column 39) for  equivT
      % expected type  equivalence[T7]
  relations_equality_TCC1: OBLIGATION equivalence?[T7](equivT);

  % Subtype TCC generated (at line 117, column 47) for  equivU
      % expected type  equivalence[U7]
  relations_equality_TCC2: OBLIGATION equivalence?[U7](equivU);


body:
  % domain:              finite
  % codomain:            infinite
  % EquivClass domain:   finite
  % EquivClass codomain: finite
  finite_to_infinite: THEORY 
  BEGIN
    T6: TYPE = bool
    U6: TYPE = nat
    IMPORTING relations[T6], relations[U6],
              rr_rel[T6, U6]

    equivT(t0, t1: T6): bool = t0 = t1
    equivU(u0, u1: U6): bool = even?(u0) = even?(u1)
    g6: [T6 -> U6] = LAMBDA (t: T6): IF t THEN 0 ELSE 1 ENDIF
    e6: [U6 -> T6] = LAMBDA (u: U6): even?(u)
    ref6: predicate[[T6, U6]] = LAMBDA (p: [T6, U6]): p`1 = even?(p`2)

    relations_equality: LEMMA  ref6 = RR(equivT, equivU, g6, e6)

    relations_equality2: LEMMA  ref6 = RR2(equivT, equivU, g6, e6)
    
  END finite_to_infinite

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 93, column 39) for  equivT
      % expected type  equivalence[T6]
  relations_equality_TCC1: OBLIGATION equivalence?[T6](equivT);

  % Subtype TCC generated (at line 93, column 47) for  equivU
      % expected type  equivalence[U6]
  relations_equality_TCC2: OBLIGATION equivalence?[U6](equivU);


body:
  % domain:              infinite
  % codomain:            infinite
  % EquivClass domain:   finite
  % EquivClass codomain: infinite
  infinite_to_infinite_trivial: THEORY 
  BEGIN
    IMPORTING ints@div
    T4: TYPE = nat
    U4: TYPE = nat
    IMPORTING relations[T4], relations[U4], rr_rel[T4, U4];

    equivT(t0, t1: T4): bool = div(t0,10) = div(t1,10)
    equivU(u0, u1: U4): bool = u0 = u1
    g4: [T4 -> U4] = LAMBDA (t: T4): div(t,10)
    e4: [U4 -> T4] = LAMBDA (u: U4): 10*u
    ref4: predicate[[T4, U4]] = LAMBDA (p: [T4, U4]): div(p`1,10) = p`2

    relations_equality: LEMMA  ref4 = RR(equivT, equivU, g4, e4)
    
    relations_equality2: LEMMA ref4 = RR2(equivT, equivU, g4, e4)

  END infinite_to_infinite_trivial

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 70, column 39) for  equivT
      % expected type  equivalence[T4]
  relations_equality_TCC1: OBLIGATION equivalence?[T4](equivT);

  % Subtype TCC generated (at line 70, column 47) for  equivU
      % expected type  equivalence[U4]
  relations_equality_TCC2: OBLIGATION equivalence?[U4](equivU);


body:
  % domain:              finite
  % codomain:            finite
  % EquivClass domain:   finite
  % EquivClass codomain: finite
  finite_nats_trivial: THEORY
  BEGIN
    T1: TYPE+ = below(3)
    U1: TYPE+ = below(6)
    IMPORTING ints@div, relations[T1], relations[U1],
               rr_rel[T1, U1];
    
    ==(t0, t1: T1): bool = t0 = t1;
    ==(u0, u1: U1): bool = div(u0,2) = div(u1,2);
    
    g1: [T1 -> U1] = LAMBDA (t: T1): 2*t
    e1: [U1 -> T1] = LAMBDA (u: U1): div(u,2)
    ref1: predicate[[T1, U1]] =
      LAMBDA (p: [T1, U1]): 2*p`1 = p`2 OR 2*p`1+1 = p`2

    relations_equality: LEMMA  RR(==,==, g1, e1) = ref1
   
    relations_equality2: LEMMA RR2(==,==, g1, e1) = ref1

  END finite_nats_trivial  

addendum:
  %%% ================ Addendum: generated declarations ================

  % Existence TCC generated (at line 34, column 2) for  T1: TYPE+ = below(3)
  T1_TCC1: OBLIGATION EXISTS (x: {s: nat | s < 3}): TRUE;

  % Existence TCC generated (at line 35, column 2) for  U1: TYPE+ = below(6)
  U1_TCC1: OBLIGATION EXISTS (x: {s: nat | s < 6}): TRUE;

  % Subtype TCC generated (at line 42, column 35) for  2 * t
      % expected type  U1
  g1_TCC1: OBLIGATION FORALL (t: T1): 2 * t < 6;

  % Subtype TCC generated (at line 43, column 35) for  div(u, 2)
      % expected type  T1
  e1_TCC1: OBLIGATION FORALL (u: U1): div(u, 2) < 3;

  % Subtype TCC generated (at line 47, column 32) for  ==
      % expected type  equivalence[T1]
  relations_equality_TCC1: OBLIGATION equivalence?[T1](==);

  % Subtype TCC generated (at line 47, column 35) for  ==
      % expected type  equivalence[U1]
  relations_equality_TCC2: OBLIGATION equivalence?[U1](==);


body:
  %--------------------------------------------------------------%
  %   Author: Dragan Stosic                                      %
  %--------------------------------------------------------------%

  % domain:              finite
  % codomain:            finite
  % EquivClass domain:   finite
  % EquivClass codomain: finite
  singleton_example: THEORY
  BEGIN
    T0: TYPE+ = {t}
    U0: TYPE+ = {u}
    IMPORTING relations[T0], relations[U0],
              rr_rel[T0, U0]

    ==(t0, t1: T0): bool = true;
    ==(u0, u1: U0): bool = true;
    g0: [T0 -> U0] = LAMBDA (t0: T0): u
    e0: [U0 -> T0] = LAMBDA (u0: U0): t
    ref0: predicate[[T0, U0]] = LAMBDA (p: [T0, U0]): true

   relations_equality: LEMMA  RR(==,==, g0, e0) = ref0
   
   relations_equality2: LEMMA RR2(==,==, g0, e0) = ref0
   
  END singleton_example

addendum:
  %%% ================ Addendum: generated declarations ================

  T0_ord_defaxiom: AXIOM T0_ord(t) = 0;

  T0_inclusive: AXIOM FORALL (T0_var: T0): t?(T0_var);

  T0_induction: AXIOM
    FORALL (p: [T0 -> boolean]):
      p(t) IMPLIES (FORALL (T0_var: T0): p(T0_var));

  T0_well_founded: AXIOM strict_well_founded?[T0](<<);

  U0_ord_defaxiom: AXIOM U0_ord(u) = 0;

  U0_inclusive: AXIOM FORALL (U0_var: U0): u?(U0_var);

  U0_induction: AXIOM
    FORALL (p: [U0 -> boolean]):
      p(u) IMPLIES (FORALL (U0_var: U0): p(U0_var));

  U0_well_founded: AXIOM strict_well_founded?[U0](<<);

  T0: TYPE

  U0: TYPE

  t?: [T0 -> boolean]

  T0_ord: [T0 -> upto(0)]

  ord(x: T0): [T0 -> upto(0)] = CASES x OF t: 0 ENDCASES

  subterm(x: T0, y: T0):  boolean = x = y;

  u?: [U0 -> boolean]

  U0_ord: [U0 -> upto(0)]

  ord(x: U0): [U0 -> upto(0)] = CASES x OF u: 0 ENDCASES

  subterm(x: U0, y: U0):  boolean = x = y;

  t: (t?)

  <<:  (strict_well_founded?[T0]) = LAMBDA (x, y: T0): FALSE;

  u: (u?)

  <<:  (strict_well_founded?[U0]) = LAMBDA (x, y: U0): FALSE;

  % Subtype TCC generated (at line 22, column 31) for  ==
      % expected type  equivalence[T0]
  relations_equality_TCC1: OBLIGATION equivalence?[T0](==);

  % Subtype TCC generated (at line 22, column 34) for  ==
      % expected type  equivalence[U0]
  relations_equality_TCC2: OBLIGATION equivalence?[U0](==);


body:
  simplest_examples: THEORY
  BEGIN
    IMPORTING singleton_example,
              finite_nats_trivial,
              infinite_to_infinite_trivial,
              finite_to_infinite,
              infinite_to_finite_finite_equival_finite_equival_classes,
              infinite_to_finite_infinite_equival_finite_equival_classes,
              infinite_to_infinite_infinite_equival_infinite_equival_classes,
              infinite_to_infinite_infinite_equival_finite_equival_classes,
              finite_to_infinite_finite_equival_infinite_equival_classes

  END simplest_examples


body:
  %--------------------------------------------------------------%
  %   Author: Dragan Stosic                                      %
  %--------------------------------------------------------------%

  relation_extension_props[T, U: TYPE+]: THEORY
   BEGIN
     IMPORTING relation_extension

   le_T: VAR equivalence[T]

   le_U: VAR equivalence[U]

   m, n: VAR [T, U] 

  % NON-EMPTY LEMMAS

   extended_equiv_class_non_empty: LEMMA
     nonempty?[[T,U]](extended_equiv_class(rel_extension(le_T, le_U))(m))

   nonempty_equivClass_impl_extended_equiv_class_non_empty: LEMMA
     nonempty?[T](EquivClass(le_T)(m`1))  IFF 
       nonempty?[[T,U]](extended_equiv_class(rel_extension(le_T, le_U))(m))

   nonempty_equivClass_iff_extended_equiv_classT_non_empty: LEMMA
     nonempty?[T](EquivClass(le_T)(m`1))  IFF 
       nonempty?[T](extended_equiv_classT(
        rel_extension(le_T, le_U),proj_tuple_1, m, m))

   nonempty_equivClass_iff_extended_equiv_classU_non_empty: LEMMA
     nonempty?[T](EquivClass(le_T)(m`1))  IFF 
       nonempty?[U](extended_equiv_classU(
        rel_extension(le_T, le_U),proj_tuple_2, m, m))

  % CLASS REPRESENTATIVE LEMMAS
    
   proj_tuple_1_equiv_class_representative: LEMMA
     m`1 = repEC_ext(le_T, le_U, m)`1 IMPLIES 
     le_T( proj_tuple_1(repEC_ext(le_T, le_U, m)), repEC(le_T)(m`1))
   
   proj_tuple_2_equiv_class_representative: LEMMA
     m`2 = repEC_ext(le_T, le_U, m)`2 IMPLIES 
     le_U( proj_tuple_2(repEC_ext(le_T, le_U, m)), repEC(le_U)(m`2));

   END relation_extension_props


body:
  top_refinement_relations: THEORY
  %------------------------------------------------------------------------------
  %
  % Theories, proofs and test:
  % Relation between domain partitioned with equivalence relation, 
  % codomain partitioned with equivalence relation and two functions: 
  % f [domain -> codomain] and g [codomain -> domain]
  %  
  %  Author:  Dragan Stosic
  %
  % In this work I have presented an approach ( aka abstract-algorithm
  % formal description ) how to obtain the transformation-relation based
  % on equivalence relations on domain and codomain and two functions: one
  % from domain to codomain and another from codomain to domain.  I named
  % this relation "refinement relation" from the following reason:

  % Short description:

  % Lets have two equivalence relations: le_T (on domain) and le_U (on
  % codomain) and two functions f [ domain - codomain ] and g[ codomain -
  % domain ].  If we pick an element t1 from the domain such that le_T(
  % t1, g(u1)) then f(t1) belongs to le_U(u2,f(t1)). According to the
  % properties of the equivalence relation instead of using f(t1) element
  % of the function f-image in some other calculus , we can substitute
  % that element with any other which belongs to the Equivalence Class
  % derived from the f(t1) element. In other words, we can refine f(t1)
  % with the class representative of the Equivalence Class(f(t1)).  We can
  % state : f(t1) refined with rep( EquivClass(f(t1)) ->
  % RR{(,)(,)...(t1,f(t1)),(t1,rep( EquivClass(f(t1))), (,)...}.

  % In other words: t1 can be either paired with the f(t1) or any element
  % that satisfied rep( EquivClass(f(t1))).

  % The same concept holds in the opposite direction: from codomain to
  % domain.

  % Note that : My intention is not to dive deep in the rewriting theory
  % and to explore equivalence relation as reduction. This work is not
  % related to the rewriting equivalence theory; this is refinement
  % between elements of collection within the equivalence class induced by
  % equivalence relation.
     
  % I have developed two different ways how to formalise the "refinement"
  % relation.  First approach is based on extended equivalence relation
  % while second approach is based on extended equivalence relation
  % induced by the inverse image of the equivalences relations
  % respectivelly ( f induces inverse image of le_U and g induces inverse
  % imagde of le_T ). Also I have established connection between those two
  % definitions of the refinement relations.

  % Finally, I have tested my conclusions through several simplest
  % examples theories.
  %------------------------------------------------------------------------------
  BEGIN

    IMPORTING relation_extension,
              relation_extension_props,
              relation_inverse_image,
              relation_inverse_extension,
              rr_rel,
              simplest_examples

  END top_refinement_relations


body:
  %--------------------------------------------------------------%
  %   Author: Dragan Stosic                                      %
  %--------------------------------------------------------------%

  relation_implication[T,U:TYPE+] :THEORY

  BEGIN
   
    R1,R2: VAR pred[[T,U]]

  % relational implication represent subrelation
    |-(R1,R2):bool = FORALL (t:T,u:U): R1(t,u) IMPLIES R2(t,u);
    
    |=(R1,R2) :bool = (R1 |- R2) AND (R2 |- R1)

    rel_impl_extensionality: LEMMA (R1 |- R2 ) IMPLIES 
       FORALL(t: T)(u: U): R1(t, u) IMPLIES R2(t, u) 

    lemma_double_impl: LEMMA ( |=(R1,R2) ) IMPLIES  
      FORALL(t:T,u:U): R1(t,u) IFF R2(t,u)

    rel_impl_is_partial_order: LEMMA partial_order?[pred[[T,U]]]( |- )
    
    double_impl_is_equivalence : LEMMA equivalence?[pred[[T,U]]]( |= )

    JUDGEMENT |- HAS_TYPE (partial_order?[pred[[T,U]]])

    JUDGEMENT |= HAS_TYPE (equivalence?[pred[[T,U]]])

    AUTO_REWRITE+ |-,|=

   END relation_implication

addendum:
  %%% ================ Addendum: generated declarations ================

  % Judgement subtype TCC generated (at line 26, column 12) for  |-
      % expected type  (partial_order?[pred[[T, U]]])
  turnstile_TCC1: OBLIGATION partial_order?[pred[[T, U]]](|-);

  % Judgement subtype TCC generated (at line 28, column 12) for  |=
      % expected type  (equivalence?[pred[[T, U]]])
  models_TCC1: OBLIGATION equivalence?[pred[[T, U]]](|=);


body:
  %--------------------------------------------------------------%
  %   Author: Dragan Stosic                                      %
  %--------------------------------------------------------------%

  relational_choice[T, U: TYPE+]: THEORY
   BEGIN
   IMPORTING relation_implication[T,U] 
    
    rel_unique_choice: bool =
        FORALL (R: pred[[T, U]]):
          (FORALL (t: T): EXISTS (u: U): R(t, u))
           IMPLIES
            (EXISTS (R1: pred[[T, U]]):
              (FORALL (t: T):
                 EXISTS (u: U):
                   R(t, u) AND
                     R1(t, u) AND (FORALL (u1: U): R1(t, u1) IMPLIES u = u1)))

    rel_choice: bool =
        FORALL (R: pred[[T, U]]):
          (FORALL (t: T): EXISTS (u: U): R(t, u)) IMPLIES
           (EXISTS (R1: pred[[T, U]]):
                (R1 |- R) AND
               (FORALL (t: T): EXISTS (u: U): R1(t, u)))

    conditional_relational_choice: bool =
        FORALL (P:pred[T])(R:pred[[T,U]]):
          (FORALL (t:T):P(t) IMPLIES  EXISTS (u:U): R(t,u))IMPLIES
             EXISTS (R1:pred[[T,U]]):
               (FORALL (t:T): P(t) IMPLIES
                  EXISTS (u:U): R(t,u) AND R1(t,u) AND 
                    (FORALL (u1:U): R1(t,u1) IMPLIES  u = u1))

    fun_choice: bool =
        FORALL (R: pred[[T, U]]):
          (FORALL (t: T): EXISTS (u: U): R(t, u)) IMPLIES
           (EXISTS (f:[T-> U]): (FORALL (t: T): R(t, f(t))))

    parametric_definite_description: bool =
        FORALL (R: pred[[T, U]]):
          (FORALL (t: T):
             EXISTS (u: U):
               R(t, u) AND (FORALL (u1: U): R(t, u1) IMPLIES u = u1))
                 IMPLIES 
                   (EXISTS (f:[T-> U]): FORALL (t: T): R(t, f(t)))

    proof_irrelevance: bool = FORALL (a1,a2:bool): a1 = a2

    independence_of_premises: bool =
       FORALL(P:pred[T])(Q:bool):
          (Q IMPLIES EXISTS(t:T):P(t)) IMPLIES 
             EXISTS(t:T): Q IMPLIES P(t)

    AUTO_REWRITE+ fun_choice, rel_unique_choice, 
                    parametric_definite_description,
                      independence_of_premises,proof_irrelevance,
                        conditional_relational_choice

   END relational_choice


body:
  %--------------------------------------------------------------%
  %   Author: Dragan Stosic                                      %
  %--------------------------------------------------------------%

  relational_choice_properties[T, U: TYPE+]: THEORY
   BEGIN

    IMPORTING relational_choice[T, U]

    fun_choice_impl_description: LEMMA fun_choice IMPLIES parametric_definite_description

    fun_choice_impl_rel_unique_choice: LEMMA fun_choice IMPLIES rel_unique_choice

    fun_choice_impl_rel_choice: LEMMA fun_choice IMPLIES rel_choice

    fun_choice_impl_rel_choice_impl_description_rel_choice: LEMMA
      fun_choice IMPLIES rel_choice IMPLIES parametric_definite_description

    fun_choice_impl_rel_choice_and_description_rel_choice: LEMMA
      fun_choice IMPLIES rel_choice AND parametric_definite_description

    fun_choice_impl_rel_unique_choice_impl_description_rel_choice: LEMMA
      fun_choice IMPLIES rel_unique_choice IMPLIES parametric_definite_description

    fun_choice_impl_rel_unique_choice_and_description_rel_choice: LEMMA
      fun_choice IMPLIES rel_unique_choice AND parametric_definite_description

    description_rel_unique_choice_imp_funct_choice: LEMMA
      parametric_definite_description IMPLIES rel_unique_choice IMPLIES fun_choice

    description_rel_and_rel_unique_choice_imp_funct_choice: LEMMA
      parametric_definite_description AND rel_unique_choice IMPLIES fun_choice

    rel_choice_and_proof_irrel_imp_guarded_rel_choice: LEMMA
      rel_unique_choice IMPLIES proof_irrelevance IMPLIES conditional_relational_choice

    relx_choice_indep_of_premises_imp_guarded_rel_choice: LEMMA
      rel_unique_choice IMPLIES independence_of_premises IMPLIES conditional_relational_choice

    fun_choice_equiv_rel_unique_param_desc: THEOREM
      fun_choice IFF rel_unique_choice AND parametric_definite_description

   END relational_choice_properties


body:
  top_choice_facts: THEORY
  %------------------------------------------------------------------------------
  %
  %  Theories and proofs: relational and functional choice facts 
  %    based on Axiom of Choice 
  %
  %  Author: Dragan Stosic
  %
  % Short description:
  %
  % Axiom of Choice, represent a statement in the language of set theory
  % that makes it possible to form sets by choosing an element
  % simultaneously from each member of an infinite collection of sets even
  % when no algorithm exists for the selection.  The axiom of choice has
  % many mathematically equivalent formulations, some of which were not
  % immediately realized to be equivalent.
  %
  % In this work I investigate the relations between the following choice
  % and description principles:
  %
  % rel_choice - Relational form of the (non extensional) axiom of choice
  % (a "set-theoretic" axiom of choice).  Relational choice can be used to
  % extract from a relation a sub-relation that describes a function, by
  % mapping every argument to a unique image.
  %
  % fun_choice - Functional form of the (non extensional) axiom of choice
  % (a "type-theoretic" axiom of choice).  This result can be used to
  % build a function from a relation that maps every input to at least one
  % output.
  %
  % rel_unique_choice - Unique relational form of the (non extensional)
  % axiom of choice (a "set-theoretic" axiom of choice)
  %
  % conditional_relational_choice - Conditional relational form of the
  % (non extensional) axiom of choice.
  %
  % parametric_definite_description - Functional Relation Reification
  % (known as Axiom of Unique Choice in topos theory; also called
  % principle of definite description.
  %
  % proof_irrelevance - as an identification treatment of all proofs of
  % the same proposition such that all proofs of the same proposition are
  % equal.
  %
  % Motivation and goal:
  %
  % In the PVS verification system ( based on classical logic ) I showed
  % that the functional formulation of the Axiom of Choice (usual
  % formulation in type theory) is equivalent to its relational
  % formulation (only formulation of set theory) plus parametric definite
  % description (aka Axiom of Unique Choice, or, Functional Relation
  % Reification ).  This shows that the axiom of choice can be assumed
  % (under its relational formulation) without known inconsistency with
  % classical logic, though parametric definite description conflicts with
  % classical logic.
  %------------------------------------------------------------------------------
  BEGIN
    IMPORTING relational_choice, 
              relational_choice_properties,
              relation_implication
  END top_choice_facts


body:
  cantor_bernstein_schroeder[A,B:Type]: THEORY

  % A proof of the Cantor-Bernstein-Schroeder Theorem
  % for sets
  %
  % Author: Anthony Narkawicz  April 2012

  BEGIN

    f : VAR [A->B]
    g : VAR [B->A]
    hab : VAR [A->B]
    hba : VAR [B->A]

    preim_B?(f)(b:B): bool = EXISTS (a:A): f(a) = b
    preim_A?(g)(a:A): bool = EXISTS (b:B): g(b) = a

    Afun(f,g)(a:A)(i:nat): RECURSIVE [A,B] =
      IF i = 0 THEN (a,f(a))
      ELSE LET bo = Afun(f,g)(a)(i-1)`2 IN
           (g(bo),f(g(bo)))
      ENDIF MEASURE i

    Afundef: LEMMA FORALL (i:nat,aa:A): LET (a,b) = Afun(f,g)(aa)(i) IN
      f(a) = b

    Afundef2: LEMMA FORALL (i:nat,a:A):
      g(Afun(f,g)(a)(i)`2) = Afun(f,g)(a)(i+1)`1

    Afuncomp: LEMMA FORALL (i,j:nat,a:A):
      Afun(f,g)(Afun(f,g)(a)(i)`1)(j) = Afun(f,g)(a)(i+j)

    Afuneq: LEMMA FORALL (i,j:nat,a1,a2:A):
      injective?(f) AND injective?(g) AND
      (Afun(f,g)(a1)(i)`1 = Afun(f,g)(a2)(j)`1 OR
       Afun(f,g)(a1)(i)`2 = Afun(f,g)(a2)(j)`2)
      IMPLIES
      FORALL (k:nat): k<=i AND k<=j IMPLIES
       Afun(f,g)(a1)(i-k) = Afun(f,g)(a2)(j-k)

    Bfun(f,g)(b:B)(i:nat): RECURSIVE [A,B] =
      IF i = 0 THEN 
        IF (EXISTS (a:A): f(a) = b)
        THEN LET a = choose({aa:A|f(aa)=b}) IN (a,b)
        ELSE (g(b),b) ENDIF
      ELSE LET bo = Bfun(f,g)(b)(i-1)`2 IN
           (g(bo),f(g(bo)))
      ENDIF MEASURE i

    Bfundef: LEMMA FORALL (b:B,i:nat):
      g(Bfun(f,g)(b)(i)`2) = Bfun(f,g)(b)(i+1)`1

    Bfundef2: LEMMA FORALL (b:B,i:posnat):
      f(Bfun(f,g)(b)(i)`1) = Bfun(f,g)(b)(i)`2

    Bfuneq: LEMMA FORALL (i,j:nat,b:B):
      injective?(f) AND injective?(g) AND
      (Bfun(f,g)(b)(i)`1 = Bfun(f,g)(b)(j)`1 OR
       Bfun(f,g)(b)(i)`2 = Bfun(f,g)(b)(j)`2)
      IMPLIES
      FORALL (k:nat): k<i AND k<j IMPLIES
       Bfun(f,g)(b)(i-k) = Bfun(f,g)(b)(j-k)

    ABfun: LEMMA FORALL (a:A,i:posnat):
      Afun(f,g)(a)(i) = Bfun(f,g)(f(a))(i)

    BAfun: LEMMA FORALL (b:B,i:nat):
      Bfun(f,g)(b)(i+1) = Afun(f,g)(g(b))(i)

    ABfuneq: LEMMA FORALL (i,j:nat,b:B,a:A):
      injective?(f) AND injective?(g) AND
      (Bfun(f,g)(b)(i)`1 = Afun(f,g)(a)(j)`1 OR
       Bfun(f,g)(b)(i)`2 = Afun(f,g)(a)(j)`2)
      IMPLIES
      FORALL (k:nat): k<i AND k<=j IMPLIES
       Bfun(f,g)(b)(i-k) = Afun(f,g)(a)(j-k)

    ABrel(f,g)(a:A)(b:B): bool = 
      (EXISTS (i:nat): b = Afun(f,g)(a)(i)`2)
      OR
      (EXISTS (i:nat): a = Bfun(f,g)(b)(i)`1)

    BArel(f,g)(b:B)(a:A): bool = ABrel(f,g)(a)(b)

    Arel(f,g)(a1:A)(a2:A): bool =
      (EXISTS (i:nat): a1 = Afun(f,g)(a2)(i)`1)
      OR
      (EXISTS (i:nat): a2 = Afun(f,g)(a1)(i)`1)

    Brel(f,g)(b1:B)(b2:B): bool =
      (EXISTS (i:nat): b1 = Bfun(f,g)(b2)(i)`2)
      OR
      (EXISTS (i:nat): b2 = Bfun(f,g)(b1)(i)`2)

    % --------------------------- %
    %    If b has no preimage     %
    % --------------------------- %

    ABrel_Arel_equiv: LEMMA FORALL (b:B,a,aa:A):
      (NOT preim_B?(f)(b)) AND ABrel(f,g)(a)(b) AND
      Arel(f,g)(a)(aa) AND injective?(f) AND 
      injective?(g) IMPLIES ABrel(f,g)(aa)(b)

    ABrel_Brel_equiv: LEMMA FORALL (b,bb:B,a:A):
      (NOT preim_B?(f)(b)) AND ABrel(f,g)(a)(b) AND
      Brel(f,g)(b)(bb) AND injective?(f) AND 
      injective?(g) IMPLIES BArel(f,g)(bb)(a)

    Brel_Arel: LEMMA FORALL (b,bb:B):
      injective?(g) IMPLIES
      (Brel(f,g)(b)(bb) IFF Arel(f,g)(g(b))(g(bb)))

    Arel_Brel: LEMMA FORALL (a,aa:A):
      injective?(f) IMPLIES
      (Arel(f,g)(a)(aa) = Brel(f,g)(f(a))(f(aa)))

    ABrel_Brel: LEMMA FORALL (b:B,a:A):
      injective?(f) AND injective?(g) IMPLIES
      (ABrel(f,g)(a)(b) IFF Brel(f,g)(f(a))(b))

    % --------------------------- %

    Afununique: LEMMA FORALL (a1,a2:A,i,j:nat):
      injective?(f) AND injective?(g) AND
      Afun(f,g)(a1)(i) = Afun(f,g)(a2)(j) IMPLIES
      Arel(f,g)(a1)(a2)

    af_fun(f,g)(a:A): [(Arel(f,g)(a)) -> (ABrel(f,g)(a))] = (LAMBDA (an:(Arel(f,g)(a))): f(an))

    ag_fun(f,g)(a:A): [(ABrel(f,g)(a)) -> (Arel(f,g)(a))] = (LAMBDA (bn:(ABrel(f,g)(a))): g(bn))

    aginj: LEMMA FORALL (a:A):
    	   injective?(g) AND injective?(f)
  	   IMPLIES bijective?(ag_fun(f,g)(a))
  	   	   OR
  		   bijective?(af_fun(f,g)(a))

    Arel_union: LEMMA FORALL (a:A): EXISTS (aa:A): Arel(f,g)(aa)(a)

    Arel_disjoint: LEMMA FORALL (a1,a2,a:A): Arel(f,g)(a1)(a) AND Arel(f,g)(a2)(a) AND injective?(g) AND injective?(f)
      IMPLIES Arel(f,g)(a1) = Arel(f,g)(a2)

    Brel_disjoint: LEMMA FORALL (b1,b2,b:B): Brel(f,g)(b1)(b) AND Brel(f,g)(b2)(b) AND injective?(g) AND injective?(f) IMPLIES
     Brel(f,g)(b1) = Brel(f,g)(b2)

    ABrel_union: LEMMA FORALL (b:B): EXISTS (a:A): ABrel(f,g)(a)(b)

    ABrel_disjoint: LEMMA FORALL (a1,a2:A,b:B): ABrel(f,g)(a1)(b) AND ABrel(f,g)(a2)(b) AND injective?(g) AND injective?(f)
      IMPLIES ABrel(f,g)(a1) = ABrel(f,g)(a2)

    Cantor_Bernstein_Schroeder: LEMMA
      injective?(f) AND
      injective?(g) IMPLIES
      EXISTS (hab): bijective?(hab)

  END cantor_bernstein_schroeder

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 20, column 31) for  i - 1
      % expected type  nat
  Afun_TCC1: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], a: A, i: nat):
      NOT i = 0 IMPLIES i - 1 >= 0;

  % Termination TCC generated (at line 20, column 18) for
      % Afun(f, g)(a)(i - 1)
  Afun_TCC2: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], a: A, i: nat):
      NOT i = 0 IMPLIES i - 1 < i;

  % Subtype TCC generated (at line 39, column 19) for  i - k
      % expected type  nat
  Afuneq_TCC1: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], i, j: nat, a1, a2: A):
      injective?(f) AND
       injective?(g) AND
        (Afun(f, g)(a1)(i)`1 = Afun(f, g)(a2)(j)`1 OR
          Afun(f, g)(a1)(i)`2 = Afun(f, g)(a2)(j)`2)
       IMPLIES (FORALL (k: nat): k <= i AND k <= j IMPLIES i - k >= 0);

  % Subtype TCC generated (at line 39, column 40) for  j - k
      % expected type  nat
  Afuneq_TCC2: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], i, j: nat, a1, a2: A):
      injective?(f) AND
       injective?(g) AND
        (Afun(f, g)(a1)(i)`1 = Afun(f, g)(a2)(j)`1 OR
          Afun(f, g)(a1)(i)`2 = Afun(f, g)(a2)(j)`2)
       IMPLIES (FORALL (k: nat): k <= i AND k <= j IMPLIES j - k >= 0);

  % Subtype TCC generated (at line 44, column 26) for  {aa: A | f(aa) = b}
      % expected type  p: (nonempty?[A])
  Bfun_TCC1: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], b: B, i: nat):
      (EXISTS (a: A): f(a) = b) AND i = 0 IMPLIES
       nonempty?[A]({aa: A | f(aa) = b});

  % Subtype TCC generated (at line 46, column 31) for  i - 1
      % expected type  nat
  Bfun_TCC2: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], b: B, i: nat):
      NOT i = 0 IMPLIES i - 1 >= 0;

  % Termination TCC generated (at line 46, column 18) for
      % Bfun(f, g)(b)(i - 1)
  Bfun_TCC3: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], b: B, i: nat):
      NOT i = 0 IMPLIES i - 1 < i;

  % Subtype TCC generated (at line 62, column 18) for  i - k
      % expected type  nat
  Bfuneq_TCC1: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], i, j: nat, b: B):
      injective?(f) AND
       injective?(g) AND
        (Bfun(f, g)(b)(i)`1 = Bfun(f, g)(b)(j)`1 OR
          Bfun(f, g)(b)(i)`2 = Bfun(f, g)(b)(j)`2)
       IMPLIES (FORALL (k: nat): k < i AND k < j IMPLIES i - k >= 0);

  % Subtype TCC generated (at line 62, column 38) for  j - k
      % expected type  nat
  Bfuneq_TCC2: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], i, j: nat, b: B):
      injective?(f) AND
       injective?(g) AND
        (Bfun(f, g)(b)(i)`1 = Bfun(f, g)(b)(j)`1 OR
          Bfun(f, g)(b)(i)`2 = Bfun(f, g)(b)(j)`2)
       IMPLIES (FORALL (k: nat): k < i AND k < j IMPLIES j - k >= 0);

  % Subtype TCC generated (at line 76, column 18) for  i - k
      % expected type  nat
  ABfuneq_TCC1: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], i, j: nat, b: B, a: A):
      injective?(f) AND
       injective?(g) AND
        (Bfun(f, g)(b)(i)`1 = Afun(f, g)(a)(j)`1 OR
          Bfun(f, g)(b)(i)`2 = Afun(f, g)(a)(j)`2)
       IMPLIES (FORALL (k: nat): k < i AND k <= j IMPLIES i - k >= 0);

  % Subtype TCC generated (at line 76, column 38) for  j - k
      % expected type  nat
  ABfuneq_TCC2: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], i, j: nat, b: B, a: A):
      injective?(f) AND
       injective?(g) AND
        (Bfun(f, g)(b)(i)`1 = Afun(f, g)(a)(j)`1 OR
          Bfun(f, g)(b)(i)`2 = Afun(f, g)(a)(j)`2)
       IMPLIES (FORALL (k: nat): k < i AND k <= j IMPLIES j - k >= 0);

  % Subtype TCC generated (at line 128, column 87) for  f(an)
      % expected type  (ABrel(f, g)(a))
  af_fun_TCC1: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], a: A, an: (Arel(f, g)(a))):
      ABrel(f, g)(a)(f(an));

  % Subtype TCC generated (at line 130, column 88) for  g(bn)
      % expected type  (Arel(f, g)(a))
  ag_fun_TCC1: OBLIGATION
    FORALL (f: [A -> B], g: [B -> A], a: A, bn: (ABrel(f, g)(a))):
      Arel(f, g)(a)(g(bn));


body:
  %-------------------------------------------------------------------------
  %
  %  This is the same as card_comp, but made to compare cardinalities of
  %  sets rather than types.  See card_comp.pvs for a discussion.
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  sets_aux: card_comp_set[T1,T2]
  %
  %-------------------------------------------------------------------------
  card_comp_set[T1: TYPE, T2: TYPE]: THEORY
   BEGIN

    S1: VAR set[T1]
    S2: VAR set[T2]

    card_lt(S1, S2): bool = NOT (EXISTS (f: [(S2) -> (S1)]): injective?(f))

    card_le(S1, S2): bool = EXISTS (f: [(S1) -> (S2)]): injective?(f)

    card_eq(S1, S2): bool = EXISTS (f: [(S1) -> (S2)]): bijective?(f)

    card_ge(S1, S2): bool = EXISTS (f: [(S2) -> (S1)]): injective?(f)

    card_gt(S1, S2): bool = NOT (EXISTS (f: [(S1) -> (S2)]): injective?(f))

   END card_comp_set


body:
  %-------------------------------------------------------------------------
  %
  %  Basic properties of the set cardinality comparison functions
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  sets_aux: card_comp_set[T1,T2], card_comp_set[T2,T1],
  %    card_comp_set_props[T1,T2]
  %
  %-------------------------------------------------------------------------
  card_comp_set_props[T1: TYPE, T2: TYPE]: THEORY

   EXPORTING ALL WITH card_comp_set[T1, T2], card_comp_set[T2, T1]

   BEGIN

    IMPORTING card_comp_set[T1, T2], card_comp_set[T2, T1]

    % The following imports are for the proofs only
    IMPORTING orders@set_dichotomous, orders@set_antisymmetric

    S1: VAR set[T1]
    S2: VAR set[T2]


    % ==========================================================================
    % We defined card_lt and card_ge as we did to avoid special casing empty
    % sets, which these results show would be necessary.
    % ==========================================================================

    card_lt_surj: LEMMA
      FORALL S1, S2:
        card_lt(S1, S2) IFF
         (EXISTS (t: (S2)): TRUE) AND
          NOT (EXISTS (f: [(S1) -> (S2)]): surjective?(f))

    card_ge_surj: LEMMA
      FORALL S1, S2:
        card_ge(S1, S2) IFF
         ((EXISTS (t: (S1)): TRUE) AND (FORALL (t: (S2)): FALSE)) OR
          (EXISTS (f: [(S1) -> (S2)]): surjective?(f))


    % ==========================================================================
    % The relationships of the functions
    % ==========================================================================

    card_lt_le: LEMMA FORALL S1, S2: card_lt(S1, S2) => card_le(S1, S2)
    card_gt_ge: LEMMA FORALL S1, S2: card_gt(S1, S2) => card_ge(S1, S2)

    card_lt_gt: LEMMA FORALL S1, S2: card_lt(S1, S2) = card_gt(S2, S1)
    card_le_ge: LEMMA FORALL S1, S2: card_le(S1, S2) = card_ge(S2, S1)
    card_gt_lt: LEMMA FORALL S1, S2: card_gt(S1, S2) = card_lt(S2, S1)
    card_ge_le: LEMMA FORALL S1, S2: card_ge(S1, S2) = card_le(S2, S1)

    card_lt_ge: LEMMA FORALL S1, S2: card_lt(S1, S2) XOR card_ge(S1, S2)
    card_le_gt: LEMMA FORALL S1, S2: card_le(S1, S2) XOR card_gt(S1, S2)

    card_eq_le_ge: LEMMA
      FORALL S1, S2: card_eq(S1, S2) IFF card_le(S1, S2) AND card_ge(S1, S2)
    card_le_lt_eq: LEMMA
      FORALL S1, S2: card_le(S1, S2) IFF card_lt(S1, S2) OR card_eq(S1, S2)
    card_ge_gt_eq: LEMMA
      FORALL S1, S2: card_ge(S1, S2) IFF card_gt(S1, S2) OR card_eq(S1, S2)

    card_lt_neq_ngt: LEMMA
      FORALL S1, S2:
        card_lt(S1, S2) => NOT card_eq(S1, S2) AND NOT card_gt(S1, S2)
    card_gt_neq_nlt: LEMMA
      FORALL S1, S2:
        card_gt(S1, S2) => NOT card_eq(S1, S2) AND NOT card_lt(S1, S2)


    % ==========================================================================
    % (anti)commutativity and (anti)symmetry of the functions
    % ==========================================================================

    card_lt_anticommutative: LEMMA
      FORALL S1, S2: card_lt(S1, S2) => NOT card_lt(S2, S1)

    card_le_antisymmetric: LEMMA
      FORALL S1, S2: card_le(S1, S2) AND card_le(S2, S1) => card_eq(S1, S2)

    card_eq_symmetric: LEMMA FORALL S1, S2: card_eq(S1, S2) = card_eq(S2, S1)

    card_ge_antisymmetric: LEMMA
      FORALL S1, S2: card_ge(S1, S2) AND card_ge(S2, S1) => card_eq(S1, S2)

    card_gt_anticommutative: LEMMA
      FORALL S1, S2: card_gt(S1, S2) => NOT card_gt(S2, S1)


    % ==========================================================================
    % dichotomy and trichotomy of the functions
    % ==========================================================================

    card_lt_trichotomous: LEMMA
      FORALL S1, S2: card_lt(S1, S2) OR card_lt(S2, S1) OR card_eq(S1, S2)

    card_le_dichotomous: LEMMA
      FORALL S1, S2: card_le(S1, S2) OR card_le(S2, S1)

    card_ge_dichotomous: LEMMA
      FORALL S1, S2: card_ge(S1, S2) OR card_ge(S2, S1)

    card_gt_trichotomous: LEMMA
      FORALL S1, S2: card_gt(S1, S2) OR card_gt(S2, S1) OR card_eq(S1, S2)

   END card_comp_set_props


body:
  %------------------------------------------------------------------------------
  % infinite IFF injective map from the naturals.
  %
  %     Author: David Lester, Manchester University
  %
  %     Version 1.0            2/1/05
  %     Version 1.1           25/6/09 Dependency on other libraries removed
  %------------------------------------------------------------------------------

  infinite_nat_def[T:TYPE]: THEORY

  BEGIN

    S,X: VAR set[T]

    infinite_def: THEOREM
          is_infinite(X) IFF (EXISTS (f:(injective?[nat,(X)])): TRUE)

    infinite_def2: LEMMA 
          is_infinite(S) IFF (EXISTS (f:(surjective?[(S),nat])): TRUE)

  END infinite_nat_def


body:
  %-------------------------------------------------------------------------
  %
  %  Countable sets, and a recharacterization of infinite sets based on
  %  the definition of countability.
  %
  %  For PVS version 3.2.  March 1, 2005
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: infinite_sets_def[T]
  %  sets_aux: card_comp_set[nat,T], card_comp_set[T,nat],
  %    card_comp_set_props[T,nat], countability[T]
  %
  %-------------------------------------------------------------------------
  countability[T: TYPE]: THEORY
   BEGIN

    IMPORTING infinite_sets_def[T]
    IMPORTING orders@integer_enumerations[nat] % Proofs only

    S: VAR set[T]

    % ==========================================================================
    % Basic definitions
    % ==========================================================================

    is_countable(S): bool = EXISTS (f: (injective?[(S), nat])): TRUE
    is_countably_infinite(S): bool = EXISTS (f: (bijective?[(S), nat])): TRUE
    is_uncountable(S): MACRO bool = NOT is_countable(S)

    countable_set: TYPE+ = (is_countable) CONTAINING emptyset[T]
    countably_infinite_set: TYPE = (is_countably_infinite)
    uncountable_set: TYPE = (is_uncountable)

    countably_infinite_countable: JUDGEMENT
      countably_infinite_set SUBTYPE_OF countable_set


    % ==========================================================================
    % Infinite subsets of a countably infinite set are countably infinite
    % ==========================================================================

    countably_infinite_subset: THEOREM
      FORALL (CountInf: countably_infinite_set), (Inf: infinite_set[T]):
        subset?(Inf, CountInf) IMPLIES is_countably_infinite(Inf)

    countable_subset: THEOREM
      FORALL S, (Count: countable_set):
        subset?(S, Count) IMPLIES is_countable(S)


    % ==========================================================================
    % Countability of the base type
    % ==========================================================================

    is_countable_type: bool = EXISTS (f: (injective?[T, nat])): TRUE
    is_countably_infinite_type: bool = EXISTS (f: (bijective?[T, nat])): TRUE
    is_uncountable_type: MACRO bool = NOT is_countable_type

    countable_type_is_countably_infinite: LEMMA
      is_countably_infinite_type IMPLIES is_countable_type

    countable_full: LEMMA is_countable_type IFF is_countable(fullset[T])
    countably_infinite_full: LEMMA
      is_countably_infinite_type IFF is_countably_infinite(fullset[T])
    uncountable_full: COROLLARY
      is_uncountable_type IFF is_uncountable(fullset[T])

    countable_type_set: LEMMA
      is_countable_type IMPLIES (FORALL S: is_countable(S))
    countably_infinite_type_set: LEMMA
      is_countably_infinite_type IMPLIES (FORALL S: is_countable(S))
    uncountably_infinite_type_set: LEMMA
      (EXISTS S: is_uncountable(S)) IMPLIES is_uncountable_type

    countable_complement: LEMMA
      is_countable_type IMPLIES (FORALL S: is_countable(complement(S)))
    countably_infinite_complement: LEMMA
      is_countably_infinite_type IMPLIES (FORALL S: is_countable(complement(S)))

   END countability

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 33, column 51) for  emptyset[T]
      % expected type  countable_set
  countable_set_TCC1: OBLIGATION is_countable(emptyset[T]);

  % Judgement subtype TCC generated (at line 38, column 4) for  x
      % expected type  countable_set
  countably_infinite_countable: OBLIGATION
    FORALL (x: countably_infinite_set): is_countable(x);


body:
  %-------------------------------------------------------------------------
  %
  %  Properties of countable (and uncountable) sets.
  %
  %  For PVS version 3.2.  February 9, 2005
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %              David Lester, Manchester University 
  %
  %  1.1:		Modified for PVS 4.2 (EXPORTs removed, IMPORTS restricted)
  %-------------------------------------------------------------------------
  countable_props[T: TYPE]: THEORY

  BEGIN

    IMPORTING countability[T], finite_sets[T]

    % These imports are just for the proofs
    IMPORTING infinite_nat_def[T]

    t: VAR T
    S, R, Q: VAR set[T]
    Fin: VAR finite_set[T]
    Inf: VAR infinite_set[T]
    A,Count, Count1, Count2: VAR countable_set[T]
    CountInf, CountInf1, CountInf2: VAR countably_infinite_set[T]
    Uncount: VAR uncountable_set[T]

    % Countably infinite sets are infinite
    infinite_countably_infinite: JUDGEMENT
      countably_infinite_set[T] SUBTYPE_OF infinite_set[T]

    countably_infinite_is_nonempty: JUDGEMENT
      countably_infinite_set SUBTYPE_OF (nonempty?[T])

    %%% Set operations on countable sets
    countably_infinite_add: JUDGEMENT
      add(t, CountInf) HAS_TYPE countably_infinite_set[T]
    countable_add: JUDGEMENT add(t, Count) HAS_TYPE countable_set[T]

    countably_infinite_remove: JUDGEMENT
      remove(t, CountInf) HAS_TYPE countably_infinite_set[T]
    countable_remove: JUDGEMENT remove(t, Count) HAS_TYPE countable_set[T]

    countably_infinite_rest: JUDGEMENT
      rest(CountInf) HAS_TYPE countably_infinite_set[T]
    countable_rest: JUDGEMENT rest(Count) HAS_TYPE countable_set[T]

    countable_intersection1: JUDGEMENT
      intersection(Count, S) HAS_TYPE countable_set[T]
    countable_intersection2: JUDGEMENT
      intersection(S, Count) HAS_TYPE countable_set[T]

    countably_infinite_difference: JUDGEMENT
      difference(CountInf, Fin) HAS_TYPE countably_infinite_set[T]
    countable_difference: JUDGEMENT
      difference(Count, S) HAS_TYPE countable_set[T]

    finite_countable: JUDGEMENT finite_set[T] SUBTYPE_OF countable_set[T]

    %%% Uncountable sets
    % Uncountable sets are infinite
    infinite_uncountable: JUDGEMENT
      uncountable_set[T] SUBTYPE_OF infinite_set[T]

    % Every infinite set has a countably infinite subset
    countably_infinite_subset_exists: THEOREM
      FORALL Inf: EXISTS CountInf: subset?(CountInf, Inf)

    % Every infinite set has a countably infinite proper subset
    countably_infinite_strict_subset_exists: THEOREM
      FORALL Inf: EXISTS CountInf: strict_subset?(CountInf, Inf)

    %%% Countable sets
    % Countable sets are finite or countably infinite
    countable_card: COROLLARY
      is_countable(S) IFF is_finite(S) OR is_countably_infinite(S)

    countably_infinite_union1: JUDGEMENT
      union(CountInf, Count) HAS_TYPE countably_infinite_set[T]
    countably_infinite_union2: JUDGEMENT
      union(Count, CountInf) HAS_TYPE countably_infinite_set[T]
    countable_union: JUDGEMENT union(Count1, Count2) HAS_TYPE countable_set[T]

    countably_infinite_def: LEMMA
      is_countably_infinite(S) IFF is_countable(S) AND is_infinite(S)

    countable_emptyset:      LEMMA is_countable(emptyset[T])
    countable_singleton:     LEMMA is_countable(singleton(t))

  % --------------- The following added back by Rick Butler ---------------


    IMPORTING card_comp_set_props[T, T], card_comp_set_props[T, nat]

    %%% Uncountable sets
    % Uncountable sets are infinite
    infinite_uncountable: JUDGEMENT
      uncountable_set[T] SUBTYPE_OF infinite_set[T]

    %%% cardinality properties of finite/countable/uncountable sets
    card_le_finite: THEOREM
      FORALL S, Fin: card_le(S, Fin) IMPLIES is_finite(S)

    card_ge_infinite: THEOREM
      FORALL S, Inf: card_ge(S, Inf) IMPLIES is_infinite(S)

    card_eq_countably_infinite: THEOREM
      FORALL S, CountInf:
        card_eq(S, CountInf) IMPLIES is_countably_infinite(S)

    card_le_countable: COROLLARY
      FORALL S, Count: card_le(S, Count) IMPLIES is_countable(S)

    card_ge_uncountable: COROLLARY
      FORALL S, Uncount: card_ge(S, Uncount) IMPLIES is_uncountable(S)

    %%% Adding and removing countable pieces from infinite sets
    countably_infinite_subset_union: LEMMA
      FORALL Q, R, S:
        subset?(Q, S) AND
         disjoint?(S, R) AND
          is_countably_infinite(R) AND is_countably_infinite(Q)
         IMPLIES card_eq(S, union(S, R))

    countable_finite_subset_union: LEMMA
      FORALL Q, R, S:
        subset?(Q, S) AND
         disjoint?(S, R) AND is_finite(R) AND is_countably_infinite(Q)
         IMPLIES card_eq(S, union(S, R))

    infinite_countable_union: THEOREM
      FORALL Inf, Count: card_eq(Inf, union(Inf, Count))

    infinite_countable_difference: THEOREM
      FORALL S, Count:
        is_finite(difference(S, Count)) OR card_eq(S, difference(S, Count))  





  END countable_props

addendum:
  %%% ================ Addendum: generated declarations ================

  % Judgement subtype TCC generated (at line 31, column 4) for  x
      % expected type  infinite_set[T]
  infinite_countably_infinite: OBLIGATION
    FORALL (x: countably_infinite_set[T]): NOT is_finite[T](x);

  % Judgement subtype TCC generated (at line 38, column 4) for
      % add(t, CountInf)
      % expected type  countably_infinite_set
  countably_infinite_add: OBLIGATION
    FORALL (CountInf, t): is_countably_infinite[T](add[T](t, CountInf));

  % Judgement subtype TCC generated (at line 39, column 27) for  add(t, Count)
      % expected type  countable_set[T]
  countable_add: OBLIGATION
    FORALL (Count, t): is_countable[T](add[T](t, Count));

  % Judgement subtype TCC generated (at line 42, column 4) for
      % remove(t, CountInf)
      % expected type  countably_infinite_set
  countably_infinite_remove: OBLIGATION
    FORALL (CountInf, t): is_countably_infinite[T](remove[T](t, CountInf));

  % Judgement subtype TCC generated (at line 43, column 30) for
      % remove(t, Count)
      % expected type  countable_set[T]
  countable_remove: OBLIGATION
    FORALL (Count, t): is_countable[T](remove[T](t, Count));

  % Judgement subtype TCC generated (at line 46, column 4) for  rest(CountInf)
      % expected type  countably_infinite_set
  countably_infinite_rest: OBLIGATION
    FORALL (CountInf): is_countably_infinite[T](rest[T](CountInf));

  % Judgement subtype TCC generated (at line 47, column 28) for  rest(Count)
      % expected type  countable_set[T]
  countable_rest: OBLIGATION FORALL (Count): is_countable[T](rest[T](Count));

  % Judgement subtype TCC generated (at line 50, column 4) for
      % intersection(Count, S)
      % expected type  countable_set[T]
  countable_intersection1: OBLIGATION
    FORALL (Count, S): is_countable[T](intersection[T](Count, S));

  % Judgement subtype TCC generated (at line 52, column 4) for
      % intersection(S, Count)
      % expected type  countable_set[T]
  countable_intersection2: OBLIGATION
    FORALL (Count, S): is_countable[T](intersection[T](S, Count));

  % Judgement subtype TCC generated (at line 55, column 4) for
      % difference(CountInf, Fin)
      % expected type  countably_infinite_set
  countably_infinite_difference: OBLIGATION
    FORALL (CountInf, Fin):
      is_countably_infinite[T](difference[T](CountInf, Fin));

  % Judgement subtype TCC generated (at line 57, column 4) for
      % difference(Count, S)
      % expected type  countable_set[T]
  countable_difference: OBLIGATION
    FORALL (Count, S): is_countable[T](difference[T](Count, S));

  % Judgement subtype TCC generated (at line 59, column 30) for  x
      % expected type  countable_set[T]
  finite_countable: OBLIGATION FORALL (x: finite_set[T]): is_countable[T](x);

  % Judgement subtype TCC generated (at line 64, column 4) for  x
      % expected type  infinite_set[T]
  infinite_uncountable: OBLIGATION
    FORALL (x: uncountable_set[T]): NOT is_finite[T](x);

  % Judgement subtype TCC generated (at line 80, column 4) for
      % union(CountInf, Count)
      % expected type  countably_infinite_set
  countably_infinite_union1: OBLIGATION
    FORALL (Count, CountInf):
      is_countably_infinite[T](union[T](CountInf, Count));

  % Judgement subtype TCC generated (at line 82, column 4) for
      % union(Count, CountInf)
      % expected type  countably_infinite_set
  countably_infinite_union2: OBLIGATION
    FORALL (Count, CountInf):
      is_countably_infinite[T](union[T](Count, CountInf));

  % Judgement subtype TCC generated (at line 83, column 29) for
      % union(Count1, Count2)
      % expected type  countable_set[T]
  countable_union: OBLIGATION
    FORALL (Count1, Count2): is_countable[T](union[T](Count1, Count2));


body:
  %------------------------------------------------------------------------------
  % Extras for countability. Somewhere in sets_aux.
  %
  %  MODIFICATIONS:
  %
  %     Author: David Lester, Manchester University 12/12/07
  %
  %------------------------------------------------------------------------------
  countability_aux[T:TYPE]: THEORY

  BEGIN

    IMPORTING countability[T],
              countable_props[T]

    t:     VAR T
    S:     VAR set[T]
    A,X,Y: VAR (is_countable)

    countably_infinite_is_nonempty: JUDGEMENT
      countably_infinite_set SUBTYPE_OF (nonempty?[T])

    countably_infinite_is_infinite: JUDGEMENT
      countably_infinite_set SUBTYPE_OF (is_infinite[T])

    countable_emptyset:      LEMMA is_countable(emptyset[T])
    countable_singleton:     LEMMA is_countable(singleton(t))
    countable_add:           LEMMA is_countable(add(t,X))
    countable_remove:        LEMMA is_countable(remove(t,X))
    countable_intersection1: LEMMA is_countable(intersection(X,S))
    countable_intersection2: LEMMA is_countable(intersection(S,X))
    countable_difference:    LEMMA is_countable(difference(X,S))

  END countability_aux


body:
  %------------------------------------------------------------------------------
  % inverse_image_Union
  %
  %     Author: David Lester, Manchester University
  %
  %     Version 1.0            14/06/09  Initial Version
  %------------------------------------------------------------------------------
  inverse_image_Union[S,T:TYPE]: THEORY

  BEGIN

    f: VAR [S->T]
    y: VAR set[S]
    X: VAR setofsets[T]

    inverse_image_Union: LEMMA inverse_image(f,Union(X)) =
                               Union({y | EXISTS (x:(X)): y=inverse_image(f,x)})

  END inverse_image_Union


body:
  %------------------------------------------------------------------------------
  % Indexed Set properties
  %
  %     Author: David Lester, Manchester University
  %
  %     Version 1.0            14/06/09  Initial Version
  %------------------------------------------------------------------------------
  indexed_sets_aux[index, T: TYPE]: THEORY

  BEGIN

    i,j: VAR index
    x:   VAR T
    A,B: VAR [index -> set[T]]
    S:   VAR set[T]

    disjoint?(A):bool = FORALL i,j: i /= j IMPLIES disjoint?(A(i),A(j))

    disjoint_indexed_set: TYPE+ = (disjoint?) CONTAINING (LAMBDA i: emptyset[T])

    IComplement(A)(i): set[T] = complement(A(i))

    IComplement_IComplement: LEMMA IComplement(IComplement(A)) = A

    IDemorgan1: LEMMA complement(IUnion(A)) = IIntersection(IComplement(A))
    IDemorgan2: LEMMA complement(IIntersection(A)) = IUnion(IComplement(A))

  END indexed_sets_aux

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 19, column 56) for  (LAMBDA i: emptyset[T])
      % expected type  disjoint_indexed_set
  disjoint_indexed_set_TCC1: OBLIGATION disjoint?((LAMBDA i: emptyset[T]));


body:
  %------------------------------------------------------------------------------
  % Indexed sets over nat
  %
  %     Author: David Lester, Manchester University
  %
  %     Version 1.0            14/06/09  Initial Version
  %
  % A new operation (along with the recurrence relations) is introduced:
  %
  %   IUnion(n,A) = A_0 u A_1 u ... u A_n
  %
  % We also show how to turn an indexed set into an increasing one
  % with the same IUnion, or a decreasing one, with the same IIntersection.
  %
  % Finally, we show that there's a disjoint Union available.
  %------------------------------------------------------------------------------
  nat_indexed_sets[T: TYPE]: THEORY

  BEGIN

    IMPORTING structures@fun_preds_partial[nat,set[T],reals.<=,subset?[T]],
              indexed_sets_aux[nat,T]

    n,i: VAR nat
    A,B: VAR sequence[set[T]]

    IUnion(n,A):set[T] = Union(image[nat,set[T]](A,{i | i <= n}))

    IUnion_0_def: LEMMA IUnion(0,A)   = A(0)
    IUnion_n_def: LEMMA IUnion(n+1,A) = union(IUnion(n,A),A(n+1))

    increasing_indexed?(A):bool = IUnion(A) = fullset[T] AND increasing?(A)

    increasing_indexed: TYPE+ = (increasing_indexed?) CONTAINING
                                                           (lambda n: fullset[T])

    increasing_IUnion: LEMMA
       EXISTS B: increasing?(B) AND
                 B(0) = A(0) AND
                 (FORALL n: B(n+1) = union(B(n),A(n+1))) AND
                 IUnion(A) = IUnion(B)

    decreasing_IIntersection: LEMMA
       EXISTS B: decreasing?(B) AND
                 B(0) = A(0) AND
                 (FORALL n: B(n+1) = intersection(B(n),A(n+1))) AND
                 IIntersection(A) = IIntersection(B)

    disjoint_IUnion: LEMMA
       EXISTS B: disjoint?(B) AND
                 (FORALL n: IUnion(n,B) = IUnion(n,A)) AND
                 B(0) = A(0) AND
                 (FORALL n: B(n+1) = difference(A(n+1),IUnion(n,A))) AND
                 IUnion(A) = IUnion(B)

  END nat_indexed_sets

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 35, column 58) for  (LAMBDA n: fullset[T])
      % expected type  increasing_indexed
  increasing_indexed_TCC1: OBLIGATION
    increasing_indexed?((LAMBDA n: fullset[T]));


body:
  %------------------------------------------------------------------------------
  % Transforming Union to IUnion and Intersection to IIntersection
  %
  %     Author: David Lester, Manchester University
  %
  %     Version 1.0            14/06/09  Initial Version
  %------------------------------------------------------------------------------
  countable_indexed_sets[T: TYPE]: THEORY

  BEGIN

    IMPORTING indexed_sets_aux[nat,T],
              countability

    X:  VAR set[T]
    XS: VAR setofsets[T]
    YS: VAR sequence[set[T]]
    n:  VAR nat

    Union_IUnion: LEMMA is_countable(XS) =>
                        EXISTS YS: Union(XS) = IUnion(YS) AND 
                                   FORALL n: empty?(YS(n)) OR XS(YS(n))

    Intersection_IIntersection:
                  LEMMA is_countable(XS) =>
                        EXISTS YS: Intersection(XS) = IIntersection(YS) AND
                                   FORALL n: full?(YS(n)) OR XS(YS(n))

  END countable_indexed_sets


body:
  %------------------------------------------------------------------------------
  % finite/infinite properties of functions
  %
  %     Author: David Lester, Manchester University
  %
  %     Version 1.0            2/1/05
  %------------------------------------------------------------------------------

  card_function[D,R:TYPE]: THEORY

    BEGIN

    f: VAR [D->R]

    infinite_bijection:  LEMMA
       bijective?(f)  AND is_infinite(fullset[D]) => is_infinite(fullset[R])
    finite_bijection:    LEMMA
       bijective?(f)  AND is_finite(fullset[D])   => is_finite(fullset[R])
    infinite_injection:  LEMMA
       injective?(f)  AND is_infinite(fullset[D]) => is_infinite(fullset[R])
    finite_injection:    LEMMA
       injective?(f)  AND is_finite(fullset[R])   => is_finite(fullset[D])
    infinite_surjection: LEMMA
       surjective?(f) AND is_infinite(fullset[R]) => is_infinite(fullset[D])
    finite_surjection:   LEMMA
       surjective?(f) AND is_finite(fullset[D])   => is_finite(fullset[R])

    END card_function


body:
  %-------------------------------------------------------------------------
  %
  %  Infinite images of a set under some function.
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: infinite_sets_def[D], infinite_sets_def[R]
  %  sets_aux: infinite_image[D,R]
  %
  %-------------------------------------------------------------------------
  infinite_image[D: TYPE, R: TYPE]: THEORY
   BEGIN

    IMPORTING infinite_sets_def[D], infinite_sets_def[R]

    infinite_image: THEOREM
      FORALL (S: set[D]), (f: [D -> R]):
        is_infinite[R](image(f, S)) => is_infinite[D](S)

    f: VAR (injective?[D, R])
    S: VAR infinite_set[D]

    infinite_injective_image: JUDGEMENT image(f, S) HAS_TYPE infinite_set[R]

   END infinite_image

addendum:
  %%% ================ Addendum: generated declarations ================

  % Judgement subtype TCC generated (at line 27, column 38) for  image(f, S)
      % expected type  infinite_set[R]
  infinite_injective_image: OBLIGATION
    FORALL (S, f): NOT is_finite[R](image[D, R](f, S));


body:
  %------------------------------------------------------------------------------
  % image of a countable set is countable
  %
  %     Author: David Lester, Manchester University
  %
  %     Version 1.0            2/1/05
  %------------------------------------------------------------------------------

  countable_image[D,R:TYPE]: THEORY
  BEGIN

    f: VAR [D->R]
    S: VAR set[D]

    IMPORTING countability,
              function_image_aux[D,R],
              infinite_image,
              card_function[D,R]

    countable_image: THEOREM is_countable(S) => is_countable(image(f)(S))

  END countable_image


body:
  %-------------------------------------------------------------------------
  %
  %  More theorems for the prelude's sets_lemmas theory.
  %
  %  For PVS version 3.2.  March 15, 2005
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: sets_lemmas[T]
  %  sets_aux: sets_lemmas_extra[T]
  %
  %-------------------------------------------------------------------------
  sets_lemmas_extra[T: TYPE]: THEORY
   BEGIN

    IMPORTING sets_lemmas[T]

    disjoint_commutative: LEMMA
      FORALL (S, R: set[T]): disjoint?(S, R) IMPLIES disjoint?(R, S)

   END sets_lemmas_extra


body:
  %-------------------------------------------------------------------------
  %
  %  Transitivity properties of the set cardinality comparison functions.
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  sets_aux: card_comp_set[T1,T2], card_comp_set[T1,T3],
  %    card_comp_set[T2,T3], card_comp_set_transitive[T1,T2,T3]
  %
  %-------------------------------------------------------------------------
  card_comp_set_transitive[T1: TYPE, T2: TYPE, T3: TYPE]: THEORY

   EXPORTING ALL WITH card_comp_set[T1, T2], card_comp_set[T2, T3],
                      card_comp_set[T1, T3]

   BEGIN

    IMPORTING card_comp_set[T1, T2], card_comp_set[T2, T3], card_comp_set[T1, T3]

    % The following import is for the proofs only
    IMPORTING orders@set_dichotomous

    S1: VAR set[T1]
    S2: VAR set[T2]
    S3: VAR set[T3]

    % card_lt
    card_lt_transitive: LEMMA
      FORALL S1, S2, S3:
        card_lt(S1, S2) AND card_lt(S2, S3) => card_lt(S1, S3)
    card_lt_le_transitive: LEMMA
      FORALL S1, S2, S3:
        card_lt(S1, S2) AND card_le(S2, S3) => card_lt(S1, S3)
    card_lt_eq_transitive: LEMMA
      FORALL S1, S2, S3:
        card_lt(S1, S2) AND card_eq(S2, S3) => card_lt(S1, S3)
    card_le_lt_transitive: LEMMA
      FORALL S1, S2, S3:
        card_le(S1, S2) AND card_lt(S2, S3) => card_lt(S1, S3)
    card_eq_lt_transitive: LEMMA
      FORALL S1, S2, S3:
        card_eq(S1, S2) AND card_lt(S2, S3) => card_lt(S1, S3)

    % card_le
    card_le_transitive: LEMMA
      FORALL S1, S2, S3:
        card_le(S1, S2) AND card_le(S2, S3) => card_le(S1, S3)
    card_le_eq_transitive: LEMMA
      FORALL S1, S2, S3:
        card_le(S1, S2) AND card_eq(S2, S3) => card_le(S1, S3)
    card_eq_le_transitive: LEMMA
      FORALL S1, S2, S3:
        card_eq(S1, S2) AND card_le(S2, S3) => card_le(S1, S3)

    % card_eq
    card_eq_transitive: LEMMA
      FORALL S1, S2, S3:
        card_eq(S1, S2) AND card_eq(S2, S3) => card_eq(S1, S3)

    % card_ge
    card_eq_ge_transitive: LEMMA
      FORALL S1, S2, S3:
        card_eq(S1, S2) AND card_ge(S2, S3) => card_ge(S1, S3)
    card_ge_eq_transitive: LEMMA
      FORALL S1, S2, S3:
        card_ge(S1, S2) AND card_eq(S2, S3) => card_ge(S1, S3)
    card_ge_transitive: LEMMA
      FORALL S1, S2, S3:
        card_ge(S1, S2) AND card_ge(S2, S3) => card_ge(S1, S3)

    % card_gt
    card_eq_gt_transitive: LEMMA
      FORALL S1, S2, S3:
        card_eq(S1, S2) AND card_gt(S2, S3) => card_gt(S1, S3)
    card_ge_gt_transitive: LEMMA
      FORALL S1, S2, S3:
        card_ge(S1, S2) AND card_gt(S2, S3) => card_gt(S1, S3)
    card_gt_eq_transitive: LEMMA
      FORALL S1, S2, S3:
        card_gt(S1, S2) AND card_eq(S2, S3) => card_gt(S1, S3)
    card_gt_ge_transitive: LEMMA
      FORALL S1, S2, S3:
        card_gt(S1, S2) AND card_ge(S2, S3) => card_gt(S1, S3)
    card_gt_transitive: LEMMA
      FORALL S1, S2, S3:
        card_gt(S1, S2) AND card_gt(S2, S3) => card_gt(S1, S3)

   END card_comp_set_transitive


body:
  %-------------------------------------------------------------------------
  %
  %  Single type properties of the cardinality comparison functions.
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  sets_aux: card_comp_set[T,T], card_comp_set_props[T,T], card_single[T],
  %    card_comp_set_transitive[T,T,T]
  %
  %-------------------------------------------------------------------------
  card_single[T: TYPE]: THEORY
   BEGIN

    IMPORTING card_comp_set_props[T, T], card_comp_set_transitive[T, T, T]

    % ==========================================================================
    % (ir)reflexivity
    % ==========================================================================

    card_lt_is_irreflexive: JUDGEMENT card_lt HAS_TYPE (irreflexive?[set[T]])
    card_le_is_reflexive:   JUDGEMENT card_le HAS_TYPE (reflexive?[set[T]])
    card_eq_is_reflexive:   JUDGEMENT card_eq HAS_TYPE (reflexive?[set[T]])
    card_ge_is_reflexive:   JUDGEMENT card_ge HAS_TYPE (reflexive?[set[T]])
    card_gt_is_irreflexive: JUDGEMENT card_gt HAS_TYPE (irreflexive?[set[T]])


    % ==========================================================================
    % (anti)symmetry
    % ==========================================================================

    card_lt_is_antisymmetric: JUDGEMENT card_lt HAS_TYPE (antisymmetric?[set[T]])
    card_eq_is_symmetric:     JUDGEMENT card_eq HAS_TYPE (symmetric?[set[T]])
    card_gt_is_antisymmetric: JUDGEMENT card_gt HAS_TYPE (antisymmetric?[set[T]])


    % ==========================================================================
    % transitivity
    % ==========================================================================

    card_lt_is_transitive: JUDGEMENT card_lt HAS_TYPE (transitive?[set[T]])
    card_le_is_transitive: JUDGEMENT card_le HAS_TYPE (transitive?[set[T]])
    card_eq_is_transitive: JUDGEMENT card_eq HAS_TYPE (transitive?[set[T]])
    card_ge_is_transitive: JUDGEMENT card_ge HAS_TYPE (transitive?[set[T]])
    card_gt_is_transitive: JUDGEMENT card_gt HAS_TYPE (transitive?[set[T]])


    % ==========================================================================
    % dichotomy
    % ==========================================================================

    card_le_is_dichotomous: JUDGEMENT card_le HAS_TYPE (dichotomous?[set[T]])
    card_ge_is_dichotomous: JUDGEMENT card_ge HAS_TYPE (dichotomous?[set[T]])


    % ==========================================================================
    % equivalence
    % ==========================================================================

    card_eq_is_equivalence: JUDGEMENT card_eq HAS_TYPE equivalence[set[T]]

   END card_single

addendum:
  %%% ================ Addendum: generated declarations ================

  % Judgement subtype TCC generated (at line 24, column 36) for  card_lt
      % expected type  (irreflexive?[set[T]])
  card_lt_is_irreflexive: OBLIGATION irreflexive?[set[T]](card_lt[T, T]);

  % Judgement subtype TCC generated (at line 25, column 36) for  card_le
      % expected type  (reflexive?[set[T]])
  card_le_is_reflexive: OBLIGATION reflexive?[set[T]](card_le[T, T]);

  % Judgement subtype TCC generated (at line 26, column 36) for  card_eq
      % expected type  (reflexive?[set[T]])
  card_eq_is_reflexive: OBLIGATION reflexive?[set[T]](card_eq[T, T]);

  % Judgement subtype TCC generated (at line 27, column 36) for  card_ge
      % expected type  (reflexive?[set[T]])
  card_ge_is_reflexive: OBLIGATION reflexive?[set[T]](card_ge[T, T]);

  % Judgement subtype TCC generated (at line 28, column 36) for  card_gt
      % expected type  (irreflexive?[set[T]])
  card_gt_is_irreflexive: OBLIGATION irreflexive?[set[T]](card_gt[T, T]);

  % Judgement subtype TCC generated (at line 35, column 38) for  card_lt
      % expected type  (antisymmetric?[set[T]])
  card_lt_is_antisymmetric: OBLIGATION antisymmetric?[set[T]](card_lt[T, T]);

  % Judgement subtype TCC generated (at line 36, column 38) for  card_eq
      % expected type  (symmetric?[set[T]])
  card_eq_is_symmetric: OBLIGATION symmetric?[set[T]](card_eq[T, T]);

  % Judgement subtype TCC generated (at line 37, column 38) for  card_gt
      % expected type  (antisymmetric?[set[T]])
  card_gt_is_antisymmetric: OBLIGATION antisymmetric?[set[T]](card_gt[T, T]);

  % Judgement subtype TCC generated (at line 44, column 35) for  card_lt
      % expected type  (transitive?[set[T]])
  card_lt_is_transitive: OBLIGATION transitive?[set[T]](card_lt[T, T]);

  % Judgement subtype TCC generated (at line 45, column 35) for  card_le
      % expected type  (transitive?[set[T]])
  card_le_is_transitive: OBLIGATION transitive?[set[T]](card_le[T, T]);

  % Judgement subtype TCC generated (at line 46, column 35) for  card_eq
      % expected type  (transitive?[set[T]])
  card_eq_is_transitive: OBLIGATION transitive?[set[T]](card_eq[T, T]);

  % Judgement subtype TCC generated (at line 47, column 35) for  card_ge
      % expected type  (transitive?[set[T]])
  card_ge_is_transitive: OBLIGATION transitive?[set[T]](card_ge[T, T]);

  % Judgement subtype TCC generated (at line 48, column 35) for  card_gt
      % expected type  (transitive?[set[T]])
  card_gt_is_transitive: OBLIGATION transitive?[set[T]](card_gt[T, T]);

  % Judgement subtype TCC generated (at line 55, column 36) for  card_le
      % expected type  (dichotomous?[set[T]])
  card_le_is_dichotomous: OBLIGATION dichotomous?[set[T]](card_le[T, T]);

  % Judgement subtype TCC generated (at line 56, column 36) for  card_ge
      % expected type  (dichotomous?[set[T]])
  card_ge_is_dichotomous: OBLIGATION dichotomous?[set[T]](card_ge[T, T]);

  % Judgement subtype TCC generated (at line 63, column 36) for  card_eq
      % expected type  equivalence[set[T]]
  card_eq_is_equivalence: OBLIGATION equivalence?[set[T]](card_eq[T, T]);


body:
  %-------------------------------------------------------------------------
  %
  %  Lemmas about set operations and their implications for the cardinality
  %  comparison relations.
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  sets_aux: card_comp_set[T,T], card_comp_set_props[T,T], card_single[T],
  %    card_comp_set_transitive[T,T,T], card_sets_lemmas[T]
  %
  %-------------------------------------------------------------------------
  card_sets_lemmas[T: TYPE]: THEORY
   BEGIN

    IMPORTING card_single[T]

    t: VAR T
    S, R: VAR set[T]

    empty_card_le: LEMMA FORALL S: card_le(emptyset[T], S)

    nonempty_card_lt: LEMMA FORALL S: card_lt(emptyset[T], S) IFF nonempty?(S)

    full_card_le: LEMMA FORALL S: card_le(S, fullset[T])

    add_card_le: LEMMA FORALL S, t: card_le(S, add(t, S))

    remove_card_ge: LEMMA FORALL S, t: card_ge(S, remove(t, S))

    subset_card_le: LEMMA FORALL S, R: subset?(S, R) => card_le(S, R)

    strict_subset_card_lt: LEMMA
      FORALL S, R: subset?(S, R) AND card_lt(S, R) => strict_subset?(S, R)

    union_card_le1: LEMMA FORALL S, R: card_le(S, union(S, R))
    union_card_le2: LEMMA FORALL S, R: card_le(R, union(S, R))

    intersection_card_le1: LEMMA FORALL S, R: card_le(intersection(S, R), S)
    intersection_card_le2: LEMMA FORALL S, R: card_le(intersection(S, R), R)

    difference_card_le: LEMMA FORALL S, R: card_le(difference(S, R), S)

   END card_sets_lemmas


body:
  %-------------------------------------------------------------------------
  %
  %  Cardinality properties of infinite sets.
  %
  %  For PVS version 3.2.  February 10, 2005
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: finite_sets[T], infinite_sets_def[T]
  %  sets_aux: card_comp_set[nat,T], card_comp_set[T,nat], card_comp_set[T,T],
  %    card_comp_set_props[T,nat], card_comp_set_props[T,T],
  %    card_sets_lemmas[T], card_single[T], countable_props[T],
  %    countability[T], infinite_sets[T]
  %
  %-------------------------------------------------------------------------
  infinite_sets[T: TYPE]: THEORY
   BEGIN

    IMPORTING countable_props[T], card_sets_lemmas[T]

    t: VAR T
    S, R: VAR set[T]
    Fin: VAR finite_set[T]
    Inf: VAR infinite_set[T]

    infinite_add_card: THEOREM FORALL Inf, t: card_eq(Inf, add(t, Inf))

    infinite_remove_card: THEOREM FORALL Inf, t: card_eq(Inf, remove(t, Inf))

    finite_infinite_lt: THEOREM
      FORALL S: (FORALL Fin: card_lt(Fin, S)) IFF is_infinite(S)

   END infinite_sets


body:
  %-------------------------------------------------------------------------
  %
  %  Implications for finiteness and infiniteness of cardinal relations.
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: infinite_sets_def[T1], infinite_sets_def[T2]
  %  sets_aux: card_comp_set[T1,T2], card_comp_set[T2,T1],
  %    card_comp_set_props[T1,T2], infinite_card[T1,T2]
  %
  %-------------------------------------------------------------------------
  infinite_card[T1: TYPE, T2: TYPE]: THEORY
   BEGIN

    IMPORTING infinite_sets_def[T1], infinite_sets_def[T2]
    IMPORTING card_comp_set_props[T1, T2]

    S1: VAR set[T1]
    S2: VAR set[T2]

    finite_card_eq: THEOREM
      FORALL S1, S2: card_eq(S1, S2) => (is_finite(S1) IFF is_finite(S2))

    infinite_card_eq: COROLLARY
      FORALL S1, S2: card_eq(S1, S2) => (is_infinite(S1) IFF is_infinite(S2))

    infinite_card_le: THEOREM
      FORALL S1, S2: card_le(S1, S2) AND is_infinite(S1) => is_infinite(S2)

    infinite_card_ge: THEOREM
      FORALL S1, S2: card_ge(S1, S2) AND is_infinite(S2) => is_infinite(S1)

    finite_card_le: THEOREM
      FORALL S1, S2: card_le(S1, S2) AND is_finite(S2) => is_finite(S1)

    finite_card_ge: THEOREM
      FORALL S1, S2: card_ge(S1, S2) AND is_finite(S1) => is_finite(S2)

   END infinite_card


body:
  %-------------------------------------------------------------------------
  %
  %  Sets of bit numbers.  This is different from the bit_vector library in
  %  only one way: the representation is a set of nats, instead of a set of
  %  below[N]s for some N.  This representation is adapted to the proofs
  %  of countability in countable_set.pvs, and so all of the adding,
  %  subtracting, bit shifting, etc. operations of bit_vector are missing
  %  (not to mention that some are not well-defined with this
  %  representation).
  %
  %  I have made several attempts at using the bit_vector library to replace
  %  this theory.  All have failed, due to the fact that there is no bit
  %  vector type; there are a countably infinite number of bit vector types.
  %  All of my attempts ultimately required me to somehow compare the
  %  value of 2 bv2nat invocations with different parameter expressions.
  %  I even tried to prove theorems relating such invocations, but those
  %  attempts were also unfruitful.
  %
  %  For PVS version 3.2.  May 11, 2005
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: finite_sets[nat], orders[nat], relations[nat], sets[nat]
  %  orders: bounded_integers[nat], bounded_nats[nat], bounded_orders[nat],
  %    bounded_sets[nat,<=], lattices[nat,<=], lower_semilattices[nat,<=],
  %    minmax_orders[nat], non_empty_bounded_sets[nat], relations_extra[nat],
  %    total_lattices[nat,<=], upper_semilattices[nat,<=]
  %  sets_aux: bits
  %
  %-------------------------------------------------------------------------

  bits: THEORY

  % Hide the theories used for proofs only
  % RWB: commented this out so that it would typecheck in PVS4.0
  %  EXPORTING ALL WITH finite_sets[nat], orders[nat], relations[nat], sets[nat],
  % 		    orders@relations_extra[nat], orders@bounded_integers[nat],
  % 		    orders@bounded_nats[nat], orders@bounded_orders[nat],
  % 		    orders@bounded_sets[nat, <=], 
  %                     orders@non_empty_bounded_sets[nat],
  % 		    orders@minmax_orders[nat], 
  %                     orders@lower_semilattices[nat, <=],
  % 		    orders@upper_semilattices[nat, <=], 
  %                     orders@lattices[nat, <=],
  % 		    orders@total_lattices[nat, <=],
  %                     orders@bounded_orders[nat]

   BEGIN

    IMPORTING orders@bounded_nats[nat]

    % Proofs only
    IMPORTING functions[finite_set, nat], functions[nat, finite_set]
    IMPORTING function_inverse[finite_set, nat]
    IMPORTING function_inverse[nat, finite_set]

    n, m: VAR nat
    S, R: VAR finite_set

    % A convenient shorthand
    lesseq: MACRO pred[[nat, nat]] =
        restrict[[real, real], [nat, nat], boolean](<=)


    % ==========================================================================
    % Convert a natural number into a set of bits (natural numbers)
    % ==========================================================================

    bounding_bits(n): set[nat] = {m: nat | n < exp2(m)}

    bounding_bits_has_least: LEMMA
      FORALL n: n > 0 IMPLIES has_least?(bounding_bits(n), lesseq)

    bit_decoding(n): RECURSIVE finite_set =
      IF n = 0 THEN emptyset[nat]
      ELSE LET bit: nat = least(lesseq)(bounding_bits(n)) - 1 IN
             add(bit, bit_decoding(n - exp2(bit)))
      ENDIF
       MEASURE n

    bit_decoding_has_greatest: LEMMA
      FORALL n: n > 0 IMPLIES has_greatest?(bit_decoding(n), lesseq)

    bit_decoding_max1: LEMMA
      FORALL n: n > 0 IMPLIES n >= exp2(greatest(lesseq)(bit_decoding(n)))

    bit_decoding_max2: LEMMA
      FORALL n:
        n > 0 IMPLIES
         greatest(lesseq)(bit_decoding(n)) =
          least(lesseq)(bounding_bits(n)) - 1

    bit_decoding_max3: LEMMA
      FORALL n, m: member(m, bit_decoding(n)) IMPLIES exp2(m) <= n


    % ==========================================================================
    % Convert a set of bits (natural numbers) into a natural number
    % ==========================================================================

    bit_encoding(S): RECURSIVE nat =
      IF empty?(S) THEN 0
      ELSE exp2(greatest(lesseq)(S)) +
            bit_encoding(remove(greatest(lesseq)(S), S))
      ENDIF
       MEASURE card(S)

    bit_encoding_member1: LEMMA FORALL S, (x: (S)): exp2(x) <= bit_encoding(S)

    bit_encoding_member2: LEMMA
      FORALL (S: non_empty_finite_set[nat]):
        bit_encoding(S) < exp2((greatest(lesseq)(S) + 1))

    bit_encoding_member3: LEMMA
      FORALL (S: non_empty_finite_set[nat]):
        least(lesseq)(bounding_bits(bit_encoding(S))) - 1 =
         greatest(lesseq)(S)


    % ==========================================================================
    % The relationship between bit_decoding and bit_encoding
    % ==========================================================================

    decoding_encoding_max: LEMMA
      FORALL (S: non_empty_finite_set[nat]):
        greatest(lesseq)(S) = greatest(lesseq)(bit_decoding(bit_encoding(S)))

    decoding_encoding_empty: LEMMA
      FORALL S: empty?(S) IFF empty?(bit_decoding(bit_encoding(S)))

    decoding_encoding_remove: LEMMA
      FORALL (S: non_empty_finite_set[nat]):
        remove(greatest(lesseq)(S), bit_decoding(bit_encoding(S))) =
         bit_decoding(bit_encoding(remove(greatest(lesseq)(S), S)))

    encoding_decoding: LEMMA FORALL n: bit_encoding(bit_decoding(n)) = n

    decoding_encoding: LEMMA FORALL S: bit_decoding(bit_encoding(S)) = S

    encoding_bijection: JUDGEMENT
      bit_encoding HAS_TYPE (bijective?[finite_set[nat], nat])

    decoding_bijection: JUDGEMENT
      bit_decoding HAS_TYPE (bijective?[nat, finite_set[nat]])

    encoding_decoding_inverse: COROLLARY bit_encoding = inverse(bit_decoding)

    decoding_encoding_inverse: COROLLARY bit_decoding = inverse(bit_encoding)

   END bits

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 79, column 33) for  n - exp2(bit)
      % expected type  nat
  bit_decoding_TCC1: OBLIGATION
    FORALL (n: nat):
      NOT n = 0 IMPLIES
       (FORALL (bit: nat):
          bit =
           least(restrict[[real, real], [nat, nat], boolean](<=))
                (bounding_bits(n))
            - 1
           IMPLIES n - exp2(bit) >= 0);

  % Termination TCC generated (at line 79, column 20) for
      % bit_decoding(n - exp2(bit))
  bit_decoding_TCC2: OBLIGATION
    FORALL (n: nat):
      NOT n = 0 IMPLIES
       (FORALL (bit: nat):
          bit =
           least(restrict[[real, real], [nat, nat], boolean](<=))
                (bounding_bits(n))
            - 1
           IMPLIES n - exp2(bit) < n);

  % Subtype TCC generated (at line 78, column 38) for  bounding_bits(n)
      % expected type  S:
                     %   (LAMBDA (S: set[nat]):
                     %      has_least?(S,
                     %                 restrict
                     %                 [[real, real], [nat, nat], boolean]
                     %                 (<=)))
  bit_decoding_TCC3: OBLIGATION
    FORALL (n: nat):
      NOT n = 0 IMPLIES
       has_least?[nat]
           (bounding_bits(n),
            restrict[[real, real], [nat, nat], boolean](<=));

  % Subtype TCC generated (at line 78, column 24) for
      % least(restrict[[real, real], [nat, nat], boolean](<=))
      %      (bounding_bits(n))
      %  - 1
      % expected type  nat
  bit_decoding_TCC4: OBLIGATION
    FORALL (n: nat):
      NOT n = 0 IMPLIES
       least[nat]
           (restrict[[real, real], [nat, nat], boolean](<=))
           (bounding_bits(n))
        - 1
        >= 0;

  % Subtype TCC generated (at line 87, column 55) for  bit_decoding(n)
      % expected type  S:
                     %   (LAMBDA (S: set[nat]):
                     %      has_greatest?(S,
                     %                    restrict
                     %                    [[real, real], [nat, nat], boolean]
                     %                    (<=)))
  bit_decoding_max1_TCC1: OBLIGATION
    FORALL (n):
      n > 0 IMPLIES
       has_greatest?[nat]
           (bit_decoding(n), restrict[[real, real], [nat, nat], boolean](<=));

  % Subtype TCC generated (at line 93, column 22) for  bounding_bits(n)
      % expected type  S:
                     %   (LAMBDA (S: set[nat]):
                     %      has_least?(S,
                     %                 restrict
                     %                 [[real, real], [nat, nat], boolean]
                     %                 (<=)))
  bit_decoding_max2_TCC1: OBLIGATION
    FORALL (n):
      n > 0 IMPLIES
       has_least?[nat]
           (bounding_bits(n),
            restrict[[real, real], [nat, nat], boolean](<=));

  % Subtype TCC generated (at line 105, column 31) for  S
      % expected type  S:
                     %   (LAMBDA (S: set[nat]):
                     %      has_greatest?(S,
                     %                    restrict
                     %                    [[real, real], [nat, nat], boolean]
                     %                    (<=)))
  bit_encoding_TCC1: OBLIGATION
    FORALL (S: finite_set[nat]):
      NOT empty?(S) IMPLIES
       has_greatest?[nat](S, restrict[[real, real], [nat, nat], boolean](<=));

  % Termination TCC generated (at line 106, column 10) for
      % bit_encoding(remove(greatest(restrict
      %                                  [[real, real], [nat, nat], boolean]
      %                                  (<=))
      %                             (S),
      %                     S))
  bit_encoding_TCC2: OBLIGATION
    FORALL (S: finite_set[nat]):
      NOT empty?(S) IMPLIES
       card[nat]
           (remove[nat]
                (greatest[nat]
                     (restrict[[real, real], [nat, nat], boolean](<=))(S),
                 S))
        < card[nat](S);

  % Subtype TCC generated (at line 118, column 20) for
      % bounding_bits(bit_encoding(S))
      % expected type  S:
                     %   (LAMBDA (S: set[nat]):
                     %      has_least?(S,
                     %                 restrict
                     %                 [[real, real], [nat, nat], boolean]
                     %                 (<=)))
  bit_encoding_member3_TCC1: OBLIGATION
    FORALL (S: non_empty_finite_set[nat]):
      has_least?[nat]
          (bounding_bits(bit_encoding(S)),
           restrict[[real, real], [nat, nat], boolean](<=));

  % Subtype TCC generated (at line 128, column 45) for
      % bit_decoding(bit_encoding(S))
      % expected type  S:
                     %   (LAMBDA (S: set[nat]):
                     %      has_greatest?(S,
                     %                    restrict
                     %                    [[real, real], [nat, nat], boolean]
                     %                    (<=)))
  decoding_encoding_max_TCC1: OBLIGATION
    FORALL (S: non_empty_finite_set[nat]):
      has_greatest?[nat]
          (bit_decoding(bit_encoding(S)),
           restrict[[real, real], [nat, nat], boolean](<=));

  % Judgement subtype TCC generated (at line 143, column 4) for  bit_encoding
      % expected type  (bijective?[finite_set[nat], nat])
  encoding_bijection: OBLIGATION
    bijective?[finite_set[nat], nat](bit_encoding);

  % Judgement subtype TCC generated (at line 146, column 4) for  bit_decoding
      % expected type  (bijective?[nat, finite_set[nat]])
  decoding_bijection: OBLIGATION
    bijective?[nat, finite_set[nat]](bit_decoding);


body:
  %-------------------------------------------------------------------------
  %
  %  Countable sets of numbers.  The countability properties are shown by
  %  providing bijections between the sets and the natural numbers.
  %
  %  For PVS version 3.2.  February 10, 2005
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: finite_sets[int], finite_sets[nat],
  %    function_image_aux[int, nat], function_image_aux[nat, int]
  %  sets_aux: countable_set
  %
  %-------------------------------------------------------------------------
  countable_set: THEORY


  BEGIN

    IMPORTING function_image_aux[int, nat], function_image_aux[nat, int], bits
    IMPORTING orders@set_antisymmetric[[nat, nat], nat]
    IMPORTING orders@set_antisymmetric[[int, int], nat]
    IMPORTING orders@set_antisymmetric[rat, nat]


    % ==========================================================================
    % Integers
    % ==========================================================================

    int_to_nat(i: int): nat = IF i < 0 THEN -2 * i - 1 ELSE 2 * i ENDIF
    nat_to_int(n: nat): int = IF even?(n) THEN n / 2 ELSE (n + 1) / -2 ENDIF

    int_to_nat_bijective: JUDGEMENT int_to_nat HAS_TYPE (bijective?[int, nat])
    nat_to_int_bijective: JUDGEMENT nat_to_int HAS_TYPE (bijective?[nat, int])


    % ==========================================================================
    % Finite sets of natural numbers
    % ==========================================================================

    % Use the bit_encoding function
    countable_family_nat: THEOREM
      EXISTS (f: [finite_set[nat] -> nat]): bijective?(f)


    % ==========================================================================
    % Finite sets of integers
    % ==========================================================================

    intset_to_natset(S: finite_set[int]): finite_set[nat] =
        image(int_to_nat, S)
    intset_to_natset_bijective: JUDGEMENT
      intset_to_natset HAS_TYPE (bijective?[finite_set[int], finite_set[nat]])

    countable_family_int: THEOREM
      EXISTS (f: [finite_set[int] -> nat]): bijective?(f)


    % ==========================================================================
    % 2-tuples of natural numbers and integers
    % ==========================================================================

    tuple_to_natset(n: [nat, nat]): finite_set[nat] =
        {i: nat | i = n`1 * 2 OR i = n`2 * 2 + 1}

    countable_nat_tuple: THEOREM
      EXISTS (f: [[nat, nat] -> nat]): bijective?(f)

    tuple_to_intset(n: [int, int]): finite_set[int] =
        {i: int | i = n`1 * 2 OR i = n`2 * 2 + 1}

    countable_int_tuple: THEOREM
      EXISTS (f: [[int, int] -> nat]): bijective?(f)


    % ==========================================================================
    % Rational numbers
    % ==========================================================================

    countable_rat: THEOREM EXISTS (f: [rat -> nat]): bijective?(f)

   END countable_set

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 32, column 42) for  -2 * i - 1
      % expected type  nat
  int_to_nat_TCC1: OBLIGATION FORALL (i: int): i < 0 IMPLIES -2 * i - 1 >= 0;

  % Subtype TCC generated (at line 32, column 58) for  2 * i
      % expected type  nat
  int_to_nat_TCC2: OBLIGATION FORALL (i: int): NOT i < 0 IMPLIES 2 * i >= 0;

  % Subtype TCC generated (at line 33, column 45) for  n / 2
      % expected type  int
  nat_to_int_TCC1: OBLIGATION
    FORALL (n: nat): even?(n) IMPLIES integer_pred(n / 2);

  % Subtype TCC generated (at line 33, column 56) for  (n + 1) / -2
      % expected type  int
  nat_to_int_TCC2: OBLIGATION
    FORALL (n: nat): NOT even?(n) IMPLIES integer_pred((n + 1) / -2);

  % Judgement subtype TCC generated (at line 35, column 34) for  int_to_nat
      % expected type  (bijective?[int, nat])
  int_to_nat_bijective: OBLIGATION bijective?[int, nat](int_to_nat);

  % Judgement subtype TCC generated (at line 36, column 34) for  nat_to_int
      % expected type  (bijective?[nat, int])
  nat_to_int_bijective: OBLIGATION bijective?[nat, int](nat_to_int);

  % Judgement subtype TCC generated (at line 55, column 4) for
      % intset_to_natset
      % expected type  (bijective?[finite_set[int], finite_set[nat]])
  intset_to_natset_bijective: OBLIGATION
    bijective?[finite_set[int], finite_set[nat]](intset_to_natset);

  % Subtype TCC generated (at line 66, column 6) for
      % {i: nat | i = n`1 * 2 OR i = n`2 * 2 + 1}
      % expected type  finite_set[nat]
  tuple_to_natset_TCC1: OBLIGATION
    FORALL (n: [nat, nat]):
      is_finite[nat]({i: nat | i = n`1 * 2 OR i = n`2 * 2 + 1});

  % Subtype TCC generated (at line 72, column 6) for
      % {i: int | i = n`1 * 2 OR i = n`2 * 2 + 1}
      % expected type  finite_set[int]
  tuple_to_intset_TCC1: OBLIGATION
    FORALL (n: [int, int]):
      is_finite[int]({i: int | i = n`1 * 2 OR i = n`2 * 2 + 1});


body:
  %-------------------------------------------------------------------------
  %
  %  Countable prelude-defined types
  %
  %  For PVS version 3.2.  March 1, 2005
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %-------------------------------------------------------------------------
  countable_types: THEORY
   BEGIN

    IMPORTING countability,
              countable_set,
              countable_props,
              infinite_nat_def,
              orders@numbers_infinite

    %% Rationals
    nat_rational: THEOREM is_countably_infinite_type[rational]

    nat_nonzero_rational: THEOREM is_countably_infinite_type[nonzero_rational]

    nat_nonneg_rat: THEOREM is_countably_infinite_type[nonneg_rat]

    nat_nonpos_rat: THEOREM is_countably_infinite_type[nonpos_rat]

    nat_negrat: THEOREM is_countably_infinite_type[negrat]

    nat_posrat: THEOREM is_countably_infinite_type[posrat]

    %% Integers
    nat_integer: THEOREM is_countably_infinite_type[integer]

    nat_nonzero_integer: THEOREM is_countably_infinite_type[nonzero_integer]

    nat_upfrom: THEOREM FORALL (i: int): is_countably_infinite_type[upfrom(i)]

    nat_above: THEOREM FORALL (i: int): is_countably_infinite_type[above(i)]

    % nonneg_int IS nat

    nat_nonpos_int: THEOREM is_countably_infinite_type[nonpos_int]

    nat_negint: THEOREM is_countably_infinite_type[negint]

    nat_posint: THEOREM is_countably_infinite_type[posint]

    nat_even_int: THEOREM is_countably_infinite_type[even_int]

    nat_odd_int: THEOREM is_countably_infinite_type[odd_int]

   END countable_types


body:
  %-------------------------------------------------------------------------
  %
  %  Operations on countable families of sets.
  %
  %  For PVS version 3.2.  February 10, 2005
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: finite_sets[finite_set[T]], finite_sets[set[T]], finite_sets[T],
  %    infinite_sets_def[finite_set[T]], infinite_sets_def[set[T]],
  %    infinite_sets_def[T]
  %  sets_aux: card_comp_set[finite_set[T],finite_set[T]],
  %    card_comp_set[finite_set[T],nat], card_comp_set[nat,finite_set[T]],
  %    card_comp_set[nat,set[T]], card_comp_set[nat,T],
  %    card_comp_set[set[T],nat], card_comp_set[set[T],set[T]],
  %    card_comp_set[set[T],T], card_comp_set[T,nat], card_comp_set[T,set[T]],
  %    card_comp_set[T,T], card_comp_set_props[finite_set[T],finite_set[T]],
  %    card_comp_set_props[finite_set[T],nat], card_comp_set_props[set[T],nat],
  %    card_comp_set_props[set[T],set[T]], card_comp_set_props[T,nat],
  %    card_comp_set_props[T,set[T]], card_comp_set_props[T,T],
  %    card_comp_set_transitive[nat,T,set[T]], card_comp_set_transitive[nat,T,T],
  %    card_power_set[T], card_sets_lemmas[T], card_single[finite_set[T]],
  %    card_single[set[T]], card_single[T], countability[finite_set[T]],
  %    countability[set[T]], countability[T], countable_props[finite_set[T]],
  %    countable_props[set[T]], countable_props[T], countable_set,
  %    countable_setofsets[T]
  %
  %-------------------------------------------------------------------------
  countable_setofsets[T: TYPE]: THEORY
   BEGIN

    IMPORTING countable_set,
              countable_props[T],
              countable_props[set[T]],
              countable_props[finite_set[T]]

    S: VAR setofsets[T]

    countable_union1: THEOREM
      FORALL S:
        is_countable[set[T]](S) AND every(is_countable)(S) =>
         is_countable[T](Union(S))

    %% Note that the converse of conutable_union1 is not quite true; it is
    %% possible to have an uncountable set whose union is countable.  For
    %% example, consider the set of natural numbers.  Its power set is
    %% uncountable, and the union of the power set is the (countable) set of
    %% natural numbers.
    countable_union2: THEOREM
      FORALL S: is_countable[T](Union(S)) => every(is_countable)(S)

    countable_intersection: THEOREM
      FORALL S:
        nonempty?(S) AND every(is_countable)(S) =>
         is_countable(Intersection(S))

    %% The finite subsets of a given set.  For a finite set, this is the
    %% powerset.  Otherwise, it is the finite elements of the powerset.

    finite_subsets(S: set[T]): set[finite_set[T]] =
        {F: finite_set[T] | subset?(F, S)}

    countable_finite_subsets: JUDGEMENT
      finite_subsets(S: countable_set[T]) HAS_TYPE countable_set[finite_set[T]]

    countably_infinite_finite_subsets: JUDGEMENT
      finite_subsets(S: countably_infinite_set[T])
        HAS_TYPE countably_infinite_set[finite_set[T]]

  END countable_setofsets

addendum:
  %%% ================ Addendum: generated declarations ================

  % Judgement subtype TCC generated (at line 66, column 4) for
      % finite_subsets(S)
      % expected type  countable_set[finite_set[T]]
  countable_finite_subsets: OBLIGATION
    FORALL (S: countable_set[T]):
      is_countable[finite_set[T]](finite_subsets(S));

  % Judgement subtype TCC generated (at line 69, column 4) for
      % finite_subsets(S)
      % expected type  countably_infinite_set[finite_set[T]]
  countably_infinite_finite_subsets: OBLIGATION
    FORALL (S: countably_infinite_set[T]):
      is_countably_infinite[finite_set[T]](finite_subsets(S));


body:
  %-------------------------------------------------------------------------
  %
  %  The relationship between the cardinality comparison functions when
  %  applied to finite sets, and the finite_sets card(S) function.
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: finite_sets[T1], finite_sets[T2]
  %  sets_aux: card_comp_set[T1,T2], card_comp_set[T2,T1],
  %    card_comp_set_props[T1,T2], card_finite[T1,T2]
  %
  %-------------------------------------------------------------------------
  card_finite[T1: TYPE, T2: TYPE]: THEORY
   BEGIN

    IMPORTING card_comp_set_props[T1, T2], finite_sets[T1], finite_sets[T2]

    n, m: VAR nat
    F1: VAR finite_set[T1]
    F2: VAR finite_set[T2]

    card_less_than: THEOREM
      FORALL F1, F2: card(F1) < card(F2) IFF card_lt(F1, F2)

    card_less_than_equal: THEOREM
      FORALL F1, F2: card(F1) <= card(F2) IFF card_le(F1, F2)

    card_equal: THEOREM FORALL F1, F2: card(F1) = card(F2) IFF card_eq(F1, F2)

    card_greater_than_equal: THEOREM
      FORALL F1, F2: card(F1) >= card(F2) IFF card_ge(F1, F2)

    card_greater_than: THEOREM
      FORALL F1, F2: card(F1) > card(F2) IFF card_gt(F1, F2)

   END card_finite


body:
  %-------------------------------------------------------------------------
  %
  %  Set cardinality.  This theory operates on both finite and infinite
  %  sets.  This theory produces and compares cardinals only for sets of a
  %  given type.  There is no facility for comparing cardinals of sets of
  %  different types.  I do not intend to rectify that omission.
  %
  %  For PVS version 3.2.  March 8, 2005
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: finite_sets[T], QuotientDefinition[set[T]]
  %  sets_aux: card_comp_set[T,T], card_comp_set_props[T,T],
  %    card_comp_set_transitive[T,T,T], card_finite[T,T], card_single[T],
  %    cardinal[T]
  %
  %-------------------------------------------------------------------------
  cardinal[T: TYPE]: THEORY
   BEGIN

    IMPORTING QuotientDefinition[set[T]], card_finite[T, T], card_single[T]

    R, S: VAR set[T]

    % A cardinal number is a maximal set of bijective sets.  We form the
    % cardinal numbers from the quotient of the card_eq relation.
    cardinal_number: TYPE = Quotient(card_eq)

    A, B, C: VAR cardinal_number

    cardinal(S): cardinal_number = quotient_map(card_eq)(S)

    cardinal_member: LEMMA FORALL S: cardinal(S)(S)

    cardinal_closed: LEMMA FORALL A, (S: (A)): A = cardinal(S)

    cardinal_empty: LEMMA cardinal(emptyset[T]) = singleton(emptyset[T])

    cardinal_finite: LEMMA
      FORALL (S: finite_set[T]), (R: (cardinal(S))): is_finite(R)

    cardinal_finite_card: LEMMA
      FORALL (S: finite_set[T]), (R: (cardinal(S))): card(R) = card(S);


    % ==========================================================================
    % Comparing cardinal numbers
    % ==========================================================================

    <(A, B): bool = card_lt(rep(card_eq)(A), rep(card_eq)(B));

    <=(A, B): bool = card_le(rep(card_eq)(A), rep(card_eq)(B));

    >=(A, B): bool = card_ge(rep(card_eq)(A), rep(card_eq)(B));

    >(A, B): bool = card_gt(rep(card_eq)(A), rep(card_eq)(B));

    % We don't need to define an analogous = operator
    cardinal_equality: LEMMA
      FORALL A, B: card_eq(rep(card_eq)(A), rep(card_eq)(B)) IFF A = B

    % Alternative way of expressing cardinality (in)equalities
    cardinal_lt: LEMMA
      FORALL A, B: A < B IFF (FORALL (S: (A)), (R: (B)): card_lt(S, R))

    cardinal_le: LEMMA
      FORALL A, B: A <= B IFF (FORALL (S: (A)), (R: (B)): card_le(S, R))

    cardinal_eq: LEMMA
      FORALL A, B: A = B IFF (FORALL (S: (A)), (R: (B)): card_eq(S, R))

    cardinal_ge: LEMMA
      FORALL A, B: A >= B IFF (FORALL (S: (A)), (R: (B)): card_ge(S, R))

    cardinal_gt: LEMMA
      FORALL A, B: A > B IFF (FORALL (S: (A)), (R: (B)): card_gt(S, R))


    % ==========================================================================
    % Relationship between the card_comp operators and cardinal (in)equalities
    % ==========================================================================

    cardinal_card_lt: LEMMA
      FORALL R, S: card_lt(R, S) IFF cardinal(R) < cardinal(S)

    cardinal_card_le: LEMMA
      FORALL R, S: card_le(R, S) IFF cardinal(R) <= cardinal(S)

    cardinal_card_eq: LEMMA
      FORALL R, S: card_eq(R, S) IFF cardinal(R) = cardinal(S)

    cardinal_card_ge: LEMMA
      FORALL R, S: card_ge(R, S) IFF cardinal(R) >= cardinal(S)

    cardinal_card_gt: LEMMA
      FORALL R, S: card_gt(R, S) IFF cardinal(R) > cardinal(S)


    % ==========================================================================
    % Relationship between the cardinal (in)equalities
    % ==========================================================================

    cardinal_lt_gt: LEMMA FORALL A, B: A <  B IFF B >  A

    cardinal_le_ge: LEMMA FORALL A, B: A <= B IFF B >= A

    cardinal_lt_le: LEMMA FORALL A, B: A <  B IFF A <= B AND NOT A =  B

    cardinal_le_lt: LEMMA FORALL A, B: A <= B IFF A <  B OR      A =  B

    cardinal_eq_lg: LEMMA FORALL A, B: A =  B IFF A <= B AND     A >= B

    cardinal_ge_gt: LEMMA FORALL A, B: A >= B IFF A >  B OR      A =  B

    cardinal_gt_ge: LEMMA FORALL A, B: A >  B IFF A >= B AND NOT A =  B

    cardinal_lt_not_ge: LEMMA FORALL A, B: A <  B IFF NOT A >= B

    cardinal_le_not_gt: LEMMA FORALL A, B: A <= B IFF NOT A >  B

    cardinal_eq_not_lg: LEMMA FORALL A, B: A =  B IFF NOT (A < B OR A > B)

    cardinal_ge_not_lt: LEMMA FORALL A, B: A >= B IFF NOT A <  B

    cardinal_gt_not_le: LEMMA FORALL A, B: A >  B IFF NOT A <= B


    % ==========================================================================
    % Order properties of the cardinal (in)equalities
    % ==========================================================================

    cardinal_lt_strict_total_order: JUDGEMENT
      < HAS_TYPE (strict_total_order?[cardinal_number])

    cardinal_le_total_order: JUDGEMENT
      <= HAS_TYPE (total_order?[cardinal_number])

    % This is already known:
    % cardinal_eq_equivalence: JUDGEMENT = HAS_TYPE equivalence[cardinal_number]

    cardinal_ge_total_order: JUDGEMENT
      >= HAS_TYPE (total_order?[cardinal_number])

    cardinal_gt_strict_total_order: JUDGEMENT
      > HAS_TYPE (strict_total_order?[cardinal_number])


    % ==========================================================================
    % Transitivity properties of the cardinal (in)equalities
    % ==========================================================================

    cardinal_lt_le_transitive: LEMMA
      FORALL A, B, C: A < B AND B <= C IMPLIES A < C

    cardinal_le_lt_transitive: LEMMA
      FORALL A, B, C: A <= B AND B < C IMPLIES A < C

    cardinal_ge_gt_transitive: LEMMA
      FORALL A, B, C: A >= B AND B > C IMPLIES A > C

    cardinal_gt_ge_transitive: LEMMA
      FORALL A, B, C: A > B AND B >= C IMPLIES A > C


    % ==========================================================================
    % Least/greatest elements
    % ==========================================================================

    cardinal_empty_least: LEMMA FORALL A: cardinal(emptyset[T]) <= A

    cardinal_full_greatest: LEMMA FORALL A: A <= cardinal(fullset[T])

   END cardinal

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 45, column 56) for  R
      % expected type  S: finite_set[T]
  cardinal_finite_card_TCC1: OBLIGATION
    FORALL (S: finite_set[T], R: (cardinal(S))): is_finite[T](R);

  % Judgement subtype TCC generated (at line 135, column 4) for  <
      % expected type  (strict_total_order?[cardinal_number])
  cardinal_lt_strict_total_order: OBLIGATION
    strict_total_order?[cardinal_number](<);

  % Judgement subtype TCC generated (at line 138, column 4) for  <=
      % expected type  (total_order?[cardinal_number])
  cardinal_le_total_order: OBLIGATION total_order?[cardinal_number](<=);

  % Judgement subtype TCC generated (at line 144, column 4) for  >=
      % expected type  (total_order?[cardinal_number])
  cardinal_ge_total_order: OBLIGATION total_order?[cardinal_number](>=);

  % Judgement subtype TCC generated (at line 147, column 4) for  >
      % expected type  (strict_total_order?[cardinal_number])
  cardinal_gt_strict_total_order: OBLIGATION
    strict_total_order?[cardinal_number](>);


body:
  %-------------------------------------------------------------------------
  %
  %  The cardinality of a set is always less than the cardinality of its
  %  power set.
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  sets_aux: card_comp_set[set[T],T], card_comp_set[T,set[T]],
  %    card_comp_set_props[T,set[T]], card_power_set[T]
  %
  %-------------------------------------------------------------------------
  card_power_set[T: TYPE]: THEORY
   BEGIN

    IMPORTING card_comp_set_props[T, set[T]]

    card_power: THEOREM FORALL (S: set[T]): card_lt(S, powerset(S))

   END card_power_set


body:
  %-------------------------------------------------------------------------
  %
  %  Compare set cardinalities for any two sets, whether finite or infinite.
  %  See cardinal.pvs for a cardinality(S) function that operates on any
  %  set, whether finite or infinite, using these definitions as a basis.
  %
  %  We have to take great care with empty sets.  The basic problem is that
  %  there is NO function from a nonempty domain to an empty range.  This is
  %  why card_lt and card_ge deal with functions that are "reversed" from
  %  those in the other definitions, so that we can talk about injective
  %  functions (which exist from empty domains to nonempty ranges) instead
  %  of surjective functions (which do not exist from nonempty domains to
  %  empty ranges).
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: functions[T1,T2], functions[T2,T1]
  %  sets_aux: card_comp[T1,T2]
  %
  %-------------------------------------------------------------------------
  card_comp[T1: TYPE, T2: TYPE]: THEORY
   BEGIN

    IMPORTING functions[T1, T2], functions[T2, T1]

    card_lt: bool = NOT (EXISTS (f: [T2 -> T1]): injective?(f))

    card_le: bool = EXISTS (f: [T1 -> T2]): injective?(f)

    card_eq: bool = EXISTS (f: [T1 -> T2]): bijective?(f)

    card_ge: bool = EXISTS (f: [T2 -> T1]): injective?(f)

    card_gt: bool = NOT (EXISTS (f: [T1 -> T2]): injective?(f))

   END card_comp


body:
  %-------------------------------------------------------------------------
  %
  %  Basic properties of the type cardinality comparison functions
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: functions[T1,T2], functions[T2,T1]
  %  sets_aux: card_comp[T1,T2], card_comp[T2,T1], card_comp_props[T1,T2]
  %
  %-------------------------------------------------------------------------
  card_comp_props[T1: TYPE, T2: TYPE]: THEORY

   EXPORTING ALL WITH functions[T1, T2], functions[T2, T1],
                      card_comp[T1, T2], card_comp[T2, T1]

   BEGIN

    IMPORTING card_comp[T1, T2], card_comp[T2, T1]

    % The following imports are for the proofs only
    IMPORTING function_inverse_def[T1, T2]
    IMPORTING function_inverse_def[T2, T1]
    IMPORTING orders@set_dichotomous[T1, T2], 
              orders@set_antisymmetric[T1, T2]


    % ==========================================================================
    % We defined card_lt and card_ge as we did to avoid special casing empty
    % sets, which these results show would be necessary.
    % ==========================================================================

    card_lt_surj: LEMMA
      card_lt[T1, T2] IFF
       (EXISTS (t: T2): TRUE) AND NOT (EXISTS (f: [T1 -> T2]): surjective?(f))

    card_ge_surj: LEMMA
      card_ge[T1, T2] IFF
       ((EXISTS (t: T1): TRUE) AND (FORALL (t: T2): FALSE)) OR
        (EXISTS (f: [T1 -> T2]): surjective?(f))


    % ==========================================================================
    % The relationships of the functions
    % ==========================================================================

    card_lt_le: LEMMA card_lt[T1, T2] => card_le[T1, T2]
    card_gt_ge: LEMMA card_gt[T1, T2] => card_ge[T1, T2]

    card_lt_gt: LEMMA card_lt[T1, T2] = card_gt[T2, T1]
    card_le_ge: LEMMA card_le[T1, T2] = card_ge[T2, T1]
    card_gt_lt: LEMMA card_gt[T1, T2] = card_lt[T2, T1]
    card_ge_le: LEMMA card_ge[T1, T2] = card_le[T2, T1]

    card_lt_ge: LEMMA card_lt[T1, T2] XOR card_ge[T1, T2]
    card_le_gt: LEMMA card_le[T1, T2] XOR card_gt[T1, T2]

    card_eq_le_ge: LEMMA
      card_eq[T1, T2] IFF card_le[T1, T2] AND card_ge[T1, T2]
    card_le_lt_eq: LEMMA
      card_le[T1, T2] IFF card_lt[T1, T2] OR card_eq[T1, T2]
    card_ge_gt_eq: LEMMA
      card_ge[T1, T2] IFF card_gt[T1, T2] OR card_eq[T1, T2]

    card_lt_neq_ngt: LEMMA
      card_lt[T1, T2] => NOT card_eq[T1, T2] AND NOT card_gt[T1, T2]
    card_gt_neq_nlt: LEMMA
      card_gt[T1, T2] => NOT card_eq[T1, T2] AND NOT card_lt[T1, T2]


    % ==========================================================================
    % (anti)commutativity and (anti)symmetry of the functions
    % ==========================================================================

    card_lt_anticommutative: LEMMA card_lt[T1, T2] => NOT card_lt[T2, T1]

    card_le_antisymmetric: LEMMA
      card_le[T1, T2] AND card_le[T2, T1] => card_eq[T1, T2]

    card_eq_symmetric: LEMMA card_eq[T1, T2] = card_eq[T2, T1]

    card_ge_antisymmetric: LEMMA
      card_ge[T1, T2] AND card_ge[T2, T1] => card_eq[T1, T2]

    card_gt_anticommutative: LEMMA card_gt[T1, T2] => NOT card_gt[T2, T1]


    % ==========================================================================
    % dichotomy and trichotomy of the functions
    % ==========================================================================

    card_lt_trichotomous: LEMMA
      card_lt[T1, T2] OR card_lt[T2, T1] OR card_eq[T1, T2]

    card_le_dichotomous: LEMMA card_le[T1, T2] OR card_le[T2, T1]

    card_ge_dichotomous: LEMMA card_ge[T1, T2] OR card_ge[T2, T1]

    card_gt_trichotomous: LEMMA
      card_gt[T1, T2] OR card_gt[T2, T1] OR card_eq[T1, T2]

   END card_comp_props


body:
  %-------------------------------------------------------------------------
  %
  %  The cardinality of a set is always less than the cardinality of its
  %  power set.
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: functions[set[T],T], functions[T,set[T]]
  %  sets_aux: card_comp[set[T],T], card_comp[T,set[T]],
  %    card_comp_props[T,set[T]], card_power[T]
  %
  %-------------------------------------------------------------------------
  card_power[T: TYPE]: THEORY
   BEGIN

    IMPORTING card_comp_props[T, set[T]]

    card_power: THEOREM card_lt[T, set[T]]

   END card_power


body:
  %-------------------------------------------------------------------------
  %
  %  Transitivity properties of the cardinality comparison functions.
  %
  %  For PVS version 3.2.  November 4, 2004
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %
  %  EXPORTS
  %  -------
  %  prelude: functions[T1,T2], functions[T1,T3], functions[T2,T1],
  %    functions[T2,T3], functions[T3,T1], functions[T3,T2]
  %  sets_aux: card_comp[T1,T2], card_comp[T1,T3], card_comp[T2,T3],
  %    card_comp_transitive[T1,T2,T3]
  %
  %-------------------------------------------------------------------------
  card_comp_transitive[T1: TYPE, T2: TYPE, T3: TYPE]: THEORY

   EXPORTING ALL WITH functions[T1, T2], functions[T1, T3], functions[T2, T1],
                      functions[T2, T3], functions[T3, T1], functions[T3, T2],
                      card_comp[T1, T2], card_comp[T2, T3], card_comp[T1, T3]

   BEGIN

    IMPORTING card_comp[T1, T2], card_comp[T2, T3], card_comp[T1, T3]

    % The following imports are for the proofs only
    IMPORTING function_inverse_def[T1, T2], function_inverse_def[T2, T3]
    IMPORTING orders@set_dichotomous[T1, T2]

    % card_lt
    card_lt_transitive: LEMMA
      card_lt[T1, T2] AND card_lt[T2, T3] => card_lt[T1, T3]
    card_lt_le_transitive: LEMMA
      card_lt[T1, T2] AND card_le[T2, T3] => card_lt[T1, T3]
    card_lt_eq_transitive: LEMMA
      card_lt[T1, T2] AND card_eq[T2, T3] => card_lt[T1, T3]
    card_le_lt_transitive: LEMMA
      card_le[T1, T2] AND card_lt[T2, T3] => card_lt[T1, T3]
    card_eq_lt_transitive: LEMMA
      card_eq[T1, T2] AND card_lt[T2, T3] => card_lt[T1, T3]

    % card_le
    card_le_transitive: LEMMA
      card_le[T1, T2] AND card_le[T2, T3] => card_le[T1, T3]
    card_le_eq_transitive: LEMMA
      card_le[T1, T2] AND card_eq[T2, T3] => card_le[T1, T3]
    card_eq_le_transitive: LEMMA
      card_eq[T1, T2] AND card_le[T2, T3] => card_le[T1, T3]

    % card_eq
    card_eq_transitive: LEMMA
      card_eq[T1, T2] AND card_eq[T2, T3] => card_eq[T1, T3]

    % card_ge
    card_eq_ge_transitive: LEMMA
      card_eq[T1, T2] AND card_ge[T2, T3] => card_ge[T1, T3]
    card_ge_eq_transitive: LEMMA
      card_ge[T1, T2] AND card_eq[T2, T3] => card_ge[T1, T3]
    card_ge_transitive: LEMMA
      card_ge[T1, T2] AND card_ge[T2, T3] => card_ge[T1, T3]

    % card_gt
    card_eq_gt_transitive: LEMMA
      card_eq[T1, T2] AND card_gt[T2, T3] => card_gt[T1, T3]
    card_ge_gt_transitive: LEMMA
      card_ge[T1, T2] AND card_gt[T2, T3] => card_gt[T1, T3]
    card_gt_eq_transitive: LEMMA
      card_gt[T1, T2] AND card_eq[T2, T3] => card_gt[T1, T3]
    card_gt_ge_transitive: LEMMA
      card_gt[T1, T2] AND card_ge[T2, T3] => card_gt[T1, T3]
    card_gt_transitive: LEMMA
      card_gt[T1, T2] AND card_gt[T2, T3] => card_gt[T1, T3]

   END card_comp_transitive


body:
  fun_below_props : THEORY
  %------------------------------------------------------------------------
  %      by Bruno Dutertre    Royal Holloway & Bedford New College
  %------------------------------------------------------------------------

  BEGIN

    n, m : VAR nat
    p : VAR posnat

    % ----- Cartesian product of {0 ... n-1} and {0 ... m-1} -----

    cartesian_bijection : THEOREM
  	(EXISTS (f: [[below[n], below[m]] -> below[n * m]]): bijective?(f))

    %  ----- Functions from {0 ... n-1} to {0 ... m-1} -----

    empty_domain1    : LEMMA (EXISTS (f: [below[0] -> below[m]]): TRUE)

    empty_domain2    : LEMMA (FORALL (f1, f2: [below[0] -> below[m]]): f1 = f2)

    empty_range      : LEMMA m = 0 IMPLIES 
                               (FORALL (f: [below[p]-> below[m]]): FALSE)

    funset_bijection : THEOREM
  	(EXISTS (f: [[below[n] -> below[m]] -> below[m ^ n]]): bijective?(f))

  END fun_below_props

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 26, column 50) for  n
      % expected type  {i: int | m /= 0 OR i >= 0}
  funset_bijection_TCC1: OBLIGATION FORALL (m, n: nat): m /= 0 OR n >= 0;


body:
  set_of_functions [ T1, T2: TYPE ]: THEORY
  %------------------------------------------------------------------------
  %  number of functions from finite set A to finite set B
  %
  %        by Bruno Dutertre    Royal Holloway & Bedford New College
  % 
  %    defines:
  % 
  %      funset(A, B): finite_set[[(A)->(B)]] = fullset[[(A)->(B)]]
  %
  %------------------------------------------------------------------------
  BEGIN

    IMPORTING fun_below_props, 
              finite_sets@func_composition

    n, m: VAR nat

    A: VAR finite_set[T1]
    B: VAR finite_set[T2]

    empty_finite_domain1    : LEMMA card(A) = 0 IMPLIES 
                                          (EXISTS (f: [(A) -> (B)]): TRUE)

    empty_finite_domain2    : LEMMA card(A) = 0 IMPLIES 
                                          (FORALL (f1, f2: [(A) -> (B)]): f1 = f2)

    empty_finite_range      : LEMMA card(B) = 0 AND card(A) /= 0 IMPLIES 
                                          (FORALL (f: [(A) -> (B)]): FALSE)

    finite_funset_bijection1: THEOREM card(A) = n AND card(B) = m IMPLIES
           (EXISTS (f: [[(A) -> (B)] -> [below[n] -> below[m]]]): bijective?(f))

    finite_funset_bijection2: THEOREM card(A) = n AND card(B) = m IMPLIES
           (EXISTS (f: [[(A) -> (B)] -> below[m ^ n]]): bijective?(f))

    finite_funset           : THEOREM is_finite_type[[(A) -> (B)]]

    funset(A, B): finite_set[[(A)->(B)]] = fullset[[(A)->(B)]]

    card_funset             : THEOREM card(funset(A, B)) = card(B) ^ card(A)

  END set_of_functions

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 35, column 48) for  n
      % expected type  {i: int | m /= 0 OR i >= 0}
  finite_funset_bijection2_TCC1: OBLIGATION
    FORALL (A: finite_set[T1], B: finite_set[T2], m, n: nat):
      card(B) = m AND card(A) = n IMPLIES m /= 0 OR n >= 0;

  % Subtype TCC generated (at line 39, column 41) for  fullset[[(A) -> (B)]]
      % expected type  finite_set[[(A) -> (B)]]
  funset_TCC1: OBLIGATION
    FORALL (A: finite_set[T1], B: finite_set[T2]):
      is_finite[[(A) -> (B)]](fullset[[(A) -> (B)]]);

  % Subtype TCC generated (at line 41, column 67) for  card(A)
      % expected type  {i: int | card(B) /= 0 OR i >= 0}
  card_funset_TCC1: OBLIGATION
    FORALL (A: finite_set[T1], B: finite_set[T2]):
      card[T2](B) /= 0 OR card[T1](A) >= 0;


body:
  power_sets [T: TYPE ]: THEORY
  %------------------------------------------------------------------------
  %  Power sets, finiteness and cardinality    (Version 1.0) 6/28/96
  %
  %      by Bruno Dutertre    Royal Holloway & Bedford New College
  % 
  %   Establishes fundamental properties.  The definition and finiteness
  %   proof have moved to the prelude.
  %  
  %------------------------------------------------------------------------

  EXPORTING ALL WITH finite_sets[nat], finite_sets[T], sets[T],
                     finite_sets_of_sets[T], set_of_functions[T, nat]

  BEGIN

    IMPORTING finite_sets@finite_sets_card_eq, finite_sets_of_sets[T], sets[T]

    S, U: VAR set[T]
    A: VAR finite_set[T]
    n: VAR nat

    B: finite_set[nat] = { n | n <= 1} 

    card_B: LEMMA  card(B) = 2

    IMPORTING set_of_functions[T, nat], finite_sets@finite_sets_eq

    powerset_bijection       : LEMMA (EXISTS (f: [(powerset(S)) -> [(S)->(B)]]):
                                                   bijective?(f))

    finite_powerset_bijection: LEMMA (EXISTS (f: [(powerset(A))->(funset(A,B))]):
                                                   bijective?(f))

    card_powerset            : THEOREM card(powerset(A)) = 2 ^ card(A)

    elem_finite_powerset     : THEOREM (FORALL (X: (powerset(A))): is_finite(X))

    SS: VAR set[set[T]]
    finite_subset_of_powerset: THEOREM subset?(SS,powerset(A)) 
                                          IMPLIES is_finite(SS)

  END power_sets

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 23, column 23) for  {n | n <= 1}
      % expected type  finite_set[nat]
  B_TCC1: OBLIGATION is_finite[nat]({n | n <= 1});


body:
  top : THEORY
  BEGIN

    IMPORTING util,
    	    minmax,
              multi_bernstein,
  	    multi_polynomial,
              poly2bernstein,
              vardirselector,
              bernstein_minmax,
              MPoly,
  	    multi_polylist,
              poly_minmax,
              Outcome,
              strat_util,
  	    strategies,
              boxes_def,
              OutBoxes,
  	    boxes
  %	    tests

  % The theories examples.pvs and benchmarks.pvs contain several examples of 
  % polynomial inequalities proved using the strategy (bernstein). To prove
  % these theories in batch mode, use the proveit utility of PVS 5.0:
  % <pvs-dir>/proveit examples benchmarks 

  % The directory Grizzly contains a prototype client-server tool for solving
  % global optimization problems.

  END top


body:
  util : THEORY
  BEGIN

    IMPORTING structures@array2list

    %%% Types 

    IntervalEndpoints : TYPE = [nat->[bool,bool]]  % Index i represent i-th var. It points to a qualification
                               % of lowwer and upper bounds of the variable in a box. It's either open/closed
                               % or bounded/unbounded.
    Vars              : TYPE = [nat->real] % Index i represents i-th var. 
                                           % It points to the value of that variable.
    DegreeMono        : TYPE = [nat->nat] % Index i represents i-th var. It points to the degree of that var.
    CoeffMono         : TYPE = [nat->nat] %
    Polynomial        : TYPE = [nat->real] % Index i represents degree i. It points to the coeffient on that
                               % degree
    Polyproduct       : TYPE = [nat->Polynomial] % Index i represents i-th var.
                               % It points to a univariate polynomial on that variable
    Coeff             : TYPE = [nat->real] % Index i represents degree i. 
                               % It points to the coefficient of that var.
    MultiPolynomial   : TYPE = [nat->Polyproduct] % Index i points to the ith-term (standard polynomial)
    MultiBernstein    : TYPE = [nat->Polyproduct] % Index i points to the ith-term (Bernstein polynomial)
    PolyList          : TYPE = list[list[list[real]]] % List representation of multi-variate polynomial

    %%% Variables 

    mpoly           : VAR MultiPolynomial
    boundedpts,  
    intendpts	  : VAR IntervalEndpoints
    rel    	  : VAR [[real,real]->bool]
    nvars,terms     : VAR posnat
    v		  : VAR nat
    degmono1,
    degmono2,
    degmono         : VAR DegreeMono
    f,
    coeffmono1,
    coeffmono2,
    coeffmono	  : VAR CoeffMono
    Avars,Bvars,
    X               : VAR Vars

    realorder?(rel) : bool = (rel = (<=)) OR (rel = (<)) OR (rel = (>=)) OR (rel = (>))
    RealOrder       : TYPE = (realorder?)
    relreal         : VAR RealOrder

    le_realorder    : JUDGEMENT <= HAS_TYPE RealOrder
    lt_realorder    : JUDGEMENT <  HAS_TYPE RealOrder
    ge_realorder    : JUDGEMENT >= HAS_TYPE RealOrder
    gt_realorder    : JUDGEMENT >  HAS_TYPE RealOrder

    zeroes(i:nat)   : MACRO real = 0
    ones(i:nat)     : MACRO real = 1

    closed_box?(nvars)(intendpts) : bool = 
      FORALL (iup:below(nvars)): intendpts(iup)`1 AND intendpts(iup)`2

    intendpts_true(i:nat): MACRO [bool,bool] = (TRUE,TRUE)
    boundedpts_true(i:nat): MACRO [bool,bool] = (TRUE,TRUE)

    bounded_points_true?(nvars)(boundedpts): bool =
      FORALL (i:below(nvars)): LET bpt = boundedpts(i) IN bpt`1 AND bpt`2

    relreal_scal : LEMMA 
      FORALL (x,y:real,pr:posreal): relreal(x,y) IFF relreal(pr*x,pr*y)

    corner_point?(nvars,degmono)(coeffmono): bool =
      FORALL (j:below(nvars)): coeffmono(j) = 0 OR coeffmono(j) = degmono(j)

    edge_point?(degmono,nvars,f,intendpts,v)(ep:bool) : bool =
      v <= nvars AND 
      (ep IMPLIES FORALL (i:subrange(v,nvars-1)):
                  f(i) = 0 AND intendpts(i)`1 OR
                  degmono(i)/=0 AND f(i) = degmono(i) AND intendpts(i)`2)

    %%% Unitbox

    unitbox?(nvars)(X) : bool = 
     FORALL (j:below(nvars)): 0 <= X(j) AND X(j) <= 1

    bounded_points_exclusive?(nvars)(boundedpts): bool = 
      FORALL (ii:below(nvars)): boundedpts(ii)`1 OR boundedpts(ii)`2

    lt_below?(nvars)(Avars,Bvars) : bool = 
      FORALL (j:below(nvars)): Avars(j)<Bvars(j)

    le_below_mono?(nvars)(degmono1,degmono2) : bool = 
      FORALL (j:below(nvars)): degmono1(j)<=degmono2(j)

    eq_below_mono?(nvars)(coeffmono1,coeffmono2) : bool = 
      FORALL (j:below(nvars)): coeffmono1(j)=coeffmono2(j)

    interval_between?(A,B:real,intpt,bdpt:[bool,bool])(xyz:real): bool =
       LET relA: [[real,real]->bool]= IF intpt`1 THEN <= ELSE < ENDIF,	
       	 relB: [[real,real]->bool]= IF intpt`2 THEN <= ELSE < ENDIF
       IN
        (bdpt`1 AND bdpt`2 IMPLIES A < B) AND
        (bdpt`1 OR bdpt`2) AND
        (bdpt`1 IMPLIES relA(A,xyz)) AND
        (bdpt`2 IMPLIES relB(xyz,B))

    boxbetween?(nvars)(Avars,Bvars,intendpts,boundedpts)(X) : bool =
      FORALL (j:below(nvars)):
       interval_between?(Avars(j),Bvars(j),intendpts(j),boundedpts(j))(X(j))
   
    %%% Translate intervals [A,B],(A,B],[A,B),(A,B),[A,infty),(A,infty),(-infty,B]
    %%% (-infty,B) to [0,1],(0,1],[0,1),(0,1),(0,1],(0,1),(0,1],(0,1), respectively

    interval_endpoints_inf_trans(Avars,Bvars,intendpts,boundedpts)(i:nat): [bool,bool] =
      IF (boundedpts(i)`1 AND boundedpts(i)`2) THEN intendpts(i)
      ELSIF boundedpts(i)`1 THEN (FALSE,intendpts(i)`1)
      ELSE  (FALSE,intendpts(i)`2)
      ENDIF

    %%% Translate X to [Avars,Bvars] for Arrays

    denormalize_lambda(nvars,X,boundedpts)(Avars,Bvars) : Vars = 
      LAMBDA (i:nat): 
        IF i < nvars THEN 
          IF (boundedpts(i)`1 AND boundedpts(i)`2) THEN 
            Avars(i) + X(i)*(Bvars(i)-Avars(i))
          ELSIF boundedpts(i)`1 AND X(i)/=0 THEN 
            (1+X(i)*(Avars(i)-1))/X(i)
  	ELSIF boundedpts(i)`2 AND X(i)/=0 THEN 
            (-1-X(i)*(-Bvars(i)-1))/X(i)
  	ELSE 0 ENDIF
        ELSE 0
        ENDIF

    normalize_lambda(nvars,X,boundedpts)(ABvars:(lt_below?(nvars))) : Vars = 
      LAMBDA (i:nat): LET (Avars,Bvars) = ABvars IN 
        IF i < nvars AND (boundedpts(i)`1 IMPLIES 
           X(i)/=Avars(i)-1) AND (boundedpts(i)`2 IMPLIES X(i)/=Bvars(i)+1) THEN
          IF (boundedpts(i)`1 AND boundedpts(i)`2) THEN 
            (X(i)-Avars(i))/(Bvars(i)-Avars(i))
  	ELSIF boundedpts(i)`1 THEN 
            1/(X(i)-Avars(i)+1)
  	ELSIF boundedpts(i)`2 THEN 
            1/(Bvars(i)+1-X(i))
  	ELSE  0 ENDIF
        ELSE 0
        ENDIF

    normalize_lambda_unitbox: LEMMA
      boxbetween?(nvars)(Avars, Bvars, intendpts, boundedpts)(X) AND
      lt_below?(nvars)(Avars,Bvars)
      IMPLIES
      unitbox?(nvars)
                (normalize_lambda(nvars, X, boundedpts)
                                 (Avars, Bvars))

    %%% Translate X to [Avars,Bvars] for Lists

    denormalize_listreal_rec(l:list[real],nnvars:upfrom(length(l)),Avars,Bvars,boundedpts): RECURSIVE 
      {norml : listn[real](length(l)) |
               FORALL(i:below(length(l))) :
                 nth(norml,i) = LET n = nnvars-length(l) IN 
  	                       IF n+i<nnvars THEN
  	       		          IF (boundedpts(n+i)`1 AND boundedpts(n+i)`2) THEN 
                                      Avars(n+i) + nth(l,i)*(Bvars(n+i)-Avars(n+i))
  				  ELSIF boundedpts(n+i)`1 AND nth(l,i)/=0 THEN 
                                      (1+nth(l,i)*(Avars(n+i)-1))/nth(l,i)
  				  ELSIF boundedpts(n+i)`2 AND nth(l,i)/=0 THEN 
                                      (-1-nth(l,i)*(-Bvars(n+i)-1))/nth(l,i)
  				  ELSE  0 ENDIF
  			       ELSE 0 ENDIF} =
      CASES l OF
        null : null,
        cons(a,r) : cons(LET n = nnvars-length(l) IN 
  	                       IF n<nnvars THEN
  	       		          IF (boundedpts(n)`1 AND boundedpts(n)`2) THEN 
                                      Avars(n) + a*(Bvars(n)-Avars(n))
  				  ELSIF boundedpts(n)`1 AND a/=0 THEN 
                                      (1+a*(Avars(n)-1))/a
  				  ELSIF boundedpts(n)`2 AND a/=0 THEN 
                                      (-1-a*(-Bvars(n)-1))/a
  				  ELSE  0 ENDIF
  			       ELSE 0 ENDIF,
                         denormalize_listreal_rec(cdr(l),nnvars,Avars,Bvars,boundedpts))
      ENDCASES
    MEASURE l BY <<

    denormalize_listreal(l:list[real])(Avars,Bvars,boundedpts): listn[real](length(l)) =
      denormalize_listreal_rec(l,length(l),Avars,Bvars,boundedpts)

    %%% Polynomials as arrays <-> Polynomials as lists

    polylist(mpoly,degmono,nvars,terms) : PolyList =
      array2list[list[list[real]]](terms)(LAMBDA(t:nat):
                array2list[list[real]](nvars)(LAMBDA(v:nat):
                          array2list[real](degmono(v)+1)(mpoly(t)(v))))   

    translist(mpl:PolyList)(t:nat)(v:nat)(d:nat) : real =
      list2array[real](0)(
                list2array[list[real]](null)(
                          list2array[list[list[real]]](null)(mpl)(t))(v))(d)

    translist_polylist_id: LEMMA  
     FORALL (t:below(terms),v:below(nvars),i:upto(degmono(v))):
       translist(polylist(mpoly,degmono,nvars,terms))(t)(v)(i) =
       mpoly(t)(v)(i)
   
    %%% Monomial utility functions

    corner_to_point(f:CoeffMono,nvars): {l : listn[real](nvars) | 
                                             unitbox?(nvars)(list2array(0)(l))} =
      array2list(nvars)(LAMBDA(v:nat):IF f(v)=0 THEN 0 ELSE 1 ENDIF)

    mono_le?(nvars)(degmono1,degmono2): bool = 
      FORALL (ii:below(nvars)): degmono1(ii)<=degmono2(ii)

    zero_poly_prod(v:nat)(i:nat): real = 0

    mono_max(degmono1,degmono2)(i:nat): nat = 
      max(degmono1(i),degmono2(i))

    mono_sum(degmono1,degmono2)(i:nat): nat = 
      degmono1(i)+degmono2(i)

  END util

addendum:
  %%% ================ Addendum: generated declarations ================

  % Judgement subtype TCC generated (at line 47, column 30) for  <=
      % expected type  RealOrder
  le_realorder: OBLIGATION realorder?(<=);

  % Judgement subtype TCC generated (at line 48, column 30) for  <
      % expected type  RealOrder
  lt_realorder: OBLIGATION realorder?(<);

  % Judgement subtype TCC generated (at line 49, column 30) for  >=
      % expected type  RealOrder
  ge_realorder: OBLIGATION realorder?(>=);

  % Judgement subtype TCC generated (at line 50, column 30) for  >
      % expected type  RealOrder
  gt_realorder: OBLIGATION realorder?(>);

  % Subtype TCC generated (at line 73, column 18) for  i
      % expected type  nat
  edge_point?_TCC1: OBLIGATION
    FORALL (nvars: posnat, v: nat, ep: bool):
      ep AND v <= nvars IMPLIES (FORALL (i: subrange(v, nvars - 1)): i >= 0);

  % Subtype TCC generated (at line 135, column 27) for  (Bvars(i) - Avars(i))
      % expected type  nznum
  normalize_lambda_TCC1: OBLIGATION
    FORALL (nvars: posnat, X: Vars, boundedpts: IntervalEndpoints,
            ABvars: (lt_below?(nvars)), i: nat, Avars: Vars, Bvars: Vars):
           boundedpts(i)`1 AND boundedpts(i)`2 AND i < nvars
       AND (boundedpts(i)`1 IMPLIES X(i) /= Avars(i) - 1)
       AND (boundedpts(i)`2 IMPLIES X(i) /= Bvars(i) + 1) AND Bvars = ABvars`2
       AND Avars = ABvars`1
       IMPLIES (Bvars(i) - Avars(i)) /= 0;

  % Subtype TCC generated (at line 137, column 13) for  (X(i) - Avars(i) + 1)
      % expected type  nznum
  normalize_lambda_TCC2: OBLIGATION
    FORALL (nvars: posnat, X: Vars, boundedpts: IntervalEndpoints,
            ABvars: (lt_below?(nvars)), i: nat, Avars: Vars, Bvars: Vars):
           boundedpts(i)`1 AND NOT (boundedpts(i)`1 AND boundedpts(i)`2)
       AND i < nvars AND (boundedpts(i)`1 IMPLIES X(i) /= Avars(i) - 1)
       AND (boundedpts(i)`2 IMPLIES X(i) /= Bvars(i) + 1) AND Bvars = ABvars`2
       AND Avars = ABvars`1
       IMPLIES (X(i) - Avars(i) + 1) /= 0;

  % Subtype TCC generated (at line 139, column 13) for  (Bvars(i) + 1 - X(i))
      % expected type  nznum
  normalize_lambda_TCC3: OBLIGATION
    FORALL (nvars: posnat, X: Vars, boundedpts: IntervalEndpoints,
            ABvars: (lt_below?(nvars)), i: nat, Avars: Vars, Bvars: Vars):
           boundedpts(i)`2 AND NOT boundedpts(i)`1
       AND NOT (boundedpts(i)`1 AND boundedpts(i)`2) AND i < nvars
       AND (boundedpts(i)`1 IMPLIES X(i) /= Avars(i) - 1)
       AND (boundedpts(i)`2 IMPLIES X(i) /= Bvars(i) + 1) AND Bvars = ABvars`2
       AND Avars = ABvars`1
       IMPLIES (Bvars(i) + 1 - X(i)) /= 0;

  % Subtype TCC generated (at line 157, column 25) for  i
      % expected type  below[length[real](norml)]
  denormalize_listreal_rec_TCC1: OBLIGATION
    FORALL (l: list[real], norml: listn[real](length[real](l)),
            i: below(length[real](l))):
      i < length[real](norml);

  % Subtype TCC generated (at line 159, column 35) for  n + i
      % expected type  nat
  denormalize_listreal_rec_TCC2: OBLIGATION
    FORALL (l: list[real], nnvars: upfrom(length(l)),
            norml: listn[real](length[real](l)), i: below(length[real](l)),
            n: int):
      n + i < nnvars AND n = nnvars - length(l) IMPLIES n + i >= 0;

  % Subtype TCC generated (at line 168, column 13) for  null
      % expected type  {norml: listn[real](length(l)) |
                     %          FORALL (i: below(length(l))):
                     %            nth(norml, i) =
                     %             IF (boundedpts(i + nnvars - length(l))`1
                     %                 AND
                     %                 boundedpts(i + nnvars - length(l))`2)
                     %               THEN Avars(i + nnvars - length(l))
                     %                    +
                     %                    Bvars(i + nnvars - length(l))
                     %                    *
                     %                    nth(l, i)
                     %                    -
                     %                    Avars(i + nnvars - length(l))
                     %                    *
                     %                    nth(l, i)
                     %             ELSIF boundedpts(i + nnvars - length(l))`1
                     %                   AND
                     %                   nth(l, i) /= 0
                     %               THEN (1
                     %                     +
                     %                     Avars(i + nnvars - length(l))
                     %                     *
                     %                     nth(l, i)
                     %                     -
                     %                     nth(l, i))
                     %                    /
                     %                    nth(l, i)
                     %             ELSIF boundedpts(i + nnvars - length(l))`2
                     %                   AND
                     %                   nth(l, i) /= 0
                     %               THEN (nth(l, i) - 1
                     %                     -
                     %                     nth(l, i)
                     %                     *
                     %                     -Bvars(i + nnvars - length(l)))
                     %                    /
                     %                    nth(l, i)
                     %             ELSE 0
                     %             ENDIF}
  denormalize_listreal_rec_TCC3: OBLIGATION
    FORALL (l: list[real], nnvars: upfrom(length[real](l)), Avars: Vars,
            Bvars: Vars, boundedpts: IntervalEndpoints):
      l = null IMPLIES
       length[real](null[real]) = length[real](l) AND
        (FORALL (i: below(length[real](l))):
           nth[real](null[real], i) =
            IF (boundedpts(i + nnvars - length[real](l))`1 AND
                 boundedpts(i + nnvars - length[real](l))`2)
              THEN Avars(i + nnvars - length[real](l)) +
                    Bvars(i + nnvars - length[real](l)) * nth[real](l, i)
                    - Avars(i + nnvars - length[real](l)) * nth[real](l, i)
            ELSIF boundedpts(i + nnvars - length[real](l))`1 AND
                   nth[real](l, i) /= 0
              THEN (1 + Avars(i + nnvars - length[real](l)) * nth[real](l, i)
                     - nth[real](l, i))
                    / nth[real](l, i)
            ELSIF boundedpts(i + nnvars - length[real](l))`2 AND
                   nth[real](l, i) /= 0
              THEN (nth[real](l, i) - 1 -
                     nth[real](l, i) * -Bvars(i + nnvars - length[real](l)))
                    / nth[real](l, i)
            ELSE 0
            ENDIF);

  % Subtype TCC generated (at line 171, column 35) for  n
      % expected type  nat
  denormalize_listreal_rec_TCC4: OBLIGATION
    FORALL (l: list[real], nnvars: upfrom(length[real](l)), a: real,
            r: list[real]):
      l = cons(a, r) IMPLIES
       (FORALL (n: int):
          n < nnvars AND n = nnvars - length(l) IMPLIES n >= 0);

  % Subtype TCC generated (at line 179, column 52) for  l
      % expected type  (cons?[real])
  denormalize_listreal_rec_TCC5: OBLIGATION
    FORALL (l: list[real], a: real, r: list[real]):
      l = cons(a, r) IMPLIES cons?[real](l);

  % Subtype TCC generated (at line 179, column 55) for  nnvars
      % expected type  upfrom(length(cdr(l)))
  denormalize_listreal_rec_TCC6: OBLIGATION
    FORALL (l: list[real], nnvars: upfrom(length[real](l)), a: real,
            r: list[real]):
      l = cons(a, r) IMPLIES nnvars >= length[real](cdr[real](l));

  % Termination TCC generated (at line 179, column 23) for
      % denormalize_listreal_rec(cdr(l), nnvars, Avars, Bvars, boundedpts)
  denormalize_listreal_rec_TCC7: OBLIGATION
    FORALL (l: list[real], a: real, r: list[real]):
      l = cons(a, r) IMPLIES <<[real](cdr[real](l), l);

  % Subtype TCC generated (at line 169, column 18) for
      % cons(LET n = nnvars - length(l) IN
      %        IF n < nnvars
      %          THEN IF (boundedpts(n)`1 AND boundedpts(n)`2)
      %                 THEN Avars(n) + a * (Bvars(n) - Avars(n))
      %               ELSIF boundedpts(n)`1 AND a /= 0
      %                 THEN (1 + a * (Avars(n) - 1)) / a
      %               ELSIF boundedpts(n)`2 AND a /= 0
      %                 THEN (-1 - a * (-Bvars(n) - 1)) / a
      %               ELSE 0
      %               ENDIF
      %        ELSE 0
      %        ENDIF,
      %      denormalize_listreal_rec(cdr(l),
      %                               nnvars,
      %                               Avars,
      %                               Bvars,
      %                               boundedpts))
      % expected type  {norml: listn[real](length(l)) |
                     %          FORALL (i: below(length(l))):
                     %            nth(norml, i) =
                     %             IF (boundedpts(i + nnvars - length(l))`1
                     %                 AND
                     %                 boundedpts(i + nnvars - length(l))`2)
                     %               THEN Avars(i + nnvars - length(l))
                     %                    +
                     %                    Bvars(i + nnvars - length(l))
                     %                    *
                     %                    nth(l, i)
                     %                    -
                     %                    Avars(i + nnvars - length(l))
                     %                    *
                     %                    nth(l, i)
                     %             ELSIF boundedpts(i + nnvars - length(l))`1
                     %                   AND
                     %                   nth(l, i) /= 0
                     %               THEN (1
                     %                     +
                     %                     Avars(i + nnvars - length(l))
                     %                     *
                     %                     nth(l, i)
                     %                     -
                     %                     nth(l, i))
                     %                    /
                     %                    nth(l, i)
                     %             ELSIF boundedpts(i + nnvars - length(l))`2
                     %                   AND
                     %                   nth(l, i) /= 0
                     %               THEN (nth(l, i) - 1
                     %                     -
                     %                     nth(l, i)
                     %                     *
                     %                     -Bvars(i + nnvars - length(l)))
                     %                    /
                     %                    nth(l, i)
                     %             ELSE 0
                     %             ENDIF}
  denormalize_listreal_rec_TCC8: OBLIGATION
    FORALL (l: list[real],
            v:
              [d1:
                 {z:
                    [l: list[real], upfrom(length(l)), Vars, Vars,
                     IntervalEndpoints] |
                          z`1 << l} ->
                 {norml: listn[real](length(d1`1)) |
                          FORALL (i: below(length(d1`1))):
                            nth(norml, i) =
                             IF (d1`5(i - length(d1`1) + d1`2)`1 AND
                                  d1`5(i - length(d1`1) + d1`2)`2)
                               THEN d1`3(i - length(d1`1) + d1`2) +
                                     d1`4(i - length(d1`1) + d1`2) *
                                      nth(d1`1, i)
                                     -
                                     d1`3(i - length(d1`1) + d1`2) *
                                      nth(d1`1, i)
                             ELSIF d1`5(i - length(d1`1) + d1`2)`1 AND
                                    nth(d1`1, i) /= 0
                               THEN (1 +
                                      d1`3(i - length(d1`1) + d1`2)
                                      *
                                      nth(d1`1, i)
                                      - nth(d1`1, i))
                                     / nth(d1`1, i)
                             ELSIF d1`5(i - length(d1`1) + d1`2)`2 AND
                                    nth(d1`1, i) /= 0
                               THEN (nth(d1`1, i) - 1 -
                                      nth(d1`1, i)
                                      *
                                      -d1`4(i - length(d1`1) + d1`2))
                                     / nth(d1`1, i)
                             ELSE 0
                             ENDIF}],
            nnvars: upfrom(length[real](l)), Avars: Vars, Bvars: Vars,
            boundedpts: IntervalEndpoints, a: real, r: list[real]):
      l = cons(a, r) IMPLIES
       length[real]
           (cons[real]
                (LET n = nnvars - length[real](l) IN
                   IF n < nnvars
                     THEN IF (boundedpts(n)`1 AND boundedpts(n)`2)
                            THEN Avars(n) + a * (Bvars(n) - Avars(n))
                          ELSIF boundedpts(n)`1 AND a /= 0
                            THEN (1 + a * (Avars(n) - 1)) / a
                          ELSIF boundedpts(n)`2 AND a /= 0
                            THEN (-1 - a * (-Bvars(n) - 1)) / a
                          ELSE 0
                          ENDIF
                   ELSE 0
                   ENDIF,
                 v(cdr[real](l), nnvars, Avars, Bvars, boundedpts)))
        = length[real](l)
        AND
        (FORALL (i: below(length[real](l))):
           nth[real]
               (cons[real]
                    (LET n = nnvars - length[real](l) IN
                       IF n < nnvars
                         THEN IF (boundedpts(n)`1 AND boundedpts(n)`2)
                                THEN Avars(n) + a * (Bvars(n) - Avars(n))
                              ELSIF boundedpts(n)`1 AND a /= 0
                                THEN (1 + a * (Avars(n) - 1)) / a
                              ELSIF boundedpts(n)`2 AND a /= 0
                                THEN (-1 - a * (-Bvars(n) - 1)) / a
                              ELSE 0
                              ENDIF
                       ELSE 0
                       ENDIF,
                     v(cdr[real](l), nnvars, Avars, Bvars, boundedpts)),
                i)
            =
            IF (boundedpts(i + nnvars - length[real](l))`1 AND
                 boundedpts(i + nnvars - length[real](l))`2)
              THEN Avars(i + nnvars - length[real](l)) +
                    Bvars(i + nnvars - length[real](l)) * nth[real](l, i)
                    - Avars(i + nnvars - length[real](l)) * nth[real](l, i)
            ELSIF boundedpts(i + nnvars - length[real](l))`1 AND
                   nth[real](l, i) /= 0
              THEN (1 + Avars(i + nnvars - length[real](l)) * nth[real](l, i)
                     - nth[real](l, i))
                    / nth[real](l, i)
            ELSIF boundedpts(i + nnvars - length[real](l))`2 AND
                   nth[real](l, i) /= 0
              THEN (nth[real](l, i) - 1 -
                     nth[real](l, i) * -Bvars(i + nnvars - length[real](l)))
                    / nth[real](l, i)
            ELSE 0
            ENDIF);

  % Subtype TCC generated (at line 184, column 31) for  length(l)
      % expected type  upfrom(length(l))
  denormalize_listreal_TCC1: OBLIGATION
    FORALL (l: list[real]): length[real](l) >= length[real](l);

  % Subtype TCC generated (at line 207, column 4) for
      % array2list(nvars)(LAMBDA (v: nat): IF f(v) = 0 THEN 0 ELSE 1 ENDIF)
      % expected type  {l: listn[real](nvars) |
                     %          unitbox?(nvars)(list2array(0)(l))}
  corner_to_point_TCC1: OBLIGATION
    FORALL (f: CoeffMono, nvars: posnat):
      unitbox?(nvars)
              (list2array[real]
                   (0)
                   (array2list[real]
                        (nvars)
                        (LAMBDA (v: nat): IF f(v) = 0 THEN 0 ELSE 1 ENDIF)));


body:
  boxes_def : THEORY
  BEGIN

    IMPORTING util,
              structures@listn[real],
  	    reals@product_below

    Box(n:posnat) : TYPE = [#
      vars_lb : listn(n),
      vars_ub : listn(n)
    #]

    setnth_box(v:nat,f:[real->real],n:posnat)(box:Box(n)) : Box(n) = (#
      vars_lb := setnth(box`vars_lb,v,f),
      vars_ub := setnth(box`vars_ub,v,f)
    #)

    map_box(n:posnat,f:[listn(n)->listn(n)])(box:Box(n)) : Box(n) = (#
      vars_lb := f(box`vars_lb),
      vars_ub := f(box`vars_ub)
    #)

    unitbox(n:posnat) : Box(n) = (#
      vars_lb := array2list(n)(zeroes),
      vars_ub := array2list(n)(ones)
    #)

    Boxes(n:posnat) : TYPE = [#
      inside,
      outside,
      unknown : list[Box(n)]
    #]

    mk_boxes(n:posnat,inside,outside,unknown:list[Box(n)]) : Boxes(n) = (#
      inside  := inside,
      outside := outside,
      unknown := unknown
    #)

    volume(n:posnat,box:Box(n)): real =
      product[below(n)](0,n-1,LAMBDA(i:below(n)):nth(box`vars_ub,i)-nth(box`vars_lb,i))
      
  END boxes_def

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 14, column 15) for
      % setnth(box`vars_lb, v, f)
      % expected type  listn[real](n)
  setnth_box_TCC1: OBLIGATION
    FORALL (v: nat, f: [real -> real], n: posnat, box: Box(n)):
      length[real](setnth[real](box`vars_lb, v, f)) = n;

  % Subtype TCC generated (at line 15, column 15) for
      % setnth(box`vars_ub, v, f)
      % expected type  listn[real](n)
  setnth_box_TCC2: OBLIGATION
    FORALL (v: nat, f: [real -> real], n: posnat, box: Box(n)):
      length[real](setnth[real](box`vars_ub, v, f)) = n;

  % Subtype TCC generated (at line 41, column 22) for  0
      % expected type  T_low[below(n)]
  volume_TCC1: OBLIGATION
    FORALL (n: posnat, box: Box(n)):
      0 >= 0 AND 0 < n OR (EXISTS (j: below(n)): j <= 0);

  % Subtype TCC generated (at line 41, column 24) for  n - 1
      % expected type  T_high[below(n)]
  volume_TCC2: OBLIGATION
    FORALL (n: posnat, box: Box(n)):
      n - 1 >= 0 AND n - 1 < n OR (EXISTS (j: below(n)): n - 1 <= j);

  % Subtype TCC generated (at line 41, column 63) for  i
      % expected type  below[length[real](box`vars_ub)]
  volume_TCC3: OBLIGATION
    FORALL (n: posnat, box: Box(n), i: below(n)):
      i < length[real](box`vars_ub);

  % Subtype TCC generated (at line 41, column 82) for  i
      % expected type  below[length[real](box`vars_lb)]
  volume_TCC4: OBLIGATION
    FORALL (n: posnat, box: Box(n), i: below(n)):
      i < length[real](box`vars_lb);

  % Assuming TCC generated (at line 24, column 4) for  reals@product[below(n)]
      % generated from assumption product.connected_domain
  volume_TCC5: OBLIGATION
    FORALL (n: posnat, box: Box(n)):
      (FORALL (x, y: below(n)), (z: integer):
         x <= z AND z <= y IMPLIES z >= 0 AND z < n);


body:
  OutBoxes[n:posnat] : DATATYPE
  BEGIN

    IMPORTING boxes_def

    UnknownBox : unknown_box?

    FullBox : full_box?

    EmptyBox : empty_box?

    Output(boxes:Boxes(n)) : boxes?

  END OutBoxes


body:
  Outcome : DATATYPE
  BEGIN

    IMPORTING list[real]

    IsTrue : istrue?

    Counterexample(counterexample:(cons?)) : isfalse?

    Unknown : unknown?

  END Outcome


body:
  minmax : THEORY
  BEGIN 

    IMPORTING util

    nvars	      : VAR nat
    depth,v     : VAR nat
    e           : VAR posreal
    a,b,d       : VAR real
    rf	      : VAR [real->real]
    l           : VAR list[real]
    rel         : VAR RealOrder
    exitatdepth : VAR bool

    Outminmax   : TYPE = [# lb_min,lb_max:real,
                            lb_var: list[real],
    	                  ub_max,ub_min:real,
                            ub_var: list[real],
                            max_depth : nat,
                            splits : nat
                          #]

    omm,
    omm1,omm2   : VAR Outminmax

    lb_le_ub?(omm): bool =
      omm`lb_min <= omm`ub_max

    single_outminmax(a,b,l,depth): Outminmax = (# 
      lb_min := a,
      lb_max := b,
      lb_var := l,
      ub_max := a,
      ub_min := b,
      ub_var := l,
      max_depth := depth,
      splits    := 0 
    #)

    empty_minmax : Outminmax = 
      single_outminmax(0,0,null,0)

    outminmax_translate(j:nat,rf)(omm): Outminmax =
      IF j < length(omm`lb_var) AND j<length(omm`ub_var) THEN
       omm WITH [lb_var := setnth(omm`lb_var,j,rf),
                 ub_var := setnth(omm`ub_var,j,rf)]
     ELSE
       omm
     ENDIF

    length_eq?(nvars)(omm): bool = 
      (cons?(omm`lb_var) OR cons?(omm`ub_var)) IMPLIES 
        length(omm`lb_var) = nvars AND length(omm`ub_var) = nvars

    %% Combine in the same interval
    combine(omm1,omm2): Outminmax =
      LET lbmax = IF    null?(omm1`lb_var) THEN omm2
  		ELSIF null?(omm2`lb_var) OR omm1`lb_max <= omm2`lb_max THEN omm1 
                  ELSE  omm2 
                  ENDIF,
          ubmin = IF    null?(omm1`ub_var) THEN omm2
  		ELSIF null?(omm2`ub_var) OR omm1`ub_min >= omm2`ub_min THEN omm1 
                  ELSE  omm2 
                  ENDIF
      IN (#
        lb_min    := min(omm1`lb_min,omm2`lb_min),
        lb_max    := IF null?(lbmax`lb_var) THEN 0 ELSE lbmax`lb_max ENDIF,
        lb_var    := lbmax`lb_var,
        ub_max    := max(omm1`ub_max,omm2`ub_max),
        ub_min    := IF null?(ubmin`ub_var) THEN 0 ELSE ubmin`ub_min ENDIF,
        ub_var    := ubmin`ub_var,
        max_depth := max(omm1`max_depth,omm2`max_depth),
        splits    := 0
      #)

    %% Combine left and right intervals
    combine_lr(v,omm1,omm2): Outminmax = 
      combine(outminmax_translate(v,LAMBDA(x:real):x/2)(omm1),
              outminmax_translate(v,LAMBDA(x:real):(x+1)/2)(omm2)) WITH [
        splits := omm1`splits + omm2`splits + 1
      ]

    % omm1 is child, omm2 is father
    combine_l(v,omm1,omm2): Outminmax = 
      combine(outminmax_translate(v,LAMBDA(x:real):x/2)(omm1),omm2)  WITH [
         splits := omm1`splits + 1
      ]

    % omm2 is father, omm1 is child
    combine_r(v,omm1,omm2): Outminmax = 
      combine(outminmax_translate(v,LAMBDA(x:real):(x+1)/2)(omm1),omm2)  WITH [
        splits := omm1`splits + 1
      ]

    % is omm2 between omm1?
    between?(omm1,omm2): bool = 
      cons?(omm1`lb_var) AND cons?(omm1`ub_var) AND 
      omm1`lb_max <= omm2`lb_min AND omm2`ub_max <= omm1`ub_min

    between_combine_lr : LEMMA
      between?(omm,combine(omm1,omm2)) IFF
      between?(omm,combine_lr(v,omm1,omm2))

    pre_sound?(omm:Outminmax) : bool =
      length(omm`lb_var) = length(omm`ub_var) AND
      omm`lb_min <= omm`ub_max AND
      (cons?(omm`lb_var) IMPLIES 
        omm`lb_min <= omm`lb_max AND
        omm`ub_min <= omm`ub_max AND
        omm`lb_max <= omm`ub_min)

    eps_localexit(e)(omm): bool = 
      cons?(omm`lb_var) AND cons?(omm`ub_var) AND 
      omm`lb_max-omm`lb_min <= e AND omm`ub_max-omm`ub_min <= e

    false_globalexit(omm): bool = FALSE

    %%%%%%%%%%%%%%%%%%% Maximum of Two Polynomials %%%%%%%%%%%%%%%%%%%

    % single_max_outminmax is for maximums of two polynomials
    % a is the max possible, b is the min possible, and d is the achieved

    single_max_outminmax(a,b,d,l,depth): Outminmax = (# 
      lb_min    := b,
      lb_max    := d,
      lb_var    := l,
      ub_max    := a,
      ub_min    := d,
      ub_var    := l,
      max_depth := depth,
      splits    := 0 
    #)

    %% Combine in the same interval
    combine_max(omm1,omm2): Outminmax =
      IF    omm1`lb_min >= omm2`ub_max THEN omm1
      ELSIF omm2`lb_min >= omm1`ub_max THEN omm2
      ELSE
       (#
        lb_min    := min(omm1`lb_min,omm2`lb_min),
        lb_max    := 0,
        lb_var    := null,
        ub_max    := max(omm1`ub_max,omm2`ub_max),
        ub_min    := 0,
        ub_var    := null,
        max_depth := max(omm1`max_depth,omm1`max_depth),
        splits    := 0
       #)
      ENDIF

    %%%%%%%%%% Exiting %%%%%%%%%%

    rel_localexit(rel)(omm)  : bool = IF rel(0,1) THEN % Case < 0 or <= 0
                                        rel(omm`ub_max,0)
                                      ELSE % Case > 0 or >= 0
                                        rel(omm`lb_min,0)
                                      ENDIF

    rel_counterex(rel)(omm) : bool = IF rel(0,1) THEN % Case < 0 or <= 0
                 		             cons?(omm`ub_var) AND NOT rel(omm`ub_min,0) 
                                     ELSE % Case > 0 or >= 0
                                       cons?(omm`lb_var) AND NOT rel(omm`lb_max,0)
                                     ENDIF

    rel_globalexit(rel,depth,exitatdepth)(omm) : bool = 
      (exitatdepth AND omm`max_depth = depth) OR
      rel_counterex(rel)(omm)

    globalexit_inv?(globalexit:[Outminmax->bool]) : bool =
      (FORALL(omm1,omm2): globalexit(omm1) IMPLIES 
        globalexit(combine(omm1,omm2))) AND
      (FORALL(n:nat,omm) : globalexit(omm) IMPLIES
        globalexit(omm WITH [splits:= n])) AND
      (FORALL(j:nat,rf,omm) : globalexit(omm) IMPLIES
        globalexit(outminmax_translate(j,rf)(omm)))

    false_globalexit_inv : JUDGEMENT
      false_globalexit HAS_TYPE (globalexit_inv?)

    rel_globalexit_inv : LEMMA
      globalexit_inv?(rel_globalexit(rel,depth,false))

    localexit_inv?(localexit:[Outminmax->bool]) : bool = 
      (FORALL(omm1,omm2): localexit(omm1) AND localexit(omm2) IMPLIES 
        localexit(combine(omm1,omm2))) AND
      (FORALL(n:nat,omm) : localexit(omm) IMPLIES
        localexit(omm WITH [splits:= n])) AND
      (FORALL(j:nat,rf,omm) : localexit(omm) IMPLIES
        localexit(outminmax_translate(j,rf)(omm)))

    eps_localexit_inv : JUDGEMENT
      eps_localexit(e) HAS_TYPE (localexit_inv?)

    rel_localexit_inv : JUDGEMENT
      rel_localexit(rel) HAS_TYPE (localexit_inv?)

  END minmax

addendum:
  %%% ================ Addendum: generated declarations ================

  % Judgement subtype TCC generated (at line 178, column 4) for
      % false_globalexit
      % expected type  (globalexit_inv?)
  false_globalexit_inv: OBLIGATION globalexit_inv?(false_globalexit);

  % Judgement subtype TCC generated (at line 192, column 4) for
      % eps_localexit(e)
      % expected type  (localexit_inv?)
  eps_localexit_inv: OBLIGATION FORALL (e): localexit_inv?(eps_localexit(e));

  % Judgement subtype TCC generated (at line 195, column 4) for
      % rel_localexit(rel)
      % expected type  (localexit_inv?)
  rel_localexit_inv: OBLIGATION
    FORALL (rel): localexit_inv?(rel_localexit(rel));


body:
  multi_bernstein : THEORY
  BEGIN

    IMPORTING reals@product_nat, 
              reals@polynomials,
  	    sigma_set@sigma_bijection[nat],
  	    reals@bernstein_polynomials,
              util

    %%%%%%%%%%%%%%%%%%%%%% Variables %%%%%%%%%%%%%%%%%%%%%%

    bsdegmono       : VAR DegreeMono
    pprod   	  : VAR Polyproduct
    a,a1            : VAR real
    X,Y             : VAR Vars
    v               : VAR nat
    nvars,terms     : VAR posnat
    cf              : VAR Coeff
    bspoly,bspolz   : VAR MultiBernstein
    coeffmono1,
    coeffmono2,
    coeffmono	  : VAR CoeffMono
    rel    	  : VAR [[real,real]->bool]
    intendpts	  : VAR IntervalEndpoints
    relreal         : VAR RealOrder

    %%%%%%%%%%%%%%%%%%%%%% Evaluating Bernstein Polynomials %%%%%%%%%%%%%%%%%%%%%%

    bsproduct_eval(pprod,bsdegmono,nvars)(X) : real = 
      product(0,nvars-1,LAMBDA (i:nat):sigma(0,bsdegmono(i),
                        LAMBDA (j:nat): IF j > bsdegmono(i) THEN 0 
                                        ELSE pprod(i)(j)*Bern(j,bsdegmono(i))(X(i)) 
                                        ENDIF))

    multibs_eval(bspoly,bsdegmono,cf,nvars,terms)(X) : real =
      sigma(0,terms-1,LAMBDA (i:nat): cf(i)*bsproduct_eval(bspoly(i),bsdegmono,nvars)(X))

    %%% Another version of evaluation for Bernstein Polynomials is needed to prove the main theorems %%%

    multibs_eval_mono(bspoly,bsdegmono,cf,nvars,terms)(coeffmono) : real = 
      sigma(0,terms-1,LAMBDA (i:nat): cf(i)*product(0,nvars-1,LAMBDA (j:nat): bspoly(i)(j)(coeffmono(j))))

    multibs_eval_rec(bspoly,bsdegmono,cf,nvars,terms,v)
                    (f:CoeffMono)(X) : RECURSIVE real =
      IF v = 0 THEN multibs_eval_mono(bspoly,bsdegmono,cf,nvars,terms)(f)*
                    product(0,nvars-1,LAMBDA (k:nat): IF f(k)<=bsdegmono(k) THEN 
                                                        Bern(f(k),bsdegmono(k))(X(k)) 
                                                      ELSE 1 ENDIF)
      ELSE sigma(0,bsdegmono(v-1),LAMBDA (d:nat): LET nf = f WITH [(v-1) := d] IN 
        multibs_eval_rec(bspoly,bsdegmono,cf,nvars,terms,v-1)(nf)(X))
      ENDIF MEASURE v

    multibs_eval_1_term: LEMMA 
      multibs_eval(bspoly,bsdegmono,cf,nvars,1)(X) = 
      multibs_eval_rec(bspoly,bsdegmono,cf,nvars,1,nvars)(zeroes)(X)

    multibs_eval_equiv: LEMMA 
      multibs_eval(bspoly,bsdegmono,cf,nvars,terms)(X) = 
      multibs_eval_rec(bspoly,bsdegmono,cf,nvars,terms,nvars)(zeroes)(X)

    multibs_eval_below_mono: LEMMA 
      (FORALL (i:below(nvars)): X(i) = Y(i)) IMPLIES
      multibs_eval(bspoly,bsdegmono,cf,nvars,terms)(X) =
      multibs_eval(bspoly,bsdegmono,cf,nvars,terms)(Y)

    multibs_eval_id : LEMMA
      FORALL (bspoly,bspolz,bsdegmono,cf,nvars,terms): 
        (FORALL(t:below(terms),v:below(nvars),i:upto(bsdegmono(v))):
         bspoly(t)(v)(i) = bspolz(t)(v)(i)) IMPLIES
        multibs_eval(bspoly,bsdegmono,cf,nvars,terms) =
        multibs_eval(bspolz,bsdegmono,cf,nvars,terms)

    %%%%%%%%%%%%%%%% Computing Bernstein Coefficients %%%%%%%%%%%%%%%%%
    
    multibscoeff(bspoly,bsdegmono,cf,nvars,terms)(coeffmono) : real = 
      sigma(0,terms-1,
            LAMBDA (i:nat): cf(i)*product(0,nvars-1,LAMBDA (j:nat): bspoly(i)(j)(coeffmono(j))))

    multibscoeff_id: LEMMA
      eq_below_mono?(nvars)(coeffmono1,coeffmono2)
      IMPLIES
      multibscoeff(bspoly,bsdegmono,cf,nvars,terms)(coeffmono1) =
      multibscoeff(bspoly,bsdegmono,cf,nvars,terms)(coeffmono2)

    Bern_coeffs_rel_rec(bspoly,bsdegmono,cf,nvars,terms,v)
                       (f:CoeffMono,rel:[[real,real]->bool],a:real) : RECURSIVE bool =
      IF v = 0 THEN rel(multibscoeff(bspoly,bsdegmono,cf,nvars,terms)(f),a)
      ELSE FORALL (d:upto(bsdegmono(v-1))): LET nf = f WITH [(v-1) := d] IN 
        Bern_coeffs_rel_rec(bspoly,bsdegmono,cf,nvars,terms,v-1)(nf,rel,a)
      ENDIF MEASURE v

    Bern_coeffs_rel(bspoly,bsdegmono,cf,nvars,terms)(rel,a) : bool = 
      Bern_coeffs_rel_rec(bspoly,bsdegmono,cf,nvars,terms,nvars)(zeroes,rel,a)

    Bern_coeffs_rel_implic: LEMMA 
      (FORALL (x:real): rel(x,a) IMPLIES rel(x,a1)) AND
      Bern_coeffs_rel_rec(bspoly,bsdegmono,cf,nvars,terms,v)(coeffmono,rel,a) IMPLIES
        Bern_coeffs_rel_rec(bspoly,bsdegmono,cf,nvars,terms,v)(coeffmono,rel,a1)	  

    Bern_coeffs_rel_def: LEMMA 
      Bern_coeffs_rel(bspoly,bsdegmono,cf,nvars,terms)(rel,a) IFF 
        (FORALL (coeffmono): le_below_mono?(nvars)(coeffmono,bsdegmono) IMPLIES 
           rel(multibscoeff(bspoly,bsdegmono,cf,nvars,terms)(coeffmono),a))

    multibs_cornerpoint_coeff: LEMMA
      LET X = LAMBDA (i:nat): IF coeffmono(i)=0 THEN 0 ELSE 1 ENDIF
      IN
        corner_point?(nvars,bsdegmono)(coeffmono) IMPLIES
        multibs_eval(bspoly,bsdegmono,cf,nvars,terms)(X) =
        multibscoeff(bspoly,bsdegmono,cf,nvars,terms)(coeffmono)

    %%%%%%%%%%% Forall X %%%%%%%%%%%%

    forall_X(bspoly,bsdegmono,cf,nvars,terms,rel,a) : bool =
      FORALL (X): unitbox?(nvars)(X) IMPLIES 
        rel(multibs_eval(bspoly,bsdegmono,cf,nvars,terms)(X),a)

    forall_X_id : LEMMA
      FORALL (bspoly,bspolz,bsdegmono,nvars,terms,rel,a): 
        (FORALL(t:below(terms),v:below(nvars),i:upto(bsdegmono(v))):
         bspoly(t)(v)(i) = bspolz(t)(v)(i)) IMPLIES
        forall_X(bspoly,bsdegmono,cf,nvars,terms,rel,a) =
        forall_X(bspolz,bsdegmono,cf,nvars,terms,rel,a)

    eval_X_between(amin,amax:real)(bspoly,bsdegmono,cf,nvars,terms)(X) : MACRO bool =
        amin <= multibs_eval(bspoly,bsdegmono,cf,nvars,terms)(X) AND
        multibs_eval(bspoly,bsdegmono,cf,nvars,terms)(X) <= amax

    forall_X_between(amin,amax:real)(bspoly,bsdegmono,cf,nvars,terms) : bool =
      FORALL (X): unitbox?(nvars)(X) IMPLIES 
        eval_X_between(amin,amax)(bspoly,bsdegmono,cf,nvars,terms)(X)

    forall_X_between_id : LEMMA
      FORALL (amin,amax:real)(bspoly,bspolz,bsdegmono,nvars,terms): 
        (FORALL(t:below(terms),v:below(nvars),i:upto(bsdegmono(v))):
         bspoly(t)(v)(i) = bspolz(t)(v)(i)) IMPLIES
        forall_X_between(amin,amax)(bspoly,bsdegmono,cf,nvars,terms) =
        forall_X_between(amin,amax)(bspolz,bsdegmono,cf,nvars,terms)

    %%%%%%%%%%%%%%%% Computing Endpoint Bernstein Coefficients %%%%%%%%%%%%%%%%%

    Bern_coeffs_endpoints_rel_rec(bspoly,bsdegmono,cf,nvars,terms,v)
                                 (f:CoeffMono,rel:[[real,real]->bool],a:real) : 
    RECURSIVE {l : list[real] | cons?(l) IMPLIES unitbox?(nvars)(list2array(0)(l)) AND
                                                 length(l)=nvars} =
      IF v = 0 THEN
        IF rel(multibscoeff(bspoly,bsdegmono,cf,nvars,terms)(f),a) THEN null
        ELSE corner_to_point(f,nvars) 
        ENDIF
      ELSE 
        LET nf0   = f WITH [(v-1):=0],
            list0 = Bern_coeffs_endpoints_rel_rec(bspoly,bsdegmono,cf,nvars,terms,v-1)
                                                 (nf0,rel,a) IN
        IF cons?(list0) THEN list0
        ELSE 
          LET nfd = f WITH [(v-1):=bsdegmono(v-1)] IN 
          Bern_coeffs_endpoints_rel_rec(bspoly,bsdegmono,cf,nvars,terms,v-1)(nfd,rel,a)
        ENDIF
      ENDIF 
     MEASURE v

    Bern_coeffs_endpoints_rel(bspoly,bsdegmono,cf,nvars,terms,intendpts)(rel,a) : 
    {l : list[real] | cons?(l) IMPLIES unitbox?(nvars)(list2array(0)(l)) AND length(l)=nvars} = 
      IF (FORALL (j:below(nvars)): intendpts(j)`1 AND intendpts(j)`2) THEN
        Bern_coeffs_endpoints_rel_rec(bspoly,bsdegmono,cf,nvars,terms,nvars)(zeroes,rel,a)
      ELSE null
      ENDIF

    Bern_coeffs_endpoints_rel_def: LEMMA 
     forall_X(bspoly,bsdegmono,cf,nvars,terms,rel,a) IMPLIES
     null?(Bern_coeffs_endpoints_rel(bspoly,bsdegmono,cf,nvars,terms,intendpts)(rel,a))

    Bern_coeffs_counterexample: LEMMA 
      LET listex = Bern_coeffs_endpoints_rel(bspoly,bsdegmono,cf,nvars,terms,intendpts)(rel,a) IN
      cons?(listex) IMPLIES 
        length(listex) = nvars AND
        NOT rel(multibs_eval(bspoly,bsdegmono,cf,nvars,terms)(list2array(0)(listex)),a)

    %%%%%%%%%% Bernstein Lemmas %%%%%%%%%

    Bern_le: LEMMA 
      Bern_coeffs_rel(bspoly,bsdegmono,cf,nvars,terms)(<=,a) IMPLIES
        forall_X(bspoly,bsdegmono,cf,nvars,terms,<=,a)

    Bern_lt: LEMMA 
      Bern_coeffs_rel(bspoly,bsdegmono,cf,nvars,terms)(<,a) IMPLIES
       forall_X(bspoly,bsdegmono,cf,nvars,terms,<,a)

    Bern_ge: LEMMA 
      Bern_coeffs_rel(bspoly,bsdegmono,cf,nvars,terms)(>=,a) IMPLIES
        forall_X(bspoly,bsdegmono,cf,nvars,terms,>=,a)

    Bern_gt: LEMMA 
      Bern_coeffs_rel(bspoly,bsdegmono,cf,nvars,terms)(>,a) IMPLIES
        forall_X(bspoly,bsdegmono,cf,nvars,terms,>,a)

    Bern_rel : LEMMA
      Bern_coeffs_rel(bspoly,bsdegmono,cf,nvars,terms)(relreal,a) IMPLIES
        forall_X(bspoly,bsdegmono,cf,nvars,terms,relreal,a)

    forall_X_between_minmax : LEMMA
      FORALL (amin,amax:real) :
        (FORALL(coeffmono):
         le_below_mono?(nvars)(coeffmono,bsdegmono) IMPLIES
         amin <= multibscoeff(bspoly, bsdegmono, cf, nvars, terms)(coeffmono) AND
         multibscoeff(bspoly, bsdegmono, cf, nvars, terms)(coeffmono) <= amax)
       IMPLIES
         forall_X_between(amin,amax)(bspoly,bsdegmono,cf,nvars,terms)

    %%%%%%%%%%% Splitting %%%%%%%%%%%%

    % i is degree for splitting, r is variable of the product, 
    % and j is the coeff index  
    Bern_split_left_mono(pprod,bsdegmono)(i:nat)(r:nat)(j:nat): real = 
      IF i/=r THEN pprod(r)(j) 
      ELSIF j>bsdegmono(i) THEN 0 
      ELSE (1/2^j)*sigma(0,j,
           LAMBDA (k:nat): IF k>j THEN 0 ELSE C(j,k)*pprod(i)(k) ENDIF) 
      ENDIF 

    Bern_split_right_mono(pprod,bsdegmono)(i:nat)(r:nat)(j:nat): real =
      IF i/=r THEN pprod(r)(j) 
      ELSIF j>bsdegmono(i) THEN 0 
      ELSE 
        (1/2^(bsdegmono(i)-j))*sigma(0,bsdegmono(i)-j,
        LAMBDA (k:nat): IF k>bsdegmono(i)-j THEN 0 
                        ELSE C(bsdegmono(i)-j,k)*pprod(i)(bsdegmono(i)-k) 
                        ENDIF) 
      ENDIF
    
    % Bern_split_left_mpoly(bspoly,bsdegmono)(i) is a MultiBernstein

    Bern_split_left_mpoly(bspoly,bsdegmono)(i:nat)(k:nat): MACRO Polyproduct = 
      Bern_split_left_mono(bspoly(k),bsdegmono)(i)

    Bern_split_right_mpoly(bspoly,bsdegmono)(i:nat)(k:nat): MACRO Polyproduct = 
      Bern_split_right_mono(bspoly(k),bsdegmono)(i)

    Bern_split_bspoly : LEMMA FORALL (i:nat,rel): i<nvars IMPLIES
        ((forall_X(Bern_split_left_mpoly(bspoly,bsdegmono)(i),bsdegmono,cf,nvars,terms,rel,a) AND
          forall_X(Bern_split_right_mpoly(bspoly,bsdegmono)(i),bsdegmono,cf,nvars,terms,rel,a))
  	IFF
  	forall_X(bspoly,bsdegmono,cf,nvars,terms,rel,a))

    Bern_eval_left: LEMMA
      rel(multibs_eval(bspoly, bsdegmono, cf, nvars, terms)(X),a) IMPLIES
      LET Xmid = X WITH [(v) := 2*X(v)] IN
      rel(multibs_eval(LAMBDA (k: nat):Bern_split_left_mono(bspoly(k), bsdegmono)(v),
                       bsdegmono, cf, nvars, terms)(Xmid),a)

    Bern_eval_left_def: LEMMA
      LET Xmid = X WITH [(v) := 2*X(v)] IN
      multibs_eval(LAMBDA (k: nat):Bern_split_left_mono(bspoly(k), bsdegmono)(v),
                       bsdegmono, cf, nvars, terms)(Xmid) =
      multibs_eval(bspoly, bsdegmono, cf, nvars, terms)(X)
      

    Bern_eval_right: LEMMA
      rel(multibs_eval(bspoly, bsdegmono, cf, nvars, terms)(X),a) IMPLIES
      LET Xmid = X WITH [(v) := 2*X(v)-1] IN
      rel(multibs_eval(LAMBDA (k: nat):Bern_split_right_mono(bspoly(k), bsdegmono)(v),
                       bsdegmono, cf, nvars, terms)(Xmid),a)

    Bern_eval_right_def: LEMMA
      LET Xmid = X WITH [(v) := 2*X(v)-1] IN
      multibs_eval(LAMBDA (k: nat):Bern_split_right_mono(bspoly(k), bsdegmono)(v),
                       bsdegmono, cf, nvars, terms)(Xmid)=
      multibs_eval(bspoly, bsdegmono, cf, nvars, terms)(X)
      

    %%%%%%%%%%% Sweeping on Polyproduct's (NOT MultiBernstein's) %%%%%%%%%%%

    % p is the recursive counter, v is the variable to split, 
    % and j is the index for the coefficient of that power (x_r^j)

    Bernstein_sweep(pprod,v)(p:nat)(j:nat): RECURSIVE real =
      IF p = 0 THEN pprod(v)(j)
      ELSE
        LET bpm = Bernstein_sweep(pprod,v)(p-1) IN
          IF j < p THEN bpm(j)
  	ELSE (1/2)*(bpm(j-1) + bpm(j))
  	ENDIF
      ENDIF
      MEASURE p

    % Bernstein_sweep(pprod,i)(p) is a Polynomial

    Bern_sweep_left(pprod,bsdegmono)(i:nat)(r:nat) : Polynomial = 
      IF i /= r THEN pprod(r)
      ELSE 
        Bernstein_sweep(pprod,i)(bsdegmono(i))
      ENDIF

    Bern_sweep_right(pprod,bsdegmono)(i:nat)(r:nat)(j:nat) : real = 
      IF i /= r THEN pprod(r)(j)
      ELSIF j <= bsdegmono(r) THEN 
        Bernstein_sweep(pprod,i)(bsdegmono(i)-j)(bsdegmono(i)) 
      ELSE 0 
      ENDIF

    Bern_sweep_left_mpoly(bspoly,bsdegmono)(i:nat)(k:nat): MACRO Polyproduct = 
      Bern_sweep_left(bspoly(k),bsdegmono)(i)

    Bern_sweep_right_mpoly(bspoly,bsdegmono)(i:nat)(k:nat): MACRO Polyproduct = 
      Bern_sweep_right(bspoly(k),bsdegmono)(i)

    Bern_sweep_eval_left: LEMMA
      rel(multibs_eval(bspoly, bsdegmono, cf, nvars, terms)(X),a) IMPLIES
      LET Xmid = X WITH [(v) := 2*X(v)] IN
      rel(multibs_eval(LAMBDA (k: nat):Bern_sweep_left(bspoly(k), bsdegmono)(v),
                       bsdegmono, cf, nvars, terms)(Xmid),a)

    Bern_sweep_eval_right: LEMMA
      rel(multibs_eval(bspoly, bsdegmono, cf, nvars, terms)(X),a) IMPLIES
      LET Xmid = X WITH [(v) := 2*X(v)-1] IN
      rel(multibs_eval(LAMBDA (k: nat):Bern_sweep_right(bspoly(k), bsdegmono)(v),
                       bsdegmono, cf, nvars, terms)(Xmid),a)

  END multi_bernstein

addendum:
  %%% ================ Addendum: generated declarations ================

  % Assuming TCC generated (at line 6, column 5) for
      % sigma_set@sigma_bijection[nat]
      % generated from assumption sigma_bijection.connected_domain
  IMP_sigma_bijection_TCC1: OBLIGATION
    (FORALL (x, y: nat), (z: integer): x <= z AND z <= y IMPLIES z >= 0);

  % Subtype TCC generated (at line 30, column 14) for  nvars - 1
      % expected type  T_high[nat]
  bsproduct_eval_TCC1: OBLIGATION
    FORALL (nvars: posnat):
      nvars - 1 >= 0 OR (EXISTS (j: nat): nvars - 1 <= j);

  % Subtype TCC generated (at line 30, column 45) for  bsdegmono(i)
      % expected type  T_high[nat]
  bsproduct_eval_TCC2: OBLIGATION
    FORALL (bsdegmono: DegreeMono, i: nat):
      bsdegmono(i) >= 0 OR (EXISTS (j: nat): bsdegmono(i) <= j);

  % Subtype TCC generated (at line 32, column 62) for  bsdegmono(i)
      % expected type  above(j - 1)
  bsproduct_eval_TCC3: OBLIGATION
    FORALL (bsdegmono: DegreeMono, i: nat, j: nat):
      NOT j > bsdegmono(i) IMPLIES bsdegmono(i) > j - 1;

  % Subtype TCC generated (at line 47, column 64) for  bsdegmono(k)
      % expected type  above(f(k) - 1)
  multibs_eval_rec_TCC1: OBLIGATION
    FORALL (bsdegmono: DegreeMono, v: nat, f: CoeffMono):
      v = 0 IMPLIES
       (FORALL (k: nat):
          f(k) <= bsdegmono(k) IMPLIES bsdegmono(k) > f(k) - 1);

  % Subtype TCC generated (at line 49, column 27) for  v - 1
      % expected type  nat
  multibs_eval_rec_TCC2: OBLIGATION
    FORALL (v: nat): NOT v = 0 IMPLIES v - 1 >= 0;

  % Subtype TCC generated (at line 49, column 17) for  bsdegmono(v - 1)
      % expected type  T_high[nat]
  multibs_eval_rec_TCC3: OBLIGATION
    FORALL (bsdegmono: DegreeMono, v: nat):
      NOT v = 0 IMPLIES
       bsdegmono(v - 1) >= 0 OR (EXISTS (j: nat): bsdegmono(v - 1) <= j);

  % Termination TCC generated (at line 50, column 6) for
      % multibs_eval_rec(bspoly, bsdegmono, cf, nvars, terms, v - 1)
  multibs_eval_rec_TCC4: OBLIGATION
    FORALL (v: nat, f: CoeffMono):
      NOT v = 0 IMPLIES
       (FORALL (d: nat, nf: CoeffMono):
          nf = f WITH [(v - 1) := d] IMPLIES v - 1 < v);

  % Subtype TCC generated (at line 147, column 70) for  null
      % expected type  {l: list[real] |
                     %          cons?(l) IMPLIES
                     %           unitbox?(nvars)(list2array(0)(l)) AND
                     %            length(l) = nvars}
  Bern_coeffs_endpoints_rel_rec_TCC1: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, cf: Coeff,
            nvars: posnat, terms: posnat, v: nat, f: CoeffMono,
            rel: [[real, real] -> bool], a: real):
      rel(multibscoeff(bspoly, bsdegmono, cf, nvars, terms)(f), a) AND v = 0
       IMPLIES
       cons?[real](null[real]) IMPLIES
        unitbox?(nvars)(list2array[real](0)(null[real])) AND
         length[real](null[real]) = nvars;

  % Subtype TCC generated (at line 148, column 11) for
      % corner_to_point(f, nvars)
      % expected type  {l: list[real] |
                     %          cons?(l) IMPLIES
                     %           unitbox?(nvars)(list2array(0)(l)) AND
                     %            length(l) = nvars}
  Bern_coeffs_endpoints_rel_rec_TCC2: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, cf: Coeff,
            nvars: posnat, terms: posnat, v: nat, f: CoeffMono,
            rel: [[real, real] -> bool], a: real):
      NOT rel(multibscoeff(bspoly, bsdegmono, cf, nvars, terms)(f), a) AND
       v = 0
       IMPLIES
       cons?[real](corner_to_point(f, nvars)) IMPLIES
        unitbox?(nvars)(list2array[real](0)(corner_to_point(f, nvars))) AND
         length[real](corner_to_point(f, nvars)) = nvars;

  % Subtype TCC generated (at line 153, column 48) for  nf0
      % expected type  CoeffMono
  Bern_coeffs_endpoints_rel_rec_TCC3: OBLIGATION
    FORALL (v: nat, f: CoeffMono):
      NOT v = 0 IMPLIES
       (FORALL (nf0: [nat -> int]):
          nf0 = f WITH [(v - 1) := 0] IMPLIES
           (FORALL (x1: nat): nf0(x1) >= 0));

  % Termination TCC generated (at line 152, column 18) for
      % Bern_coeffs_endpoints_rel_rec(bspoly,
      %                               bsdegmono,
      %                               cf,
      %                               nvars,
      %                               terms,
      %                               v - 1)
  Bern_coeffs_endpoints_rel_rec_TCC4: OBLIGATION
    FORALL (v: nat, f: CoeffMono):
      NOT v = 0 IMPLIES
       (FORALL (nf0: [nat -> int]):
          nf0 = f WITH [(v - 1) := 0] IMPLIES v - 1 < v);

  % Subtype TCC generated (at line 166, column 9) for  null
      % expected type  {l: list[real] |
                     %          cons?(l) IMPLIES
                     %           unitbox?(nvars)(list2array(0)(l)) AND
                     %            length(l) = nvars}
  Bern_coeffs_endpoints_rel_TCC1: OBLIGATION
    FORALL (nvars: posnat, intendpts: IntervalEndpoints):
      NOT (FORALL (j: below(nvars)): intendpts(j)`1 AND intendpts(j)`2)
       IMPLIES
       cons?[real](null[real]) IMPLIES
        unitbox?(nvars)(list2array[real](0)(null[real])) AND
         length[real](null[real]) = nvars;

  % Subtype TCC generated (at line 217, column 25) for  j
      % expected type  T_high[nat]
  Bern_split_left_mono_TCC1: OBLIGATION
    FORALL (bsdegmono: DegreeMono, i, r, j: nat):
      NOT j > bsdegmono(i) AND NOT i /= r IMPLIES
       j >= 0 OR (EXISTS (j_1: nat): j <= j_1);

  % Subtype TCC generated (at line 218, column 48) for  k
      % expected type  {i: nat | i <= j}
  Bern_split_left_mono_TCC2: OBLIGATION
    FORALL (bsdegmono: DegreeMono, i, r, j: nat):
      NOT j > bsdegmono(i) AND NOT i /= r IMPLIES
       (FORALL (k: nat): NOT k > j IMPLIES k <= j);

  % Subtype TCC generated (at line 225, column 37) for  bsdegmono(i) - j
      % expected type  T_high[nat]
  Bern_split_right_mono_TCC1: OBLIGATION
    FORALL (bsdegmono: DegreeMono, i, r, j: nat):
      NOT j > bsdegmono(i) AND NOT i /= r IMPLIES
       bsdegmono(i) - j >= 0 OR (EXISTS (j_1: nat): bsdegmono(i) - j <= j_1);

  % Subtype TCC generated (at line 227, column 29) for  bsdegmono(i) - j
      % expected type  nat
  Bern_split_right_mono_TCC2: OBLIGATION
    FORALL (bsdegmono: DegreeMono, i, r, j: nat):
      NOT j > bsdegmono(i) AND NOT i /= r IMPLIES
       (FORALL (k: nat):
          NOT k > bsdegmono(i) - j IMPLIES bsdegmono(i) - j >= 0);

  % Subtype TCC generated (at line 227, column 44) for  k
      % expected type  {i_1: nat | i_1 <= bsdegmono(i) - j}
  Bern_split_right_mono_TCC3: OBLIGATION
    FORALL (bsdegmono: DegreeMono, i, r, j: nat):
      NOT j > bsdegmono(i) AND NOT i /= r IMPLIES
       (FORALL (k: nat):
          NOT k > bsdegmono(i) - j IMPLIES k <= bsdegmono(i) - j);

  % Subtype TCC generated (at line 227, column 56) for  bsdegmono(i) - k
      % expected type  nat
  Bern_split_right_mono_TCC4: OBLIGATION
    FORALL (bsdegmono: DegreeMono, i, r, j: nat):
      NOT j > bsdegmono(i) AND NOT i /= r IMPLIES
       (FORALL (k: nat):
          NOT k > bsdegmono(i) - j IMPLIES bsdegmono(i) - k >= 0);

  % Subtype TCC generated (at line 281, column 17) for  j - 1
      % expected type  nat
  Bernstein_sweep_TCC1: OBLIGATION
    FORALL (pprod: Polyproduct, v: nat, p: nat,
            v1:
              [[Polyproduct, nat] -> [{z1: nat | z1 < p} -> [nat -> real]]],
            j: nat):
      NOT p = 0 IMPLIES
       (FORALL (bpm: [nat -> real]):
          NOT j < p AND bpm = v1(pprod, v)(p - 1) IMPLIES j - 1 >= 0);

  % Termination TCC generated (at line 279, column 16) for
      % Bernstein_sweep(pprod, v)(p - 1)
  Bernstein_sweep_TCC2: OBLIGATION
    FORALL (p: nat): NOT p = 0 IMPLIES p - 1 < p;

  % Subtype TCC generated (at line 297, column 31) for  bsdegmono(i) - j
      % expected type  nat
  Bern_sweep_right_TCC1: OBLIGATION
    FORALL (bsdegmono: DegreeMono, i, r, j: nat):
      j <= bsdegmono(r) AND NOT i /= r IMPLIES bsdegmono(i) - j >= 0;


body:
  % This theory contains the following strategies for selecting a variable:
  %   AltVarLeftRight : Select variables in alternate way, split left first
  %   AltVarRightLeft : Select variables in alternate way, split right first
  %   MaxVarMinDir    : Select the variable of maximum variation and the direction with the minimum coefficient
  %   MaxVarMaxDir    : Select the variable of maximum variation and the direction with the maximum coefficient

  vardirselector : THEORY
  BEGIN

    IMPORTING multi_bernstein

    bspoly      : VAR MultiBernstein
    bsdegmono   : VAR DegreeMono
    nvars,terms : VAR posnat
    cf          : VAR Coeff
    level,v     : VAR nat

    % Parameters are bspoly,bsdegmono,nvars,terms,cf,level  (bool=true is Left)

    VarSelector : TYPE = [[MultiBernstein,DegreeMono,posnat,posnat,Coeff,nat]->[bool,nat]] 
       
    % Alternate variable, Left-Right direction
    AltVarLeftRight(bspoly,bsdegmono,nvars,terms,cf,level): [bool,nat]  = 
      (true,level)

    % Alternate variable, Right-Left direction
    AltVarRightLeft(bspoly,bsdegmono,nvars,terms,cf,level): [bool,nat] = 
      (false,level)

    var_coeff_range_rec(bspoly,bsdegmono,nvars,terms,cf,v,(iup:upto(bsdegmono(v)))) : 
      RECURSIVE [# currmin: real, currmax:real, firstc:real,lastc:real #] =
      LET coefffun  = multibscoeff(bspoly,bsdegmono,cf,nvars,terms), 
          thismono  = zeroes WITH [(v):=iup], 
          thiscoeff = coefffun(thismono) 
      IN 
        IF iup=0 THEN 
          (# currmin := thiscoeff,
             currmax := thiscoeff,
             firstc  := thiscoeff,
             lastc   := thiscoeff #)
        ELSE 
          LET vcrrlast = var_coeff_range_rec(bspoly,bsdegmono,nvars,terms,cf,v,iup-1) IN
            (# currmin := min(vcrrlast`currmin,thiscoeff),
               currmax := max(vcrrlast`currmax,thiscoeff),
               firstc  := vcrrlast`firstc,
               lastc   := IF iup=bsdegmono(v) THEN thiscoeff ELSE vcrrlast`lastc ENDIF #)
        ENDIF 
    MEASURE iup

    var_maxcoeff_rec(bspoly,bsdegmono,nvars,terms,cf,v): 
      RECURSIVE [# variable:nat,firstc:real,lastc:real #] =
      LET vcrr       = var_coeff_range_rec(bspoly,bsdegmono,nvars,terms,cf,v,bsdegmono(v)),
          thisanswer = (# variable := v,
                          firstc   := vcrr`firstc,
                          lastc    := vcrr`lastc #) 
      IN
        IF v = 0 THEN thisanswer
        ELSE 
          LET vmr = var_maxcoeff_rec(bspoly,bsdegmono,nvars,terms,cf,v-1),
  	    vcrrlast = var_coeff_range_rec(bspoly,bsdegmono,nvars,terms,cf,vmr`variable,
                                             bsdegmono(vmr`variable)),
  	    lastanswer =  (# variable :=vmr`variable,
                               firstc   :=vcrrlast`firstc,
                               lastc    :=vcrrlast`lastc #) IN
  	IF vcrr`currmax-vcrr`currmin > vcrrlast`currmax-vcrrlast`currmin THEN 
            thisanswer
  	ELSE 
            lastanswer  
          ENDIF
        ENDIF 
    MEASURE v

    MaxVarMinDir(bspoly,bsdegmono,nvars,terms,cf,level): [bool,nat] = 
      LET vcrr = var_maxcoeff_rec(bspoly,bsdegmono,nvars,terms,cf,nvars-1) IN
        (vcrr`firstc<=vcrr`lastc,vcrr`variable)

    MaxVarMaxDir(bspoly,bsdegmono,nvars,terms,cf,level): [bool,nat] = 
      LET vcrr = var_maxcoeff_rec(bspoly,bsdegmono,nvars,terms,cf,nvars-1) IN
        (vcrr`firstc > vcrr`lastc,vcrr`variable)

  END vardirselector

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 34, column 29) for  thismono
      % expected type  CoeffMono
  var_coeff_range_rec_TCC1: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, v: nat, (iup: upto(bsdegmono(v))),
            coefffun: [CoeffMono -> real]):
      coefffun = multibscoeff(bspoly, bsdegmono, cf, nvars, terms) IMPLIES
       (FORALL (thismono: [nat -> real]):
          thismono = (LAMBDA (i: nat): 0) WITH [(v) := iup] IMPLIES
           (FORALL (x1: nat):
              rational_pred(thismono(x1)) AND
               integer_pred(thismono(x1)) AND thismono(x1) >= 0));

  % Subtype TCC generated (at line 42, column 77) for  iup - 1
      % expected type  upto(bsdegmono(v))
  var_coeff_range_rec_TCC2: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, v: nat, (iup: upto(bsdegmono(v))),
            coefffun: [CoeffMono -> real]):
      coefffun = multibscoeff(bspoly, bsdegmono, cf, nvars, terms) IMPLIES
       (FORALL (thismono: [nat -> real]):
          thismono = (LAMBDA (i: nat): 0) WITH [(v) := iup] IMPLIES
           (FORALL (thiscoeff: real):
              NOT iup = 0 AND thiscoeff = coefffun(thismono) IMPLIES
               iup - 1 >= 0 AND iup - 1 <= bsdegmono(v)));

  % Termination TCC generated (at line 42, column 23) for
      % var_coeff_range_rec(bspoly, bsdegmono, nvars, terms, cf, v, iup - 1)
  var_coeff_range_rec_TCC3: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, v: nat, (iup: upto(bsdegmono(v))),
            coefffun: [CoeffMono -> real]):
      coefffun = multibscoeff(bspoly, bsdegmono, cf, nvars, terms) IMPLIES
       (FORALL (thismono: [nat -> real]):
          thismono = (LAMBDA (i: nat): 0) WITH [(v) := iup] IMPLIES
           (FORALL (thiscoeff: real):
              NOT iup = 0 AND thiscoeff = coefffun(thismono) IMPLIES
               iup - 1 < iup));

  % Subtype TCC generated (at line 59, column 67) for  v - 1
      % expected type  nat
  var_maxcoeff_rec_TCC1: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, v: nat,
            vcrr:
              [# currmax: real, currmin: real, firstc: real, lastc: real #]):
      vcrr =
       var_coeff_range_rec(bspoly, bsdegmono, nvars, terms, cf, v,
                           bsdegmono(v))
       IMPLIES
       (FORALL (thisanswer: [# firstc: real, lastc: real, variable: nat #]):
          NOT v = 0 AND
           thisanswer =
            (# variable := v, firstc := vcrr`firstc, lastc := vcrr`lastc #)
           IMPLIES v - 1 >= 0);

  % Termination TCC generated (at line 59, column 18) for
      % var_maxcoeff_rec(bspoly, bsdegmono, nvars, terms, cf, v - 1)
  var_maxcoeff_rec_TCC2: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, v: nat,
            vcrr:
              [# currmax: real, currmin: real, firstc: real, lastc: real #]):
      vcrr =
       var_coeff_range_rec(bspoly, bsdegmono, nvars, terms, cf, v,
                           bsdegmono(v))
       IMPLIES
       (FORALL (thisanswer: [# firstc: real, lastc: real, variable: nat #]):
          NOT v = 0 AND
           thisanswer =
            (# variable := v, firstc := vcrr`firstc, lastc := vcrr`lastc #)
           IMPLIES v - 1 < v);

  % Subtype TCC generated (at line 61, column 43) for  bsdegmono(vmr`variable)
      % expected type  upto(bsdegmono(vmr`variable))
  var_maxcoeff_rec_TCC3: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, v: nat,
            v1:
              [{z: [MultiBernstein, DegreeMono, posnat, posnat, Coeff, nat] |
                        z`6 < v} ->
                 [# firstc: real, lastc: real, variable: nat #]],
            vcrr:
              [# currmax: real, currmin: real, firstc: real, lastc: real #]):
      vcrr =
       var_coeff_range_rec(bspoly, bsdegmono, nvars, terms, cf, v,
                           bsdegmono(v))
       IMPLIES
       (FORALL (thisanswer: [# firstc: real, lastc: real, variable: nat #]):
          NOT v = 0 AND
           thisanswer =
            (# variable := v, firstc := vcrr`firstc, lastc := vcrr`lastc #)
           IMPLIES
           (FORALL (vmr: [# firstc: real, lastc: real, variable: nat #]):
              vmr = v1(bspoly, bsdegmono, nvars, terms, cf, v - 1) IMPLIES
               bsdegmono(vmr`variable) <= bsdegmono(vmr`variable)));

  % Subtype TCC generated (at line 52, column 75) for  bsdegmono(v)
      % expected type  upto(bsdegmono(v))
  var_maxcoeff_rec_TCC4: OBLIGATION
    FORALL (bsdegmono: DegreeMono, v: nat): bsdegmono(v) <= bsdegmono(v);

  % Subtype TCC generated (at line 74, column 64) for  nvars - 1
      % expected type  nat
  MaxVarMinDir_TCC1: OBLIGATION FORALL (nvars: posnat): nvars - 1 >= 0;


body:
  bernstein_minmax : THEORY
  BEGIN 

    IMPORTING vardirselector,
  	    structures@for_iterate,
              multi_bernstein,
  	    minmax
   
    bspoly,
    bspolz      : VAR MultiBernstein
    bsdegmono   : VAR DegreeMono
    nvars,terms : VAR posnat
    cf          : VAR Coeff
    f           : VAR CoeffMono
    intendpts   : VAR IntervalEndpoints
    depth,v     : VAR nat
    e           : VAR posreal
    a,b         : VAR real
    rf	      : VAR [real->real]
    l           : VAR list[real]
    ep          : VAR bool
    varselect   : VAR VarSelector
    omm,
    omm1,omm2   : VAR Outminmax

    unit_box_lb?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm): bool =
      cons?(omm`lb_var) IMPLIES
        (length(omm`lb_var) = nvars AND
         LET lb_varlam  = list2array(0)(omm`lb_var) IN
           (FORALL (iup:below(nvars)): 
  	   interval_between?(0,1,intendpts(iup),(true,true))(lb_varlam(iup)))
  	   AND
             multibs_eval(bspoly,bsdegmono,cf,nvars,terms)(lb_varlam) = omm`lb_max)

    unit_box_lb_id : LEMMA
      (FORALL(t:below(terms),v:below(nvars),i:upto(bsdegmono(v))):
         bspoly(t)(v)(i) = bspolz(t)(v)(i)) IMPLIES
      unit_box_lb?(bspoly,bsdegmono,nvars,terms,cf,intendpts) =
      unit_box_lb?(bspolz,bsdegmono,nvars,terms,cf,intendpts)

    unit_box_ub?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm): bool =
      cons?(omm`ub_var) IMPLIES
        (length(omm`ub_var) = nvars AND
        LET ub_varlam  = list2array(0)(omm`ub_var) IN
           (FORALL (iup:below(nvars)): 
  	   interval_between?(0,1,intendpts(iup),(true,true))(ub_varlam(iup))) AND
             multibs_eval(bspoly,bsdegmono,cf,nvars,terms)(ub_varlam) = omm`ub_min)

    unit_box_ub_id : LEMMA
      (FORALL(t:below(terms),v:below(nvars),i:upto(bsdegmono(v))):
         bspoly(t)(v)(i) = bspolz(t)(v)(i)) IMPLIES
      unit_box_ub?(bspoly,bsdegmono,nvars,terms,cf,intendpts) =
      unit_box_ub?(bspolz,bsdegmono,nvars,terms,cf,intendpts)

    sound?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm) : bool =
      forall_X_between(omm`lb_min,omm`ub_max)(bspoly,bsdegmono,cf,nvars,terms) AND
      unit_box_lb?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm) AND
      unit_box_ub?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm) AND
      length_eq?(nvars)(omm)

    sound_id : LEMMA
      (FORALL(t:below(terms),v:below(nvars),i:upto(bsdegmono(v))):
         bspoly(t)(v)(i) = bspolz(t)(v)(i)) IMPLIES
      sound?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm) =
      sound?(bspolz,bsdegmono,nvars,terms,cf,intendpts)(omm)

    sound_lb_le_ub: LEMMA
      sound?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm)
      IMPLIES
      lb_le_ub?(omm)
      
    combine_sound: LEMMA
      (EXISTS (VPr:[Vars->bool]): FORALL (X:(unitbox?(nvars))): (VPr(X) 
      IMPLIES eval_X_between(omm1`lb_min,omm1`ub_max)(bspoly,bsdegmono,cf,nvars,terms)(X))
      AND ((NOT VPr(X)) 
      IMPLIES eval_X_between(omm2`lb_min,omm2`ub_max)(bspoly,bsdegmono,cf,nvars,terms)(X)))
      AND
      unit_box_lb?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm1) AND
      unit_box_ub?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm1) AND
      unit_box_lb?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm2) AND
      unit_box_ub?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm2) AND
      length_eq?(nvars)(omm1) AND length_eq?(nvars)(omm2)
      IMPLIES
      sound?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(combine(omm1,omm2))
   
    Bern_coeffs_minmax_rec(bspoly,bsdegmono,cf,nvars,terms,f,
                           depth,intendpts,v,
  			 (ep:(edge_point?(bsdegmono,nvars,f,intendpts,v)))): 
      RECURSIVE {omm:Outminmax |
        (FORALL (nf:CoeffMono): (FORALL (i:below(nvars)): nf(i)<=bsdegmono(i) AND 
                                        (v <= i IMPLIES f(i)=nf(i)))
        	      		      IMPLIES
  			      omm`lb_min <= multibscoeff(bspoly,bsdegmono,cf,nvars,terms)(nf)  AND
                                multibscoeff(bspoly,bsdegmono,cf,nvars,terms)(nf) <= omm`ub_max) AND
        unit_box_lb?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm) AND
        unit_box_ub?(bspoly,bsdegmono,nvars,terms,cf,intendpts)(omm) AND
        length_eq?(nvars)(omm) AND
        omm`max_depth = depth} =
      IF v = 0 THEN 
        LET coefffun      = multibscoeff(bspoly,bsdegmono,cf,nvars,terms),
            thiscoeff     = coefffun(f),
    	  thisvar       = IF ep THEN corner_to_point(f,nvars) ELSE null ENDIF,
            thisachval    = IF ep THEN thiscoeff ELSE 0 ENDIF IN
          single_outminmax(thiscoeff,thisachval,thisvar,depth) 
      ELSE 
        LET iepts = intendpts(v-1) IN
          iterate_left(0,bsdegmono(v-1),
           LAMBDA(d:upto(bsdegmono(v-1))):
             LET nf    = f WITH [(v-1) := d],
                 nep   = ep AND (d=0 AND iepts`1 OR 
                                 bsdegmono(v-1)/=0 AND 
                                 d=bsdegmono(v-1) AND iepts`2) IN
             Bern_coeffs_minmax_rec(bspoly,bsdegmono,cf,nvars,terms,nf,depth,intendpts,v-1,nep),
           combine)
      ENDIF 
      MEASURE v

    Bern_coeffs_minmax(bspoly,bsdegmono,cf,nvars,terms,depth,intendpts) : 
      (sound?(bspoly,bsdegmono,nvars,terms,cf,intendpts)) = 
      Bern_coeffs_minmax_rec(bspoly,bsdegmono,cf,nvars,terms,zeroes,depth,intendpts,nvars,true)

    Bern_coeffs_minmax_length: LEMMA 
      LET omm = Bern_coeffs_minmax(bspoly,bsdegmono,cf,nvars,terms,depth,intendpts) IN
      length_eq?(nvars)(omm)

    Bern_coeffs_minmax_maxdepth: LEMMA 
      LET omm = Bern_coeffs_minmax(bspoly,bsdegmono,cf,nvars,terms,depth,intendpts) IN
      omm`max_depth = depth

    Bern_coeffs_minmax_var: LEMMA 
     LET omm = Bern_coeffs_minmax(bspoly,bsdegmono,cf,nvars,terms,depth,intendpts),
         bseval = multibs_eval(bspoly, bsdegmono, cf, nvars, terms) 
     IN
       (cons?(omm`lb_var) OR cons?(omm`ub_var)) IMPLIES
         bseval(list2array(0)(omm`lb_var)) = omm`lb_max AND
         bseval(list2array(0)(omm`ub_var)) = omm`ub_min

    localexit  : VAR [Outminmax -> bool]

    globalexit : VAR [Outminmax->bool]

    %%%% BEGIN 3M: used to close TCC obligations
    list2array_sound_pi : LEMMA
      FORALL(l:list[real],t:real) : 
        list2array(t)(l) = LAMBDA(i: nat):
          IF i < length(l) THEN nth(l,i)
          ELSE t
        ENDIF 
    %%%% END 3M

    Bernstein_minmax_rec(bspoly,bsdegmono,nvars,terms,cf,depth,(level:upto(depth)),
                         localexit,globalexit,intendpts,varselect,omm) : 
      RECURSIVE (sound?(bspoly,bsdegmono,nvars,terms,cf,intendpts)) =
      LET bp     = translist(polylist(bspoly,bsdegmono,nvars,terms)),
          minmax = Bern_coeffs_minmax(bp,bsdegmono,cf,nvars,terms,level,intendpts)
      IN
        IF level = depth OR localexit(minmax) OR between?(omm,minmax) OR globalexit(minmax) THEN
          minmax
        ELSE
          LET
  	  varsel       = varselect(bp,bsdegmono,nvars,terms,cf,level),
            v            = mod(varsel`2,nvars),
  	  spleft       = Bern_split_left_mpoly(bp,bsdegmono)(mod(varsel`2,nvars)),
  	  spright      = Bern_split_right_mpoly(bp,bsdegmono)(mod(varsel`2,nvars)),
  	  ipleft       = intendpts WITH [(v)`2 := true],
  	  ipright      = intendpts WITH [(v)`1 := true],
  	  (LR1,LR2)    = IF varsel`1 THEN (spleft,spright) ELSE (spright,spleft) ENDIF,
  	  LR1intendpts = IF varsel`1 THEN ipleft ELSE ipright ENDIF,
  	  LR2intendpts = IF varsel`1 THEN ipright ELSE ipleft ENDIF,
  	  combine_this = IF varsel`1 THEN combine_l ELSE combine_r ENDIF,
  	  newmm1       = combine(omm,minmax),
            level        = level + 1,
            bslr1        = Bernstein_minmax_rec(LR1,bsdegmono,nvars,terms,cf,depth,level,
                                                localexit,globalexit,LR1intendpts,varselect,newmm1)
  	IN
            IF globalexit(bslr1) THEN
              combine_this(v,bslr1,minmax)
            ELSE 
              LET
  	      newmm2   = combine(newmm1,bslr1),
                bslr2    = Bernstein_minmax_rec(LR2,bsdegmono,nvars,terms,cf,depth,level,
                                                localexit,globalexit,LR2intendpts,varselect,newmm2),
  	      bslrleft = IF varsel`1 THEN bslr1 ELSE bslr2 ENDIF,
  	      bslrright = IF varsel`1 THEN bslr2 ELSE bslr1 ENDIF
              IN
                combine_lr(v,bslrleft,bslrright)
  	  ENDIF
        ENDIF
        MEASURE depth-level

    Bernstein_minmax(bspoly,bsdegmono,nvars,terms,cf,depth,localexit,globalexit,
                     intendpts,varselect) : (sound?(bspoly,bsdegmono,nvars,terms,cf,intendpts)) =
      Bernstein_minmax_rec(bspoly,bsdegmono,nvars,terms,cf,depth,0,
                           localexit,globalexit,intendpts,varselect,empty_minmax)

  END bernstein_minmax

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 104, column 8) for
      % single_outminmax(thiscoeff, thisachval, thisvar, depth)
      % expected type  {omm: Outminmax |
                     %               (FORALL
                     %                (nf: CoeffMono):
                     %                (FORALL
                     %                 (i: below(nvars)):
                     %                 nf(i) <= bsdegmono(i)
                     %                 AND
                     %                 (v <= i IMPLIES f(i) = nf(i)))
                     %                IMPLIES
                     %                omm`lb_min
                     %                <=
                     %                multibscoeff
                     %                (bspoly, bsdegmono, cf, nvars, terms)
                     %                (nf)
                     %                AND
                     %                multibscoeff
                     %                (bspoly, bsdegmono, cf, nvars, terms)
                     %                (nf)
                     %                <=
                     %                omm`ub_max)
                     %           AND unit_box_lb?(bspoly,
                     %                            bsdegmono,
                     %                            nvars,
                     %                            terms,
                     %                            cf,
                     %                            intendpts)
                     %                           (omm)
                     %           AND unit_box_ub?(bspoly,
                     %                            bsdegmono,
                     %                            nvars,
                     %                            terms,
                     %                            cf,
                     %                            intendpts)
                     %                           (omm)
                     %           AND length_eq?(nvars)(omm)
                     %           AND omm`max_depth = depth}
  Bern_coeffs_minmax_rec_TCC1: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, cf: Coeff,
            nvars: posnat, terms: posnat, f: CoeffMono, depth: nat,
            intendpts: IntervalEndpoints, v: nat,
            (ep: (edge_point?(bsdegmono, nvars, f, intendpts, v)))):
      v = 0 IMPLIES
       (FORALL (coefffun: [CoeffMono -> real]):
          coefffun = multibscoeff(bspoly, bsdegmono, cf, nvars, terms)
           IMPLIES
           (FORALL (thiscoeff: real):
              thiscoeff = coefffun(f) IMPLIES
               (FORALL (thisvar: list[real]):
                  thisvar =
                   IF ep THEN corner_to_point(f, nvars) ELSE null ENDIF
                   IMPLIES
                   (FORALL (thisachval: real):
                      thisachval = IF ep THEN thiscoeff ELSE 0 ENDIF IMPLIES
                            FORALL (nf: CoeffMono):
                              (FORALL (i: below(nvars)):
                                 nf(i) <= bsdegmono(i) AND
                                  (v <= i IMPLIES f(i) = nf(i)))
                               IMPLIES
                               single_outminmax(thiscoeff,
                                                thisachval,
                                                thisvar,
                                                depth)`lb_min
                                <=
                                multibscoeff(bspoly,
                                             bsdegmono,
                                             cf,
                                             nvars,
                                             terms)
                                            (nf)
                                AND
                                multibscoeff(bspoly,
                                             bsdegmono,
                                             cf,
                                             nvars,
                                             terms)
                                            (nf)
                                 <=
                                 single_outminmax(thiscoeff,
                                                  thisachval,
                                                  thisvar,
                                                  depth)`ub_max
                        AND unit_box_lb?(bspoly,
                                         bsdegmono,
                                         nvars,
                                         terms,
                                         cf,
                                         intendpts)
                                        (single_outminmax
                                         (thiscoeff,
                                          thisachval,
                                          thisvar,
                                          depth))
                        AND unit_box_ub?(bspoly,
                                         bsdegmono,
                                         nvars,
                                         terms,
                                         cf,
                                         intendpts)
                                        (single_outminmax
                                         (thiscoeff,
                                          thisachval,
                                          thisvar,
                                          depth))
                        AND length_eq?(nvars)
                                      (single_outminmax
                                       (thiscoeff,
                                        thisachval,
                                        thisvar,
                                        depth))
                        AND single_outminmax(thiscoeff,
                                             thisachval,
                                             thisvar,
                                             depth)`max_depth
                             = depth))));

  % Subtype TCC generated (at line 107, column 33) for  v - 1
      % expected type  nat
  Bern_coeffs_minmax_rec_TCC2: OBLIGATION
    FORALL (bsdegmono: DegreeMono, nvars: posnat, f: CoeffMono,
            intendpts: IntervalEndpoints, v: nat,
            (ep: (edge_point?(bsdegmono, nvars, f, intendpts, v)))):
      NOT v = 0 IMPLIES
       (FORALL (iepts: [bool, bool]):
          iepts = intendpts(v - 1) IMPLIES v - 1 >= 0);

  % Subtype TCC generated (at line 113, column 89) for  nep
      % expected type  (edge_point?(bsdegmono, nvars, nf, intendpts, v - 1))
  Bern_coeffs_minmax_rec_TCC3: OBLIGATION
    FORALL (bsdegmono: DegreeMono, nvars: posnat, f: CoeffMono,
            intendpts: IntervalEndpoints, v: nat,
            (ep: (edge_point?(bsdegmono, nvars, f, intendpts, v)))):
      NOT v = 0 IMPLIES
       (FORALL (iepts: [bool, bool]):
          iepts = intendpts(v - 1) IMPLIES
           (FORALL (d: upto(bsdegmono(v - 1)), nf: CoeffMono):
              nf = f WITH [(v - 1) := d] IMPLIES
               (FORALL (nep: boolean):
                  nep =
                   (ep AND
                     (d = 0 AND iepts`1 OR
                       bsdegmono(v - 1) /= 0 AND
                        d = bsdegmono(v - 1) AND iepts`2))
                   IMPLIES
                   edge_point?(bsdegmono, nvars, nf, intendpts, v - 1)
                              (nep))));

  % Termination TCC generated (at line 113, column 11) for
      % Bern_coeffs_minmax_rec(bspoly, bsdegmono, cf, nvars, terms, nf,
      %                        depth, intendpts, v - 1, nep)
  Bern_coeffs_minmax_rec_TCC4: OBLIGATION
    FORALL (bsdegmono: DegreeMono, nvars: posnat, f: CoeffMono,
            intendpts: IntervalEndpoints, v: nat,
            (ep: (edge_point?(bsdegmono, nvars, f, intendpts, v)))):
      NOT v = 0 IMPLIES
       (FORALL (iepts: [bool, bool]):
          iepts = intendpts(v - 1) IMPLIES
           (FORALL (d: upto(bsdegmono(v - 1)), nf: CoeffMono):
              nf = f WITH [(v - 1) := d] IMPLIES
               (FORALL (nep: boolean):
                  nep =
                   (ep AND
                     (d = 0 AND iepts`1 OR
                       bsdegmono(v - 1) /= 0 AND
                        d = bsdegmono(v - 1) AND iepts`2))
                   IMPLIES v - 1 < v)));

  % Subtype TCC generated (at line 108, column 9) for
      % LAMBDA (d: upto(bsdegmono(v - 1))):
      %   LET nf = f WITH [(v - 1) := d],
      %       nep =
      %         ep AND
      %          (d = 0 AND iepts`1 OR
      %            bsdegmono(v - 1) /= 0 AND
      %             d = bsdegmono(v - 1) AND iepts`2)
      %     IN
      %     Bern_coeffs_minmax_rec(bspoly, bsdegmono, cf, nvars, terms, nf,
      %                            depth, intendpts, v - 1, nep)
      % expected type  IterateBody[Outminmax](0, bsdegmono(v - 1))
  Bern_coeffs_minmax_rec_TCC5: OBLIGATION
    FORALL (bsdegmono: DegreeMono, nvars: posnat, f: CoeffMono,
            intendpts: IntervalEndpoints, v: nat,
            (ep: (edge_point?(bsdegmono, nvars, f, intendpts, v)))):
      NOT v = 0 IMPLIES
       (FORALL (iepts: [bool, bool]):
          iepts = intendpts(v - 1) IMPLIES
           (FORALL (x: int):
              x >= 0 AND x <= bsdegmono(v - 1) IFF
               0 <= x AND x <= bsdegmono(v - 1)));

  % Subtype TCC generated (at line 107, column 8) for
      % iterate_left(0, bsdegmono(v - 1),
      %              LAMBDA (d: upto(bsdegmono(v - 1))):
      %                LET nf = f WITH [(v - 1) := d],
      %                    nep =
      %                      ep AND
      %                       (d = 0 AND iepts`1 OR
      %                         bsdegmono(v - 1) /= 0 AND
      %                          d = bsdegmono(v - 1) AND iepts`2)
      %                  IN
      %                  Bern_coeffs_minmax_rec(bspoly,
      %                                         bsdegmono,
      %                                         cf,
      %                                         nvars,
      %                                         terms,
      %                                         nf,
      %                                         depth,
      %                                         intendpts,
      %                                         v - 1,
      %                                         nep),
      %              combine)
      % expected type  {omm: Outminmax |
                     %               (FORALL
                     %                (nf: CoeffMono):
                     %                (FORALL
                     %                 (i: below(nvars)):
                     %                 nf(i) <= bsdegmono(i)
                     %                 AND
                     %                 (v <= i IMPLIES f(i) = nf(i)))
                     %                IMPLIES
                     %                omm`lb_min
                     %                <=
                     %                multibscoeff
                     %                (bspoly, bsdegmono, cf, nvars, terms)
                     %                (nf)
                     %                AND
                     %                multibscoeff
                     %                (bspoly, bsdegmono, cf, nvars, terms)
                     %                (nf)
                     %                <=
                     %                omm`ub_max)
                     %           AND unit_box_lb?(bspoly,
                     %                            bsdegmono,
                     %                            nvars,
                     %                            terms,
                     %                            cf,
                     %                            intendpts)
                     %                           (omm)
                     %           AND unit_box_ub?(bspoly,
                     %                            bsdegmono,
                     %                            nvars,
                     %                            terms,
                     %                            cf,
                     %                            intendpts)
                     %                           (omm)
                     %           AND length_eq?(nvars)(omm)
                     %           AND omm`max_depth = depth}
  Bern_coeffs_minmax_rec_TCC6: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, cf: Coeff,
            nvars: posnat, terms: posnat, f: CoeffMono, depth: nat,
            intendpts: IntervalEndpoints, v: nat,
            v1:
              [d1:
                 {z:
                    [MultiBernstein, bsdegmono: DegreeMono, Coeff,
                     nvars: posnat, posnat, f: CoeffMono, nat,
                     intendpts: IntervalEndpoints, v: nat,
                     (edge_point?(bsdegmono, nvars, f, intendpts, v))] |
                          z`9 < v} ->
                 {omm: Outminmax |
                               FORALL (nf: CoeffMono):
                                 (FORALL (i: below(d1`4)):
                                    nf(i) <= d1`2(i) AND
                                     (d1`9 <= i IMPLIES d1`6(i) = nf(i)))
                                  IMPLIES
                                  omm`lb_min <=
                                   multibscoeff(d1`1, d1`2, d1`3, d1`4, d1`5)
                                               (nf)
                                   AND
                                   multibscoeff(d1`1, d1`2, d1`3, d1`4, d1`5)
                                               (nf)
                                    <= omm`ub_max
                           AND unit_box_lb?(d1`1,
                                            d1`2,
                                            d1`4,
                                            d1`5,
                                            d1`3,
                                            d1`8)
                                           (omm)
                           AND unit_box_ub?(d1`1,
                                            d1`2,
                                            d1`4,
                                            d1`5,
                                            d1`3,
                                            d1`8)
                                           (omm)
                           AND length_eq?(d1`4)(omm)
                           AND omm`max_depth = d1`7}],
            (ep: (edge_point?(bsdegmono, nvars, f, intendpts, v)))):
      NOT v = 0 IMPLIES
       (FORALL (iepts: [bool, bool]):
          iepts = intendpts(v - 1) IMPLIES
                FORALL (nf_1: CoeffMono):
                  (FORALL (i: below(nvars)):
                     nf_1(i) <= bsdegmono(i) AND
                      (v <= i IMPLIES f(i) = nf_1(i)))
                   IMPLIES
                   iterate_left[Outminmax]
                       (0, bsdegmono(v - 1),
                        LAMBDA (d: upto(bsdegmono(v - 1))):
                          LET nf = f WITH [(v - 1) := d],
                              nep =
                                ep AND
                                 (d = 0 AND iepts`1 OR
                                   bsdegmono(v - 1) /= 0 AND
                                    d = bsdegmono(v - 1) AND iepts`2)
                            IN
                            v1(bspoly, bsdegmono, cf, nvars, terms, nf,
                               depth, intendpts, v - 1, nep),
                        combine)`lb_min
                    <=
                    multibscoeff(bspoly, bsdegmono, cf, nvars, terms)(nf_1)
                    AND
                    multibscoeff(bspoly, bsdegmono, cf, nvars, terms)(nf_1)
                     <=
                     iterate_left[Outminmax]
                         (0, bsdegmono(v - 1),
                          LAMBDA (d: upto(bsdegmono(v - 1))):
                            LET nf = f WITH [(v - 1) := d],
                                nep =
                                  ep AND
                                   (d = 0 AND iepts`1 OR
                                     bsdegmono(v - 1) /= 0 AND
                                      d = bsdegmono(v - 1) AND iepts`2)
                              IN
                              v1(bspoly, bsdegmono, cf, nvars, terms, nf,
                                 depth, intendpts, v - 1, nep),
                          combine)`ub_max
            AND unit_box_lb?(bspoly, bsdegmono, nvars, terms, cf, intendpts)
                            (iterate_left[Outminmax]
                                 (0, bsdegmono(v - 1),
                                  LAMBDA (d: upto(bsdegmono(v - 1))):
                                    LET nf
                                        =
                                        f WITH [(v - 1) := d],
                                        nep
                                        =
                                        ep
                                        AND
                                        (d = 0 AND iepts`1
                                         OR
                                         bsdegmono(v - 1) /= 0
                                         AND
                                         d = bsdegmono(v - 1) AND iepts`2)
                                      IN
                                      v1
                                      (bspoly,
                                       bsdegmono,
                                       cf,
                                       nvars,
                                       terms,
                                       nf,
                                       depth,
                                       intendpts,
                                       v - 1,
                                       nep),
                                  combine))
            AND unit_box_ub?(bspoly, bsdegmono, nvars, terms, cf, intendpts)
                            (iterate_left[Outminmax]
                                 (0, bsdegmono(v - 1),
                                  LAMBDA (d: upto(bsdegmono(v - 1))):
                                    LET nf
                                        =
                                        f WITH [(v - 1) := d],
                                        nep
                                        =
                                        ep
                                        AND
                                        (d = 0 AND iepts`1
                                         OR
                                         bsdegmono(v - 1) /= 0
                                         AND
                                         d = bsdegmono(v - 1) AND iepts`2)
                                      IN
                                      v1
                                      (bspoly,
                                       bsdegmono,
                                       cf,
                                       nvars,
                                       terms,
                                       nf,
                                       depth,
                                       intendpts,
                                       v - 1,
                                       nep),
                                  combine))
            AND length_eq?(nvars)
                          (iterate_left[Outminmax]
                               (0, bsdegmono(v - 1),
                                LAMBDA (d: upto(bsdegmono(v - 1))):
                                  LET nf
                                      =
                                      f WITH [(v - 1) := d],
                                      nep
                                      =
                                      ep
                                      AND
                                      (d = 0 AND iepts`1
                                       OR
                                       bsdegmono(v - 1) /= 0
                                       AND
                                       d = bsdegmono(v - 1) AND iepts`2)
                                    IN
                                    v1(bspoly,
                                       bsdegmono,
                                       cf,
                                       nvars,
                                       terms,
                                       nf,
                                       depth,
                                       intendpts,
                                       v - 1,
                                       nep),
                                combine))
            AND iterate_left[Outminmax]
                    (0, bsdegmono(v - 1),
                     LAMBDA (d: upto(bsdegmono(v - 1))):
                       LET nf = f WITH [(v - 1) := d],
                           nep =
                             ep AND
                              (d = 0 AND iepts`1 OR
                                bsdegmono(v - 1) /= 0 AND
                                 d = bsdegmono(v - 1) AND iepts`2)
                         IN
                         v1(bspoly, bsdegmono, cf, nvars, terms, nf, depth,
                            intendpts, v - 1, nep),
                     combine)`max_depth
                 = depth);

  % Subtype TCC generated (at line 106, column 28) for  v - 1
      % expected type  nat
  Bern_coeffs_minmax_rec_TCC7: OBLIGATION
    FORALL (bsdegmono: DegreeMono, nvars: posnat, f: CoeffMono,
            intendpts: IntervalEndpoints, v: nat,
            (ep: (edge_point?(bsdegmono, nvars, f, intendpts, v)))):
      NOT v = 0 IMPLIES v - 1 >= 0;

  % Subtype TCC generated (at line 120, column 88) for  TRUE
      % expected type  (edge_point?(bsdegmono, nvars, LAMBDA (i: nat): 0,
                     %              intendpts, nvars))
  Bern_coeffs_minmax_TCC1: OBLIGATION
    FORALL (bsdegmono: DegreeMono, nvars: posnat,
            intendpts: IntervalEndpoints):
      edge_point?(bsdegmono, nvars, LAMBDA (i: nat): 0, intendpts, nvars)
                 (TRUE);

  % Subtype TCC generated (at line 120, column 4) for
      % Bern_coeffs_minmax_rec(bspoly, bsdegmono, cf, nvars, terms,
      %                        LAMBDA (i: nat): 0, depth, intendpts, nvars,
      %                        TRUE)
      % expected type  (sound?(bspoly, bsdegmono, nvars, terms, cf,
                     %         intendpts))
  Bern_coeffs_minmax_TCC2: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, cf: Coeff,
            nvars: posnat, terms: posnat, depth: nat,
            intendpts: IntervalEndpoints):
      sound?(bspoly, bsdegmono, nvars, terms, cf, intendpts)
            (Bern_coeffs_minmax_rec(bspoly, bsdegmono, cf, nvars, terms,
                                    LAMBDA (i: nat): 0, depth, intendpts,
                                    nvars, TRUE));

  % Subtype TCC generated (at line 189, column 14) for  depth - level
      % expected type  naturalnumber
  Bernstein_minmax_rec_TCC1: OBLIGATION
    FORALL (depth: nat, (level: upto(depth))): depth - level >= 0;

  % Subtype TCC generated (at line 158, column 8) for  minmax
      % expected type  (sound?(bspoly, bsdegmono, nvars, terms, cf,
                     %         intendpts))
  Bernstein_minmax_rec_TCC2: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, depth: nat, (level: upto(depth)),
            localexit: [Outminmax -> bool], globalexit: [Outminmax -> bool],
            intendpts: IntervalEndpoints, omm: Outminmax,
            bp: [nat -> [nat -> [nat -> real]]]):
      bp = translist(polylist(bspoly, bsdegmono, nvars, terms)) IMPLIES
       (FORALL (minmax:
                  (sound?(bp, bsdegmono, nvars, terms, cf, intendpts))):
          (level = depth OR
            localexit(minmax) OR between?(omm, minmax) OR globalexit(minmax))
           AND
           minmax =
            Bern_coeffs_minmax(bp, bsdegmono, cf, nvars, terms, level,
                               intendpts)
           IMPLIES
           sound?(bspoly, bsdegmono, nvars, terms, cf, intendpts)(minmax));

  % Subtype TCC generated (at line 165, column 35) for  v
      % expected type  nat
  Bernstein_minmax_rec_TCC3: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, depth: nat, (level: upto(depth)),
            localexit: [Outminmax -> bool], globalexit: [Outminmax -> bool],
            intendpts: IntervalEndpoints, varselect: VarSelector,
            omm: Outminmax, bp: [nat -> [nat -> [nat -> real]]]):
      bp = translist(polylist(bspoly, bsdegmono, nvars, terms)) IMPLIES
       (FORALL (minmax:
                  (sound?(bp, bsdegmono, nvars, terms, cf, intendpts))):
               NOT level = depth AND NOT localexit(minmax)
           AND NOT between?(omm, minmax) AND NOT globalexit(minmax)
           AND minmax =
                Bern_coeffs_minmax(bp, bsdegmono, cf, nvars, terms, level,
                                   intendpts)
           IMPLIES
           (FORALL (varsel: [bool, nat]):
              varsel = varselect(bp, bsdegmono, nvars, terms, cf, level)
               IMPLIES
               (FORALL (v: {k | abs(k) < abs(nvars)}):
                  v = mod(varsel`2, nvars) IMPLIES
                   (FORALL (spleft: [nat -> Polyproduct]):
                      (spleft =
                        (LAMBDA (k: nat):
                           Bern_split_left_mono(bp(k), bsdegmono)
                                               (mod(varsel`2, nvars))))
                       IMPLIES
                       (FORALL (spright: [nat -> Polyproduct]):
                          (spright =
                            (LAMBDA (k: nat):
                               Bern_split_right_mono(bp(k), bsdegmono)
                                                    (mod(varsel`2, nvars))))
                           IMPLIES v >= 0)))));

  % Subtype TCC generated (at line 173, column 81) for  level
      % expected type  upto(depth)
  Bernstein_minmax_rec_TCC4: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, depth: nat, (level: upto(depth)),
            localexit: [Outminmax -> bool], globalexit: [Outminmax -> bool],
            intendpts: IntervalEndpoints, varselect: VarSelector,
            omm: Outminmax, bp: [nat -> [nat -> [nat -> real]]]):
      bp = translist(polylist(bspoly, bsdegmono, nvars, terms)) IMPLIES
       (FORALL (minmax:
                  (sound?(bp, bsdegmono, nvars, terms, cf, intendpts))):
               NOT level = depth AND NOT localexit(minmax)
           AND NOT between?(omm, minmax) AND NOT globalexit(minmax)
           AND minmax =
                Bern_coeffs_minmax(bp, bsdegmono, cf, nvars, terms, level,
                                   intendpts)
           IMPLIES
           (FORALL (varsel: [bool, nat]):
              varsel = varselect(bp, bsdegmono, nvars, terms, cf, level)
               IMPLIES
               (FORALL (v: {k | abs(k) < abs(nvars)}):
                  v = mod(varsel`2, nvars) IMPLIES
                   (FORALL (spleft: [nat -> Polyproduct]):
                      (spleft =
                        (LAMBDA (k: nat):
                           Bern_split_left_mono(bp(k), bsdegmono)
                                               (mod(varsel`2, nvars))))
                       IMPLIES
                       (FORALL (spright: [nat -> Polyproduct]):
                          (spright =
                            (LAMBDA (k: nat):
                               Bern_split_right_mono(bp(k), bsdegmono)
                                                    (mod(varsel`2, nvars))))
                           IMPLIES
                           (FORALL (ipleft: IntervalEndpoints):
                              ipleft = intendpts WITH [(v)`2 := TRUE] IMPLIES
                               (FORALL (ipright: IntervalEndpoints):
                                  ipright = intendpts WITH [(v)`1 := TRUE]
                                   IMPLIES
                                   (FORALL (LR1: [nat -> Polyproduct],
                                            LR2: [nat -> Polyproduct]):
                                      LR2
                                      =
                                      IF varsel`1
                                      THEN (spleft, spright)
                                      ELSE (spright, spleft)
                                      ENDIF`2
                                      AND
                                      LR1
                                      =
                                      IF varsel`1
                                      THEN (spleft, spright)
                                      ELSE (spright, spleft)
                                      ENDIF`1
                                      IMPLIES
                                      (FORALL
                                       (LR1intendpts: IntervalEndpoints):
                                       LR1intendpts
                                       =
                                       IF varsel`1
                                       THEN ipleft
                                       ELSE ipright
                                       ENDIF
                                       IMPLIES
                                       (FORALL
                                        (LR2intendpts: IntervalEndpoints):
                                        LR2intendpts
                                        =
                                        IF varsel`1
                                        THEN ipright
                                        ELSE ipleft
                                        ENDIF
                                        IMPLIES
                                        (FORALL
                                         (combine_this:
                                          [[nat, Outminmax, Outminmax] ->
                                           Outminmax]):
                                         combine_this
                                         =
                                         IF varsel`1
                                         THEN combine_l
                                         ELSE combine_r
                                         ENDIF
                                         IMPLIES
                                         (FORALL
                                          (newmm1: Outminmax):
                                          newmm1 = combine(omm, minmax)
                                          IMPLIES
                                          (FORALL
                                           (level1: posint):
                                           level1 = level + 1
                                           IMPLIES
                                           level1 <= depth)))))))))))));

  % Termination TCC generated (at line 173, column 25) for
      % Bernstein_minmax_rec(LR1, bsdegmono, nvars, terms, cf, depth, level,
      %                      localexit, globalexit, LR1intendpts, varselect,
      %                      newmm1)
  Bernstein_minmax_rec_TCC5: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, depth: nat, (level: upto(depth)),
            localexit: [Outminmax -> bool], globalexit: [Outminmax -> bool],
            intendpts: IntervalEndpoints, varselect: VarSelector,
            omm: Outminmax, bp: [nat -> [nat -> [nat -> real]]]):
      bp = translist(polylist(bspoly, bsdegmono, nvars, terms)) IMPLIES
       (FORALL (minmax:
                  (sound?(bp, bsdegmono, nvars, terms, cf, intendpts))):
               NOT level = depth AND NOT localexit(minmax)
           AND NOT between?(omm, minmax) AND NOT globalexit(minmax)
           AND minmax =
                Bern_coeffs_minmax(bp, bsdegmono, cf, nvars, terms, level,
                                   intendpts)
           IMPLIES
           (FORALL (varsel: [bool, nat]):
              varsel = varselect(bp, bsdegmono, nvars, terms, cf, level)
               IMPLIES
               (FORALL (v: {k | abs(k) < abs(nvars)}):
                  v = mod(varsel`2, nvars) IMPLIES
                   (FORALL (spleft: [nat -> Polyproduct]):
                      (spleft =
                        (LAMBDA (k: nat):
                           Bern_split_left_mono(bp(k), bsdegmono)
                                               (mod(varsel`2, nvars))))
                       IMPLIES
                       (FORALL (spright: [nat -> Polyproduct]):
                          (spright =
                            (LAMBDA (k: nat):
                               Bern_split_right_mono(bp(k), bsdegmono)
                                                    (mod(varsel`2, nvars))))
                           IMPLIES
                           (FORALL (ipleft: IntervalEndpoints):
                              ipleft = intendpts WITH [(v)`2 := TRUE] IMPLIES
                               (FORALL (ipright: IntervalEndpoints):
                                  ipright = intendpts WITH [(v)`1 := TRUE]
                                   IMPLIES
                                   (FORALL (LR1: [nat -> Polyproduct],
                                            LR2: [nat -> Polyproduct]):
                                      LR2
                                      =
                                      IF varsel`1
                                      THEN (spleft, spright)
                                      ELSE (spright, spleft)
                                      ENDIF`2
                                      AND
                                      LR1
                                      =
                                      IF varsel`1
                                      THEN (spleft, spright)
                                      ELSE (spright, spleft)
                                      ENDIF`1
                                      IMPLIES
                                      (FORALL
                                       (LR1intendpts: IntervalEndpoints):
                                       LR1intendpts
                                       =
                                       IF varsel`1
                                       THEN ipleft
                                       ELSE ipright
                                       ENDIF
                                       IMPLIES
                                       (FORALL
                                        (LR2intendpts: IntervalEndpoints):
                                        LR2intendpts
                                        =
                                        IF varsel`1
                                        THEN ipright
                                        ELSE ipleft
                                        ENDIF
                                        IMPLIES
                                        (FORALL
                                         (combine_this:
                                          [[nat, Outminmax, Outminmax] ->
                                           Outminmax]):
                                         combine_this
                                         =
                                         IF varsel`1
                                         THEN combine_l
                                         ELSE combine_r
                                         ENDIF
                                         IMPLIES
                                         (FORALL
                                          (newmm1: Outminmax):
                                          newmm1 = combine(omm, minmax)
                                          IMPLIES
                                          (FORALL
                                           (level1: posint):
                                           level1 = level + 1
                                           IMPLIES
                                           depth - level1
                                           <
                                           depth - level)))))))))))));

  % Subtype TCC generated (at line 177, column 12) for
      % combine_this(v, bslr1, minmax)
      % expected type  (sound?(bspoly, bsdegmono, nvars, terms, cf,
                     %         intendpts))
  Bernstein_minmax_rec_TCC6: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, depth: nat, (level: upto(depth)),
            v1:
              [d1:
                 {z:
                    [MultiBernstein, DegreeMono, posnat, posnat, Coeff,
                     depth: nat, upto(depth), [Outminmax -> bool],
                     [Outminmax -> bool], IntervalEndpoints, VarSelector,
                     Outminmax] |
                          z`6 - z`7 < depth - level} ->
                 (sound?(d1`1, d1`2, d1`3, d1`4, d1`5, d1`10))],
            localexit: [Outminmax -> bool], globalexit: [Outminmax -> bool],
            intendpts: IntervalEndpoints, varselect: VarSelector,
            omm: Outminmax, bp: [nat -> [nat -> [nat -> real]]]):
      bp = translist(polylist(bspoly, bsdegmono, nvars, terms)) IMPLIES
       (FORALL (minmax:
                  (sound?(bp, bsdegmono, nvars, terms, cf, intendpts))):
               NOT level = depth AND NOT localexit(minmax)
           AND NOT between?(omm, minmax) AND NOT globalexit(minmax)
           AND minmax =
                Bern_coeffs_minmax(bp, bsdegmono, cf, nvars, terms, level,
                                   intendpts)
           IMPLIES
           (FORALL (varsel: [bool, nat]):
              varsel = varselect(bp, bsdegmono, nvars, terms, cf, level)
               IMPLIES
               (FORALL (v: {k | abs(k) < abs(nvars)}):
                  v = mod(varsel`2, nvars) IMPLIES
                   (FORALL (spleft: [nat -> Polyproduct]):
                      (spleft =
                        (LAMBDA (k: nat):
                           Bern_split_left_mono(bp(k), bsdegmono)
                                               (mod(varsel`2, nvars))))
                       IMPLIES
                       (FORALL (spright: [nat -> Polyproduct]):
                          (spright =
                            (LAMBDA (k: nat):
                               Bern_split_right_mono(bp(k), bsdegmono)
                                                    (mod(varsel`2, nvars))))
                           IMPLIES
                           (FORALL (ipleft: IntervalEndpoints):
                              ipleft = intendpts WITH [(v)`2 := TRUE] IMPLIES
                               (FORALL (ipright: IntervalEndpoints):
                                  ipright = intendpts WITH [(v)`1 := TRUE]
                                   IMPLIES
                                   (FORALL (LR1: [nat -> Polyproduct],
                                            LR2: [nat -> Polyproduct]):
                                      LR2
                                      =
                                      IF varsel`1
                                      THEN (spleft, spright)
                                      ELSE (spright, spleft)
                                      ENDIF`2
                                      AND
                                      LR1
                                      =
                                      IF varsel`1
                                      THEN (spleft, spright)
                                      ELSE (spright, spleft)
                                      ENDIF`1
                                      IMPLIES
                                      (FORALL
                                       (LR1intendpts: IntervalEndpoints):
                                       LR1intendpts
                                       =
                                       IF varsel`1
                                       THEN ipleft
                                       ELSE ipright
                                       ENDIF
                                       IMPLIES
                                       (FORALL
                                        (LR2intendpts: IntervalEndpoints):
                                        LR2intendpts
                                        =
                                        IF varsel`1
                                        THEN ipright
                                        ELSE ipleft
                                        ENDIF
                                        IMPLIES
                                        (FORALL
                                         (combine_this:
                                          [[nat, Outminmax, Outminmax] ->
                                           Outminmax]):
                                         combine_this
                                         =
                                         IF varsel`1
                                         THEN combine_l
                                         ELSE combine_r
                                         ENDIF
                                         IMPLIES
                                         (FORALL
                                          (newmm1: Outminmax):
                                          newmm1 = combine(omm, minmax)
                                          IMPLIES
                                          (FORALL
                                           (level1: posint):
                                           level1 = level + 1
                                           IMPLIES
                                           (FORALL
                                            (bslr1:
                                             (sound?
                                              (LR1,
                                               bsdegmono,
                                               nvars,
                                               terms,
                                               cf,
                                               LR1intendpts))):
                                            globalexit(bslr1)
                                            AND
                                            bslr1
                                            =
                                            v1
                                            (LR1,
                                             bsdegmono,
                                             nvars,
                                             terms,
                                             cf,
                                             depth,
                                             level1,
                                             localexit,
                                             globalexit,
                                             LR1intendpts,
                                             varselect,
                                             newmm1)
                                            IMPLIES
                                            sound?
                                            (bspoly,
                                             bsdegmono,
                                             nvars,
                                             terms,
                                             cf,
                                             intendpts)
                                            (combine_this
                                             (v,
                                              bslr1,
                                              minmax))))))))))))))));

  % Subtype TCC generated (at line 186, column 14) for
      % combine_lr(v, bslrleft, bslrright)
      % expected type  (sound?(bspoly, bsdegmono, nvars, terms, cf,
                     %         intendpts))
  Bernstein_minmax_rec_TCC7: OBLIGATION
    FORALL (bspoly: MultiBernstein, bsdegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, depth: nat, (level: upto(depth)),
            v1:
              [d1:
                 {z:
                    [MultiBernstein, DegreeMono, posnat, posnat, Coeff,
                     depth: nat, upto(depth), [Outminmax -> bool],
                     [Outminmax -> bool], IntervalEndpoints, VarSelector,
                     Outminmax] |
                          z`6 - z`7 < depth - level} ->
                 (sound?(d1`1, d1`2, d1`3, d1`4, d1`5, d1`10))],
            localexit: [Outminmax -> bool], globalexit: [Outminmax -> bool],
            intendpts: IntervalEndpoints, varselect: VarSelector,
            omm: Outminmax, bp: [nat -> [nat -> [nat -> real]]]):
      bp = translist(polylist(bspoly, bsdegmono, nvars, terms)) IMPLIES
       (FORALL (minmax:
                  (sound?(bp, bsdegmono, nvars, terms, cf, intendpts))):
               NOT level = depth AND NOT localexit(minmax)
           AND NOT between?(omm, minmax) AND NOT globalexit(minmax)
           AND minmax =
                Bern_coeffs_minmax(bp, bsdegmono, cf, nvars, terms, level,
                                   intendpts)
           IMPLIES
           (FORALL (varsel: [bool, nat]):
              varsel = varselect(bp, bsdegmono, nvars, terms, cf, level)
               IMPLIES
               (FORALL (v: {k | abs(k) < abs(nvars)}):
                  v = mod(varsel`2, nvars) IMPLIES
                   (FORALL (spleft: [nat -> Polyproduct]):
                      (spleft =
                        (LAMBDA (k: nat):
                           Bern_split_left_mono(bp(k), bsdegmono)
                                               (mod(varsel`2, nvars))))
                       IMPLIES
                       (FORALL (spright: [nat -> Polyproduct]):
                          (spright =
                            (LAMBDA (k: nat):
                               Bern_split_right_mono(bp(k), bsdegmono)
                                                    (mod(varsel`2, nvars))))
                           IMPLIES
                           (FORALL (ipleft: IntervalEndpoints):
                              ipleft = intendpts WITH [(v)`2 := TRUE] IMPLIES
                               (FORALL (ipright: IntervalEndpoints):
                                  ipright = intendpts WITH [(v)`1 := TRUE]
                                   IMPLIES
                                   (FORALL (LR1: [nat -> Polyproduct],
                                            LR2: [nat -> Polyproduct]):
                                      LR2
                                      =
                                      IF varsel`1
                                      THEN (spleft, spright)
                                      ELSE (spright, spleft)
                                      ENDIF`2
                                      AND
                                      LR1
                                      =
                                      IF varsel`1
                                      THEN (spleft, spright)
                                      ELSE (spright, spleft)
                                      ENDIF`1
                                      IMPLIES
                                      (FORALL
                                       (LR1intendpts: IntervalEndpoints):
                                       LR1intendpts
                                       =
                                       IF varsel`1
                                       THEN ipleft
                                       ELSE ipright
                                       ENDIF
                                       IMPLIES
                                       (FORALL
                                        (LR2intendpts: IntervalEndpoints):
                                        LR2intendpts
                                        =
                                        IF varsel`1
                                        THEN ipright
                                        ELSE ipleft
                                        ENDIF
                                        IMPLIES
                                        (FORALL
                                         (combine_this:
                                          [[nat, Outminmax, Outminmax] ->
                                           Outminmax]):
                                         combine_this
                                         =
                                         IF varsel`1
                                         THEN combine_l
                                         ELSE combine_r
                                         ENDIF
                                         IMPLIES
                                         (FORALL
                                          (newmm1: Outminmax):
                                          newmm1 = combine(omm, minmax)
                                          IMPLIES
                                          (FORALL
                                           (level1: posint):
                                           level1 = level + 1
                                           IMPLIES
                                           (FORALL
                                            (bslr1:
                                             (sound?
                                              (LR1,
                                               bsdegmono,
                                               nvars,
                                               terms,
                                               cf,
                                               LR1intendpts))):
                                            NOT globalexit(bslr1)
                                            AND
                                            bslr1
                                            =
                                            v1
                                            (LR1,
                                             bsdegmono,
                                             nvars,
                                             terms,
                                             cf,
                                             depth,
                                             level1,
                                             localexit,
                                             globalexit,
                                             LR1intendpts,
                                             varselect,
                                             newmm1)
                                            IMPLIES
                                            (FORALL
                                             (newmm2: Outminmax):
                                             newmm2 = combine(newmm1, bslr1)
                                             IMPLIES
                                             (FORALL
                                              (bslr2:
                                               (sound?
                                                (LR2,
                                                 bsdegmono,
                                                 nvars,
                                                 terms,
                                                 cf,
                                                 LR2intendpts))):
                                              bslr2
                                              =
                                              v1
                                              (LR2,
                                               bsdegmono,
                                               nvars,
                                               terms,
                                               cf,
                                               depth,
                                               level1,
                                               localexit,
                                               globalexit,
                                               LR2intendpts,
                                               varselect,
                                               newmm2)
                                              IMPLIES
                                              (FORALL
                                               (bslrleft: Outminmax):
                                               bslrleft
                                               =
                                               IF varsel`1
                                               THEN bslr1
                                               ELSE bslr2
                                               ENDIF
                                               IMPLIES
                                               (FORALL
                                                (bslrright: Outminmax):
                                                bslrright
                                                =
                                                IF varsel`1
                                                THEN bslr2
                                                ELSE bslr1
                                                ENDIF
                                                IMPLIES
                                                sound?
                                                (bspoly,
                                                 bsdegmono,
                                                 nvars,
                                                 terms,
                                                 cf,
                                                 intendpts)
                                                (combine_lr
                                                 (v,
                                                  bslrleft,
                                                  bslrright))))))))))))))))))));

  % Subtype TCC generated (at line 193, column 63) for  0
      % expected type  upto(depth)
  Bernstein_minmax_TCC1: OBLIGATION FORALL (depth: nat): 0 <= depth;


body:
  multi_polynomial : THEORY
  BEGIN

    IMPORTING reals@product_nat, 
              reals@polynomials,
  	    sigma_set@sigma_bijection[nat],
              util,
  	    reals@sq

    %%%%%%%%%%%%%%%%%%%%%% Variables %%%%%%%%%%%%%%%%%%%%%%

    polydegmono,
    polydegmono1,
    polydegmono2    : VAR DegreeMono
    mpoly,
    mpoly1,mpoly2   : VAR MultiPolynomial
    pprod,
    pprod1,pprod2   : VAR Polyproduct
    a               : VAR real
    X,Avars,Bvars   : VAR Vars
    v,jj            : VAR nat
    nvars,terms,
    terms1,terms2   : VAR posnat
    cf,cf1,cf2      : VAR Coeff
    rel    	  : VAR [[real,real]->bool]
    boundedpts,
    intendpts	  : VAR IntervalEndpoints

    %%%%%%%%%%%%%%%%%%%%%% Evaluating Polynomials %%%%%%%%%%%%%%%%%%%%

    polyproduct_eval(pprod,polydegmono,nvars)(X) : real = 
      product(0,nvars-1,LAMBDA (i:nat):polynomial(pprod(i),polydegmono(i))(X(i)))

    multipoly_eval(mpoly,polydegmono,cf,nvars,terms)(X) : real =
      sigma(0,terms-1,LAMBDA (i:nat): cf(i)*polyproduct_eval(mpoly(i),polydegmono,nvars)(X))

    %%%%%%%%%%%%% Translating to the Interval [0,1] %%%%%%%%%%%%

    polyprod_translate(pprod,polydegmono,nvars)(Avars,Bvars,boundedpts)(i:nat) : Polynomial =
      IF    boundedpts(i)`1 AND boundedpts(i)`2 THEN
        poly_translate(pprod(i),polydegmono(i))(Avars(i),Bvars(i))
      ELSIF boundedpts(i)`1 THEN poly_translate_inf_pos(pprod(i),polydegmono(i))(Avars(i))
      ELSE  poly_translate_inf_neg(pprod(i),polydegmono(i))(Bvars(i))
      ENDIF

    multipoly_translate(mpoly,polydegmono,nvars,boundedpts)(Avars,Bvars)(k:nat) :  Polyproduct = 
      polyprod_translate(mpoly(k),polydegmono,nvars)(Avars,Bvars,boundedpts)

    multipoly_translate_denormalize: LEMMA 
      lt_below?(nvars)(Avars,Bvars) AND bounded_points_exclusive?(nvars)(boundedpts) AND
      (FORALL (ii:below(nvars)): (NOT (boundedpts(ii)`1 AND boundedpts(ii)`2)) IMPLIES X(ii)/=0)
      IMPLIES
        LET pconst = product(0,nvars-1,LAMBDA (i:nat): 
                                       IF NOT (boundedpts(i)`1 AND boundedpts(i)`2) THEN 
                                         X(i)^polydegmono(i) 
                                       ELSE 1 ENDIF)
        IN
          multipoly_eval(multipoly_translate(mpoly,polydegmono,nvars,boundedpts)(Avars,Bvars),
                       polydegmono,cf,nvars,terms)(X) 
          =
          pconst*multipoly_eval(mpoly,polydegmono,cf,nvars,terms)
                               (denormalize_lambda(nvars,X,boundedpts)(Avars,Bvars))

    multipoly_translate_normalize: LEMMA 
      lt_below?(nvars)(Avars,Bvars)
      AND (FORALL (ii:below(nvars)): (boundedpts(ii)`1 IMPLIES 
           X(ii)/=Avars(ii)-1) AND (boundedpts(ii)`2 IMPLIES X(ii)/=Bvars(ii)+1))
      AND bounded_points_exclusive?(nvars)(boundedpts)
        IMPLIES
        LET pconst = product(0,nvars-1,LAMBDA (i:nat): 
                                       IF (boundedpts(i)`1 AND NOT boundedpts(i)`2) THEN 
                                         (X(i)-Avars(i)+1)^polydegmono(i)
        			       	     ELSIF (boundedpts(i)`2 AND NOT boundedpts(i)`1) THEN 
                                         (Bvars(i)+1-X(i))^polydegmono(i)
  				     ELSE 1 ENDIF)
        IN
          pconst*multipoly_eval(multipoly_translate(mpoly,polydegmono,nvars,boundedpts)(Avars,Bvars),
                       polydegmono,cf,nvars,terms)(normalize_lambda(nvars,X,boundedpts)(Avars,Bvars)) =
          multipoly_eval(mpoly,polydegmono,cf,nvars,terms)(X)

    multipoly_translate_bounded_def: LEMMA 
      boxbetween?(nvars)(Avars,Bvars,intendpts,boundedpts)(X) AND 
      bounded_points_true?(nvars)(boundedpts) IMPLIES
      multipoly_eval(multipoly_translate(mpoly,polydegmono,nvars,boundedpts)(Avars,Bvars),
                     polydegmono,cf,nvars,terms)(normalize_lambda(nvars,X,boundedpts)(Avars,Bvars)) =
      multipoly_eval(mpoly,polydegmono,cf,nvars,terms)(X)

    multipoly_translate_def: LEMMA 
      lt_below?(nvars)(Avars,Bvars) AND 
      bounded_points_exclusive?(nvars)(boundedpts) IMPLIES
      FORALL (rel:RealOrder):
        (FORALL (X): boxbetween?(nvars)(zeroes,ones,
         interval_endpoints_inf_trans(Avars,Bvars,intendpts,boundedpts),boundedpts_true)(X) IMPLIES 
         rel(multipoly_eval(multipoly_translate(mpoly,polydegmono,nvars,boundedpts)(Avars,Bvars),
                            polydegmono,cf,nvars,terms)(X),0))
        IFF
         (FORALL (X): boxbetween?(nvars)(Avars,Bvars,intendpts,boundedpts)(X) IMPLIES 
                      rel(multipoly_eval(mpoly,polydegmono,cf,nvars,terms)(X),0))

    %%%%%%% Forall X For Polynomials %%%%%%%

    eval_X_poly_rel(rel,a)(mpoly,polydegmono,cf,nvars,terms)(X) : MACRO bool =
      rel(multipoly_eval(mpoly,polydegmono,cf,nvars,terms)(X),a)

    forall_X_poly_rel(rel,a)(mpoly,polydegmono,cf,nvars,terms,Avars,Bvars,
  	intendpts,boundedpts) : bool =
      FORALL (X): boxbetween?(nvars)(Avars,Bvars,intendpts,boundedpts)(X) IMPLIES 
        eval_X_poly_rel(rel,a)(mpoly,polydegmono,cf,nvars,terms)(X)

    eval_X_poly_between(amin,amax:real)(mpoly,polydegmono,cf,nvars,terms)(X) : MACRO bool =
        	eval_X_poly_rel(>=,amin)(mpoly,polydegmono,cf,nvars,terms)(X) AND
        	eval_X_poly_rel(<=,amax)(mpoly,polydegmono,cf,nvars,terms)(X)

    forall_X_poly_between(amin,amax:real)(mpoly,polydegmono,cf,nvars,terms,Avars,Bvars,
  	intendpts,boundedpts) : bool =
      FORALL (X): boxbetween?(nvars)(Avars,Bvars,intendpts,boundedpts)(X) IMPLIES 
        eval_X_poly_between(amin,amax)(mpoly,polydegmono,cf,nvars,terms)(X)

    forall_X_poly_interval(mpoly,polydegmono,cf,nvars,terms,Avars,Bvars,
      intendpts,boundedpts,rel,a) : bool =
      FORALL (X): boxbetween?(nvars)(Avars,Bvars,intendpts,boundedpts)(X) IMPLIES 
        rel(multipoly_eval(mpoly,polydegmono,cf,nvars,terms)(X),a)

    %%%%%%%%%%%%%%%%%%%%%% Adding, Subtracting, Multiplying, Scalaring Polynomials %%%%%%%%%%%%%%%%%%%%

    multipoly_zero_above(mpoly,polydegmono)(t:nat)(v:nat)(d:nat): real = 
      IF d>polydegmono(v) THEN 0 ELSE mpoly(t)(v)(d) ENDIF

    multipoly_zero_above_def: LEMMA 
      multipoly_eval(mpoly,polydegmono,cf,nvars,terms) = 
      multipoly_eval(multipoly_zero_above(mpoly,polydegmono),polydegmono,cf,nvars,terms)

    multipoly_add_coeff(cf1,cf2,terms1,terms2)(i:nat): real =
      IF i<terms1 THEN cf1(i) ELSE cf2(i-terms1) ENDIF

    multipoly_add(mpoly1,mpoly2,terms1,terms2)(i:nat) : Polyproduct =
      IF i<terms1 THEN mpoly1(i) ELSE mpoly2(i-terms1) ENDIF

    multipoly_add_def: LEMMA 
      multipoly_eval(mpoly1,polydegmono1,cf1,nvars,terms1)(X)+
      multipoly_eval(mpoly2,polydegmono2,cf2,nvars,terms2)(X) =
      multipoly_eval(multipoly_add(multipoly_zero_above(mpoly1,polydegmono1),
                     multipoly_zero_above(mpoly2,polydegmono2),terms1,terms2),
                     mono_max(polydegmono1,polydegmono2),
                     multipoly_add_coeff(cf1,cf2,terms1,terms2),nvars,terms1+terms2)(X)

    multipoly_scalar_coeff(a,cf)(i:nat): real = a*cf(i)

    multipoly_scalar_def: LEMMA 
      a*multipoly_eval(mpoly,polydegmono,cf,nvars,terms) = 
      multipoly_eval(mpoly,polydegmono,multipoly_scalar_coeff(a,cf),nvars,terms)

    multipoly_sub_def: LEMMA 
      multipoly_eval(mpoly1,polydegmono1,cf1,nvars,terms1)(X)-
      multipoly_eval(mpoly2,polydegmono2,cf2,nvars,terms2)(X) =
      multipoly_eval(multipoly_add(multipoly_zero_above(mpoly1,polydegmono1),
                     multipoly_zero_above(mpoly2,polydegmono2),terms1,terms2),
                     mono_max(polydegmono1,polydegmono2),
                     multipoly_add_coeff(cf1,multipoly_scalar_coeff(-1,cf2),terms1,terms2),
                                         nvars,terms1+terms2)(X)

    polyproduct_product(pprod1,pprod2,polydegmono1,polydegmono2)(v:nat)(d:nat): real = 
        IF d<=mono_sum(polydegmono1,polydegmono2)(v) THEN
          sigma(0,d,LAMBDA (i:nat):IF i<=polydegmono1(v) THEN pprod1(v)(i) 
                                   ELSE 0 ENDIF*
                                   IF i<=d AND d-i<=polydegmono2(v) THEN pprod2(v)(d-i) 
                                   ELSE 0 ENDIF)
        ELSE 0 ENDIF

    polyproduct_product_def: LEMMA 
      polyproduct_eval(polyproduct_product(pprod1,pprod2,polydegmono1,polydegmono2),
                       mono_sum(polydegmono1,polydegmono2),nvars)(X) =
      polyproduct_eval(pprod1,polydegmono1,nvars)(X)*polyproduct_eval(pprod2,polydegmono2,nvars)(X)

    multipoly_product_coeff(cf1,cf2,terms1,terms2,jj)(i:nat): RECURSIVE real =
      IF jj = 0 THEN
        IF   i<terms1 THEN cf1(i)*cf2(jj)
        ELSE 0        ENDIF
      ELSE
        IF    i<jj*terms1     THEN multipoly_product_coeff(cf1,cf2,terms1,terms2,jj-1)(i)
        ELSIF i<(jj+1)*terms1 THEN cf1(i-jj*terms1)*cf2(jj)
        ELSE  0 		    ENDIF
      ENDIF
      MEASURE jj

    multipoly_product(mpoly1,mpoly2,polydegmono1,polydegmono2,terms1,terms2,jj)(i:nat): 
    RECURSIVE Polyproduct =
      IF jj=0 THEN
        IF i<terms1 THEN polyproduct_product(mpoly1(i),mpoly2(jj),polydegmono1,polydegmono2)
        ELSE zero_poly_prod ENDIF
      ELSE
        IF i<jj*terms1	THEN 
          multipoly_product(mpoly1,mpoly2,polydegmono1,polydegmono2,terms1,terms2,jj-1)(i)
        ELSIF i<(jj+1)*terms1	THEN 
          polyproduct_product(mpoly1(i-jj*terms1),mpoly2(jj),polydegmono1,polydegmono2)
        ELSE zero_poly_prod ENDIF
      ENDIF
      MEASURE jj

    multipoly_product_def: LEMMA 
      multipoly_eval(mpoly1,polydegmono1,cf1,nvars,terms1)(X)*
      multipoly_eval(mpoly2,polydegmono2,cf2,nvars,terms2)(X) =
      multipoly_eval(multipoly_product(mpoly1,mpoly2,polydegmono1,polydegmono2,terms1,terms2,terms2-1),
                     mono_sum(polydegmono1,polydegmono2),
                     multipoly_product_coeff(cf1,cf2,terms1,terms2,terms2-1),nvars,terms1*terms2)(X)

    multipoly_sq_coeff(cf,terms)(i:nat): real = multipoly_product_coeff(cf,cf,terms,terms,terms-1)(i)

    multipoly_sq(mpoly,polydegmono,terms)(i:nat): Polyproduct = 
      multipoly_product(mpoly,mpoly,polydegmono,polydegmono,terms,terms,terms-1)(i)

    const_degmono(cc:nat,polydegmono)(i:nat): nat = cc*polydegmono(i)

    multipoly_sq_def: LEMMA
      sq(multipoly_eval(mpoly,polydegmono,cf,nvars,terms)(X)) = 
      multipoly_eval(multipoly_sq(mpoly,polydegmono,terms),const_degmono(2,polydegmono),multipoly_sq_coeff(cf,terms),nvars,sq(terms))(X)

  END multi_polynomial

addendum:
  %%% ================ Addendum: generated declarations ================

  % Assuming TCC generated (at line 6, column 5) for
      % sigma_set@sigma_bijection[nat]
      % generated from assumption sigma_bijection.connected_domain
  IMP_sigma_bijection_TCC1: OBLIGATION
    (FORALL (x, y: nat), (z: integer): x <= z AND z <= y IMPLIES z >= 0);

  % Subtype TCC generated (at line 32, column 14) for  nvars - 1
      % expected type  T_high[nat]
  polyproduct_eval_TCC1: OBLIGATION
    FORALL (nvars: posnat):
      nvars - 1 >= 0 OR (EXISTS (j: nat): nvars - 1 <= j);

  % Subtype TCC generated (at line 55, column 44) for  polydegmono(i)
      % expected type  {i_1: int | X(i) /= 0 OR i_1 >= 0}
  multipoly_translate_denormalize_TCC1: OBLIGATION
    FORALL (Avars, Bvars, X: Vars, boundedpts: IntervalEndpoints,
            nvars: posnat, polydegmono: DegreeMono):
      (FORALL (ii: below(nvars)):
         (NOT (boundedpts(ii)`1 AND boundedpts(ii)`2)) IMPLIES X(ii) /= 0)
       AND
       bounded_points_exclusive?(nvars)(boundedpts) AND
        lt_below?(nvars)(Avars, Bvars)
       IMPLIES
       (FORALL (i: nat):
          NOT (boundedpts(i)`1 AND boundedpts(i)`2) IMPLIES
           X(i) /= 0 OR polydegmono(i) >= 0);

  % Subtype TCC generated (at line 72, column 57) for  polydegmono(i)
      % expected type  {i_1: int | NOT 1 + X(i) - Avars(i) = 0 OR i_1 >= 0}
  multipoly_translate_normalize_TCC1: OBLIGATION
    FORALL (Avars, Bvars, X: Vars, boundedpts: IntervalEndpoints,
            nvars: posnat, polydegmono: DegreeMono):
      bounded_points_exclusive?(nvars)(boundedpts) AND
       (FORALL (ii: below(nvars)):
          (boundedpts(ii)`1 IMPLIES X(ii) /= Avars(ii) - 1) AND
           (boundedpts(ii)`2 IMPLIES X(ii) /= Bvars(ii) + 1))
        AND lt_below?(nvars)(Avars, Bvars)
       IMPLIES
       (FORALL (i: nat):
          boundedpts(i)`1 AND NOT boundedpts(i)`2 IMPLIES
           NOT 1 + X(i) - Avars(i) = 0 OR polydegmono(i) >= 0);

  % Subtype TCC generated (at line 74, column 57) for  polydegmono(i)
      % expected type  {i_1: int | NOT (1 + Bvars(i) - X(i)) = 0 OR i_1 >= 0}
  multipoly_translate_normalize_TCC2: OBLIGATION
    FORALL (Avars, Bvars, X: Vars, boundedpts: IntervalEndpoints,
            nvars: posnat, polydegmono: DegreeMono):
      bounded_points_exclusive?(nvars)(boundedpts) AND
       (FORALL (ii: below(nvars)):
          (boundedpts(ii)`1 IMPLIES X(ii) /= Avars(ii) - 1) AND
           (boundedpts(ii)`2 IMPLIES X(ii) /= Bvars(ii) + 1))
        AND lt_below?(nvars)(Avars, Bvars)
       IMPLIES
       (FORALL (i: nat):
          boundedpts(i)`2 AND
           NOT boundedpts(i)`1 AND
            NOT (boundedpts(i)`1 AND NOT boundedpts(i)`2)
           IMPLIES NOT (1 + Bvars(i) - X(i)) = 0 OR polydegmono(i) >= 0);

  % Subtype TCC generated (at line 85, column 84) for  (Avars, Bvars)
      % expected type  (lt_below?(nvars))
  multipoly_translate_bounded_def_TCC1: OBLIGATION
    FORALL (Avars, Bvars, X: Vars, boundedpts, intendpts: IntervalEndpoints,
            nvars: posnat):
      bounded_points_true?(nvars)(boundedpts) AND
       boxbetween?(nvars)(Avars, Bvars, intendpts, boundedpts)(X)
       IMPLIES lt_below?(nvars)(Avars, Bvars);

  % Subtype TCC generated (at line 134, column 37) for  i - terms1
      % expected type  nat
  multipoly_add_coeff_TCC1: OBLIGATION
    FORALL (terms1: posnat, i: nat): NOT i < terms1 IMPLIES i - terms1 >= 0;

  % Subtype TCC generated (at line 164, column 16) for  d
      % expected type  T_high[nat]
  polyproduct_product_TCC1: OBLIGATION
    FORALL (polydegmono1: DegreeMono, polydegmono2: DegreeMono, v, d: nat):
      d <= mono_sum(polydegmono1, polydegmono2)(v) IMPLIES
       d >= 0 OR (EXISTS (j: nat): d <= j);

  % Subtype TCC generated (at line 166, column 81) for  d - i
      % expected type  nat
  polyproduct_product_TCC2: OBLIGATION
    FORALL (polydegmono1: DegreeMono, polydegmono2: DegreeMono, v, d: nat):
      d <= mono_sum(polydegmono1, polydegmono2)(v) IMPLIES
       (FORALL (i: nat):
          i <= d AND d - i <= polydegmono2(v) IMPLIES d - i >= 0);

  % Subtype TCC generated (at line 180, column 79) for  jj - 1
      % expected type  nat
  multipoly_product_coeff_TCC1: OBLIGATION
    FORALL (terms1: posnat, jj: nat, i: nat):
      i < jj * terms1 AND NOT jj = 0 IMPLIES jj - 1 >= 0;

  % Termination TCC generated (at line 180, column 33) for
      % multipoly_product_coeff(cf1, cf2, terms1, terms2, jj - 1)
  multipoly_product_coeff_TCC2: OBLIGATION
    FORALL (terms1: posnat, jj: nat, i: nat):
      i < jj * terms1 AND NOT jj = 0 IMPLIES jj - 1 < jj;

  % Subtype TCC generated (at line 181, column 37) for  i - jj * terms1
      % expected type  nat
  multipoly_product_coeff_TCC3: OBLIGATION
    FORALL (terms1: posnat, jj: nat, i: nat):
      i < (jj + 1) * terms1 AND NOT i < jj * terms1 AND NOT jj = 0 IMPLIES
       i - jj * terms1 >= 0;

  % Subtype TCC generated (at line 203, column 91) for  terms2 - 1
      % expected type  nat
  multipoly_product_def_TCC1: OBLIGATION
    FORALL (terms2: posnat): terms2 - 1 >= 0;

  % Subtype TCC generated (at line 216, column 121) for  sq(terms)
      % expected type  posnat
  multipoly_sq_def_TCC1: OBLIGATION
    FORALL (terms: posnat):
      rational_pred(sq(terms)) AND
       integer_pred(sq(terms)) AND sq(terms) >= 0 AND sq(terms) > 0;


body:
  poly2bernstein : THEORY
  BEGIN

    IMPORTING multi_polynomial,
              multi_bernstein

    polydegmono,
    bsdegmono   : VAR DegreeMono
    pprod       : VAR Polyproduct
    mpoly       : VAR MultiPolynomial
    nvars,terms : VAR posnat
    cf          : VAR Coeff

    bs_convert_mono(pprod,polydegmono,bsdegmono,nvars)(j:nat)(s:nat): real =
      IF s>bsdegmono(j) THEN 0 
      ELSE sigma(0,s,LAMBDA(i:nat):IF i>s OR i>polydegmono(j) THEN 0 
                                   ELSE pprod(j)(i)*(C(s,i)/C(bsdegmono(j),i)) 
                                   ENDIF) 
      ENDIF
     
    bs_convert_poly(mpoly,polydegmono,bsdegmono,nvars,terms)(r:nat): Polyproduct = 
      bs_convert_mono(mpoly(r),polydegmono,bsdegmono,nvars)

    bs_convert_poly_def: LEMMA le_below_mono?(nvars)(polydegmono,bsdegmono) IMPLIES
      multipoly_eval(mpoly,polydegmono,cf,nvars,terms) = 
      multibs_eval(bs_convert_poly(mpoly,polydegmono,bsdegmono,nvars,terms),
                   bsdegmono,cf,nvars,terms)

  END poly2bernstein

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 16, column 17) for  s
      % expected type  T_high[nat]
  bs_convert_mono_TCC1: OBLIGATION
    FORALL (bsdegmono: DegreeMono, j, s: nat):
      NOT s > bsdegmono(j) IMPLIES s >= 0 OR (EXISTS (j: nat): s <= j);

  % Subtype TCC generated (at line 17, column 55) for  i
      % expected type  {i: nat | i <= s}
  bs_convert_mono_TCC2: OBLIGATION
    FORALL (polydegmono: DegreeMono, bsdegmono: DegreeMono, j, s: nat):
      NOT s > bsdegmono(j) IMPLIES
       (FORALL (i: nat): NOT i > s AND NOT i > polydegmono(j) IMPLIES i <= s);

  % Subtype TCC generated (at line 17, column 73) for  i
      % expected type  {i: nat | i <= bsdegmono(j)}
  bs_convert_mono_TCC3: OBLIGATION
    FORALL (polydegmono: DegreeMono, bsdegmono: DegreeMono, j, s: nat):
      NOT s > bsdegmono(j) IMPLIES
       (FORALL (i: nat):
          NOT i > s AND NOT i > polydegmono(j) IMPLIES i <= bsdegmono(j));


body:
  poly_minmax : THEORY
  BEGIN 

    IMPORTING poly2bernstein,
              bernstein_minmax
   
    mpoly	      : VAR MultiPolynomial
    polydegmono : VAR DegreeMono
    nvars,terms : VAR posnat
    cf          : VAR Coeff
    boundedpts,
    intendpts   : VAR IntervalEndpoints
    depth,v     : VAR nat
    Avars,Bvars : VAR Vars
    varselect   : VAR VarSelector
    rel         : VAR [[real,real]->bool]
    localexit   : VAR [Outminmax -> bool]
    globalexit  : VAR [Outminmax->bool]
    omm         : VAR Outminmax

    % Points in a finite interval [A,B]

    box_poly_lb?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(omm): bool =
      cons?(omm`lb_var) IMPLIES
        (length(omm`lb_var) = nvars AND
         LET lb_varlam  = list2array(0)(omm`lb_var) IN
           (FORALL (iup:below(nvars)): 
  	   interval_between?(Avars(iup),Bvars(iup),intendpts(iup),boundedpts(iup))(lb_varlam(iup))) AND
             multipoly_eval(mpoly,polydegmono,cf,nvars,terms)(lb_varlam) = omm`lb_max)

    box_poly_ub?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(omm): bool =
      cons?(omm`ub_var) IMPLIES
        (length(omm`ub_var) = nvars AND
        LET ub_varlam  = list2array(0)(omm`ub_var) IN
           (FORALL (iup:below(nvars)): 
  	   interval_between?(Avars(iup),Bvars(iup),intendpts(iup),boundedpts(iup))(ub_varlam(iup))) AND
             multipoly_eval(mpoly,polydegmono,cf,nvars,terms)(ub_varlam) = omm`ub_min)

    % Points in an infinite interval

    inf_box_poly_lb?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(rel,omm): bool =
      cons?(omm`lb_var) IMPLIES
        (length(omm`lb_var) = nvars AND
         LET lb_varlam  = list2array(0)(omm`lb_var) IN
           (FORALL (iup:below(nvars)): 
  	   interval_between?(Avars(iup),Bvars(iup),intendpts(iup),boundedpts(iup))(lb_varlam(iup))) AND
             (rel(omm`lb_max,0) IFF
              rel(multipoly_eval(mpoly,polydegmono,cf,nvars,terms)(lb_varlam),0)))

    inf_box_poly_ub?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(rel,omm): bool =
      cons?(omm`ub_var) IMPLIES
        (length(omm`ub_var) = nvars AND
        LET ub_varlam  = list2array(0)(omm`ub_var) IN
           (FORALL (iup:below(nvars)): 
  	   interval_between?(Avars(iup),Bvars(iup),intendpts(iup),boundedpts(iup))(ub_varlam(iup))) AND
             (rel(omm`ub_min,0) IFF
              rel(multipoly_eval(mpoly,polydegmono,cf,nvars,terms)(ub_varlam),0)))

    % Soundness on a finite interval [A,B]

    sound_poly_fin?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(omm) : bool =
      forall_X_poly_between(omm`lb_min,omm`ub_max)(mpoly,polydegmono,cf,nvars,terms,Avars,Bvars,
  	intendpts,boundedpts) AND
      box_poly_lb?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(omm) AND
      box_poly_ub?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(omm) AND
      length_eq?(nvars)(omm)

    % Soundness on an infinite interval

    sound_poly_inf?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(omm) : bool =
      FORALL (relreal:RealOrder):
        (relreal(omm`lb_min,0) AND relreal(omm`ub_max,0) IMPLIES
        forall_X_poly_rel(relreal,0)(mpoly,polydegmono,cf,nvars,terms,Avars,Bvars,
  	intendpts,boundedpts)) AND
        inf_box_poly_lb?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)
                        (relreal,omm) AND
        inf_box_poly_ub?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)
                        (relreal,omm) AND
        length_eq?(nvars)(omm) AND
        omm`lb_min <= omm`ub_max

    sound_poly?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(omm) : bool =
      lt_below?(nvars)(Avars,Bvars)
      AND
      bounded_points_exclusive?(nvars)(boundedpts) IMPLIES
      ((bounded_points_true?(nvars)(boundedpts) AND 
          sound_poly_fin?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(omm))
      OR
      ((NOT bounded_points_true?(nvars)(boundedpts)) AND 
          sound_poly_inf?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(omm)))

    sound_poly_lb_le_ub: LEMMA
      sound_poly?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)(omm) AND
      lt_below?(nvars)(Avars,Bvars) AND
      bounded_points_exclusive?(nvars)(boundedpts) 
      IMPLIES
      lb_le_ub?(omm)

    % mpoly: A multi-variate polynomial, e.g., LAMBDA(terms:nat)(variable:nat)(deg:nat):coefficient
    % polydegmono: The degree of each variable, e.g., LAMBDA(variable:nat):degree
    % nvars: Number of variables
    % terms: Number of terms
    % cf : Coeffients per term, e.g., LAMBDA(terms:nat):coefficient
    % Avars: Lower bounds of variables, e.g., LAMBDA(variable:nat):lower_bound
    % Bvars: Upper bounds of variables, e.g., LAMBDA(variable:nat):upper_bound
    % depth: Search depth
    % localexit: A function that determines when a branch can be pruned. Unless you know what you
    %   are doing consider using eps_localexit(precision), where precision is a positive real number.
    % globalexit: A function that determines when the algorithm must terminate (for any other reason
    %   than normal termination or maximum depth). Unless you know what you are doing consider
    %   using false_globalexit.
    % intendpts: Encoding of open/close lower and upper variable bounds, e.g., 
    %   LAMBDA(variables:nat):(lb_bool,ub_bool), where true = closed and false=open.
    % boundedpts: Encoding of finite/infinite lower and upper variable bounds, e.g.,
    %   LAMBDA(variables:nat):(lb_bool,ub_bool), where true = finite and false=infinite.
    %   [IMPORTANT REMARK: Independently of the value of boundpts, Avars < Bvars]
    % varselect: A function that selects the next varible to sub-divide and which sub-interval
    %   should be considered first, e.g., left=true, right=false. Unless you know what you are
    %   doing consider using maxvarselect.

    multipolynomial_minmax(mpoly,polydegmono,nvars,terms,
                           cf,Avars,Bvars,depth,localexit,globalexit,
                           intendpts,boundedpts,varselect) : 
      (sound_poly?(mpoly,polydegmono,nvars,terms,cf,Avars,Bvars,boundedpts,intendpts)) =
      LET mpolytr = multipoly_translate(mpoly,polydegmono,nvars,boundedpts)(Avars,Bvars),
          bspoly = bs_convert_poly(mpolytr,polydegmono,polydegmono,nvars,terms),
  	infintendpts = interval_endpoints_inf_trans(Avars,Bvars,intendpts,boundedpts),
          bs_minmax = Bernstein_minmax(bspoly,polydegmono,nvars,terms,cf,depth,
                                       localexit,globalexit,infintendpts,varselect) IN
        bs_minmax WITH [ 
          lb_var := denormalize_listreal(bs_minmax`lb_var)(Avars,Bvars,boundedpts),
          ub_var := denormalize_listreal(bs_minmax`ub_var)(Avars,Bvars,boundedpts) 
        ]

    poly       : VAR Polynomial
    deg        : VAR nat
    intendpt,
    boundedpt  : VAR [bool,bool]
    var_lb,
    var_ub     : VAR real

    % poly: A one-variable polynomial, e.g., LAMBDA(deg:nat):coefficient
    % deg: The degree of the polynomial
    % var_lb: Lower bound of the variable
    % var_ub: Upper bound of the variable
    %   [IMPORTANT REMARK: Independently of the value of boundpts, var_lb < var_ub]
    % depth: Search depth, e.g., 40
    % localexit,globalexit: see multipolynomial_minmax.
    % intendpoints: Encoding of open/close lower and upper variable bound, e.g., 
    %   (lb_bool,ub_bool), where true = closed and false=open. 
    % boundedpt: Encoding of finite/infinite lower and upper variable bound, e.g.,
    %   (lb_bool,ub_bool), where true = finite and false=infinite.
    % varselect: see multipolynomial_minmax.

    polynomial_minmax(poly,deg,var_lb,var_ub,depth,localexit,globalexit,
                      intendpt,boundedpt,varselect) : Outminmax = 
      multipolynomial_minmax(LAMBDA(terms:nat):LAMBDA(variable:nat):poly,
                             LAMBDA(variable:nat):deg,1,1,LAMBDA(terms:nat):1,
                             LAMBDA(variable:nat):var_lb,LAMBDA(variable:nat):var_ub,
                             depth,localexit,globalexit,
                             LAMBDA(variable:nat):intendpt,LAMBDA(variable:nat):boundedpt,
                             varselect)

  END poly_minmax

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 130, column 6) for
      % bs_minmax
      %   WITH [lb_var
      %           := denormalize_listreal(bs_minmax`lb_var)
      %                                  (Avars, Bvars, boundedpts),
      %         ub_var
      %           := denormalize_listreal(bs_minmax`ub_var)
      %                                  (Avars, Bvars, boundedpts)]
      % expected type  (sound_poly?(mpoly, polydegmono, nvars, terms, cf,
                     %              Avars, Bvars, boundedpts, intendpts))
  multipolynomial_minmax_TCC1: OBLIGATION
    FORALL (mpoly: MultiPolynomial, polydegmono: DegreeMono, nvars: posnat,
            terms: posnat, cf: Coeff, Avars: Vars, Bvars: Vars, depth: nat,
            localexit: [Outminmax -> bool], globalexit: [Outminmax -> bool],
            intendpts: IntervalEndpoints, boundedpts: IntervalEndpoints,
            varselect: VarSelector, mpolytr: [nat -> Polyproduct]):
      mpolytr =
       multipoly_translate(mpoly, polydegmono, nvars, boundedpts)
                          (Avars, Bvars)
       IMPLIES
       (FORALL (bspoly: [nat -> Polyproduct]):
          bspoly =
           bs_convert_poly(mpolytr, polydegmono, polydegmono, nvars, terms)
           IMPLIES
           (FORALL (infintendpts: [nat -> [bool, bool]]):
              infintendpts =
               interval_endpoints_inf_trans(Avars,
                                            Bvars,
                                            intendpts,
                                            boundedpts)
               IMPLIES
               (FORALL (bs_minmax:
                          (sound?(bspoly, polydegmono, nvars, terms, cf,
                                  infintendpts))):
                  bs_minmax =
                   Bernstein_minmax(bspoly, polydegmono, nvars, terms, cf,
                                    depth, localexit, globalexit,
                                    infintendpts, varselect)
                   IMPLIES
                   sound_poly?(mpoly, polydegmono, nvars, terms, cf, Avars,
                               Bvars, boundedpts, intendpts)
                              ((bs_minmax
                                  WITH [lb_var
                                        := denormalize_listreal
                                           (bs_minmax`lb_var)
                                           (Avars, Bvars, boundedpts),
                                        ub_var
                                        := denormalize_listreal
                                           (bs_minmax`ub_var)
                                           (Avars, Bvars, boundedpts)])))));


body:
  MPoly : THEORY
  BEGIN

    IMPORTING util,
              multi_polynomial

    mpoly        : VAR MultiPolynomial
    mdeg         : VAR DegreeMono
    mcoeff       : VAR Coeff
    nvars,terms  : VAR posnat
    rel          : VAR RealOrder
    Avars,Bvars  : VAR Vars
    boundedpts,
    intendpts    : VAR IntervalEndpoints

    MPoly : TYPE = [#
      mpoly  : MultiPolynomial,
      mdeg   : DegreeMono,
      terms  : posnat,
      mcoeff : Coeff
    #]
   
    mk_mpoly(mpoly,mdeg,terms,mcoeff) : MACRO MPoly = (#
      mpoly  := mpoly,
      mdeg   := mdeg,
      terms  := terms,
      mcoeff := mcoeff
    #)

    MPolyRel : TYPE = MPoly WITH [# rel:RealOrder #]

    mk_mpoly(mpoly,mdeg,terms,mcoeff,rel) : MACRO MPolyRel = (#
      mpoly  := mpoly,
      mdeg   := mdeg,
      terms  := terms,
      mcoeff := mcoeff,
      rel    := rel
    #)

    mpolyrel2mpoly(mpr:MPolyRel): MACRO MPoly = (#
      mpoly  := mpr`mpoly,
      mdeg   := mpr`mdeg,
      terms  := mpr`terms,
      mcoeff := mpr`mcoeff
    #)

    CONVERSION mpolyrel2mpoly

    MVars : TYPE = [#
      numvars : posnat,
      vars_lb,
      vars_ub : Vars, 
      iepts,
      bdpts   : IntervalEndpoints
    #]

    mk_mvars(nvars,Avars,Bvars,intendpts,boundedpts) : MACRO MVars = (#
      numvars := nvars,
      vars_lb := Avars,
      vars_ub := Bvars,
      iepts   := intendpts,
      bdpts   := boundedpts
    #)

    mvars_between?(mv:MVars) : MACRO [Vars->bool] =
      boxbetween?(mv`numvars)(mv`vars_lb,mv`vars_ub,mv`iepts,mv`bdpts)

    mpoly_eval(mp:MPoly,nvars) : MACRO [Vars->real] =
      multipoly_eval(mp`mpoly,mp`mdeg,mp`mcoeff,nvars,mp`terms)

  END MPoly


body:
  strat_util : THEORY
  BEGIN

    IMPORTING MPoly,
              poly_minmax,
  	    Outcome

    rel          : VAR RealOrder
    nvars        : VAR posnat
    depth        : VAR nat
    varselect    : VAR VarSelector
    precision    : VAR posreal
    omm          : VAR Outminmax
    exitatdepth  : VAR bool

    multipoly_minmax(mp:MPoly,mv:MVars,depth,varselect,precision) : Outminmax = 
      multipolynomial_minmax(mp`mpoly,mp`mdeg,mv`numvars,mp`terms,mp`mcoeff,
                             mv`vars_lb,mv`vars_ub,depth,eps_localexit(precision),false_globalexit,
                             mv`iepts,boundedpts_true,varselect)

    multipoly_minmax_sound : LEMMA 
      FORALL(mp:MPoly,mv:MVars,depth,varselect,precision):
        lt_below?(mv`numvars)(mv`vars_lb,mv`vars_ub) IMPLIES
        sound_poly_fin?(mp`mpoly,mp`mdeg,mv`numvars,mp`terms,mp`mcoeff,
                        mv`vars_lb,mv`vars_ub,boundedpts_true,mv`iepts)
                       (multipoly_minmax(mp,mv,depth,varselect,precision))

    multipoly_strategy(mpr:MPolyRel,mv:MVars,depth,varselect,exitatdepth) : Outcome = 
      LET omm = multipolynomial_minmax(mpr`mpoly,mpr`mdeg,mv`numvars,mpr`terms,
                                       mpr`mcoeff,mv`vars_lb,mv`vars_ub,
                                       depth,
                                       rel_localexit(mpr`rel),rel_globalexit(mpr`rel,depth,exitatdepth),
  				     mv`iepts,mv`bdpts,varselect)
      IN 
        IF rel_localexit(mpr`rel)(omm) THEN 
          IsTrue
        ELSIF rel_counterex(mpr`rel)(omm) THEN 
          IF mpr`rel(0,1) THEN 
            Counterexample(omm`ub_var) 
          ELSE 
            Counterexample(omm`lb_var)
          ENDIF
        ELSE
          Unknown
        ENDIF

    multipoly_strategy_true : LEMMA 
      FORALL(mpr:MPolyRel,mv:MVars,depth,varselect):
        lt_below?(mv`numvars)(mv`vars_lb,mv`vars_ub) AND 
        bounded_points_exclusive?(mv`numvars)(mv`bdpts) AND
        istrue?(multipoly_strategy(mpr,mv,depth,varselect,true)) IMPLIES
          forall_X_poly_interval(mpr`mpoly,mpr`mdeg,mpr`mcoeff,mv`numvars,mpr`terms,
                                 mv`vars_lb,mv`vars_ub,mv`iepts,mv`bdpts,mpr`rel,0)

    multipoly_strategy_false : LEMMA 
      FORALL(mpr:MPolyRel,mv:MVars,depth,varselect):
        lt_below?(mv`numvars)(mv`vars_lb,mv`vars_ub) AND 
        bounded_points_exclusive?(mv`numvars)(mv`bdpts) AND
        isfalse?(multipoly_strategy(mpr,mv,depth,varselect,false)) IMPLIES
        NOT forall_X_poly_interval(mpr`mpoly,mpr`mdeg,mpr`mcoeff,mv`numvars,mpr`terms,
                                   mv`vars_lb,mv`vars_ub,mv`iepts,mv`bdpts,mpr`rel,0)

    multipoly_strategy_counterexample : LEMMA 
      FORALL(mpr:MPolyRel,mv:MVars,depth,varselect):
        LET mpstrat = multipoly_strategy(mpr,mv,depth,varselect,false) IN
          lt_below?(mv`numvars)(mv`vars_lb,mv`vars_ub) AND 
          bounded_points_exclusive?(mv`numvars)(mv`bdpts) AND
          isfalse?(mpstrat) IMPLIES
            (NOT mpr`rel(multipoly_eval(mpr`mpoly,mpr`mdeg,mpr`mcoeff,mv`numvars,mpr`terms)
                                   (list2array(0)(counterexample(mpstrat))),0)) AND 
            boxbetween?(mv`numvars)(mv`vars_lb,mv`vars_ub,mv`iepts,mv`bdpts)
                              (list2array(0)(counterexample(mpstrat)))

  END strat_util

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 39, column 25) for  omm`ub_var
      % expected type  (cons?)
  multipoly_strategy_TCC1: OBLIGATION
    FORALL (mpr: MPolyRel, mv: MVars, depth: nat, varselect: VarSelector,
            exitatdepth: bool,
            omm:
              (sound_poly?(mpr`mpoly, mpr`mdeg, mv`numvars, mpr`terms,
                           mpr`mcoeff, mv`vars_lb, mv`vars_ub, mv`bdpts,
                           mv`iepts))):
      mpr`rel(0, 1) AND
       rel_counterex(mpr`rel)(omm) AND
        NOT rel_localexit(mpr`rel)(omm) AND
         omm =
          multipolynomial_minmax(mpr`mpoly, mpr`mdeg, mv`numvars, mpr`terms,
                                 mpr`mcoeff, mv`vars_lb, mv`vars_ub, depth,
                                 rel_localexit(mpr`rel),
                                 rel_globalexit(mpr`rel, depth, exitatdepth),
                                 mv`iepts, mv`bdpts, varselect)
       IMPLIES cons?[real](omm`ub_var);

  % Subtype TCC generated (at line 41, column 25) for  omm`lb_var
      % expected type  (cons?)
  multipoly_strategy_TCC2: OBLIGATION
    FORALL (mpr: MPolyRel, mv: MVars, depth: nat, varselect: VarSelector,
            exitatdepth: bool,
            omm:
              (sound_poly?(mpr`mpoly, mpr`mdeg, mv`numvars, mpr`terms,
                           mpr`mcoeff, mv`vars_lb, mv`vars_ub, mv`bdpts,
                           mv`iepts))):
      NOT mpr`rel(0, 1) AND
       rel_counterex(mpr`rel)(omm) AND
        NOT rel_localexit(mpr`rel)(omm) AND
         omm =
          multipolynomial_minmax(mpr`mpoly, mpr`mdeg, mv`numvars, mpr`terms,
                                 mpr`mcoeff, mv`vars_lb, mv`vars_ub, depth,
                                 rel_localexit(mpr`rel),
                                 rel_globalexit(mpr`rel, depth, exitatdepth),
                                 mv`iepts, mv`bdpts, varselect)
       IMPLIES cons?[real](omm`lb_var);


body:
  boxes : THEORY
  BEGIN

    IMPORTING structures@listn[real],
              structures@for_iterate[real],
              poly2bernstein,
              strat_util,
              OutBoxes

    unpack(n:posnat,box:OutBoxes[n]): Boxes(n) =
      IF full_box?(box) THEN
        mk_boxes(n,(:unitbox(n):),null[Box(n)],null[Box(n)])
      ELSIF empty_box?(box) THEN
        mk_boxes(n,null[Box(n)],(:unitbox(n):),null[Box(n)])
      ELSIF unknown_box?(box) THEN
        mk_boxes(n,null[Box(n)],null[Box(n)],(:unitbox(n):))
      ELSE
        boxes(box)
      ENDIF

    translate_box(n:posnat,v:nat,bs:Boxes(n),f:[real->real]) : Boxes(n) =
      mk_boxes(n,
               map(LAMBDA(box:Box(n)):setnth_box(v,f,n)(box),inside(bs)),
               map(LAMBDA(box:Box(n)):setnth_box(v,f,n)(box),outside(bs)),
               map(LAMBDA(box:Box(n)):setnth_box(v,f,n)(box),unknown(bs)))

    repack(n:posnat,bs1,bs2:Boxes(n)) : OutBoxes[n] =
      Output(mk_boxes(n,
  	            append(inside(bs1),inside(bs2)),
                      append(outside(bs1),outside(bs2)),
                      append(unknown(bs1),unknown(bs2))))

    optimize_bp(nvars:posnat)(bp:MPolyRel) : MPolyRel = 
      bp WITH [mpoly := translist(polylist(bp`mpoly,bp`mdeg,nvars,bp`terms))]

    neg_mp(mp:MPolyRel) : MPolyRel =
      mp WITH [rel := LAMBDA(a,b:real):NOT mp`rel(a,b)]

    coeffs_rel_bp(nvars:posnat)(bp:MPolyRel) : bool =
      Bern_coeffs_rel(bp`mpoly,bp`mdeg,bp`mcoeff,nvars,bp`terms)(bp`rel,0)    

    split_left_bp(v:nat)(bp:MPolyRel) : MPolyRel = 
      bp WITH [mpoly := Bern_split_left_mpoly(bp`mpoly,bp`mdeg)(v)]

    split_right_bp(v:nat)(bp:MPolyRel) : MPolyRel =
      bp WITH [mpoly := Bern_split_right_mpoly(bp`mpoly,bp`mdeg)(v)]

    Boxes_strategy_rec(bps:list[MPolyRel],nvars:posnat,precision:[nat->posreal],
                       exit:bool,depth:nat,level:upto(depth)) : 
      RECURSIVE OutBoxes[nvars] =
      LET obps = map(optimize_bp(nvars),bps),
          nbps = map(neg_mp,bps) IN
      IF every(coeffs_rel_bp(nvars),obps) THEN
        FullBox
      ELSIF some(coeffs_rel_bp(nvars),nbps) THEN
        EmptyBox
      ELSIF exit OR level=depth THEN
        UnknownBox
      ELSE 
        LET v             = mod(level,nvars),
            level         = level + 1,
            exit          = precision(v) >= 1,
            precision     = precision WITH [(v) := 2*precision(v)],
            bsleft        = Boxes_strategy_rec(map(split_left_bp(v),obps),nvars,
                                               precision,exit,depth,level),
            bsright       = Boxes_strategy_rec(map(split_right_bp(v),obps),nvars,
                                               precision,exit,depth,level) IN
        IF full_box?(bsleft) AND full_box?(bsright) THEN
          FullBox
        ELSIF empty_box?(bsleft) AND empty_box?(bsright) THEN
          EmptyBox
        ELSIF unknown_box?(bsleft) AND unknown_box?(bsright) THEN
          UnknownBox
        ELSE 
          LET tleft  = translate_box(nvars,v,unpack(nvars,bsleft),LAMBDA(x:real):x/2),
              tright = translate_box(nvars,v,unpack(nvars,bsright),LAMBDA(x:real):(x+1)/2) IN
            repack(nvars,tleft,tright)
        ENDIF
      ENDIF
    MEASURE depth-level

    Boxes_strategy(bps:list[MPolyRel],nvars:posnat,depth:nat,precision:[nat->posreal]) : Boxes(nvars) =
      LET bs = Boxes_strategy_rec(bps,nvars,precision,false,depth,0) IN
        unpack(nvars,bs)

    mp_to_bp(mv:MVars)(mp:MPolyRel):MPolyRel =
      LET p  = multipoly_translate(mp`mpoly,mp`mdeg,mv`numvars,boundedpts_true)(mv`vars_lb,mv`vars_ub) IN
      mp WITH [mpoly := bs_convert_poly(p,mp`mdeg,mp`mdeg,mv`numvars,mp`terms)]

    add_real(x,y:real): real = x+y

    boxes_strategy_and(mps:list[MPolyRel],mv:MVars,depth:nat,precision:posreal) : 
      [nat,real,nat,real,nat,real,Boxes(mv`numvars)] =    
      LET bps  = map(mp_to_bp(mv),mps),
          bs   = Boxes_strategy(bps,mv`numvars,depth,LAMBDA(n:nat):precision),
  	lin  = length(bs`inside),
  	vin  = iterate_left_id(0,lin-1,LAMBDA(k:subrange(0,lin-1)):volume(mv`numvars,nth(bs`inside,k)),
                                 add_real,0),
  	lout = length(bs`outside),
  	vout = iterate_left_id(0,lout-1,LAMBDA(k:subrange(0,lout-1)):volume(mv`numvars,nth(bs`outside,k)),
                                 add_real,0),
  	lun  = length(bs`unknown),
  	vun  = iterate_left_id(0,lun-1,LAMBDA(k:subrange(0,lun-1)):volume(mv`numvars,nth(bs`unknown,k)),
                                 add_real,0),
          f    = map_box(mv`numvars,LAMBDA(l:listn(mv`numvars)):
                                          denormalize_listreal(l)
                                          (mv`vars_lb,mv`vars_ub,boundedpts_true)) IN
      (lin,vin,lout,vout,lun,vun,
       mk_boxes(mv`numvars,map(f,inside(bs)),map(f,outside(bs)),map(f,unknown(bs))))

    boxes_strategy(mp:MPolyRel,mv:MVars,depth:nat,precision:posreal) : 
      [nat,real,nat,real,nat,real,Boxes(mv`numvars)] =    
      boxes_strategy_and((:mp:),mv,depth,precision)

    boxes_strategy_or(mps:list[MPolyRel],mv:MVars,depth:nat,precision:posreal) : 
      [nat,real,nat,real,nat,real,Boxes(mv`numvars)] =    
      LET mps = map(neg_mp,mps),
          (lin,vin,lout,vout,lun,vun,bs)  = boxes_strategy_and(mps,mv,depth,precision) IN
      (lout,vout,lin,vin,lun,vun,mk_boxes(mv`numvars,outside(bs),inside(bs),unknown(bs)))	

  END boxes

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 18, column 12) for  box
      % expected type  (boxes?[n])
  unpack_TCC1: OBLIGATION
    FORALL (n: posnat, box: OutBoxes[n]):
      NOT unknown_box?(box) AND NOT empty_box?(box) AND NOT full_box?(box)
       IMPLIES boxes?[n](box);

  % Subtype TCC generated (at line 37, column 20) for
      % LAMBDA (a, b: real): NOT mp`rel(a, b)
      % expected type  RealOrder
  neg_mp_TCC1: OBLIGATION
    FORALL (mp: MPolyRel): realorder?(LAMBDA (a, b: real): NOT mp`rel(a, b));

  % Subtype TCC generated (at line 80, column 10) for  depth - level
      % expected type  naturalnumber
  Boxes_strategy_rec_TCC1: OBLIGATION
    FORALL (depth: nat, level: upto(depth)): depth - level >= 0;

  % Subtype TCC generated (at line 62, column 36) for  v
      % expected type  nat
  Boxes_strategy_rec_TCC2: OBLIGATION
    FORALL (bps: list[MPolyRel], nvars: posnat, exit: bool, depth: nat,
            level: upto(depth), obps: list[MPolyRel]):
      obps = map(optimize_bp(nvars), bps) IMPLIES
       (FORALL (nbps: list[MPolyRel]):
               NOT exit AND NOT level = depth
           AND NOT some(coeffs_rel_bp(nvars), nbps)
           AND NOT every(coeffs_rel_bp(nvars), obps)
           AND nbps = map(neg_mp, bps)
           IMPLIES
           (FORALL (v: {k | abs(k) < abs(nvars)}):
              v = mod(level, nvars) IMPLIES
               (FORALL (level1: posint): level1 = level + 1 IMPLIES v >= 0)));

  % Subtype TCC generated (at line 65, column 66) for  level
      % expected type  upto(depth)
  Boxes_strategy_rec_TCC3: OBLIGATION
    FORALL (bps: list[MPolyRel], nvars: posnat, precision: [nat -> posreal],
            exit: bool, depth: nat, level: upto(depth),
            obps: list[MPolyRel]):
      obps = map(optimize_bp(nvars), bps) IMPLIES
       (FORALL (nbps: list[MPolyRel]):
               NOT exit AND NOT level = depth
           AND NOT some(coeffs_rel_bp(nvars), nbps)
           AND NOT every(coeffs_rel_bp(nvars), obps)
           AND nbps = map(neg_mp, bps)
           IMPLIES
           (FORALL (v: {k | abs(k) < abs(nvars)}):
              v = mod(level, nvars) IMPLIES
               (FORALL (level1: posint):
                  level1 = level + 1 IMPLIES
                   (FORALL (exit1: bool):
                      exit1 = precision(v) >= 1 IMPLIES
                       (FORALL (precision1: [nat -> posreal]):
                          precision1 =
                           precision WITH [(v) := 2 * precision(v)]
                           IMPLIES level1 <= depth)))));

  % Termination TCC generated (at line 64, column 26) for
      % Boxes_strategy_rec(map(split_left_bp(v), obps), nvars, precision,
      %                    exit, depth, level)
  Boxes_strategy_rec_TCC4: OBLIGATION
    FORALL (bps: list[MPolyRel], nvars: posnat, precision: [nat -> posreal],
            exit: bool, depth: nat, level: upto(depth),
            obps: list[MPolyRel]):
      obps = map(optimize_bp(nvars), bps) IMPLIES
       (FORALL (nbps: list[MPolyRel]):
               NOT exit AND NOT level = depth
           AND NOT some(coeffs_rel_bp(nvars), nbps)
           AND NOT every(coeffs_rel_bp(nvars), obps)
           AND nbps = map(neg_mp, bps)
           IMPLIES
           (FORALL (v: {k | abs(k) < abs(nvars)}):
              v = mod(level, nvars) IMPLIES
               (FORALL (level1: posint):
                  level1 = level + 1 IMPLIES
                   (FORALL (exit1: bool):
                      exit1 = precision(v) >= 1 IMPLIES
                       (FORALL (precision1: [nat -> posreal]):
                          precision1 =
                           precision WITH [(v) := 2 * precision(v)]
                           IMPLIES depth - level1 < depth - level)))));

  % Subtype TCC generated (at line 83, column 64) for  0
      % expected type  upto(depth)
  Boxes_strategy_TCC1: OBLIGATION FORALL (depth: nat): 0 <= depth;

  % Subtype TCC generated (at line 132, column 22) for  k_1
      % expected type  below[length[Box(mv`numvars)](bs`inside)]
  boxes_strategy_and_TCC1: OBLIGATION
    FORALL (mps: list[MPolyRel], mv: MVars, depth: nat, precision: posreal,
            bps: list[MPolyRel]):
      bps = map(mp_to_bp(mv), mps) IMPLIES
       (FORALL (bs: Boxes(mv`numvars)):
          bs =
           Boxes_strategy(bps, mv`numvars, depth, LAMBDA (n: nat): precision)
           IMPLIES
           (FORALL (lin: nat):
              lin = length(bs`inside) IMPLIES
               (FORALL (k_1: subrange(0, lin - 1)):
                  k_1 >= 0 AND k_1 < length[Box(mv`numvars)](bs`inside))));

  % Subtype TCC generated (at line 132, column 22) for  k_1
      % expected type  below[length[Box(mv`numvars)](bs`outside)]
  boxes_strategy_and_TCC2: OBLIGATION
    FORALL (mps: list[MPolyRel], mv: MVars, depth: nat, precision: posreal,
            bps: list[MPolyRel]):
      bps = map(mp_to_bp(mv), mps) IMPLIES
       (FORALL (bs: Boxes(mv`numvars)):
          bs =
           Boxes_strategy(bps, mv`numvars, depth, LAMBDA (n: nat): precision)
           IMPLIES
           (FORALL (lin: nat):
              lin = length(bs`inside) IMPLIES
               (FORALL (vin: real):
                  vin =
                   for(0, lin - 1, 0,
                       LAMBDA (k_1: subrange(0, lin - 1), t: real):
                         add_real(t,
                                  volume(mv`numvars, nth(bs`inside, k_1))))
                   IMPLIES
                   (FORALL (lout: nat):
                      lout = length(bs`outside) IMPLIES
                       (FORALL (k_11: subrange(0, lout - 1)):
                          k_11 >= 0 AND
                           k_11 < length[Box(mv`numvars)](bs`outside))))));

  % Subtype TCC generated (at line 132, column 22) for  k_1
      % expected type  below[length[Box(mv`numvars)](bs`unknown)]
  boxes_strategy_and_TCC3: OBLIGATION
    FORALL (mps: list[MPolyRel], mv: MVars, depth: nat, precision: posreal,
            bps: list[MPolyRel]):
      bps = map(mp_to_bp(mv), mps) IMPLIES
       (FORALL (bs: Boxes(mv`numvars)):
          bs =
           Boxes_strategy(bps, mv`numvars, depth, LAMBDA (n: nat): precision)
           IMPLIES
           (FORALL (lin: nat):
              lin = length(bs`inside) IMPLIES
               (FORALL (vin: real):
                  vin =
                   for(0, lin - 1, 0,
                       LAMBDA (k_1: subrange(0, lin - 1), t: real):
                         add_real(t,
                                  volume(mv`numvars, nth(bs`inside, k_1))))
                   IMPLIES
                   (FORALL (lout: nat):
                      lout = length(bs`outside) IMPLIES
                       (FORALL (vout: real):
                          vout =
                           for(0, lout - 1, 0,
                               LAMBDA (k_1: subrange(0, lout - 1), t: real):
                                 add_real(t,
                                          volume
                                          (mv`numvars,
                                           nth(bs`outside, k_1))))
                           IMPLIES
                           (FORALL (lun: nat):
                              lun = length(bs`unknown) IMPLIES
                               (FORALL (k_11: subrange(0, lun - 1)):
                                  k_11 >= 0 AND
                                   k_11 <
                                    length[Box(mv`numvars)]
                                        (bs`unknown))))))));

  % Subtype TCC generated (at line 106, column 40) for
      % denormalize_listreal(l)
      %                     (mv`vars_lb, mv`vars_ub,
      %                      LAMBDA (i: nat): (TRUE, TRUE))
      % expected type  listn[real](mv`numvars)
  boxes_strategy_and_TCC4: OBLIGATION
    FORALL (mps: list[MPolyRel], mv: MVars, depth: nat, precision: posreal,
            bps: list[MPolyRel]):
      bps = map(mp_to_bp(mv), mps) IMPLIES
       (FORALL (bs: Boxes(mv`numvars)):
          bs =
           Boxes_strategy(bps, mv`numvars, depth, LAMBDA (n: nat): precision)
           IMPLIES
           (FORALL (lin: nat):
              lin = length(bs`inside) IMPLIES
               (FORALL (vin: real):
                  vin =
                   for(0, lin - 1, 0,
                       LAMBDA (k_1: subrange(0, lin - 1), t: real):
                         add_real(t,
                                  volume(mv`numvars, nth(bs`inside, k_1))))
                   IMPLIES
                   (FORALL (lout: nat):
                      lout = length(bs`outside) IMPLIES
                       (FORALL (vout: real):
                          vout =
                           for(0, lout - 1, 0,
                               LAMBDA (k_1: subrange(0, lout - 1), t: real):
                                 add_real(t,
                                          volume
                                          (mv`numvars,
                                           nth(bs`outside, k_1))))
                           IMPLIES
                           (FORALL (lun: nat):
                              lun = length(bs`unknown) IMPLIES
                               (FORALL (vun: real):
                                  vun =
                                   for(0,
                                       lun - 1,
                                       0,
                                       LAMBDA
                                       (k_1: subrange(0, lun - 1), t: real):
                                       add_real
                                       (t,
                                        volume
                                        (mv`numvars, nth(bs`unknown, k_1))))
                                   IMPLIES
                                   (FORALL (l: listn[real](mv`numvars)):
                                      length[real]
                                      (denormalize_listreal
                                       (l)
                                       (mv`vars_lb,
                                        mv`vars_ub,
                                        LAMBDA (i: nat): (TRUE, TRUE)))
                                      =
                                      mv`numvars))))))));


body:
  strategies : THEORY
  BEGIN

    IMPORTING structures@Unit,
              strat_util

    %% This constant is used by the strategies to check if all the required theories 
    %% have been imported in the current context

    BernsteinStrategy__ : Unit 

  END strategies


body:
  multi_polylist: THEORY
  BEGIN

    IMPORTING util,reals@polynomials,
              multi_polynomial,
    	    MPoly

    MonoList: TYPE = list[nat]

    n,i        : VAR nat
    xvar       : VAR [nat->real]
    x,y        : VAR real
    ml,ml1,ml2 : VAR MonoList
    c	     : VAR real

    maxnum(x,y:nat): {z:nat |
      z>=x AND z>=y AND (z=x OR z=y)} =
      IF x>=y THEN x ELSE y ENDIF

    max(ml1,ml2): RECURSIVE {ml |
      length[nat](ml)=maxnum(length[nat](ml1),length[nat](ml2)) AND
      FORALL (i:nat): i<length(ml) IMPLIES
      	   	    nth(ml,i) = IF null?(ml1) OR i>=length(ml1) THEN nth(ml2,i)
      	   	    	        ELSIF null?(ml2) OR i>=length(ml2) THEN nth(ml1,i)
  				ELSE maxnum(nth(ml1,i),nth(ml2,i)) ENDIF } =
      IF null?(ml1) THEN ml2
      ELSIF null?(ml2) THEN ml1
      ELSE cons(maxnum(car(ml1),car(ml2)),max(cdr(ml1),cdr(ml2)))
      ENDIF MEASURE length(ml1)+length(ml2)

    max_id: LEMMA max(ml,ml)=ml

    max_cdr: LEMMA null?(ml1) OR null?(ml2) OR cdr(max(ml1,ml2)) = max(cdr(ml1),cdr(ml2))

    max_sym: LEMMA max(ml1,ml2)=max(ml2,ml1)

    max_assoc: LEMMA max(ml,max(ml1,ml2))=max(max(ml,ml1),ml2)

    %%% A function that turns x(i)^n into a monomial 

    varmono(i,n): RECURSIVE MonoList =
      IF i=0 THEN (: n :) ELSE cons(0,varmono(i-1,n)) ENDIF MEASURE i

    %%% Evaluation of monomials 

    monolist_eval_rec(ml,c,i)(xvar): RECURSIVE 
      {r : real | r = c*product(0,length(ml)-1,LAMBDA (k:nat): 
           IF k<length(ml) THEN xvar(k+i)^nth(ml,k) 
  	 ELSE 1 ENDIF) } =
      IF null?(ml) THEN c
      ELSE monolist_eval_rec(cdr(ml),c*xvar(i)^car(ml),i+1)(xvar)
      ENDIF 
    MEASURE ml BY <<

    monolist_eval(ml)(xvar) : real =
      monolist_eval_rec(ml,1,0)(xvar)

    monolist_eval_prod: LEMMA 
      monolist_eval(ml)(xvar) =
        product(0,length(ml)-1,LAMBDA (i:nat): IF i<length(ml) THEN xvar(i)^nth(ml,i) 
  	                                     ELSE 1 ENDIF)

    %%% Multiplying monomials, which is really adding them

    monosum(ml1,ml2) : RECURSIVE {pml2:MonoList|
      FORALL (xvar): monolist_eval(pml2)(xvar) 
        = monolist_eval(ml1)(xvar)*monolist_eval(ml2)(xvar)} =
    IF null?(ml1) THEN ml2
    ELSIF null?(ml2) THEN ml1
    ELSE cons(car(ml1)+car(ml2),monosum(cdr(ml1),cdr(ml2)))
    ENDIF
    MEASURE length(ml1)+length(ml2)

    ;+(ml1,ml2) : MACRO MonoList = monosum(ml1,ml2)

    %%% Multivariate Polynomials

    MultiPolyList: TYPE = list[[real,MonoList]]

    mpl,mpl1,mpl2 : VAR MultiPolyList

    meval(mpl)(xvar) : RECURSIVE real =
      IF null?(mpl) THEN 0
      ELSE LET (coe,mon) = car(mpl) IN
        coe*monolist_eval(mon)(xvar) + meval(cdr(mpl))(xvar)
      ENDIF MEASURE length(mpl)

    meval_sigma: LEMMA 
      meval(mpl)(xvar) =
        sigma(0,length(mpl)-1,LAMBDA (i:nat): IF i<length(mpl) THEN
          nth(mpl,i)`1*monolist_eval(nth(mpl,i)`2)(xvar) ELSE 0 ENDIF)

    %%% Degree 

    degree(mpl): RECURSIVE {ml |
      (NOT null?(mpl)) IMPLIES
      FORALL (i:below(length(mpl))):
        ml = max(nth(mpl,i)`2,ml) AND
        length(ml)>=length(nth(mpl,i)`2)} =
      IF null?(mpl) THEN (: :)
      ELSIF null?(cdr(mpl)) THEN car(mpl)`2
      ELSE max(car(mpl)`2,degree(cdr(mpl)))
      ENDIF MEASURE length(mpl)

    degree_zero: LEMMA
      null?(degree(mpl)) IMPLIES
      FORALL (i:nat): i<length(mpl) IMPLIES
        null?(nth(mpl,i)`2)

    %%% Converting to a Polynomial

    multipoly_to_poly(mpl)(t:nat)(v:nat)(d:nat): real =
      IF t<length(mpl) AND v<length(nth(mpl,t)`2) AND d=nth(nth(mpl,t)`2,v)
        THEN 1
      ELSIF t<length(mpl) AND null?(nth(mpl,t)`2) AND d=0 THEN 1
      ELSIF t<length(mpl) AND v>=length(nth(mpl,t)`2) AND d=0 THEN 1
      ELSE 0 ENDIF

    multipoly_to_mpoly(mpl): MPoly =
      IF length(mpl)=0 THEN mk_mpoly(LAMBDA (t:nat): LAMBDA (v:nat): LAMBDA (d:nat): 0,
        		    	 	  LAMBDA (v:nat): 0, 1,LAMBDA (i:nat): 0)
      ELSE mk_mpoly(multipoly_to_poly(mpl),list2array[nat](0)(degree(mpl)),
  			length(mpl),LAMBDA (i:nat): IF i<length(mpl) THEN nth(mpl,i)`1 ELSE 0 ENDIF) ENDIF

    %%% Simplifying 

    mp_simp_rec(swiped,toswipe,ans:MultiPolyList,mono:MonoList,thiscoeff:real):
      RECURSIVE {mpl | FORALL (xvar): meval(mpl)(xvar)=meval(swiped)(xvar)+meval(toswipe)(xvar)
  		     +meval(ans)(xvar)+thiscoeff*monolist_eval(mono)(xvar)} =
      IF null?(swiped) AND null?(toswipe) AND thiscoeff/=0 THEN cons((thiscoeff,mono),ans)
      ELSIF null?(swiped) AND null?(toswipe) THEN ans
      ELSIF null?(toswipe) AND thiscoeff/=0 THEN 
            mp_simp_rec(null,cdr(swiped),cons((thiscoeff,mono),ans),car(swiped)`2,car(swiped)`1)
      ELSIF null?(toswipe) THEN 
            mp_simp_rec(null,cdr(swiped),ans,car(swiped)`2,car(swiped)`1)
      ELSIF mono = car(toswipe)`2 THEN mp_simp_rec(swiped,
      	       	 		cdr(toswipe),ans,mono,car(toswipe)`1+thiscoeff)
      ELSE mp_simp_rec(cons(car(toswipe),swiped),cdr(toswipe),ans,mono,thiscoeff)
      ENDIF MEASURE lex2(length(swiped)+length(toswipe),length(toswipe))

    mp_simp(mpl): {mulist:MultiPolyList| meval(mpl)=meval(mulist)} =
      IF null?(mpl) THEN mpl
      ELSE mp_simp_rec(null,mpl,null,car(mpl)`2,0) ENDIF

    %%% Construction of MultyPolyList

    mpconst(c): MultiPolyList = (: (c, (: :)) :)

    mpmonom(c,i,n): MultiPolyList = (: (c,varmono(i,n)) :)

    mpvar(i): MultiPolyList = mpmonom(1,i,1)

    mpvarn(i,n): MultiPolyList = mpmonom(1,i,n)

    mpsum(mpl1,mpl2): {mpl|meval(mpl)=meval(mpl1)+meval(mpl2)} = mp_simp(append(mpl1,mpl2))

    ;+(mpl1,mpl2): MACRO MultiPolyList = mpsum(mpl1,mpl2)

    mpprod_rec(mpl1,mpl2): RECURSIVE {mpl |
      FORALL (xvar): meval(mpl)(xvar)=
      	   	   meval(mpl1)(xvar)*meval(mpl2)(xvar)} =
      IF null?(mpl1) THEN (: :)
      ELSIF null?(mpl2) THEN (: :)
      ELSIF null?(cdr(mpl1)) AND null?(cdr(mpl2))
        THEN (: (car(mpl1)`1*car(mpl2)`1,
                 monosum(car(mpl1)`2,car(mpl2)`2)) :)
      ELSIF null?(cdr(mpl1)) THEN
        mpprod_rec(mpl1,cdr(mpl2))+mpprod_rec(mpl1,(: car(mpl2) :))
      ELSE mpprod_rec(cdr(mpl1),mpl2)+mpprod_rec((: car(mpl1) :),mpl2)
      ENDIF MEASURE length(mpl1)+length(mpl2)

    mpprod(mpl1,mpl2): {mpl |
      FORALL (xvar): meval(mpl)(xvar)=
      	   	   meval(mpl1)(xvar)*meval(mpl2)(xvar)} =
      mp_simp(mpprod_rec(mpl1,mpl2))

    ;*(mpl1,mpl2): MACRO MultiPolyList = mpprod(mpl1,mpl2)

    mpscal(c,mpl): RECURSIVE MultiPolyList =
      IF null?(mpl) THEN mpl
      ELSE cons((c*car(mpl)`1,car(mpl)`2),mpscal(c,cdr(mpl))) ENDIF
      MEASURE length(mpl)

    ;*(c,mpl): MACRO MultiPolyList = mpscal(c,mpl)

    mpminus(mpl1,mpl2): MultiPolyList =
      mpl1 + ((-1)*mpl2)

    ;-(mpl1,mpl2): MACRO MultiPolyList = mpminus(mpl1,mpl2)

    mppow(mpl,n): RECURSIVE MultiPolyList =
      IF n = 0 THEN (: (1,(: :)) :)
      ELSIF n = 1 THEN mpl
      ELSE mpl*mppow(mpl,n-1) ENDIF
      MEASURE n

    ;^(mpl,n): MACRO MultiPolyList = mppow(mpl,n)

    mpneg(mpl): MultiPolyList = (-1)*mpl

    ;-(mpl): MACRO MultiPolyList = mpneg(mpl)
    
    rnz: VAR nzreal

    mpdiv(mpl,rnz): MultiPolyList = (1/rnz)*mpl

    ;/(mpl,rnz): MACRO MultiPolyList = mpdiv(mpl,rnz)

    mpsq(mpl): MACRO MultiPolyList = mpl*mpl

    %%% Lemmas for rewriting

    multipolylist_eval: LEMMA
      meval(mpl)(xvar) = mpoly_eval(multipoly_to_mpoly(mpl),max(length(degree(mpl)),1))(xvar)

    multipolylist_const: LEMMA
      meval(mpconst(c))(xvar) = c

    multipolylist_monom: LEMMA 
      meval(mpmonom(c,i,n))(xvar) = c*xvar(i)^n

    multipolylist_var: LEMMA 
      meval(mpvar(i))(xvar) = xvar(i)

    multipolylist_varn: LEMMA 
      meval(mpvarn(i,n))(xvar) = xvar(i)^n

    multipolylist_sum: LEMMA
      meval(mpl1+mpl2)(xvar) = meval(mpl1)(xvar)+meval(mpl2)(xvar)

    multipolylist_prod: LEMMA
      meval(mpl1*mpl2)(xvar) = meval(mpl1)(xvar)*meval(mpl2)(xvar)
    
    multipolylist_scal: LEMMA
      meval(c*mpl)(xvar) = c*meval(mpl)(xvar)

    multipolylist_pow: LEMMA
      meval(mpl^n)(xvar) = meval(mpl)(xvar)^n

    multipolylist_neg: LEMMA
      meval(-mpl)(xvar) = -meval(mpl)(xvar)

    multipolylist_minus: LEMMA
      meval(mpl1-mpl2)(xvar) = meval(mpl1)(xvar)-meval(mpl2)(xvar)

    multipolylist_div: LEMMA
      meval(mpl/rnz)(xvar) = meval(mpl)(xvar)/rnz

    multipolylist_sq: LEMMA
      meval(mpsq(mpl))(xvar) = sq(meval(mpl)(xvar))

  END multi_polylist

addendum:
  %%% ================ Addendum: generated declarations ================

  % Subtype TCC generated (at line 18, column 17) for  x
      % expected type  {z: nat | z >= x AND z >= y AND (z = x OR z = y)}
  maxnum_TCC1: OBLIGATION
    FORALL (x, y: nat): x >= y IMPLIES x >= x AND x >= y;

  % Subtype TCC generated (at line 18, column 24) for  y
      % expected type  {z: nat | z >= x AND z >= y AND (z = x OR z = y)}
  maxnum_TCC2: OBLIGATION
    FORALL (x, y: nat): NOT x >= y IMPLIES y >= x AND y >= y;

  % Subtype TCC generated (at line 23, column 70) for  i
      % expected type  below[length[nat](ml2)]
  max_TCC1: OBLIGATION
    FORALL (ml1, ml2, ml: MonoList):
      length[nat](ml) = maxnum(length[nat](ml1), length[nat](ml2)) IMPLIES
       (FORALL (i: nat):
          (null?(ml1) OR i >= length(ml1)) AND i < length(ml) IMPLIES
           i < length[nat](ml2));

  % Subtype TCC generated (at line 24, column 70) for  i
      % expected type  below[length[nat](ml1)]
  max_TCC2: OBLIGATION
    FORALL (ml1, ml2, ml: MonoList):
      length[nat](ml) = maxnum(length[nat](ml1), length[nat](ml2)) IMPLIES
       (FORALL (i: nat):
          (null?(ml2) OR i >= length(ml2)) AND
           NOT null?(ml1) AND NOT i >= length(ml1) AND i < length(ml)
           IMPLIES i < length[nat](ml1));

  % Subtype TCC generated (at line 25, column 24) for  i
      % expected type  below[length[nat](ml1)]
  max_TCC3: OBLIGATION
    FORALL (ml1, ml2, ml: MonoList):
      length[nat](ml) = maxnum(length[nat](ml1), length[nat](ml2)) IMPLIES
       (FORALL (i: nat):
               NOT null?(ml2) AND NOT i >= length(ml2) AND NOT null?(ml1)
           AND NOT i >= length(ml1) AND i < length(ml)
           IMPLIES i < length[nat](ml1));

  % Subtype TCC generated (at line 25, column 35) for  i
      % expected type  below[length[nat](ml2)]
  max_TCC4: OBLIGATION
    FORALL (ml1, ml2, ml: MonoList):
      length[nat](ml) = maxnum(length[nat](ml1), length[nat](ml2)) IMPLIES
       (FORALL (i: nat):
               NOT null?(ml2) AND NOT i >= length(ml2) AND NOT null?(ml1)
           AND NOT i >= length(ml1) AND i < length(ml)
           IMPLIES i < length[nat](ml2));

  % Subtype TCC generated (at line 26, column 23) for  ml2
      % expected type  {ml |
                     %          length[nat](ml) =
                     %           maxnum(length[nat](ml1), length[nat](ml2))
                     %           AND
                     %           (FORALL (i: nat):
                     %              i < length(ml) IMPLIES
                     %               nth(ml, i) =
                     %                IF null?(ml1) OR i >= length(ml1)
                     %                THEN nth(ml2, i)
                     %                ELSIF null?(ml2) OR i >= length(ml2)
                     %                THEN nth(ml1, i)
                     %                ELSE maxnum(nth(ml1, i), nth(ml2, i))
                     %                ENDIF)}
  max_TCC5: OBLIGATION
    FORALL (ml1, ml2: MonoList):
      null?(ml1) IMPLIES
       length[nat](ml2) = maxnum(length[nat](ml1), length[nat](ml2)) AND
        (FORALL (i: nat):
           i < length[nat](ml2) IMPLIES
            nth[nat](ml2, i) =
             IF null?[nat](ml1) OR i >= length[nat](ml1)
               THEN nth[nat](ml2, i)
             ELSIF null?[nat](ml2) OR i >= length[nat](ml2)
               THEN nth[nat](ml1, i)
             ELSE maxnum(nth[nat](ml1, i), nth[nat](ml2, i))
             ENDIF);

  % Subtype TCC generated (at line 27, column 26) for  ml1
      % expected type  {ml |
                     %          length[nat](ml) =
                     %           maxnum(length[nat](ml1), length[nat](ml2))
                     %           AND
                     %           (FORALL (i: nat):
                     %              i < length(ml) IMPLIES
                     %               nth(ml, i) =
                     %                IF null?(ml1) OR i >= length(ml1)
                     %                THEN nth(ml2, i)
                     %                ELSIF null?(ml2) OR i >= length(ml2)
                     %                THEN nth(ml1, i)
                     %                ELSE maxnum(nth(ml1, i), nth(ml2, i))
                     %                ENDIF)}
  max_TCC6: OBLIGATION
    FORALL (ml1, ml2: MonoList):
      null?(ml2) AND NOT null?(ml1) IMPLIES
       length[nat](ml1) = maxnum(length[nat](ml1), length[nat](ml2)) AND
        (FORALL (i: nat):
           i < length[nat](ml1) IMPLIES
            nth[nat](ml1, i) =
             IF null?[nat](ml1) OR i >= length[nat](ml1)
               THEN nth[nat](ml2, i)
             ELSIF null?[nat](ml2) OR i >= length[nat](ml2)
               THEN nth[nat](ml1, i)
             ELSE maxnum(nth[nat](ml1, i), nth[nat](ml2, i))
             ENDIF);

  % Subtype TCC generated (at line 28, column 25) for  ml1
      % expected type  (cons?[nat])
  max_TCC7: OBLIGATION
    FORALL (ml1, ml2: MonoList):
      NOT null?(ml2) AND NOT null?(ml1) IMPLIES cons?[nat](ml1);

  % Subtype TCC generated (at line 28, column 34) for  ml2
      % expected type  (cons?[nat])
  max_TCC8: OBLIGATION
    FORALL (ml1, ml2: MonoList):
      NOT null?(ml2) AND NOT null?(ml1) IMPLIES cons?[nat](ml2);

  % Termination TCC generated (at line 28, column 40) for
      % max(cdr(ml1), cdr(ml2))
  max_TCC9: OBLIGATION
    FORALL (ml1, ml2: MonoList):
      NOT null?(ml2) AND NOT null?(ml1) IMPLIES
       length[nat](cdr[nat](ml1)) + length[nat](cdr[nat](ml2)) <
        length[nat](ml1) + length[nat](ml2);

  % Subtype TCC generated (at line 28, column 9) for
      % cons(maxnum(car(ml1), car(ml2)), max(cdr(ml1), cdr(ml2)))
      % expected type  {ml |
                     %          length[nat](ml) =
                     %           maxnum(length[nat](ml1), length[nat](ml2))
                     %           AND
                     %           (FORALL (i: nat):
                     %              i < length(ml) IMPLIES
                     %               nth(ml, i) =
                     %                IF null?(ml1) OR i >= length(ml1)
                     %                THEN nth(ml2, i)
                     %                ELSIF null?(ml2) OR i >= length(ml2)
                     %                THEN nth(ml1, i)
                     %                ELSE maxnum(nth(ml1, i), nth(ml2, i))
                     %                ENDIF)}
  max_TCC10: OBLIGATION
    FORALL (ml1, ml2: MonoList,
            v:
              [d1:
                 {z: [MonoList, MonoList] |
                          length(z`1) + length(z`2) <
                           length(ml1) + length(ml2)} ->
                 {ml |
                          length[nat](ml) =
                           maxnum(length[nat](d1`1), length[nat](d1`2))
                           AND
                           (FORALL (i: nat):
                              i < length(ml) IMPLIES
                               nth(ml, i) =
                                IF null?(d1`1) OR i >= length(d1`1)
                                  THEN nth(d1`2, i)
                                ELSIF null?(d1`2) OR i >= length(d1`2)
                                  THEN nth(d1`1, i)
                                ELSE maxnum(nth(d1`1, i), nth(d1`2, i))
                                ENDIF)}]):
      NOT null?(ml2) AND NOT null?(ml1) IMPLIES
       length[nat]
           (cons[nat]
                (maxnum(car[nat](ml1), car[nat](ml2)),
                 v(cdr[nat](ml1), cdr[nat](ml2))))
        = maxnum(length[nat](ml1), length[nat](ml2))
        AND
        (FORALL (i: nat):
           i <
            length[nat]
                (cons[nat]
                     (maxnum(car[nat](ml1), car[nat](ml2)),
                      v(cdr[nat](ml1), cdr[nat](ml2))))
            IMPLIES
            nth[nat]
                (cons[nat]
                     (maxnum(car[nat](ml1), car[nat](ml2)),
                      v(cdr[nat](ml1), cdr[nat](ml2))),
                 i)
             =
             IF null?[nat](ml1) OR i >= length[nat](ml1)
               THEN nth[nat](ml2, i)
             ELSIF null?[nat](ml2) OR i >= length[nat](ml2)
               THEN nth[nat](ml1, i)
             ELSE maxnum(nth[nat](ml1, i), nth[nat](ml2, i))
             ENDIF);

  % Subtype TCC generated (at line 33, column 49) for  max(ml1, ml2)
      % expected type  (cons?[nat])
  max_cdr_TCC1: OBLIGATION
    FORALL (ml1, ml2: MonoList):
      NOT null?(ml1) AND NOT null?(ml2) IMPLIES cons?[nat](max(ml1, ml2));

  % Subtype TCC generated (at line 42, column 44) for  i - 1
      % expected type  nat
  varmono_TCC1: OBLIGATION FORALL (i: nat): NOT i = 0 IMPLIES i - 1 >= 0;

  % Termination TCC generated (at line 42, column 36) for  varmono(i - 1, n)
  varmono_TCC2: OBLIGATION FORALL (i: nat): NOT i = 0 IMPLIES i - 1 < i;

  % Subtype TCC generated (at line 47, column 32) for  length(ml) - 1
      % expected type  T_high[nat]
  monolist_eval_rec_TCC1: OBLIGATION
    FORALL (ml):
      length[nat](ml) - 1 >= 0 OR (EXISTS (j: nat): length[nat](ml) - 1 <= j);

  % Subtype TCC generated (at line 48, column 40) for  nth(ml, k)
      % expected type  {i_1: int | NOT xvar(i + k) = 0 OR i_1 >= 0}
  monolist_eval_rec_TCC2: OBLIGATION
    FORALL (i, ml, xvar, k: nat):
      k < length(ml) IMPLIES NOT xvar(i + k) = 0 OR nth[nat](ml, k) >= 0;

  % Subtype TCC generated (at line 50, column 22) for  c
      % expected type  {r: real |
                     %          r =
                     %           c *
                     %            product(0,
                     %                    length(ml) - 1,
                     %                    LAMBDA
                     %                    (k: nat):
                     %                    IF k < length(ml)
                     %                    THEN xvar(i + k) ^ nth(ml, k)
                     %                    ELSE 1
                     %                    ENDIF)}
  monolist_eval_rec_TCC3: OBLIGATION
    FORALL (ml: MonoList, c: real, i: nat, xvar: [nat -> real]):
      null?(ml) IMPLIES
       c =
        c *
         product[nat]
             (0, length[nat](ml) - 1,
              LAMBDA (k: nat):
                IF k < length[nat](ml) THEN xvar(i + k) ^ nth[nat](ml, k)
                ELSE 1
                ENDIF);

  % Subtype TCC generated (at line 51, column 31) for  ml
      % expected type  (cons?[nat])
  monolist_eval_rec_TCC4: OBLIGATION
    FORALL (ml: MonoList): NOT null?(ml) IMPLIES cons?[nat](ml);

  % Subtype TCC generated (at line 51, column 45) for  car(ml)
      % expected type  {i_1: int | xvar(i) /= 0 OR i_1 >= 0}
  monolist_eval_rec_TCC5: OBLIGATION
    FORALL (ml: MonoList, i: nat, xvar: [nat -> real]):
      NOT null?(ml) IMPLIES xvar(i) /= 0 OR car[nat](ml) >= 0;

  % Termination TCC generated (at line 51, column 9) for
      % monolist_eval_rec(cdr(ml), c * xvar(i) ^ car(ml), i + 1)
  monolist_eval_rec_TCC6: OBLIGATION
    FORALL (ml: MonoList): NOT null?(ml) IMPLIES <<[nat](cdr[nat](ml), ml);

  % Subtype TCC generated (at line 51, column 9) for
      % monolist_eval_rec(cdr(ml), c * xvar(i) ^ car(ml), i + 1)(xvar)
      % expected type  {r: real |
                     %          r =
                     %           c *
                     %            product(0,
                     %                    length(ml) - 1,
                     %                    LAMBDA
                     %                    (k: nat):
                     %                    IF k < length(ml)
                     %                    THEN xvar(i + k) ^ nth(ml, k)
                     %                    ELSE 1
                     %                    ENDIF)}
  monolist_eval_rec_TCC7: OBLIGATION
    FORALL (ml: MonoList,
            v:
              [d1: {z: [MonoList, real, nat] | z`1 << ml} ->
                 [xvar: [nat -> real] ->
                    {r: real |
                             r =
                              d1`2 *
                               product(0,
                                       length(d1`1) - 1,
                                       LAMBDA
                                       (k: nat):
                                       IF k < length(d1`1)
                                       THEN xvar(k + d1`3) ^ nth(d1`1, k)
                                       ELSE 1
                                       ENDIF)}]],
            c: real, i: nat, xvar: [nat -> real]):
      NOT null?(ml) IMPLIES
       v(cdr[nat](ml), c * xvar(i) ^ car[nat](ml), i + 1)(xvar) =
        c *
         product[nat]
             (0, length[nat](ml) - 1,
              LAMBDA (k: nat):
                IF k < length[nat](ml) THEN xvar(i + k) ^ nth[nat](ml, k)
                ELSE 1
                ENDIF);

  % Subtype TCC generated (at line 60, column 74) for  nth(ml, i)
      % expected type  {i_1: int | xvar(i) /= 0 OR i_1 >= 0}
  monolist_eval_prod_TCC1: OBLIGATION
    FORALL (ml: MonoList, xvar: [nat -> real], i: nat):
      i < length(ml) IMPLIES xvar(i) /= 0 OR nth[nat](ml, i) >= 0;

  % Subtype TCC generated (at line 68, column 21) for  ml2
      % expected type  {pml2: MonoList |
                     %          FORALL (xvar):
                     %            monolist_eval(pml2)(xvar) =
                     %             monolist_eval(ml1)(xvar) *
                     %              monolist_eval(ml2)(xvar)}
  monosum_TCC1: OBLIGATION
    FORALL (ml1: MonoList, ml2: MonoList):
      null?(ml1) IMPLIES
       (FORALL (xvar):
          monolist_eval(ml2)(xvar) =
           monolist_eval(ml1)(xvar) * monolist_eval(ml2)(xvar));

  % Subtype TCC generated (at line 69, column 24) for  ml1
      % expected type  {pml2: MonoList |
                     %          FORALL (xvar):
                     %            monolist_eval(pml2)(xvar) =
                     %             monolist_eval(ml1)(xvar) *
                     %              monolist_eval(ml2)(xvar)}
  monosum_TCC2: OBLIGATION
    FORALL (ml1: MonoList, ml2: MonoList):
      null?(ml2) AND NOT null?(ml1) IMPLIES
       (FORALL (xvar):
          monolist_eval(ml1)(xvar) =
           monolist_eval(ml1)(xvar) * monolist_eval(ml2)(xvar));

  % Subtype TCC generated (at line 70, column 7) for
      % cons(car(ml1) + car(ml2), monosum(cdr(ml1), cdr(ml2)))
      % expected type  {pml2: MonoList |
                     %          FORALL (xvar):
                     %            monolist_eval(pml2)(xvar) =
                     %             monolist_eval(ml1)(xvar) *
                     %              monolist_eval(ml2)(xvar)}
  monosum_TCC3: OBLIGATION
    FORALL (ml1: MonoList, ml2: MonoList):
      NOT null?(ml2) AND NOT null?(ml1) IMPLIES
       (FORALL (xvar,
                v:
                  [d1:
                     {z: [MonoList, MonoList] |
                              length[nat](z`1) + length[nat](z`2) <
                               length[nat](ml1) + length[nat](ml2)} ->
                     {pml2: MonoList |
                              FORALL (xvar_1: [nat -> real]):
                                monolist_eval(pml2)(xvar_1) =
                                 monolist_eval(d1`1)(xvar_1) *
                                  monolist_eval(d1`2)(xvar_1)}]):
          monolist_eval(cons[nat]
                            (car[nat](ml1) + car[nat](ml2),
                             v(cdr[nat](ml1), cdr[nat](ml2))))
                       (xvar)
           = monolist_eval(ml1)(xvar) * monolist_eval(ml2)(xvar));

  % Subtype TCC generated (at line 85, column 47) for  mpl
      % expected type  (cons?[[real, MonoList]])
  meval_TCC1: OBLIGATION
    FORALL (mpl: MultiPolyList):
      NOT null?(mpl) IMPLIES
       (FORALL (coe: real, mon: MonoList):
          mon = car(mpl)`2 AND coe = car(mpl)`1 IMPLIES
           cons?[[real, MonoList]](mpl));

  % Termination TCC generated (at line 85, column 37) for  meval(cdr(mpl))
  meval_TCC2: OBLIGATION
    FORALL (mpl: MultiPolyList):
      NOT null?(mpl) IMPLIES
       (FORALL (coe: real, mon: MonoList):
          mon = car(mpl)`2 AND coe = car(mpl)`1 IMPLIES
           length[[real, MonoList]](cdr[[real, MonoList]](mpl)) <
            length[[real, MonoList]](mpl));

  % Subtype TCC generated (at line 84, column 29) for  mpl
      % expected type  (cons?[[real, MonoList]])
  meval_TCC3: OBLIGATION
    FORALL (mpl: MultiPolyList):
      NOT null?(mpl) IMPLIES cons?[[real, MonoList]](mpl);

  % Subtype TCC generated (at line 90, column 14) for  length(mpl) - 1
      % expected type  T_high[nat]
  meval_sigma_TCC1: OBLIGATION
    FORALL (mpl: MultiPolyList):
      length[[real, MonoList]](mpl) - 1 >= 0 OR
       (EXISTS (j: nat): length[[real, MonoList]](mpl) - 1 <= j);

  % Subtype TCC generated (at line 100, column 23) for  (: :)
      % expected type  {ml |
                     %          (NOT null?(mpl)) IMPLIES
                     %           (FORALL (i: below(length(mpl))):
                     %              ml = max(nth(mpl, i)`2, ml) AND
                     %               length(ml) >= length(nth(mpl, i)`2))}
  degree_TCC1: OBLIGATION
    FORALL (mpl: MultiPolyList):
      null?(mpl) IMPLIES
       (NOT null?[[real, MonoList]](mpl)) IMPLIES
        (FORALL (i: below(length[[real, MonoList]](mpl))):
           (: :) = max(nth[[real, MonoList]](mpl, i)`2, (: :)) AND
            length[nat]((: :)) >=
             length[nat](nth[[real, MonoList]](mpl, i)`2));

  % Subtype TCC generated (at line 101, column 31) for  car(mpl)`2
      % expected type  {ml |
                     %          (NOT null?(mpl)) IMPLIES
                     %           (FORALL (i: below(length(mpl))):
                     %              ml = max(nth(mpl, i)`2, ml) AND
                     %               length(ml) >= length(nth(mpl, i)`2))}
  degree_TCC2: OBLIGATION
    FORALL (mpl: MultiPolyList):
      null?(cdr(mpl)) AND NOT null?(mpl) IMPLIES
       (NOT null?[[real, MonoList]](mpl)) IMPLIES
        (FORALL (i: below(length[[real, MonoList]](mpl))):
           car[[real, MonoList]](mpl)`2 =
            max(nth[[real, MonoList]](mpl, i)`2,
                car[[real, MonoList]](mpl)`2)
            AND
            length[nat](car[[real, MonoList]](mpl)`2) >=
             length[nat](nth[[real, MonoList]](mpl, i)`2));

  % Termination TCC generated (at line 102, column 24) for  degree(cdr(mpl))
  degree_TCC3: OBLIGATION
    FORALL (mpl: MultiPolyList):
      NOT null?(cdr(mpl)) AND NOT null?(mpl) IMPLIES
       length[[real, MonoList]](cdr[[real, MonoList]](mpl)) <
        length[[real, MonoList]](mpl);

  % Subtype TCC generated (at line 102, column 9) for
      % max(car(mpl)`2, degree(cdr(mpl)))
      % expected type  {ml |
                     %          (NOT null?(mpl)) IMPLIES
                     %           (FORALL (i: below(length(mpl))):
                     %              ml = max(nth(mpl, i)`2, ml) AND
                     %               length(ml) >= length(nth(mpl, i)`2))}
  degree_TCC4: OBLIGATION
    FORALL (mpl: MultiPolyList,
            v:
              [mpl1: {z: MultiPolyList | length(z) < length(mpl)} ->
                 {ml |
                          (NOT null?(mpl1)) IMPLIES
                           (FORALL (i: below(length(mpl1))):
                              ml = max(nth(mpl1, i)`2, ml) AND
                               length(ml) >= length(nth(mpl1, i)`2))}]):
      NOT null?(cdr(mpl)) AND NOT null?(mpl) IMPLIES
       (NOT null?[[real, MonoList]](mpl)) IMPLIES
        (FORALL (i: below(length[[real, MonoList]](mpl))):
           max(car[[real, MonoList]](mpl)`2, v(cdr[[real, MonoList]](mpl))) =
            max(nth[[real, MonoList]](mpl, i)`2,
                max(car[[real, MonoList]](mpl)`2,
                    v(cdr[[real, MonoList]](mpl))))
            AND
            length[nat]
                (max(car[[real, MonoList]](mpl)`2,
                     v(cdr[[real, MonoList]](mpl))))
             >= length[nat](nth[[real, MonoList]](mpl, i)`2));

  % Subtype TCC generated (at line 123, column 3) for  length(mpl)
      % expected type  posnat
  multipoly_to_mpoly_TCC1: OBLIGATION
    FORALL (mpl: MultiPolyList):
      NOT length(mpl) = 0 IMPLIES length[[real, MonoList]](mpl) > 0;

  % Subtype TCC generated (at line 130, column 62) for
      % cons((thiscoeff, mono), ans)
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(ans)(xvar) + meval(swiped)(xvar) +
                     %              meval(toswipe)(xvar)
                     %              + thiscoeff * monolist_eval(mono)(xvar)}
  mp_simp_rec_TCC1: OBLIGATION
    FORALL (swiped, toswipe, ans: MultiPolyList, mono: MonoList,
            thiscoeff: real):
      null?(swiped) AND null?(toswipe) AND thiscoeff /= 0 IMPLIES
       (FORALL (xvar):
          meval(cons[[real, MonoList]]((thiscoeff, mono), ans))(xvar) =
           meval(ans)(xvar) + meval(swiped)(xvar) + meval(toswipe)(xvar) +
            thiscoeff * monolist_eval(mono)(xvar));

  % Subtype TCC generated (at line 131, column 48) for  ans
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(ans)(xvar) + meval(swiped)(xvar) +
                     %              meval(toswipe)(xvar)
                     %              + thiscoeff * monolist_eval(mono)(xvar)}
  mp_simp_rec_TCC2: OBLIGATION
    FORALL (swiped, toswipe, ans: MultiPolyList, mono: MonoList,
            thiscoeff: real):
      null?(swiped) AND
       null?(toswipe) AND
        NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES
       (FORALL (xvar):
          meval(ans)(xvar) =
           meval(ans)(xvar) + meval(swiped)(xvar) + meval(toswipe)(xvar) +
            thiscoeff * monolist_eval(mono)(xvar));

  % Subtype TCC generated (at line 133, column 31) for  swiped
      % expected type  (cons?[[real, MonoList]])
  mp_simp_rec_TCC3: OBLIGATION
    FORALL (swiped, toswipe: MultiPolyList, thiscoeff: real):
      null?(toswipe) AND
       thiscoeff /= 0 AND
        NOT (null?(swiped) AND null?(toswipe)) AND
         NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES cons?[[real, MonoList]](swiped);

  % Termination TCC generated (at line 133, column 10) for
      % mp_simp_rec(null, cdr(swiped), cons((thiscoeff, mono), ans),
      %             car(swiped)`2, car(swiped)`1)
  mp_simp_rec_TCC4: OBLIGATION
    FORALL (swiped, toswipe: MultiPolyList, thiscoeff: real):
      null?(toswipe) AND
       thiscoeff /= 0 AND
        NOT (null?(swiped) AND null?(toswipe)) AND
         NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES
       lex2(length[[real, MonoList]](null[[real, MonoList]]) +
             length[[real, MonoList]](cdr[[real, MonoList]](swiped)),
            length[[real, MonoList]](cdr[[real, MonoList]](swiped)))
        <
        lex2(length[[real, MonoList]](swiped) +
              length[[real, MonoList]](toswipe),
             length[[real, MonoList]](toswipe));

  % Subtype TCC generated (at line 133, column 10) for
      % mp_simp_rec(null, cdr(swiped), cons((thiscoeff, mono), ans),
      %             car(swiped)`2, car(swiped)`1)
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(ans)(xvar) + meval(swiped)(xvar) +
                     %              meval(toswipe)(xvar)
                     %              + thiscoeff * monolist_eval(mono)(xvar)}
  mp_simp_rec_TCC5: OBLIGATION
    FORALL (swiped, toswipe, ans: MultiPolyList, mono: MonoList,
            thiscoeff: real):
      null?(toswipe) AND
       thiscoeff /= 0 AND
        NOT (null?(swiped) AND null?(toswipe)) AND
         NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES
       (FORALL (xvar,
                v:
                  [d1:
                     {z:
                        [MultiPolyList, MultiPolyList, MultiPolyList,
                         MonoList, real] |
                              lex2(length[[real, MonoList]](z`1) +
                                    length[[real, MonoList]](z`2),
                                   length[[real, MonoList]](z`2))
                               <
                               lex2(length[[real, MonoList]](swiped) +
                                     length[[real, MonoList]](toswipe),
                                    length[[real, MonoList]](toswipe))} ->
                     {mpl |
                              FORALL (xvar_1: [nat -> real]):
                                meval(mpl)(xvar_1) =
                                 meval(d1`1)(xvar_1) + meval(d1`2)(xvar_1) +
                                  meval(d1`3)(xvar_1)
                                  + d1`5 * monolist_eval(d1`4)(xvar_1)}]):
          meval(v(null[[real, MonoList]], cdr[[real, MonoList]](swiped),
                  cons[[real, MonoList]]((thiscoeff, mono), ans),
                  car[[real, MonoList]](swiped)`2,
                  car[[real, MonoList]](swiped)`1))
               (xvar)
           =
           meval(ans)(xvar) + meval(swiped)(xvar) + meval(toswipe)(xvar) +
            thiscoeff * monolist_eval(mono)(xvar));

  % Subtype TCC generated (at line 135, column 31) for  swiped
      % expected type  (cons?[[real, MonoList]])
  mp_simp_rec_TCC6: OBLIGATION
    FORALL (swiped, toswipe: MultiPolyList, thiscoeff: real):
      null?(toswipe) AND
       NOT (null?(toswipe) AND thiscoeff /= 0) AND
        NOT (null?(swiped) AND null?(toswipe)) AND
         NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES cons?[[real, MonoList]](swiped);

  % Termination TCC generated (at line 135, column 10) for
      % mp_simp_rec(null, cdr(swiped), ans, car(swiped)`2, car(swiped)`1)
  mp_simp_rec_TCC7: OBLIGATION
    FORALL (swiped, toswipe: MultiPolyList, thiscoeff: real):
      null?(toswipe) AND
       NOT (null?(toswipe) AND thiscoeff /= 0) AND
        NOT (null?(swiped) AND null?(toswipe)) AND
         NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES
       lex2(length[[real, MonoList]](null[[real, MonoList]]) +
             length[[real, MonoList]](cdr[[real, MonoList]](swiped)),
            length[[real, MonoList]](cdr[[real, MonoList]](swiped)))
        <
        lex2(length[[real, MonoList]](swiped) +
              length[[real, MonoList]](toswipe),
             length[[real, MonoList]](toswipe));

  % Subtype TCC generated (at line 135, column 10) for
      % mp_simp_rec(null, cdr(swiped), ans, car(swiped)`2, car(swiped)`1)
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(ans)(xvar) + meval(swiped)(xvar) +
                     %              meval(toswipe)(xvar)
                     %              + thiscoeff * monolist_eval(mono)(xvar)}
  mp_simp_rec_TCC8: OBLIGATION
    FORALL (swiped, toswipe, ans: MultiPolyList, mono: MonoList,
            thiscoeff: real):
      null?(toswipe) AND
       NOT (null?(toswipe) AND thiscoeff /= 0) AND
        NOT (null?(swiped) AND null?(toswipe)) AND
         NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES
       (FORALL (xvar,
                v:
                  [d1:
                     {z:
                        [MultiPolyList, MultiPolyList, MultiPolyList,
                         MonoList, real] |
                              lex2(length[[real, MonoList]](z`1) +
                                    length[[real, MonoList]](z`2),
                                   length[[real, MonoList]](z`2))
                               <
                               lex2(length[[real, MonoList]](swiped) +
                                     length[[real, MonoList]](toswipe),
                                    length[[real, MonoList]](toswipe))} ->
                     {mpl |
                              FORALL (xvar_1: [nat -> real]):
                                meval(mpl)(xvar_1) =
                                 meval(d1`1)(xvar_1) + meval(d1`2)(xvar_1) +
                                  meval(d1`3)(xvar_1)
                                  + d1`5 * monolist_eval(d1`4)(xvar_1)}]):
          meval(v(null[[real, MonoList]], cdr[[real, MonoList]](swiped), ans,
                  car[[real, MonoList]](swiped)`2,
                  car[[real, MonoList]](swiped)`1))
               (xvar)
           =
           meval(ans)(xvar) + meval(swiped)(xvar) + meval(toswipe)(xvar) +
            thiscoeff * monolist_eval(mono)(xvar));

  % Subtype TCC generated (at line 136, column 21) for  toswipe
      % expected type  (cons?[[real, MonoList]])
  mp_simp_rec_TCC9: OBLIGATION
    FORALL (swiped, toswipe: MultiPolyList, thiscoeff: real):
      NOT null?(toswipe) AND
       NOT (null?(toswipe) AND thiscoeff /= 0) AND
        NOT (null?(swiped) AND null?(toswipe)) AND
         NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES cons?[[real, MonoList]](toswipe);

  % Termination TCC generated (at line 136, column 37) for
      % mp_simp_rec(swiped, cdr(toswipe), ans, mono,
      %             car(toswipe)`1 + thiscoeff)
  mp_simp_rec_TCC10: OBLIGATION
    FORALL (swiped, toswipe: MultiPolyList, mono: MonoList, thiscoeff: real):
           mono = car(toswipe)`2 AND NOT null?(toswipe)
       AND NOT (null?(toswipe) AND thiscoeff /= 0)
       AND NOT (null?(swiped) AND null?(toswipe))
       AND NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES
       lex2(length[[real, MonoList]](swiped) +
             length[[real, MonoList]](cdr[[real, MonoList]](toswipe)),
            length[[real, MonoList]](cdr[[real, MonoList]](toswipe)))
        <
        lex2(length[[real, MonoList]](swiped) +
              length[[real, MonoList]](toswipe),
             length[[real, MonoList]](toswipe));

  % Subtype TCC generated (at line 136, column 37) for
      % mp_simp_rec(swiped, cdr(toswipe), ans, mono,
      %             car(toswipe)`1 + thiscoeff)
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(ans)(xvar) + meval(swiped)(xvar) +
                     %              meval(toswipe)(xvar)
                     %              + thiscoeff * monolist_eval(mono)(xvar)}
  mp_simp_rec_TCC11: OBLIGATION
    FORALL (swiped, toswipe, ans: MultiPolyList, mono: MonoList,
            thiscoeff: real):
           mono = car(toswipe)`2 AND NOT null?(toswipe)
       AND NOT (null?(toswipe) AND thiscoeff /= 0)
       AND NOT (null?(swiped) AND null?(toswipe))
       AND NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES
       (FORALL (xvar,
                v:
                  [d1:
                     {z:
                        [MultiPolyList, MultiPolyList, MultiPolyList,
                         MonoList, real] |
                              lex2(length[[real, MonoList]](z`1) +
                                    length[[real, MonoList]](z`2),
                                   length[[real, MonoList]](z`2))
                               <
                               lex2(length[[real, MonoList]](swiped) +
                                     length[[real, MonoList]](toswipe),
                                    length[[real, MonoList]](toswipe))} ->
                     {mpl |
                              FORALL (xvar_1: [nat -> real]):
                                meval(mpl)(xvar_1) =
                                 meval(d1`1)(xvar_1) + meval(d1`2)(xvar_1) +
                                  meval(d1`3)(xvar_1)
                                  + d1`5 * monolist_eval(d1`4)(xvar_1)}]):
          meval(v(swiped, cdr[[real, MonoList]](toswipe), ans, mono,
                  car[[real, MonoList]](toswipe)`1 + thiscoeff))
               (xvar)
           =
           meval(ans)(xvar) + meval(swiped)(xvar) + meval(toswipe)(xvar) +
            thiscoeff * monolist_eval(mono)(xvar));

  % Termination TCC generated (at line 138, column 9) for
      % mp_simp_rec(cons(car(toswipe), swiped), cdr(toswipe), ans, mono,
      %             thiscoeff)
  mp_simp_rec_TCC12: OBLIGATION
    FORALL (swiped, toswipe: MultiPolyList, mono: MonoList, thiscoeff: real):
           NOT mono = car(toswipe)`2 AND NOT null?(toswipe)
       AND NOT (null?(toswipe) AND thiscoeff /= 0)
       AND NOT (null?(swiped) AND null?(toswipe))
       AND NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES
       lex2(length[[real, MonoList]]
                (cons[[real, MonoList]]
                     (car[[real, MonoList]](toswipe), swiped))
             + length[[real, MonoList]](cdr[[real, MonoList]](toswipe)),
            length[[real, MonoList]](cdr[[real, MonoList]](toswipe)))
        <
        lex2(length[[real, MonoList]](swiped) +
              length[[real, MonoList]](toswipe),
             length[[real, MonoList]](toswipe));

  % Subtype TCC generated (at line 138, column 9) for
      % mp_simp_rec(cons(car(toswipe), swiped), cdr(toswipe), ans, mono,
      %             thiscoeff)
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(ans)(xvar) + meval(swiped)(xvar) +
                     %              meval(toswipe)(xvar)
                     %              + thiscoeff * monolist_eval(mono)(xvar)}
  mp_simp_rec_TCC13: OBLIGATION
    FORALL (swiped, toswipe, ans: MultiPolyList, mono: MonoList,
            thiscoeff: real):
           NOT mono = car(toswipe)`2 AND NOT null?(toswipe)
       AND NOT (null?(toswipe) AND thiscoeff /= 0)
       AND NOT (null?(swiped) AND null?(toswipe))
       AND NOT (null?(swiped) AND null?(toswipe) AND thiscoeff /= 0)
       IMPLIES
       (FORALL (xvar,
                v:
                  [d1:
                     {z:
                        [MultiPolyList, MultiPolyList, MultiPolyList,
                         MonoList, real] |
                              lex2(length[[real, MonoList]](z`1) +
                                    length[[real, MonoList]](z`2),
                                   length[[real, MonoList]](z`2))
                               <
                               lex2(length[[real, MonoList]](swiped) +
                                     length[[real, MonoList]](toswipe),
                                    length[[real, MonoList]](toswipe))} ->
                     {mpl |
                              FORALL (xvar_1: [nat -> real]):
                                meval(mpl)(xvar_1) =
                                 meval(d1`1)(xvar_1) + meval(d1`2)(xvar_1) +
                                  meval(d1`3)(xvar_1)
                                  + d1`5 * monolist_eval(d1`4)(xvar_1)}]):
          meval(v(cons[[real, MonoList]]
                      (car[[real, MonoList]](toswipe), swiped),
                  cdr[[real, MonoList]](toswipe), ans, mono, thiscoeff))
               (xvar)
           =
           meval(ans)(xvar) + meval(swiped)(xvar) + meval(toswipe)(xvar) +
            thiscoeff * monolist_eval(mono)(xvar));

  % Subtype TCC generated (at line 143, column 9) for
      % mp_simp_rec(null, mpl, null, car(mpl)`2, 0)
      % expected type  {mulist: MultiPolyList | meval(mpl) = meval(mulist)}
  mp_simp_TCC1: OBLIGATION
    FORALL (mpl: MultiPolyList):
      NOT null?(mpl) IMPLIES
       meval(mpl) =
        meval(mp_simp_rec(null[[real, MonoList]], mpl,
                          null[[real, MonoList]],
                          car[[real, MonoList]](mpl)`2, 0));

  % Subtype TCC generated (at line 147, column 37) for  (: :)
      % expected type  (null?)
  mpconst_TCC1: OBLIGATION
    every[number]
        (LAMBDA (x: number):
                number_field_pred(x) AND real_pred(x) AND rational_pred(x)
            AND integer_pred(x) AND x >= 0)
        ((: :))
     AND null?[nat]((: :));

  % Subtype TCC generated (at line 155, column 63) for
      % mp_simp(append(mpl1, mpl2))
      % expected type  {mpl | meval(mpl) = meval(mpl1) + meval(mpl2)}
  mpsum_TCC1: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      meval(mp_simp(append[[real, MonoList]](mpl1, mpl2))) =
       (+[[nat -> real]])(meval(mpl1), meval(mpl2));

  % Subtype TCC generated (at line 162, column 24) for  (: :)
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(mpl1)(xvar) * meval(mpl2)(xvar)}
  mpprod_rec_TCC1: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      null?(mpl1) IMPLIES
       (FORALL (xvar):
          meval((: :))(xvar) = meval(mpl1)(xvar) * meval(mpl2)(xvar));

  % Subtype TCC generated (at line 163, column 27) for  (: :)
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(mpl1)(xvar) * meval(mpl2)(xvar)}
  mpprod_rec_TCC2: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      null?(mpl2) AND NOT null?(mpl1) IMPLIES
       (FORALL (xvar):
          meval((: :))(xvar) = meval(mpl1)(xvar) * meval(mpl2)(xvar));

  % Subtype TCC generated (at line 164, column 41) for  mpl2
      % expected type  (cons?[[real, MonoList]])
  mpprod_rec_TCC3: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      null?(cdr(mpl1)) AND NOT null?(mpl2) AND NOT null?(mpl1) IMPLIES
       cons?[[real, MonoList]](mpl2);

  % Subtype TCC generated (at line 166, column 51) for  (: :)
      % expected type  list[[real, MonoList]]
  mpprod_rec_TCC4: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      null?(cdr(mpl1)) AND
       null?(cdr(mpl2)) AND NOT null?(mpl2) AND NOT null?(mpl1)
       IMPLIES
       every
           [[numfield,
             {pml2: MonoList |
                      FORALL (xvar):
                        monolist_eval(pml2)(xvar) =
                         monolist_eval(car(mpl1)`2)(xvar) *
                          monolist_eval(car(mpl2)`2)(xvar)}]]
           (LAMBDA (t: [numfield, MonoList]): real_pred(t`1))((: :));

  % Subtype TCC generated (at line 165, column 11) for
      % (: (car(mpl1)`1 * car(mpl2)`1, monosum(car(mpl1)`2, car(mpl2)`2)) :)
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(mpl1)(xvar) * meval(mpl2)(xvar)}
  mpprod_rec_TCC5: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      null?(cdr(mpl1)) AND
       null?(cdr(mpl2)) AND NOT null?(mpl2) AND NOT null?(mpl1)
       IMPLIES
       (FORALL (xvar):
          meval((: (car[[real, MonoList]](mpl1)`1 *
                     car[[real, MonoList]](mpl2)`1,
                    monosum(car[[real, MonoList]](mpl1)`2,
                            car[[real, MonoList]](mpl2)`2)) :))
               (xvar)
           = meval(mpl1)(xvar) * meval(mpl2)(xvar));

  % Termination TCC generated (at line 168, column 6) for
      % mpprod_rec(mpl1, cdr(mpl2))
  mpprod_rec_TCC6: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      null?(cdr(mpl1)) AND
       NOT (null?(cdr(mpl1)) AND null?(cdr(mpl2))) AND
        NOT null?(mpl2) AND NOT null?(mpl1)
       IMPLIES
       length[[real, MonoList]](mpl1) +
        length[[real, MonoList]](cdr[[real, MonoList]](mpl2))
        < length[[real, MonoList]](mpl1) + length[[real, MonoList]](mpl2);

  % Termination TCC generated (at line 168, column 33) for
      % mpprod_rec(mpl1, (: car(mpl2) :))
  mpprod_rec_TCC7: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      null?(cdr(mpl1)) AND
       NOT (null?(cdr(mpl1)) AND null?(cdr(mpl2))) AND
        NOT null?(mpl2) AND NOT null?(mpl1)
       IMPLIES
       length[[real, MonoList]](mpl1) +
        length[[real, MonoList]]((: car[[real, MonoList]](mpl2) :))
        < length[[real, MonoList]](mpl1) + length[[real, MonoList]](mpl2);

  % Subtype TCC generated (at line 168, column 6) for
      % mpprod_rec(mpl1, cdr(mpl2)) + mpprod_rec(mpl1, (: car(mpl2) :))
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(mpl1)(xvar) * meval(mpl2)(xvar)}
  mpprod_rec_TCC8: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      null?(cdr(mpl1)) AND
       NOT (null?(cdr(mpl1)) AND null?(cdr(mpl2))) AND
        NOT null?(mpl2) AND NOT null?(mpl1)
       IMPLIES
       (FORALL (xvar,
                v:
                  [d1:
                     {z: [MultiPolyList, MultiPolyList] |
                              length[[real, MonoList]](z`1) +
                               length[[real, MonoList]](z`2)
                               <
                               length[[real, MonoList]](mpl1) +
                                length[[real, MonoList]](mpl2)} ->
                     {mpl |
                              FORALL (xvar_1: [nat -> real]):
                                meval(mpl)(xvar_1) =
                                 meval(d1`1)(xvar_1) *
                                  meval(d1`2)(xvar_1)}]):
          meval(v(mpl1, cdr[[real, MonoList]](mpl2)) +
                 v(mpl1, (: car[[real, MonoList]](mpl2) :)))
               (xvar)
           = meval(mpl1)(xvar) * meval(mpl2)(xvar));

  % Termination TCC generated (at line 169, column 9) for
      % mpprod_rec(cdr(mpl1), mpl2)
  mpprod_rec_TCC9: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      NOT null?(cdr(mpl1)) AND
       NOT (null?(cdr(mpl1)) AND null?(cdr(mpl2))) AND
        NOT null?(mpl2) AND NOT null?(mpl1)
       IMPLIES
       length[[real, MonoList]](cdr[[real, MonoList]](mpl1)) +
        length[[real, MonoList]](mpl2)
        < length[[real, MonoList]](mpl1) + length[[real, MonoList]](mpl2);

  % Termination TCC generated (at line 169, column 36) for
      % mpprod_rec((: car(mpl1) :), mpl2)
  mpprod_rec_TCC10: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      NOT null?(cdr(mpl1)) AND
       NOT (null?(cdr(mpl1)) AND null?(cdr(mpl2))) AND
        NOT null?(mpl2) AND NOT null?(mpl1)
       IMPLIES
       length[[real, MonoList]]((: car[[real, MonoList]](mpl1) :)) +
        length[[real, MonoList]](mpl2)
        < length[[real, MonoList]](mpl1) + length[[real, MonoList]](mpl2);

  % Subtype TCC generated (at line 169, column 9) for
      % mpprod_rec(cdr(mpl1), mpl2) + mpprod_rec((: car(mpl1) :), mpl2)
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(mpl1)(xvar) * meval(mpl2)(xvar)}
  mpprod_rec_TCC11: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      NOT null?(cdr(mpl1)) AND
       NOT (null?(cdr(mpl1)) AND null?(cdr(mpl2))) AND
        NOT null?(mpl2) AND NOT null?(mpl1)
       IMPLIES
       (FORALL (xvar,
                v:
                  [d1:
                     {z: [MultiPolyList, MultiPolyList] |
                              length[[real, MonoList]](z`1) +
                               length[[real, MonoList]](z`2)
                               <
                               length[[real, MonoList]](mpl1) +
                                length[[real, MonoList]](mpl2)} ->
                     {mpl |
                              FORALL (xvar_1: [nat -> real]):
                                meval(mpl)(xvar_1) =
                                 meval(d1`1)(xvar_1) *
                                  meval(d1`2)(xvar_1)}]):
          meval(v(cdr[[real, MonoList]](mpl1), mpl2) +
                 v((: car[[real, MonoList]](mpl1) :), mpl2))
               (xvar)
           = meval(mpl1)(xvar) * meval(mpl2)(xvar));

  % Subtype TCC generated (at line 175, column 4) for
      % mp_simp(mpprod_rec(mpl1, mpl2))
      % expected type  {mpl |
                     %          FORALL (xvar):
                     %            meval(mpl)(xvar) =
                     %             meval(mpl1)(xvar) * meval(mpl2)(xvar)}
  mpprod_TCC1: OBLIGATION
    FORALL (mpl1: MultiPolyList, mpl2: MultiPolyList):
      FORALL (xvar):
        meval(mp_simp(mpprod_rec(mpl1, mpl2)))(xvar) =
         meval(mpl1)(xvar) * meval(mpl2)(xvar);

  % Termination TCC generated (at line 181, column 40) for
      % mpscal(c, cdr(mpl))
  mpscal_TCC1: OBLIGATION
    FORALL (mpl: MultiPolyList):
      NOT null?(mpl) IMPLIES
       length[[real, MonoList]](cdr[[real, MonoList]](mpl)) <
        length[[real, MonoList]](mpl);

  % Subtype TCC generated (at line 192, column 33) for  (: :)
      % expected type  list[[real, (null?[nat])]]
  mppow_TCC1: OBLIGATION
    FORALL (n: nat):
      n = 0 IMPLIES
       every[[real, (null?)]]
           (LAMBDA (t: [real, list[number]]):
              every[number]
                  (LAMBDA (x: number):
                          number_field_pred(x) AND real_pred(x)
                      AND rational_pred(x) AND integer_pred(x) AND x >= 0)
                  (t`2)
               AND null?[nat](t`2))
           ((: :));

  % Subtype TCC generated (at line 214, column 58) for
      % max(length(degree(mpl)), 1)
      % expected type  posnat
  multipolylist_eval_TCC1: OBLIGATION
    FORALL (mpl: MultiPolyList): max(length[nat](degree(mpl)), 1) > 0;

  % Subtype TCC generated (at line 220, column 44) for  n
      % expected type  {i_1: int | xvar(i) /= 0 OR i_1 >= 0}
  multipolylist_monom_TCC1: OBLIGATION
    FORALL (i, n: nat, xvar: [nat -> real]): xvar(i) /= 0 OR n >= 0;

  % Subtype TCC generated (at line 238, column 42) for  n
      % expected type  {i: int | meval(mpl)(xvar) /= 0 OR i >= 0}
  multipolylist_pow_TCC1: OBLIGATION
    FORALL (mpl: MultiPolyList, n: nat, xvar: [nat -> real]):
      meval(mpl)(xvar) /= 0 OR n >= 0;


body:
  %%% ADT file generated from OutBoxes

  OutBoxes_adt[n: posnat]: THEORY
   BEGIN

    OutBoxes: TYPE

    IMPORTING boxes_def

    unknown_box?, full_box?, empty_box?, boxes?: [OutBoxes -> boolean]

    boxes: [(boxes?) -> Boxes(n)]

    UnknownBox: (unknown_box?)

    FullBox: (full_box?)

    EmptyBox: (empty_box?)

    Output: [Boxes(n) -> (boxes?)]

    OutBoxes_ord: [OutBoxes -> upto(3)]

    OutBoxes_ord_defaxiom: AXIOM
      OutBoxes_ord(UnknownBox) = 0 AND
       OutBoxes_ord(FullBox) = 1 AND
        OutBoxes_ord(EmptyBox) = 2 AND
         (FORALL (boxes: Boxes(n)): OutBoxes_ord(Output(boxes)) = 3);

    ord(x: OutBoxes): [OutBoxes -> upto(3)] =
        CASES x
          OF UnknownBox: 0, FullBox: 1, EmptyBox: 2, Output(Output1_var): 3
          ENDCASES

    OutBoxes_UnknownBox_extensionality: AXIOM
      FORALL (unknown_box?_var: (unknown_box?),
              unknown_box?_var2: (unknown_box?)):
        unknown_box?_var = unknown_box?_var2;

    OutBoxes_FullBox_extensionality: AXIOM
      FORALL (full_box?_var: (full_box?), full_box?_var2: (full_box?)):
        full_box?_var = full_box?_var2;

    OutBoxes_EmptyBox_extensionality: AXIOM
      FORALL (empty_box?_var: (empty_box?), empty_box?_var2: (empty_box?)):
        empty_box?_var = empty_box?_var2;

    OutBoxes_Output_extensionality: AXIOM
      FORALL (boxes?_var: (boxes?), boxes?_var2: (boxes?)):
        boxes(boxes?_var) = boxes(boxes?_var2) IMPLIES
         boxes?_var = boxes?_var2;

    OutBoxes_Output_eta: AXIOM
      FORALL (boxes?_var: (boxes?)): Output(boxes(boxes?_var)) = boxes?_var;

    OutBoxes_boxes_Output: AXIOM
      FORALL (Output1_var: Boxes(n)):
        boxes(Output(Output1_var)) = Output1_var;

    OutBoxes_inclusive: AXIOM
      FORALL (OutBoxes_var: OutBoxes):
        unknown_box?(OutBoxes_var) OR
         full_box?(OutBoxes_var) OR
          empty_box?(OutBoxes_var) OR boxes?(OutBoxes_var);

    OutBoxes_induction: AXIOM
      FORALL (p: [OutBoxes -> boolean]):
        (p(UnknownBox) AND
          p(FullBox) AND
           p(EmptyBox) AND
            (FORALL (Output1_var: Boxes(n)): p(Output(Output1_var))))
         IMPLIES (FORALL (OutBoxes_var: OutBoxes): p(OutBoxes_var));

    subterm(x: OutBoxes, y: OutBoxes):  boolean = x = y;

    <<:  (strict_well_founded?[OutBoxes]) = LAMBDA (x, y: OutBoxes): FALSE;

    OutBoxes_well_founded: AXIOM strict_well_founded?[OutBoxes](<<);

    reduce_nat(unknown_box?_fun: nat, full_box?_fun: nat,
               empty_box?_fun: nat, boxes?_fun: [Boxes(n) -> nat]):
          [OutBoxes -> nat] =
        LAMBDA (OutBoxes_adtvar: OutBoxes):
          LET red: [OutBoxes -> nat] =
                reduce_nat(unknown_box?_fun, full_box?_fun, empty_box?_fun,
                           boxes?_fun)
            IN
            CASES OutBoxes_adtvar
              OF UnknownBox: unknown_box?_fun,
                 FullBox: full_box?_fun,
                 EmptyBox: empty_box?_fun,
                 Output(Output1_var): boxes?_fun(Output1_var)
              ENDCASES;

    REDUCE_nat(unknown_box?_fun: [OutBoxes -> nat],
               full_box?_fun: [OutBoxes -> nat],
               empty_box?_fun: [OutBoxes -> nat],
               boxes?_fun: [[Boxes(n), OutBoxes] -> nat]):
          [OutBoxes -> nat] =
        LAMBDA (OutBoxes_adtvar: OutBoxes):
          LET red: [OutBoxes -> nat] =
                REDUCE_nat(unknown_box?_fun, full_box?_fun, empty_box?_fun,
                           boxes?_fun)
            IN
            CASES OutBoxes_adtvar
              OF UnknownBox: unknown_box?_fun(OutBoxes_adtvar),
                 FullBox: full_box?_fun(OutBoxes_adtvar),
                 EmptyBox: empty_box?_fun(OutBoxes_adtvar),
                 Output(Output1_var):
                   boxes?_fun(Output1_var, OutBoxes_adtvar)
              ENDCASES;

    reduce_ordinal(unknown_box?_fun: ordinal, full_box?_fun: ordinal,
                   empty_box?_fun: ordinal,
                   boxes?_fun: [Boxes(n) -> ordinal]):
          [OutBoxes -> ordinal] =
        LAMBDA (OutBoxes_adtvar: OutBoxes):
          LET red: [OutBoxes -> ordinal] =
                reduce_ordinal(unknown_box?_fun, full_box?_fun,
                               empty_box?_fun, boxes?_fun)
            IN
            CASES OutBoxes_adtvar
              OF UnknownBox: unknown_box?_fun,
                 FullBox: full_box?_fun,
                 EmptyBox: empty_box?_fun,
                 Output(Output1_var): boxes?_fun(Output1_var)
              ENDCASES;

    REDUCE_ordinal(unknown_box?_fun: [OutBoxes -> ordinal],
                   full_box?_fun: [OutBoxes -> ordinal],
                   empty_box?_fun: [OutBoxes -> ordinal],
                   boxes?_fun: [[Boxes(n), OutBoxes] -> ordinal]):
          [OutBoxes -> ordinal] =
        LAMBDA (OutBoxes_adtvar: OutBoxes):
          LET red: [OutBoxes -> ordinal] =
                REDUCE_ordinal(unknown_box?_fun, full_box?_fun,
                               empty_box?_fun, boxes?_fun)
            IN
            CASES OutBoxes_adtvar
              OF UnknownBox: unknown_box?_fun(OutBoxes_adtvar),
                 FullBox: full_box?_fun(OutBoxes_adtvar),
                 EmptyBox: empty_box?_fun(OutBoxes_adtvar),
                 Output(Output1_var):
                   boxes?_fun(Output1_var, OutBoxes_adtvar)
              ENDCASES;
   END OutBoxes_adt


