# TheoryBodies

body:
  metric_vect[n,m:posnat] : THEORY
  BEGIN

    IMPORTING vectors@vectors
    IMPORTING cont_vect[n,m]

    
      f(v: Vector[n])(x: real): Vector[n]

      ex(v: Vector[1]): real = v(0)

      CONVERSION ex

      d(x,y:real): real = abs(x-y)

      dn(x,y: Vector[n]): real = norm[n](x-y)


  END metric_vect


body:
  limit_vect_real[n: posnat]: THEORY
  BEGIN

    IMPORTING vectors@vect_fun_ops[n], 
              reals@abs_lems, 
              analysis@epsilon_lemmas

    f, f1, f2: VAR [ Vector -> real]
    g : VAR [Vector -> nzreal]
    epsilon, delta : VAR posreal
    a,x,v: VAR Vector
    l,l1,l2,b,c,y1,y2: VAR real

    %---------------------------------------------------
    %  Convergence of f at a point a towards a limit l
    %---------------------------------------------------

    convergence(f, a, l) : bool = 
  	FORALL epsilon : EXISTS delta : 
  	    FORALL x: %%% 0 < norm(x-a) AND
                        norm(x-a) < delta          %% AND x in dom(f)
                   IMPLIES abs(f(x) - l) < epsilon

    cv_unique    : LEMMA convergence(f, a, l1) AND convergence(f, a, l2)
                        IMPLIES l1 = l2

    cv_in_domain : LEMMA convergence(f, x, l) IMPLIES l = f(x)

    %-------------------------------------------
    %  convergence and operations on functions
    %-------------------------------------------

    cv_sum   : LEMMA convergence(f1, a, l1) AND convergence(f2, a, l2)
                       IMPLIES convergence(f1 + f2, a, l1 + l2)

    cv_neg   : LEMMA convergence(f, a, l)
                       IMPLIES convergence(- f, a, - l)

    cv_diff  : LEMMA convergence(f1, a, l1) AND convergence(f2, a, l2)
                       IMPLIES convergence(f1 - f2, a, l1 - l2)


    cv_prod  : LEMMA convergence(f1, a, l1) AND convergence(f2, a, l2)
                       IMPLIES convergence(f1 * f2, a, l1 * l2)

    cv_const : LEMMA convergence(const_fun(b), v, b)

    cv_scal  : LEMMA convergence(f, a, l)
                       IMPLIES convergence(b * f, a, b * l)


    cv_inv   : LEMMA convergence(g, a, l) AND l /= 0
                       IMPLIES convergence(1 / g, a, 1 / l)

    cv_div   : LEMMA convergence(f, a, l1) AND convergence(g, a, l2) AND l2 /= 0
                       IMPLIES convergence(f / g, a, l1 / l2)

    %-------------------------
    %  f is convergent at a    
    %-------------------------

    convergent?(f, a) : bool = EXISTS l : convergence(f, a, l)

    lim(f, (x0 : {a | convergent?(f, a)})) : real =  
          epsilon(LAMBDA l : convergence(f, x0, l))

    lim_fun_lemma   : LEMMA FORALL f, (x0 : {a | convergent?(f, a)}) :
                            convergence(f, x0, lim(f, x0))

    lim_fun_def     : LEMMA FORALL f, l, (x0 : {a | convergent?(f, a)}) :
                               lim(f, x0) = l IFF convergence(f, x0, l)

    convergence_equiv    : LEMMA convergence(f, a, l) IFF 
                                    convergent?(f, a) AND lim(f, a) = l
          
    convergent_in_domain : LEMMA convergent?(f, x) IFF convergence(f, x, f(x))
          
    lim_in_domain        : LEMMA convergent?(f, x) IMPLIES lim(f, x) = f(x)
          

    %------------------------------------------
    %  Operations preserving convergence at a 
    %------------------------------------------

    sum_fun_convergent  : LEMMA convergent?(f1, a) AND convergent?(f2, a)
                                  IMPLIES convergent?(f1 + f2, a)

    neg_fun_convergent : LEMMA convergent?(f, a) IMPLIES convergent?(- f, a)
          
    diff_fun_convergent : LEMMA convergent?(f1, a) AND convergent?(f2, a)
                                  IMPLIES convergent?(f1 - f2, a)

    prod_fun_convergent : LEMMA convergent?(f1, a) AND convergent?(f2, a)
                                  IMPLIES convergent?(f1 * f2, a)

    const_fun_convergent: LEMMA convergent?(const_fun(b), v)
          
    scal_fun_convergent : LEMMA convergent?(f, a) IMPLIES convergent?(b * f, a)
          
    inv_fun_convergent  : LEMMA convergent?(g, a) AND lim(g, a) /= 0
                                   IMPLIES convergent?(1/g, a)

    div_fun_convergent  : LEMMA convergent?(f, a) AND convergent?(g, a)
                                  AND lim(g, a) /= 0 IMPLIES convergent?(f / g, a)


    %----------------------------
    %  Same things with lim(a)
    %----------------------------

    lim_sum_fun      : LEMMA convergent?(f1, a) AND convergent?(f2, a)
                               IMPLIES lim(f1 + f2, a) = lim(f1, a) + lim(f2, a)

    lim_neg_fun : LEMMA convergent?(f, a) 
                               IMPLIES lim(- f, a) = - lim(f, a)
          
    lim_diff_fun     : LEMMA convergent?(f1, a) AND convergent?(f2, a)
                               IMPLIES lim(f1 - f2, a) = lim(f1, a) - lim(f2, a)

    lim_prod_fun     : LEMMA convergent?(f1, a) AND convergent?(f2, a)
                               IMPLIES lim(f1 * f2, a) = lim(f1, a) * lim(f2, a)

    lim_const_fun    : LEMMA lim(const_fun(b), v) = b

    lim_scal_fun     : LEMMA convergent?(f, a) 
                               IMPLIES lim(b * f, a) = b * lim(f, a)
          
    lim_inv_fun      : LEMMA convergent?(g, a) AND lim(g, a) /= 0
                               IMPLIES lim(1/g, a) = 1/lim(g, a)

    lim_div_fun      : LEMMA convergent?(f, a) AND convergent?(g, a) AND lim(g, a) /= 0
                               IMPLIES lim(f / g, a) = lim(f, a)/lim(g, a)


    %-----------------------------
    %  Limit preserve order
    %-----------------------------

    convergence_order : LEMMA
  	FORALL f1, f2, a, l1, l2 :
  		convergence(f1, a, l1)
  	    AND convergence(f2, a, l2)
  	    AND (FORALL x : f1(x) <= f2(x))
  	IMPLIES l1 <= l2
    

    %-------------------------------------------
    %  Bounds on function are bounds on limits
    %-------------------------------------------

    convergence_lower_bound : COROLLARY
  	FORALL f, b, a, l :
  		convergence(f, a, l)
  	    AND (FORALL x : b <= f(x))
  	IMPLIES b <= l

    convergence_upper_bound : COROLLARY
  	FORALL f, b, a, l :
  		convergence(f, a, l)
  	    AND (FORALL x : f(x) <= b)
  	IMPLIES l <= b


    %--------------------
    %  Bounds on limits
    %--------------------

    lim_le1 : LEMMA
          convergent?(f, a) AND (FORALL x : f(x) <= b) IMPLIES lim(f, a) <= b

    lim_ge1 : LEMMA
          convergent?(f, a) AND (FORALL x : f(x) >= b) IMPLIES lim(f, a) >= b
    
    lim_order1 : LEMMA convergent?(f1, a) AND convergent?(f2, a)
                       AND (FORALL x : f1(x) <= f2(x)) 
                           IMPLIES lim(f1, a) <= lim(f2, a)

  END limit_vect_real

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

  % Subtype TCC generated (at line 112, column 50) for  a
      % expected type  {a | convergent?(f1 + f2, a)}
  lim_sum_fun_TCC1: OBLIGATION
    FORALL (a: Vector[n], f1, f2: [Vector[n] -> real]):
      convergent?(f2, a) AND convergent?(f1, a) IMPLIES
       convergent?((+[n])(f1, f2), a);

  % Subtype TCC generated (at line 115, column 46) for  a
      % expected type  {a | convergent?(-f, a)}
  lim_neg_fun_TCC1: OBLIGATION
    FORALL (a: Vector[n], f: [Vector[n] -> real]):
      convergent?(f, a) IMPLIES convergent?(-f, a);

  % Subtype TCC generated (at line 118, column 50) for  a
      % expected type  {a | convergent?(f1 - f2, a)}
  lim_diff_fun_TCC1: OBLIGATION
    FORALL (a: Vector[n], f1, f2: [Vector[n] -> real]):
      convergent?(f2, a) AND convergent?(f1, a) IMPLIES
       convergent?((-[n])(f1, f2), a);

  % Subtype TCC generated (at line 121, column 50) for  a
      % expected type  {a | convergent?(f1 * f2, a)}
  lim_prod_fun_TCC1: OBLIGATION
    FORALL (a: Vector[n], f1, f2: [Vector[n] -> real]):
      convergent?(f2, a) AND convergent?(f1, a) IMPLIES
       convergent?(*[n](f1, f2), a);

  % Subtype TCC generated (at line 123, column 45) for  v
      % expected type  {a | convergent?(const_fun(b), a)}
  lim_const_fun_TCC1: OBLIGATION
    FORALL (b: real, v: Vector[n]): convergent?(const_fun[n](b), v);

  % Subtype TCC generated (at line 126, column 48) for  a
      % expected type  {a | convergent?(b * f, a)}
  lim_scal_fun_TCC1: OBLIGATION
    FORALL (a: Vector[n], b: real, f: [Vector[n] -> real]):
      convergent?(f, a) IMPLIES convergent?(*[n](b, f), a);

  % Subtype TCC generated (at line 129, column 46) for  a
      % expected type  {a | convergent?(1 / g, a)}
  lim_inv_fun_TCC1: OBLIGATION
    FORALL (a: Vector[n], g: [Vector[n] -> nzreal]):
      lim(g, a) /= 0 AND convergent?(g, a) IMPLIES convergent?(/[n](1, g), a);

  % Subtype TCC generated (at line 132, column 48) for  a
      % expected type  {a | convergent?(f / g, a)}
  lim_div_fun_TCC1: OBLIGATION
    FORALL (a: Vector[n], f: [Vector[n] -> real], g: [Vector[n] -> nzreal]):
      lim(g, a) /= 0 AND convergent?(g, a) AND convergent?(f, a) IMPLIES
       convergent?(/[n](f, g), a);


body:
  top : THEORY
  %----------------------------------------------------------------------------

  %
  %   Vectors Library V3.0               1/6/2009
  %
  %   Authors:  Cesar Munoz              National Institute of Aerospace
  %             Rick Butler              NASA Langley
  %             Ben Di Vito              NASA Langley
  %             Jeff Maddalon            NASA Langley
  %             Hanne Gottliebsen        National Institute of Aerospace
  %
  %
  %   Strategies: vect-distr, vect-distr-off
  %
  %----------------------------------------------------------------------------
  BEGIN
    IMPORTING 
       vectors,         	  % N-dimensional vectors and operations
       nvectors,            % N-dimensional vectors based on finite sequences 
       vectors_rew,     	  % Adds distributive rewrites
                        	  % See strategies (vect-distr) (vect-distr-off) 
       vect2D,          	  % Define 2-D Vector from N-dimensional vectors
       vect3D,          	  % Define 3-D Vector from N-dimensional vectors

       vectors_2D,       	  % 2-dimensional vectors and operations
       vectors_2D_rew,   	  % Adds distributive rewrites
                        	  % See strategies (vect-distr) (vect-distr-off) 

       vectors_3D,       	  % 3-dimensional vectors and operations
       vectors_3D_rew,   	  % Adds distributive rewrites
                        	  % See strategies (vect-distr) (vect-distr-off) 

       vectors_4D,       	  % 4-dimensional vectors and operations

       vectors_cos,     	  % Law of cosines for n-D vectors 
       vectors_2D_cos,   	  % Law of cosines for 2D vectors 
       vectors_3D_cos,   	  % Law of cosines for 3D vectors 

       distance,        	  % distance function
       distance_2D,      	  % 2D-distance function
       distance_3D,      	  % 3D-distance function

       lines,           	  % Using vectors to define lines, and motion
       lines_2D,         	  % Using vectors to define lines, and motion
       lines_3D,         	  % Using vectors to define lines, and motion

       law_cos_pos_2D,   	  % Law of cosines for 2D positions 
       law_cos_pos_3D,   	  % Law of cosines for 3D positions 

       closest_approach,    % calculate t_cpa for moving particles     
       closest_approach_2D, % calculate t_cpa for moving particles      
       closest_approach_relative_2D, % 
       closest_approach_3D, % calculate t_cpa for moving particles      

       perpendicular_2D,    % line perpendicular to a line through a point
       perpendicular_3D,    % line perpendicular to a line through a point
       intersections_2D,    % finding intersection points of lines
       basis_2D,            % orthonormal basis

       matrices,            % Theory of matrices

       vect_trig_2D,        % trigonometric properties of 2D vectors
       vect_trig_3D,        % trigonometric properties of 3D vectors

       cross_3D,            % cross-product
       linear_independence_3D,   % linear independence
       sigma_2D,            % summations over 2D vectors
       sigma_3D,            % summations over 3D vectors
       sigma_fseq_3D,
       fseqs_ops_vect3,

       vect_3D_2D,          % Projection of a 3D vector (x,y,z) into (x,y) 
       vect_4D_3D_2D,       % Projection of a 4D vector (x,y,z,t) into (x,y,z) and (x,y) 
       det_2D,              % 2D determinant
       parallel_2D,         % 2D parallel
       parallel_3D,         % 3D parallel
       angles_2D,           % angle of vector 
       trackAngles_2D,      % track angles (Air Traffic Management)
       between_2D,          % defines predicate between?(v1,v2)(u)  EXPERIMENTAL

       vect3_basis,
       ECEF,                % Earth-Centered Earth Fixed Cartesian coordinate system

       vect_fun_ops,        % defines function operators
       vect2_fun_ops,
       vect3_fun_ops,
       linear_transformations_2D, % Linear Functions [Vect2 -> Vect2] AND [Vect2 -> real]

       vectors_dot_alt,     % dot product defined using sigma[nat] rather than sigma[below(n)]

       test_vec             % test auto_rewrite+ statements

  END top


body:
  vectors[n: posnat]: THEORY
  %----------------------------------------------------------------------------
  % N-dimensional vectors of reals and operations (zero-based)
  %----------------------------------------------------------------------------
  BEGIN
     
     IMPORTING reals@sigma_below[n], reals@sqrt

     Index     : TYPE = below(n) 
     Vector    : TYPE = [Index -> real]
     VectN     : TYPE = Vector

     a,b,c     : VAR real
     nza       : VAR nzreal
     u,v,w     : VAR Vector
     i         : VAR Index

  %  ----------- Special vectors ---------------------------------------------

     zero: Vector =  LAMBDA(i):(0) 
     const_vec(a): Vector  =  LAMBDA(i):(a) ;

  %  ----------- Vector Operations -------------------------------------------

     -(v): Vector =  LAMBDA i: -v(i) ;

     +(u,v)(i): real = u(i) + v(i) ;

     -(u,v)(i): real = u(i) - v(i) ;

     *(u,v): real = sigma(0,n-1,LAMBDA i:u(i)*v(i)) ;   % Dot Product

     *(a,v): Vector = LAMBDA i:a*v(i) ;

  %  ----------- Vector Functions  -------------------------------------------

     sqv(v): nnreal = v*v

     sos(v): nnreal = sigma(0,n-1,LAMBDA i:sq(v(i)))

     sqv_rew        : LEMMA v*v = sqv(v)

     sqv_sos        : LEMMA sqv(v) = sos(v)

     norm(v): nnreal = sqrt(sqv(v))

     zero_vector?(v) : MACRO bool =
       v = zero

     nz_vector?(v)   : MACRO bool = 
       v /= zero

     normalized?(v)  : MACRO bool = 
       norm(v) = 1
   
     Nz_vector   : TYPE = (nz_vector?)
     Normalized  : TYPE = (normalized?)

     unity(i): Normalized  =  zero WITH [i := 1]

     nzu,nzv     : VAR Nz_vector

  %  ----------- Vector Component Lemmas -------------------------------------

     comp_distr_add  : LEMMA (u + v)(i) = u(i) + v(i)  

     comp_distr_sub  : LEMMA (u - v)(i) = u(i) - v(i)  

     comp_distr_scal : LEMMA (a*v)(i) = a*v(i)            

     comp_distr_neg  : LEMMA (-v)(i) = -v(i)    

     comp_zero       : LEMMA zero(i) = 0

     comps_eq        : LEMMA u = v IFF FORALL i: u(i) = v(i)    

     norm_comp_eq_0  : LEMMA norm(v) = 0 IFF FORALL i: v(i)=0
     
     norm_sqv_eq_0   : LEMMA norm(v) = 0 IFF sqv(v) = 0

     norm_eq_0       : LEMMA norm(v) = 0 IFF v = zero

     norm_zero       : LEMMA norm(zero) = 0 

     sqv_zero        : LEMMA sqv(zero) = 0

     sqv_eq_0        : LEMMA sqv(v) = 0 IFF v = zero

     v_neq_zero      : LEMMA v /= zero IFF sqv(v) > 0

     v_neq_0         : LEMMA v /= zero IFF sigma(0,n-1,(LAMBDA i: sq(v(i)))) > 0

     sq_dot_eq_0     : LEMMA v*v = 0 IFF v = zero

     nzv_comp_neq_0  : LEMMA nz_vector?(v) IFF EXISTS(i): v(i) /= 0

  %  ----------- JUDGEMENTS -------------------------------------

     nz_norm_gt_0 : JUDGEMENT 
       norm(nzu) HAS_TYPE posreal

     nz_sqv_gt_0 : JUDGEMENT 
       sqv(nzu) HAS_TYPE posreal

     normalized_nz : JUDGEMENT
       Normalized SUBTYPE_OF Nz_vector

     neg_nzv : JUDGEMENT
       -(nzu) HAS_TYPE Nz_vector

     nz_nzv : JUDGEMENT
       *(nza,nzv) HAS_TYPE Nz_vector

  %  ----------- Vector Operation Lemmas -------------------------------------

     neg_zero       : LEMMA -zero = zero

     add_zero_left  : LEMMA zero + v = v

     add_zero_right : LEMMA v + zero = v

     add_comm       : LEMMA u+v = v+u

     add_assoc      : LEMMA u+(v+w) = (u+v)+w

     add_move_left  : LEMMA u + w = v IFF w = v - u   

     add_move_right : LEMMA u + w = v IFF u = v - w

     add_move_both  : LEMMA v = u + w IFF u = v - w

     add_neg_sub    : LEMMA v + -u = v - u

     add_cancel     : LEMMA v + w - v = w
     
     add_cancel_neg : LEMMA -v + w + v = w

     add_cancel2    : LEMMA w - v + v = w
     
     add_cancel_neg2 : LEMMA w + v - v = w

     add_cancel_left: LEMMA u + v = u + w IMPLIES v = w  

     add_cancel_right: LEMMA u + v = w + v IMPLIES u = w  
   
     add_eq_zero      : LEMMA u + v = zero IFF u = -v
   
     neg_shift        : LEMMA u = -v IFF -u = v

     sub_cancel_left: LEMMA u - v = u - w IMPLIES v = w  

     sub_cancel_right: LEMMA u - v = w - v IMPLIES u = w 

     sub_zero_left  : LEMMA zero - v = -v

     sub_zero_right : LEMMA v - zero = v

     sub_eq_args    : LEMMA v - v = zero

     sub_eq_zero    : LEMMA u - v = zero IFF u = v

     sub_cancel     : LEMMA v - w - v = -w

     sub_cancel_neg : LEMMA -v - w + v = -w

     neg_add_left   : LEMMA -v + v = zero

     neg_add_right  : LEMMA v + -v = zero

     neg_distr_sub  : LEMMA -(v - u) = u - v

     neg_neg        : LEMMA --v = v

     neg_distr_add  : LEMMA -(u + v) = -u - v

     dot_neg_left        : LEMMA (-u)*w = -(u*w)

     dot_neg_right       : LEMMA u*(-w) = -(u*w)

     neg_dot_neg         : LEMMA (-u)*(-v) = u*v 

     dot_zero_left       : LEMMA zero * v = 0

     dot_zero_right      : LEMMA v * zero  = 0

     dot_comm            : LEMMA u*v = v*u

     dot_assoc           : LEMMA a*(v*w) = (a*v)*w

     dot_eq_args_ge      : LEMMA u*u >= 0

     add_comm_assoc_left : LEMMA (u+v)+w = (u+w)+v   

     add_comm_assoc_right: LEMMA u+(v+w) = v+(u+w)   

     dot_add_right  : LEMMA u*(v+w) = u*v + u*w

     dot_add_left   : LEMMA (v+w)*u = v*u + w*u

     dot_sub_right  : LEMMA u*(v-w) = u*v - u*w

     dot_sub_left   : LEMMA (v-w)*u = v*u - w*u

     dot_divby           : LEMMA nza*u = nza*v IMPLIES u = v  

     dot_scal_left       : LEMMA (a*u)*v = a*(u*v)

     dot_scal_right      : LEMMA u*(a*v) = a*(u*v)

     dot_scal_comm_assoc : LEMMA (a*u)*v = (a*v)*u   

     scal_comm_assoc     : LEMMA a*(b*u) = b*(a*u)   

     dot_scal_canon      : LEMMA (a*u)*(b*v) = (a*b)*(u*v)    

     scal_add_left       : LEMMA (a+b)*u = a*u + b*u 

     scal_sub_left       : LEMMA (a-b)*u = a*u - b*u 

     scal_add_right      : LEMMA a*(u+v) = a*u + a*v 

     scal_sub_right      : LEMMA a*(u-v) = a*u - a*v 

     scal_assoc          : LEMMA a*(b*u) = (a*b)*u 

     scal_neg            : LEMMA a*(-v) = (-a)*v  

     scal_cross          : LEMMA (1/nza) * v = w IFF v = nza*w 

     scal_div_mult_left  : LEMMA (a/nza)*u = v IFF a*u = nza*v   %%%

     scal_div_mult_right : LEMMA u = (a/nza)*v IFF nza*u = a*v   %%%

     scal_zero      : LEMMA a * zero = zero

     scal_0         : LEMMA 0 * v = zero

     scal_1         : LEMMA 1 * v = v

     scal_neg_1     : LEMMA -1 * v = -v

     scal_cancel    : LEMMA a*nzv = b*nzv IMPLIES a = b    

     scal_eq_zero   : LEMMA a*v = zero IMPLIES a = 0 OR v = zero 

     dot_ge_dist    : LEMMA w*u >= w*v IMPLIES w*(u-v) >= 0 

     dot_gt_dist    : LEMMA w*u > w*v  IMPLIES w*(u-v) > 0 

     idem_right     : LEMMA a * v = v IFF (a = 1 OR v = zero)

     sqv_neg        : LEMMA sqv(-v) = sqv(v)

     sqv_add        : LEMMA sqv(u+v) = sqv(u) + sqv(v) + 2*u*v

     sqv_scal       : LEMMA sqv(a*v) = sq(a)*sqv(v)

     sqv_sub        : LEMMA sqv(u-v) = sqv(u) + sqv(v) - 2*u*v

     sqv_sub_scal    : LEMMA sqv(u-a*v) = sqv(u) - 2*a*u*v + sq(a)*sqv(v)

     sqv_sym        : LEMMA sqv(u-v) = sqv(v-u)   

     sqrt_sqv_sq    : LEMMA sqrt(sqv(v)) * sqrt(sqv(v)) = sqv(v)

     norm_sym       : LEMMA norm(u-v) = norm(v-u)

     norm_neg       : LEMMA norm(-u)  = norm(u)

     dot_sq_norm    : LEMMA u*u = sq(norm(u))

     sq_norm        : LEMMA sq(norm(u)) = sqv(u) 

     sqrt_sqv_norm  : LEMMA sqrt(sqv(v)) = norm(v)

     norms_eq_sqv   : LEMMA norm(u) = norm(v) IFF sqv(u) = sqv(v)

     norms_eq_sos   : LEMMA norm(u) = norm(v) IFF sos(u) = sos(v)

     norm_le_sqv    : LEMMA norm(u) <= norm(v) IFF sqv(u) <= sqv(v)

     norm_lt_sqv    : LEMMA norm(u) < norm(v) IFF sqv(u) < sqv(v)

     norm_scal      : LEMMA norm(a*v) = abs(a)*norm(v) ;

     ^(nzv)         : Normalized = (1/norm(nzv))*nzv             

     normalize(nzv) : MACRO Normalized = ^(nzv)

     norm_normalize : LEMMA
       norm(^(nzv)) = 1     

     dot_normalize  : LEMMA 
       ^(nzu) * ^(nzv) = nzu*nzv/(norm(nzu)*norm(nzv))

     normalize_normalize: LEMMA ^(^(nzv)) = ^(nzv)   

     normalized_id  : LEMMA norm(nzv)*^(nzv) = nzv

     normalize_scal : LEMMA ^(nza*nzv) = sign(nza)*^(nzv)

     cauchy_schwarz : LEMMA sq(u*v) <= sqv(u)*sqv(v)

     dot_norm        : LEMMA -norm(u)*norm(v) <= u*v AND u*v <= norm(u)*norm(v)

     schwarz        : LEMMA abs(u*v) <= norm(u)*norm(v)

     schwarz_cor    : LEMMA sqrt(sqv(u+v)) <= sqrt(sqv(u)) + sqrt(sqv(v))
    
     norm_triangle   : LEMMA norm(u-w) <= norm(u-v) + norm(v-w) 

     norm_add_le     : LEMMA norm(u+v) <= norm(u) + norm(v)

     norm_sub_le     : LEMMA norm(u-v) <= norm(u) + norm(v)

     norm_sub_ge     : LEMMA norm(u-v) >= norm(u) - norm(v)

     norm_ge_comps   : LEMMA norm(u) >= abs(u(i))                 

     v0,v1,v2 : VAR Vector

     sq_norm_dist   : LEMMA 
       LET a = v1-v0, b = v1-v2, c = v2-v0 IN    
         sq(norm(c)) = sq(norm(a)) + sq(norm(b)) - 2*a*b

  % ---------- Predicates over vectors ---------

    parallel?(u,v): bool = 
      EXISTS (nzk:nzreal):  u = nzk*v

    dir_parallel?(u,v): bool = 
      EXISTS (pk:posreal):  u = pk*v 

    parallel_refl : LEMMA
      parallel?(u,u)

    parallel_symm : LEMMA
      parallel?(u,v) IFF parallel?(v,u)

    parallel_trans : LEMMA
      parallel?(u,v) AND parallel?(v,w) IMPLIES
      parallel?(u,w)

    parallel_zero : LEMMA
      parallel?(u,zero) IFF u = zero

    dir_parallel : LEMMA
      dir_parallel?(u,v) IMPLIES parallel?(u,v) 

    orthogonal?(u,v): bool =  u * v = 0 

    pythagorean : LEMMA
      orthogonal?(u,v) IMPLIES
      sqv(u+v) = sqv(u) + sqv(v)

    norm_add_ge_left : LEMMA
      orthogonal?(u,v) IMPLIES
      norm(u+v) >= norm(u) 

    norm_add_ge_right : LEMMA
      orthogonal?(u,v) IMPLIES
      norm(u+v) >= norm(v)

  % ---------- Auto Rewrites ------------------------------------

     AUTO_REWRITE+ neg_zero
     AUTO_REWRITE+ add_zero_left  
     AUTO_REWRITE+ add_zero_right 
     AUTO_REWRITE+ sub_zero_left  
     AUTO_REWRITE+ sub_zero_right 
     AUTO_REWRITE+ sub_eq_args    
     AUTO_REWRITE+ neg_add_left   
     AUTO_REWRITE+ neg_add_right  
     AUTO_REWRITE+ dot_zero_left  
     AUTO_REWRITE+ dot_zero_right 
     AUTO_REWRITE+ scal_zero      
     AUTO_REWRITE+ scal_0         
     AUTO_REWRITE+ scal_1         
     AUTO_REWRITE+ scal_neg_1         
     AUTO_REWRITE+ sqv_zero
     AUTO_REWRITE+ norm_zero
     AUTO_REWRITE+ norm_normalize
     AUTO_REWRITE+ add_neg_sub    
     AUTO_REWRITE+ neg_neg        
     AUTO_REWRITE+ dot_scal_left      
     AUTO_REWRITE+ dot_scal_right     
     AUTO_REWRITE+ dot_scal_canon                
     AUTO_REWRITE+ scal_assoc     
     AUTO_REWRITE+ sqv_neg        
     AUTO_REWRITE+ sqrt_sqv_sq
     AUTO_REWRITE+ norm_neg      
     AUTO_REWRITE+ comp_zero
     AUTO_REWRITE+ add_cancel
     AUTO_REWRITE+ sub_cancel
     AUTO_REWRITE+ add_cancel_neg
     AUTO_REWRITE+ sub_cancel_neg
     AUTO_REWRITE+ add_cancel2
     AUTO_REWRITE+ add_cancel_neg2

  %  ---- Turn off dangerous and unhelpful rewrites for auto-rewrite-theory --

     AUTO_REWRITE-    add_comm          % LEMMA u+v = v+u
     AUTO_REWRITE-    dot_comm          % LEMMA u*v = v*u
     AUTO_REWRITE-    dot_assoc         % LEMMA a*(v*w) = (a*v)*w   
     AUTO_REWRITE-    sqv_sym           % LEMMA sqv(u-v) = sqv(v-u) 
     AUTO_REWRITE-    norm_sym          % LEMMA norm(u-v) = norm(v-u)
     AUTO_REWRITE-    dot_sq_norm       % LEMMA u*u = sq(norm(u))

  END vectors

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

  % Subtype TCC generated (at line 31, column 26) for  n - 1
      % expected type  T_high[below(n)]
  times_TCC1: OBLIGATION
    n - 1 >= 0 AND n - 1 < n OR (EXISTS (j: below(n)): n - 1 <= j);

  % Subtype TCC generated (at line 37, column 20) for  v * v
      % expected type  nnreal
  sqv_TCC1: OBLIGATION FORALL (v: Vector): v * v >= 0;

  % Subtype TCC generated (at line 59, column 28) for  zero WITH [i := 1]
      % expected type  Normalized
  unity_TCC1: OBLIGATION FORALL (i: Index): norm((zero WITH [i := 1])) = 1;

  % Judgement subtype TCC generated (at line 100, column 5) for  norm(nzu)
      % expected type  posreal
  nz_norm_gt_0: OBLIGATION FORALL (nzu): norm(nzu) > 0;

  % Judgement subtype TCC generated (at line 103, column 5) for  sqv(nzu)
      % expected type  posreal
  nz_sqv_gt_0: OBLIGATION FORALL (nzu): sqv(nzu) > 0;

  % Judgement subtype TCC generated (at line 106, column 5) for  x
      % expected type  Nz_vector
  normalized_nz: OBLIGATION FORALL (x: Normalized): x /= zero;

  % Judgement subtype TCC generated (at line 109, column 5) for  -nzu
      % expected type  Nz_vector
  neg_nzv: OBLIGATION FORALL (nzu): -nzu /= zero;

  % Judgement subtype TCC generated (at line 112, column 5) for  nza * nzv
      % expected type  Nz_vector
  nz_nzv: OBLIGATION FORALL (nza, nzv): nza * nzv /= zero;

  % Subtype TCC generated (at line 286, column 33) for  (1 / norm(nzv)) * nzv
      % expected type  Normalized
  caret_TCC1: OBLIGATION
    FORALL (nzv: Nz_vector): norm((1 / norm(nzv)) * nzv) = 1;


body:
  vectors_rew[n: posnat]: THEORY

  %
  %   Additional more aggressive rewrites
  %

  BEGIN

    IMPORTING vectors[n]

    u,v,w    : VAR Vector
    a,b      : VAR real


    AUTO_REWRITE+  comp_distr_add  
    AUTO_REWRITE+  comp_distr_sub  
    AUTO_REWRITE+  comp_distr_scal  

    AUTO_REWRITE+ sqv_scal
    AUTO_REWRITE+ norm_scal

    AUTO_REWRITE+ neg_distr_sub  
    AUTO_REWRITE+ neg_distr_add  
    AUTO_REWRITE+ dot_add_right  
    AUTO_REWRITE+ dot_add_left 
    AUTO_REWRITE+ dot_sub_right  
    AUTO_REWRITE+ dot_sub_left 
    AUTO_REWRITE+ scal_add_left      
    AUTO_REWRITE+ scal_sub_left  
    AUTO_REWRITE+ scal_add_right
    AUTO_REWRITE+ scal_sub_right


  %  AUTO_REWRITE+  sqv_add        
  %  AUTO_REWRITE+  sqv_sub        

  END vectors_rew


body:
  vectors_2D_def : THEORY
  BEGIN

    Vect2 : TYPE = [#  x, y: real  #]
    
    mk_vect2(x,y:real) : MACRO Vect2 =  (# x := x, y := y #) 

    CONVERSION mk_vect2
    
  END vectors_2D_def


body:
  vectors_3D_def : THEORY
  BEGIN
    
    IMPORTING vectors_2D_def

    Vect3 : TYPE = Vect2 WITH [#  z: real  #]
    
    mk_vect3(x,y,z: real) : MACRO Vect3 =  (# x := x, y := y, z := z #) 

    CONVERSION mk_vect3
    
  END vectors_3D_def


body:
  vectors_3D: THEORY
  %----------------------------------------------------------------------------
  %
  %  The Vect3 type is a record [#  x, y, z: real  #]
  %  but the vect3 conversion allows one to write (x,y,z) 
  %
  %----------------------------------------------------------------------------
  BEGIN

     IMPORTING reals@sqrt, vectors_3D_def

     Vector   : TYPE = Vect3
     u,v,w    : VAR Vector
     a,b,c    : VAR real
     nza      : VAR nzreal 

  %  ----------- Special vectors ---------------------------------------------

     zero: Vector =  (0,0,0)
     const_vec(a): Vector = (a,a,a) ;

  %  ----------- Vector Operations -------------------------------------------

     -(v)  : Vector = ( -v`x, -v`y, -v`z ) ;

     +(u,v): Vector = ( u`x + v`x, u`y + v`y, u`z + v`z ) ;

     -(u,v): Vector = ( u`x - v`x, u`y - v`y, u`z - v`z ) ;

     *(u,v): real  =  u`x * v`x + u`y * v`y + u`z * v`z ;       % dot product

     *(a,v): Vector = ( a * v`x, a * v`y,  a * v`z ) ;

  %  ----------- Vector Functions  -------------------------------------------

     sqv(v): nnreal = v*v

     sos(v): nnreal = sq(v`x)+sq(v`y)+sq(v`z)     

     sqv_rew        : LEMMA v*v = sqv(v)

     sqv_sos        : LEMMA sqv(v) = sos(v)

     norm(v): nnreal = sqrt(sqv(v))

     zero_vector?(v): MACRO bool =
       v = zero

     nz_vector?(v): MACRO bool = 
       v /= zero

     zero_vect3? : MACRO PRED[Vector] = zero_vector?
     nz_vect3?   : MACRO PRED[Vector] = nz_vector?

     normalized?(v): MACRO bool = 
       norm(v) = 1
   
     Nz_vector   : TYPE = (nz_vector?)
     Nz_vect3    : TYPE = Nz_vector
     Normalized  : TYPE = (normalized?)

     iv: Vector = (1,0,0)
     jv: Vector = (0,1,0)
     kv: Vector = (0,0,1)

     nzu,nzv     : VAR Nz_vector

  %  ----------- Vector Component Lemmas

     basis          : LEMMA a*iv + b*jv +c*kv  = (a,b,c)

     vx_distr_add   : LEMMA (v + w)`x = v`x + w`x  
     vy_distr_add   : LEMMA (v + w)`y = v`y + w`y  
     vz_distr_add   : LEMMA (v + w)`z = v`z + w`z  

     vx_distr_sub   : LEMMA (v - w)`x = v`x - w`x  
     vy_distr_sub   : LEMMA (v - w)`y = v`y - w`y  
     vz_distr_sub   : LEMMA (v - w)`z = v`z - w`z  

     vx_scal        : LEMMA (a*v)`x = a*v`x                       
     vy_scal        : LEMMA (a*v)`y = a*v`y                       
     vz_scal        : LEMMA (a*v)`z = a*v`z                       

     vx_neg         : LEMMA (-v)`x = -v`x
     vy_neg         : LEMMA (-v)`y = -v`y
     vz_neg         : LEMMA (-v)`z = -v`z

     comp_eq_x      : LEMMA u = w IMPLIES u`x = w`x       
     comp_eq_y      : LEMMA u = w IMPLIES u`y = w`y       
     comp_eq_z      : LEMMA u = w IMPLIES u`z = w`z       

     comps_eq       : LEMMA u = w IFF u`x = w`x AND u`y = w`y AND u`z = w`z       

     comp_zero_x    : LEMMA zero`x = 0
     comp_zero_y    : LEMMA zero`y = 0
     comp_zero_z    : LEMMA zero`z = 0

     norm_xyz_eq_0  : LEMMA norm(v) = 0 IFF v`x =0 AND v`y=0 AND v`z=0
     
     norm_sqv_eq_0  : LEMMA norm(v) = 0 IFF sqv(v) = 0

     norm_eq_0      : LEMMA norm(v) = 0 IFF v = zero

     norm_zero      : LEMMA norm(zero) = 0 

     sqv_zero       : LEMMA sqv(zero) = 0

     sqv_eq_0       : LEMMA sqv(v) = 0 IFF v = zero

     v_neq_zero     : LEMMA v /= zero IFF sqv(v) > 0

     sq_dot_eq_0    : LEMMA v*v = 0 IFF v = zero

     nzv_xyz_neq_0  : LEMMA nz_vector?(v) IFF v`x /= 0 OR v`y /= 0 OR v`z /= 0 

  %  ----------- JUDGEMENTS -------------------------------------

     nz_norm_gt_0 : JUDGEMENT 
       norm(nzu) HAS_TYPE posreal

     nz_sqv_gt_0 : JUDGEMENT 
       sqv(nzu) HAS_TYPE posreal

     nz_nvz_left : JUDGEMENT
       mk_vect3(nza,b,c) HAS_TYPE Nz_vector

     nz_nvz_middle : JUDGEMENT
       mk_vect3(b,nza,c) HAS_TYPE Nz_vector

     nz_nvz_right : JUDGEMENT
       mk_vect3(b,c,nza) HAS_TYPE Nz_vector

     normalized_nz : JUDGEMENT
       Normalized SUBTYPE_OF Nz_vector

     neg_nzv : JUDGEMENT
       -(nzu) HAS_TYPE Nz_vector

     nz_nzv : JUDGEMENT
       *(nza,nzv) HAS_TYPE Nz_vector

  %  ----------- Vector Operation Lemmas -------------------------------------
     
     neg_zero         : LEMMA -zero = zero

     add_zero_left    : LEMMA zero + v = v

     add_zero_right   : LEMMA v + zero = v

     add_comm         : LEMMA u+v = v+u

     add_assoc        : LEMMA u+(v+w) = (u+v)+w

     add_move_left    : LEMMA u + w = v IFF w = v - u   

     add_move_right   : LEMMA u + w = v IFF u = v - w

     add_move_both    : LEMMA v = u + w IFF u = v - w

     add_neg_sub      : LEMMA v + -u = v - u

     add_cancel       : LEMMA v + w - v = w
     
     add_cancel_neg   : LEMMA -v + w + v = w

     add_cancel2      : LEMMA w - v + v = w
     
     add_cancel_neg2  : LEMMA w + v - v = w

     add_cancel_left  : LEMMA u + v = u + w IMPLIES v = w  

     add_cancel_right : LEMMA u + v = w + v IMPLIES u = w  

     add_eq_zero      : LEMMA u + v = zero IFF u = -v
   
     neg_shift        : LEMMA u = -v IFF -u = v


     sub_cancel_left  : LEMMA u - v = u - w IMPLIES v = w  

     sub_cancel_right : LEMMA u - v = w - v IMPLIES u = w 

     sub_zero_left    : LEMMA zero - v = -v

     sub_zero_right   : LEMMA v - zero = v

     sub_eq_args      : LEMMA v - v = zero

     sub_eq_zero      : LEMMA u - v = zero IFF u = v

     sub_cancel       : LEMMA v - w - v = -w

     sub_cancel_neg   : LEMMA -v - w + v = -w


     neg_add_left     : LEMMA -v + v = zero

     neg_add_right    : LEMMA v + -v = zero

     neg_distr_sub    : LEMMA -(v - u) = u - v

     neg_neg          : LEMMA --v = v

     neg_distr_add    : LEMMA -(u + v) = -u - v

     dot_neg_left     : LEMMA (-u)*w = -(u*w)

     dot_neg_right    : LEMMA u*(-w) = -(u*w)

     neg_dot_neg      : LEMMA (-u)*(-v) = u*v 

     dot_zero_left    : LEMMA zero * v = 0

     dot_zero_right   : LEMMA v * zero  = 0

     dot_comm         : LEMMA u*v = v*u

     dot_assoc        : LEMMA a*(v*w) = (a*v)*w

     dot_eq_args_ge   : LEMMA u*u >= 0

     add_comm_assoc_left : LEMMA (u+v)+w = (u+w)+v   

     add_comm_assoc_right: LEMMA u+(v+w) = v+(u+w)   

     dot_add_right  : LEMMA u*(v+w) = u*v + u*w

     dot_add_left : LEMMA (v+w)*u = v*u + w*u

     dot_sub_right  : LEMMA u*(v-w) = u*v - u*w

     dot_sub_left : LEMMA (v-w)*u = v*u - w*u

     dot_divby           : LEMMA nza*u = nza*v IMPLIES u = v   

     dot_scal_left       : LEMMA (a*u)*v = a*(u*v)

     dot_scal_right      : LEMMA u*(a*v) = a*(u*v)

     dot_scal_comm_assoc : LEMMA (a*u)*v = (a*v)*u  

     scal_comm_assoc     : LEMMA a*(b*u) = b*(a*u)  

     dot_scal_canon      : LEMMA (a*u)*(b*v) = (a*b)*(u*v)      

     scal_add_left  : LEMMA (a+b)*u = a*u + b*u 

     scal_sub_left  : LEMMA (a-b)*u = a*u - b*u 

     scal_add_right      : LEMMA a*(u+v) = a*u + a*v 

     scal_sub_right      : LEMMA a*(u-v) = a*u - a*v 

     scal_assoc     : LEMMA a*(b*u) = (a*b)*u  

     scal_neg       : LEMMA a*(-v) = (-a)*v  

     scal_cross     : LEMMA (1/nza) * v = w IFF v = nza*w 

     scal_zero      : LEMMA a * zero = zero

     scal_0         : LEMMA 0 * v = zero

     scal_1         : LEMMA 1 * v = v 

     scal_neg_1     : LEMMA -1 * v = -v

     scal_cancel    : LEMMA a*nzv = b*nzv IMPLIES a = b    

     scal_div_mult_left  : LEMMA (a/nza)*u = v IFF a*u = nza*v   %%%

     scal_div_mult_right : LEMMA u = (a/nza)*v IFF nza*u = a*v   %%%

     scal_eq_zero   : LEMMA c*v = zero IMPLIES c = 0 OR v = zero 

     dot_ge_dist    : LEMMA w*u >= w*v IMPLIES w*(u-v) >= 0 

     dot_gt_dist    : LEMMA w*u > w*v  IMPLIES w*(u-v) > 0 

     idem_right     : LEMMA a * v = v IFF (a = 1 OR v = zero)

     sqv_neg        : LEMMA sqv(-v) = sqv(v)

     sqv_add        : LEMMA sqv(u+v) = sqv(u) + sqv(v) + 2*u*v

     sqv_scal       : LEMMA sqv(a*v) = sq(a)*sqv(v)

     sqv_sub        : LEMMA sqv(u-v) = sqv(u) + sqv(v) - 2*u*v

     sqv_sub_scal    : LEMMA sqv(u-a*v) = sqv(u) - 2*a*u*v + sq(a)*sqv(v) 

     sqv_sym        : LEMMA sqv(u-v) = sqv(v-u)   

     sqrt_sqv_sq    : LEMMA sqrt(sqv(v)) * sqrt(sqv(v)) = sqv(v)

     norm_sym       : LEMMA norm(u-v) = norm(v-u)

     norm_neg       : LEMMA norm(-u)  = norm(u)

     dot_sq_norm    : LEMMA u*u = sq(norm(u))

     sq_norm        : LEMMA sq(norm(u)) = sqv(u)

     sqrt_sqv_norm  : LEMMA sqrt(sqv(v)) = norm(v)

     norms_eq_sqv   : LEMMA norm(u) = norm(v) IFF sqv(u) = sqv(v)

     norms_eq_sos   : LEMMA norm(u) = norm(v) IFF sos(u) = sos(v)

     norm_le_sqv    : LEMMA norm(u) <= norm(v) IFF sqv(u) <= sqv(v)

     norm_lt_sqv    : LEMMA norm(u) < norm(v) IFF sqv(u) < sqv(v)

     norm_scal      : LEMMA norm(a*v) = abs(a)*norm(v) ;

     ^(nzv)         : Normalized = (1/norm(nzv))*nzv              

     normalize(nzv) : MACRO Normalized = ^(nzv)

     norm_normalize : LEMMA
       norm(^(nzv)) = 1     

     dot_normalize  : LEMMA 
       ^(nzu) * ^(nzv) = nzu*nzv/(norm(nzu)*norm(nzv))

     normalize_normalize: LEMMA ^(^(nzv)) = ^(nzv)      

     normalized_id  : LEMMA norm(nzv)*^(nzv) = nzv

     normalize_scal : LEMMA ^(nza*nzv) = sign(nza)*^(nzv)

     cauchy_schwarz : LEMMA sq(u*v) <= sqv(u)*sqv(v)

     dot_norm        : LEMMA -norm(u)*norm(v) <= u*v AND u*v <= norm(u)*norm(v)

     schwarz        : LEMMA abs(u*v) <= norm(u)*norm(v)

     schwarz_cor    : LEMMA sqrt(sqv(u+v)) <= sqrt(sqv(u)) + sqrt(sqv(v))

     norm_triangle   : LEMMA norm(u-w) <= norm(u-v) + norm(v-w) 

     norm_add_le     : LEMMA norm(u+v) <= norm(u) + norm(v)

     norm_sub_le     : LEMMA norm(u-v) <= norm(u) + norm(v)

     norm_sub_ge     : LEMMA norm(u-v) >= norm(u) - norm(v)

     norm_ge_comps   : LEMMA norm(u) >= abs(u`x) AND
                             norm(u) >= abs(u`y) AND               
                             norm(u) >= abs(u`z)                      

     v0,v1,v2  : VAR Vect3
     sq_norm_dist   : LEMMA LET a = v1-v0, b = v1-v2, c = v2-v0 IN    
                               sq(norm(c)) = sq(norm(a)) + sq(norm(b)) - 2*a*b

  % ---------- Predicates over vectors ---------

    parallel?(u,v): bool = 
      EXISTS (nzk:nzreal):  u = nzk*v 

    dir_parallel?(u,v): bool =  
      EXISTS (pk:posreal):  u = pk*v 

    parallel_refl : LEMMA
      parallel?(u,u)

    parallel_symm : LEMMA
      parallel?(u,v) IFF parallel?(v,u)

    parallel_trans : LEMMA
      parallel?(u,v) AND parallel?(v,w) IMPLIES
      parallel?(u,w)

    parallel_zero : LEMMA
      parallel?(u,zero) IFF u = zero

    dir_parallel : LEMMA
      dir_parallel?(u,v) IMPLIES parallel?(u,v) 

    orthogonal?(u,v): bool =  u * v = 0 

    pythagorean : LEMMA
      orthogonal?(u,v) IMPLIES
      sqv(u+v) = sqv(u) + sqv(v)

    norm_add_ge_left : LEMMA
      orthogonal?(u,v) IMPLIES
      norm(u+v) >= norm(u) 

    norm_add_ge_right : LEMMA
      orthogonal?(u,v) IMPLIES
      norm(u+v) >= norm(v)

  % ---------- Auto Rewrites  -----------------------

     AUTO_REWRITE+ neg_zero
     AUTO_REWRITE+ add_zero_left  
     AUTO_REWRITE+ add_zero_right 
     AUTO_REWRITE+ sub_zero_left  
     AUTO_REWRITE+ sub_zero_right 
     AUTO_REWRITE+ sub_eq_args    
     AUTO_REWRITE+ neg_add_left   
     AUTO_REWRITE+ neg_add_right  
     AUTO_REWRITE+ dot_zero_left  
     AUTO_REWRITE+ dot_zero_right 
     AUTO_REWRITE+ scal_zero      
     AUTO_REWRITE+ scal_0         
     AUTO_REWRITE+ scal_1 
     AUTO_REWRITE+ scal_neg_1        
     AUTO_REWRITE+ sqv_zero
     AUTO_REWRITE+ norm_zero      
     AUTO_REWRITE+ add_neg_sub    
     AUTO_REWRITE+ neg_neg        
     AUTO_REWRITE+ dot_scal_left      
     AUTO_REWRITE+ dot_scal_right     
     AUTO_REWRITE+ dot_scal_canon                 
     AUTO_REWRITE+ scal_assoc     
     AUTO_REWRITE+ sqv_neg        
     AUTO_REWRITE+ sqrt_sqv_sq
     AUTO_REWRITE+ norm_neg 
     AUTO_REWRITE+ norm_normalize      
     AUTO_REWRITE+ comp_zero_x
     AUTO_REWRITE+ comp_zero_y
     AUTO_REWRITE+ comp_zero_z
     AUTO_REWRITE+ add_cancel
     AUTO_REWRITE+ sub_cancel
     AUTO_REWRITE+ add_cancel_neg
     AUTO_REWRITE+ sub_cancel_neg
     AUTO_REWRITE+ add_cancel2
     AUTO_REWRITE+ add_cancel_neg2

  %  ---- Turn off dangerous and unhelpful rewrites for auto-rewrite-theory --

     AUTO_REWRITE-    add_comm          % LEMMA u+v = v+u
     AUTO_REWRITE-    dot_comm          % LEMMA u*v = v*u
     AUTO_REWRITE-    dot_assoc         % LEMMA a*(v*w) = (a*v)*w   
     AUTO_REWRITE-    sqv_sym           % LEMMA sqv(u-v) = sqv(v-u) 
     AUTO_REWRITE-    norm_sym          % LEMMA norm(u-v) = norm(v-u)
     AUTO_REWRITE-    dot_sq_norm       % LEMMA u*u = sq(norm(u))

  END vectors_3D

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

  % Subtype TCC generated (at line 36, column 20) for  v * v
      % expected type  nnreal
  sqv_TCC1: OBLIGATION FORALL (v: Vector): v * v >= 0;

  % Judgement subtype TCC generated (at line 119, column 5) for  norm(nzu)
      % expected type  posreal
  nz_norm_gt_0: OBLIGATION FORALL (nzu): norm(nzu) > 0;

  % Judgement subtype TCC generated (at line 122, column 5) for  sqv(nzu)
      % expected type  posreal
  nz_sqv_gt_0: OBLIGATION FORALL (nzu): sqv(nzu) > 0;

  % Judgement subtype TCC generated (at line 8, column 41) for
      % (# x := nza, y := b, z := c #)
      % expected type  Nz_vector
  nz_nvz_left: OBLIGATION
    FORALL (b, c, nza): (# x := nza, y := b, z := c #) /= zero;

  % Judgement subtype TCC generated (at line 8, column 41) for
      % (# x := b, y := nza, z := c #)
      % expected type  Nz_vector
  nz_nvz_middle: OBLIGATION
    FORALL (b, c, nza): (# x := b, y := nza, z := c #) /= zero;

  % Judgement subtype TCC generated (at line 8, column 41) for
      % (# x := b, y := c, z := nza #)
      % expected type  Nz_vector
  nz_nvz_right: OBLIGATION
    FORALL (b, c, nza): (# x := b, y := c, z := nza #) /= zero;

  % Judgement subtype TCC generated (at line 134, column 5) for  x
      % expected type  Nz_vector
  normalized_nz: OBLIGATION FORALL (x: Normalized): x /= zero;

  % Judgement subtype TCC generated (at line 137, column 5) for  -nzu
      % expected type  Nz_vector
  neg_nzv: OBLIGATION FORALL (nzu): -nzu /= zero;

  % Judgement subtype TCC generated (at line 140, column 5) for  nza * nzv
      % expected type  Nz_vector
  nz_nzv: OBLIGATION FORALL (nza, nzv): nza * nzv /= zero;

  % Subtype TCC generated (at line 316, column 33) for  (1 / norm(nzv)) * nzv
      % expected type  Normalized
  caret_TCC1: OBLIGATION
    FORALL (nzv: Nz_vector): norm((1 / norm(nzv)) * nzv) = 1;


body:
  test_vec: THEORY
  %---------------------------------------------------------------------------
  %
  % All lemmas should prove with  (SKOSIMP*) (ASSERT)
  %
  %---------------------------------------------------------------------------
  BEGIN

    IMPORTING vectors_3D
    u,v,v1,v2,v3,v4,w: VAR Vect3

  %   IMPORTING vectors_2D
  %   u,v,v1,v2,v3,w: VAR Vect2

     a,b,c,d:  VAR real


     t1: LEMMA v1 - v1 + w = w

     t1b: LEMMA w - v + v = w

     t1c: LEMMA w + v - v = w

     t2: LEMMA v1 - v1 - w = -w

     t3: LEMMA v + w - v = w

     t4: LEMMA v + (v1 + v2 + v3) - v = v1 + v2 + v3

     t5: LEMMA v - (v1 + v2 + v3) - v = -(v1 + v2 + v3)

     t6: LEMMA v * (v1 - v1) = 0

     t7: LEMMA (v1 - v1)*v = 0

     t8: LEMMA v1*(v2 + zero) = v1*v2 + v1*zero

     t9: LEMMA a*(v1 - v1) + a*(b*v) - (a*b)*v = zero

     t10: LEMMA norm(a*(v1 - v1) - (a*b)*v + a*(b*v) ) = 0
     

     t11: LEMMA sqv(-v + w + v) = sqv(w)

     t12: LEMMA norm(-v - w + v) = norm(w)

     t13: LEMMA -(v-u) + (v-u) = zero   

     t14: LEMMA norm(--v) = norm(v)

     t15: LEMMA c*(a*u)*(b*v)*(d*w)*(a*v3*(b*v2)*(c*v1)) = 
                   a*b*c*(u*v)*((d*w)*(a*v1))*(b*v3)*(c*v2)

     t16: LEMMA ((a+b)*u)*v = a*(u*v) + b*(u*v)
     t17: LEMMA u*((a+b)*v)  = ((a+b)*u)*v 
     t18: LEMMA a*(sqv(-w)*u) = (a*sqv(w))*u

     t19: LEMMA sqv(-w)*(u+v)  = sqv(w)*u + sqv(w)*v
     t20: LEMMA (a*v)*(norm(-w)*u) = a*(v*u)*norm(w)

  %  IMPORTING vectors_2D_rew

     t21: LEMMA sqv(a*u)*sqv(v) = sq(a)*sqv(u)* sqv(v)       
     t22: LEMMA norm(a*u)*norm(v) = abs(a)*norm(u)*norm(v)    

     t23: LEMMA v1*(v2 + v3) = v1*v2 + v1*v3
     t24: LEMMA v1*(v2 - v3) = v1*v2 - v1*v3

     t25: LEMMA a*v1*(v2 - v3) = (a*v1)*v2 - (a*v1)*v3
     t26: LEMMA v1*(b*v2 - c*v3) = (b*v1)*v2 - c*(v1*v3)

     t27: LEMMA sq(a*v1*(v2 - b*v3)) = sq((a*v1)*v2 - (a*b*v1)*v3)
     t28: LEMMA norm(sqv(-w)*(u+v))*v1*(v2 - b*v3) = 
                    (norm(sqv(w)*u + sqv(w)*v)*v1)*v2 - 
                       (norm(sqv(w)*u + sqv(w)*v)*b*v1)*v3

     t29: LEMMA (v1*v2 + v1*v3)*(sqv(-w)*u) = (v1*(v2 + v3))*sqv(w)*u

     t30: LEMMA a*(v*u)*norm(w)*(u*v) + (sqv(a*u)*sqv(v)) *(u*v) 
                   = (((a*v)*(norm(-w)*u)+sq(a)*sqv(u)* sqv(v) )*u)*v  

     t31: LEMMA -w + v - v = -w

     t32: LEMMA -w + v - v = -w

     IMPORTING reals@sqrt_rew

     t33: LEMMA (sqrt(1)*v)*w = v*(sqrt(1)*w)

     t34: LEMMA v3 = (sqrt(4)*v*w,2*w`y,3)
                IMPLIES v3`x = 2*v*w
     
     t35: LEMMA (v1 + a*v3)`x  = v1`x + a*v3`x

     t37: LEMMA ((v1*v2 + v1*v3)*((w+v)`y)*u) = (w`y+v`y)*(v1*(v2 + v3))*u

     t38: LEMMA (v1+v2)*(v3-v4) = v1*v3 - v1*v4 + v2*v3 - v2*v4

     t39: LEMMA (a*u)*(b*v)*c*(u+v+w)`x = (a*b*c)*(u*v)*(u`x+v`x+w`x)

     IMPORTING vectors_rew[10]

     vv,vv2: VAR Vector[10]
     t96: LEMMA (vv + a*vv2)(3)  = vv(3) + a*vv2(3)  %% AUTO-REWRITE FAILS

  END test_vec


body:
  vectors_dot_alt[n: posnat]: THEORY
  %------------------------------------------------------------------------------
  % The n-dimensional dot-product  is defined as follows:
  %
  %    Vector    : TYPE = [below(n) -> real]
  %
  %    *(u,v): real = sigma[below(n)](0,n-1,LAMBDA i:u(i)*v(i)) 
  %
  %
  % For many situations this is a good definition.   But, the summation
  % function is defined with parameter [below(n)] which can be a real nuisance when trying
  % to perform induction proofs (e.g. See deriv_dot_prod in the vect_analysis library).
  % The following alternate definition uses a sigma[nat] which eliminates this problem
  % though it is uglier because of the need to guard the u(j)*v(j) with an IF-THEN-ELSE
  %------------------------------------------------------------------------------

  BEGIN
     
     IMPORTING vectors[n], reals@sigma_nat

     u,v,w     : VAR Vector
     i         : VAR Index

     dot(u,v): real = sigma[nat](0,n-1, LAMBDA (j: nat): IF j < n THEN u(j)*v(j)
                                        ELSE 0 ENDIF)

     m: VAR nat
     dot_rew_prep: LEMMA m < n IMPLIES
                         sigma[nat](0, m, LAMBDA (j: nat): IF j < n THEN u(j) * v(j) ELSE 0 ENDIF)
                         = sigma(0, m, LAMBDA (i: Index[n]): u(i) * v(i))

     dot_rew: LEMMA dot(u,v) = u*v

  END vectors_dot_alt

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

  % Subtype TCC generated (at line 24, column 33) for  n - 1
      % expected type  T_high[nat]
  dot_TCC1: OBLIGATION n - 1 >= 0 OR (EXISTS (j: nat): n - 1 <= j);

  % Subtype TCC generated (at line 29, column 37) for  m
      % expected type  T_high[nat]
  dot_rew_prep_TCC1: OBLIGATION
    FORALL (m: nat): m < n IMPLIES m >= 0 OR (EXISTS (j: nat): m <= j);

  % Subtype TCC generated (at line 30, column 34) for  m
      % expected type  T_high[below(n)]
  dot_rew_prep_TCC2: OBLIGATION
    FORALL (m: nat):
      m < n IMPLIES m >= 0 AND m < n OR (EXISTS (j: below(n)): m <= j);


body:
  vectors_2D: THEORY
  %----------------------------------------------------------------------------
  %
  %  The Vect2 type is a record [#  x, y: real  #]
  %  but the vect2 conversion allows one to write (x,y) 
  %
  %----------------------------------------------------------------------------
  BEGIN

     IMPORTING reals@sqrt,vectors_2D_def

     Vector    : TYPE = Vect2
     u,v,w,z   : VAR Vector
     a,b,c     : VAR real
     nza       : VAR nzreal

  %  ----------- Special vectors ---------------------------------------------

     zero: Vector = (0,0) 
     const_vec(a): Vector = (a,a)

     zero_vector?(v): MACRO bool =
       v = zero

     nz_vector?(v): MACRO bool = 
       v /= zero

     zero_vect2? : MACRO PRED[Vector] = zero_vector?
     nz_vect2?   : MACRO PRED[Vector] = nz_vector?

     Nz_vector   : TYPE = (nz_vector?)
     Nz_vect2    : TYPE = Nz_vector

  %  ----------- Vector Operations -------------------------------------------

     -(v)  : Vector = (-v`x, -v`y) ;

     +(u,v): Vector = (u`x + v`x, u`y + v`y) ;

     -(u,v): Vector = (u`x - v`x, u`y - v`y) ;

     *(u,v): real  =  u`x * v`x + u`y * v`y ;         % dot product

     *(a,v): Vector = (a * v`x, a * v`y) ;

  %  ----------- Vector Functions  -------------------------------------------

     sqv(v): nnreal = v*v

     sos(v): nnreal = sq(v`x) + sq(v`y)        

     sqv_rew    : LEMMA v*v = sqv(v)

     sqv_sos    : LEMMA sqv(v) = sos(v)

     norm(v): nnreal = sqrt(sqv(v))

     normalized?(v): MACRO bool = 
       norm(v) = 1
    
     Normalized  : TYPE = (normalized?)
    
     iv: Normalized = (1,0)
     jv: Normalized = (0,1)

     nzu,nzv     : VAR Nz_vector

  %  ----------- Vector Component Lemmas

     basis          : LEMMA a*iv + b*jv  = (a,b)

     vx_distr_add   : LEMMA (v + w)`x = v`x + w`x  
     vy_distr_add   : LEMMA (v + w)`y = v`y + w`y  

     vx_distr_sub   : LEMMA (v - w)`x = v`x - w`x  
     vy_distr_sub   : LEMMA (v - w)`y = v`y - w`y  

     vx_scal        : LEMMA (a*v)`x = a*v`x              
     vy_scal        : LEMMA (a*v)`y = a*v`y              

     vx_neg         : LEMMA (-v)`x = -v`x
     vy_neg         : LEMMA (-v)`y = -v`y

     comp_eq_x      : LEMMA u = w IMPLIES u`x = w`x      
     comp_eq_y      : LEMMA u = w IMPLIES u`y = w`y      

     comps_eq       : LEMMA u = w IFF u`x = w`x AND u`y = w`y       

     comp_zero_x    : LEMMA zero`x = 0
     comp_zero_y    : LEMMA zero`y = 0

     norm_xy_eq_0   : LEMMA norm(v) = 0 IFF v`x =0 AND v`y=0
      
     norm_sqv_eq_0  : LEMMA norm(v) = 0 IFF sqv(v) = 0

     norm_eq_0      : LEMMA norm(v) = 0 IFF v = zero

     norm_zero      : LEMMA norm(zero) = 0 

     sqv_zero       : LEMMA sqv(zero) = 0

     sqv_eq_0       : LEMMA sqv(v) = 0 IFF v = zero

     v_neq_zero     : LEMMA v /= zero IFF sqv(v) > 0

     sq_dot_eq_0    : LEMMA v*v = 0 IFF v = zero

     nzv_xy_neq_0   : LEMMA nz_vector?(v) IFF v`x /= 0 OR v`y /= 0 
    
  %  ----------- JUDGEMENTS -------------------------------------

     nz_norm_gt_0 : JUDGEMENT 
       norm(nzu) HAS_TYPE posreal

     nz_sqv_gt_0 : JUDGEMENT 
       sqv(nzu) HAS_TYPE posreal

     nz_nvz_left : JUDGEMENT
       mk_vect2(nza,b) HAS_TYPE Nz_vector

     nz_nvz_right : JUDGEMENT
       mk_vect2(b,nza) HAS_TYPE Nz_vector

     normalized_nz : JUDGEMENT
       Normalized SUBTYPE_OF Nz_vector

     neg_nzv : JUDGEMENT
       -(nzu) HAS_TYPE Nz_vector

     nz_nzv : JUDGEMENT
       *(nza,nzv) HAS_TYPE Nz_vector

  %  ----------- Vector Operation Lemmas -------------------------------------

     neg_zero         : LEMMA -zero=zero

     add_zero_left    : LEMMA zero + v = v

     add_zero_right   : LEMMA v + zero = v

     add_comm         : LEMMA u+v = v+u

     add_assoc        : LEMMA u+(v+w) = (u+v)+w

     add_move_left    : LEMMA u + w = v IFF w = v - u   

     add_move_right   : LEMMA u + w = v IFF u = v - w

     add_move_both    : LEMMA v = u + w IFF u = v - w

     add_neg_sub      : LEMMA v + -u = v - u

     add_cancel       : LEMMA v + w - v = w
      
     add_cancel_neg   : LEMMA -v + w + v = w

     add_cancel2      : LEMMA w - v + v = w
      
     add_cancel_neg2  : LEMMA w + v - v = w

     add_cancel_left  : LEMMA u + v = u + w IMPLIES v = w  

     add_cancel_right : LEMMA u + v = w + v IMPLIES u = w  

     add_eq_zero      : LEMMA u + v = zero IFF u = -v
   
     neg_shift        : LEMMA u = -v IFF -u = v

     sub_cancel_left  : LEMMA u - v = u - w IMPLIES v = w  

     sub_cancel_right : LEMMA u - v = w - v IMPLIES u = w 

     sub_zero_left    : LEMMA zero - v = -v

     sub_zero_right   : LEMMA v - zero = v

     sub_eq_args      : LEMMA v - v = zero

     sub_eq_zero      : LEMMA u - v = zero IFF u = v

     sub_cancel       : LEMMA v - w - v = -w

     sub_cancel_neg   : LEMMA -v - w + v = -w

     neg_add_left     : LEMMA -v + v = zero

     neg_add_right    : LEMMA v + -v = zero

     neg_distr_sub    : LEMMA -(v - u) = u - v

     neg_neg          : LEMMA --v = v

     neg_distr_add    : LEMMA -(u + v) = -u - v

     dot_neg_left     : LEMMA (-u)*w = -(u*w)

     dot_neg_right    : LEMMA u*(-w) = -(u*w)

     neg_dot_neg      : LEMMA (-u)*(-v) = u*v 

     dot_zero_left    : LEMMA zero * v = 0

     dot_zero_right   : LEMMA v * zero  = 0

     dot_comm         : LEMMA u*v = v*u

     dot_assoc        : LEMMA a*(v*w) = (a*v)*w

     dot_eq_args_ge   : LEMMA u*u >= 0

     add_comm_assoc_left : LEMMA (u+v)+w = (u+w)+v   

     add_comm_assoc_right: LEMMA u+(v+w) = v+(u+w)   

     dot_add_right    : LEMMA u*(v+w) = u*v + u*w

     dot_add_left     : LEMMA (v+w)*u = v*u + w*u

     dot_sub_right    : LEMMA u*(v-w) = u*v - u*w

     dot_sub_left     : LEMMA (v-w)*u = v*u - w*u

     add_dot_add      : LEMMA (u+v)*(w+z) = u*w+u*z+v*w+v*z


     dot_divby           : LEMMA nza*u = nza*v IMPLIES u = v  

     dot_scal_left       : LEMMA (a*u)*v = a*(u*v)

     dot_scal_right      : LEMMA u*(a*v) = a*(u*v)

     dot_scal_comm_assoc : LEMMA (a*u)*v = (a*v)*u  
     
     scal_assoc          : LEMMA a*(b*u) = (a*b)*u 

     scal_comm_assoc     : LEMMA a*(b*u) = b*(a*u)  

     dot_scal_canon      : LEMMA (a*u)*(b*v) = (a*b)*(u*v)    

     scal_add_left       : LEMMA (a+b)*u = a*u + b*u 

     scal_sub_left       : LEMMA (a-b)*u = a*u - b*u 

     scal_add_right      : LEMMA a*(u+v) = a*u + a*v 

     scal_sub_right      : LEMMA a*(u-v) = a*u - a*v 
     
     scal_neg       : LEMMA a*(-v) = (-a)*v  

     scal_cross     : LEMMA (1/nza) * v = w IFF v = nza*w 

     scal_zero      : LEMMA a * zero = zero

     scal_0         : LEMMA 0 * v = zero 

     scal_1         : LEMMA 1 * v = v 

     scal_neg_1     : LEMMA -1 * v = -v

     scal_cancel    : LEMMA a*nzv = b*nzv IMPLIES a = b  

     scal_div_mult_left  : LEMMA (a/nza)*u = v IFF a*u = nza*v  

     scal_div_mult_right : LEMMA u = (a/nza)*v IFF nza*u = a*v  

     scal_eq_zero   : LEMMA c*v = zero IMPLIES c = 0 OR v = zero 

     dot_ge_dist    : LEMMA w*u >= w*v IMPLIES w*(u-v) >= 0 

     dot_gt_dist    : LEMMA w*u > w*v  IMPLIES w*(u-v) > 0 

     idem_right     : LEMMA a * v = v IFF (a = 1 OR v = zero)

     sqv_neg        : LEMMA sqv(-v) = sqv(v)

     sqv_add        : LEMMA sqv(u+v) = sqv(u) + sqv(v) + 2*u*v

     sqv_scal       : LEMMA sqv(a*v) = sq(a)*sqv(v)

     sqv_sub        : LEMMA sqv(u-v) = sqv(u) + sqv(v) - 2*u*v

     sqv_sub_scal    : LEMMA sqv(u-a*v) = sqv(u) - 2*a*u*v + sq(a)*sqv(v) 

     sqv_sym        : LEMMA sqv(u-v) = sqv(v-u) 

     sqrt_sqv_sq    : LEMMA sqrt(sqv(v)) * sqrt(sqv(v)) = sqv(v)

     norm_sym       : LEMMA norm(u-v) = norm(v-u)

     norm_neg       : LEMMA norm(-u)  = norm(u)

     dot_sq_norm    : LEMMA u*u = sq(norm(u))

     sq_norm        : LEMMA sq(norm(u)) = sqv(u)

     sqv_eq_norm_eq : LEMMA FORALL (Dnn:nnreal): sqv(u) = sq(Dnn) IMPLIES norm(u) = Dnn

     norm_eq_sqv_eq : LEMMA FORALL (Dnn:nnreal): norm(u) = Dnn IMPLIES sqv(u) = sq(Dnn)

     sqrt_sqv_norm  : LEMMA sqrt(sqv(v)) = norm(v)

     norms_eq_sqv   : LEMMA norm(u) = norm(v) IFF sqv(u) = sqv(v)

     norms_eq_sos    : LEMMA norm(u) = norm(v) IFF sos(u) = sos(v)

     norm_le_sqv    : LEMMA norm(u) <= norm(v) IFF sqv(u) <= sqv(v)

     norm_lt_sqv    : LEMMA norm(u) < norm(v) IFF sqv(u) < sqv(v)

     norm_scal      : LEMMA norm(a*v) = abs(a)*norm(v) 

     ;^(nzv)         : Normalized = (1/norm(nzv))*nzv        

     normalize(nzv) : MACRO Normalized = ^(nzv)

     norm_normalize : LEMMA
       norm(^(nzv)) = 1     

     dot_normalize  : LEMMA 
       ^(nzu) * ^(nzv) = nzu*nzv/(norm(nzu)*norm(nzv))

     normalize_normalize: LEMMA ^(^(nzv)) = ^(nzv)    

     normalized_id  : LEMMA norm(nzv)*^(nzv) = nzv

     normalize_scal : LEMMA ^(nza*nzv) = sign(nza)*^(nzv)

     cauchy_schwarz : LEMMA sq(u*v) <= sqv(u)*sqv(v)

     dot_norm        : LEMMA -norm(u)*norm(v) <= u*v AND u*v <= norm(u)*norm(v)

     schwarz        : LEMMA abs(u*v) <= norm(u)*norm(v)

     schwarz_converse: LEMMA norm(u)*norm(nzv) = abs(u*nzv) IMPLIES 
     		      	    EXISTS (cr:real): cr*nzv = u

     schwarz_cor    : LEMMA sqrt(sqv(u+v)) <= sqrt(sqv(u)) + sqrt(sqv(v))

     norm_triangle   : LEMMA norm(u-w) <= norm(u-v) + norm(v-w) 

     norm_add_le     : LEMMA norm(u+v) <= norm(u) + norm(v)

     norm_sub_le     : LEMMA norm(u-v) <= norm(u) + norm(v)

     norm_sub_ge     : LEMMA norm(u-v) >= norm(u) - norm(v)

     norm_ge_comps   : LEMMA norm(u) >= abs(u`x) AND
                             norm(u) >= abs(u`y)                 

     v0,v1,v2  : VAR Vect2

     sq_norm_dist   : LEMMA LET a = v1-v0, b = v1-v2, c = v2-v0 IN  
                                sq(norm(c)) = sq(norm(a)) + sq(norm(b)) - 2*a*b

  % ---------- Predicates over vectors ---------

     parallel?(u,v): bool = 
       EXISTS (nzk:nzreal):  u = nzk*v

     dir_parallel?(u,v): bool = 
       EXISTS (pk:posreal):  u = pk*v 

     parallel_refl : LEMMA
       parallel?(u,u)

     parallel_symm : LEMMA
       parallel?(u,v) IFF parallel?(v,u)

     parallel_trans : LEMMA
       parallel?(u,v) AND parallel?(v,w) IMPLIES
       parallel?(u,w)

     parallel_zero : LEMMA
       parallel?(u,zero) IFF u = zero

     dir_parallel : LEMMA
       dir_parallel?(u,v) IMPLIES parallel?(u,v) 

     orthogonal?(u,v): bool =  u * v = 0 
    
     pythagorean : LEMMA
       orthogonal?(u,v) IMPLIES
       sqv(u+v) = sqv(u) + sqv(v)

     norm_add_ge_left : LEMMA
       orthogonal?(u,v) IMPLIES
       norm(u+v) >= norm(u) 

     norm_add_ge_right : LEMMA
       orthogonal?(u,v) IMPLIES
       norm(u+v) >= norm(v)

  %  ----- following moved to basis_2D.pvs ----------------
  %
  %    orthogonal_basis: LEMMA
  %      u /= zero AND
  %      v /= zero AND
  %      orthogonal?(u,v) IMPLIES
  %      w = ((w*u)/sqv(u))*u + ((w*v)/sqv(v))*v

  % ---------- Auto Rewrites  -----------------------

     AUTO_REWRITE+ neg_zero              % -zero=zero
     AUTO_REWRITE+ add_zero_left         % zero + v = -v
     AUTO_REWRITE+ add_zero_right        % v + zero = v
     AUTO_REWRITE+ sub_zero_left         % zero - v = -v
     AUTO_REWRITE+ sub_zero_right        % v - zero = v
     AUTO_REWRITE+ sub_eq_args           % v - v = zero
     AUTO_REWRITE+ neg_add_left          % -v + v = zero
     AUTO_REWRITE+ neg_add_right         % v + -v = zero
     AUTO_REWRITE+ dot_zero_left         % zero * v = 0
     AUTO_REWRITE+ dot_zero_right        % v * zero  = 0
     AUTO_REWRITE+ scal_zero             % a * zero = zero
     AUTO_REWRITE+ scal_0                % 0 * v = zero   
     AUTO_REWRITE+ scal_1                % 1 * v = v
     AUTO_REWRITE+ scal_neg_1            % -1 * v = -v
     AUTO_REWRITE+ sqv_zero              % sqv(zero) = 0
     AUTO_REWRITE+ norm_zero             % norm(zero) = 0 
     AUTO_REWRITE+ add_neg_sub           % v + -u = v - u
     AUTO_REWRITE+ neg_neg               % --v = v
     AUTO_REWRITE+ dot_scal_left         % (a*u)*v = a*(u*v)
     AUTO_REWRITE+ dot_scal_right        % u*(a*v) = a*(u*v)
     AUTO_REWRITE+ dot_scal_canon        % (a*u)*(b*v) = (a*b)*(u*v)   
     AUTO_REWRITE+ scal_assoc            % a*(b*u) = (a*b)*u 
     AUTO_REWRITE+ sqv_neg               % sqv(-v) = sqv(v)
     AUTO_REWRITE+ sqrt_sqv_sq           % sqrt(sqv(v)) * sqrt(sqv(v)) = sqv(v)  
     AUTO_REWRITE+ norm_neg              % norm(-u) = norm(u)
     AUTO_REWRITE+ norm_normalize        % norm(^(nzv)) = 1
     AUTO_REWRITE+ comp_zero_x           % zero`x = 0
     AUTO_REWRITE+ comp_zero_y           % zero`y = 0
     AUTO_REWRITE+ add_cancel            % v + w - v = w
     AUTO_REWRITE+ sub_cancel            % v - w - v = -w
     AUTO_REWRITE+ add_cancel_neg        % -v + w + v = w
     AUTO_REWRITE+ sub_cancel_neg        % -v - w + v = -w
     AUTO_REWRITE+ add_cancel2           % w - v + v = w
     AUTO_REWRITE+ add_cancel_neg2       % w + v - v = w

  %  ---- Turn off dangerous and unhelpful rewrites for auto-rewrite-theory --

     AUTO_REWRITE-    zero
     AUTO_REWRITE-    add_comm           % u+v = v+u
     AUTO_REWRITE-    dot_comm           % u*v = v*u
     AUTO_REWRITE-    dot_assoc          % a*(v*w) = (a*v)*w   
     AUTO_REWRITE-    sqv_sym            % sqv(u-v) = sqv(v-u) 
     AUTO_REWRITE-    norm_sym           % norm(u-v) = norm(v-u)
     AUTO_REWRITE-    dot_sq_norm        % u*u = sq(norm(u))

    bolzano_weierstrass: LEMMA
      FORALL (M:posnat,VS:[nat->Vect2]):
        (FORALL (i:nat): norm(VS(i))<=M)
        IMPLIES (EXISTS (ns:[nat->nat],acp:Vect2):
          (FORALL (j:nat): ns(j)>=j) AND
          (FORALL (epsil:posreal): EXISTS (K:posnat):
  	  FORALL (j:nat): j>=K IMPLIES norm(VS(ns(j))-acp)<epsil)
  	AND norm(acp)<=M)

  END vectors_2D

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

  % Subtype TCC generated (at line 48, column 20) for  v * v
      % expected type  nnreal
  sqv_TCC1: OBLIGATION FORALL (v: Vector): v * v >= 0;

  % Subtype TCC generated (at line 63, column 20) for  mk_vect2(1, 0)
      % expected type  Normalized
  iv_TCC1: OBLIGATION norm((# x := 1, y := 0 #)) = 1;

  % Subtype TCC generated (at line 64, column 20) for  mk_vect2(0, 1)
      % expected type  Normalized
  jv_TCC1: OBLIGATION norm((# x := 0, y := 1 #)) = 1;

  % Judgement subtype TCC generated (at line 113, column 5) for  norm(nzu)
      % expected type  posreal
  nz_norm_gt_0: OBLIGATION FORALL (nzu): norm(nzu) > 0;

  % Judgement subtype TCC generated (at line 116, column 5) for  sqv(nzu)
      % expected type  posreal
  nz_sqv_gt_0: OBLIGATION FORALL (nzu): sqv(nzu) > 0;

  % Judgement subtype TCC generated (at line 6, column 38) for
      % (# x := nza, y := b #)
      % expected type  Nz_vector
  nz_nvz_left: OBLIGATION FORALL (b, nza): (# x := nza, y := b #) /= zero;

  % Judgement subtype TCC generated (at line 6, column 38) for
      % (# x := b, y := nza #)
      % expected type  Nz_vector
  nz_nvz_right: OBLIGATION FORALL (b, nza): (# x := b, y := nza #) /= zero;

  % Judgement subtype TCC generated (at line 125, column 5) for  x
      % expected type  Nz_vector
  normalized_nz: OBLIGATION FORALL (x: Normalized): x /= zero;

  % Judgement subtype TCC generated (at line 128, column 5) for  -nzu
      % expected type  Nz_vector
  neg_nzv: OBLIGATION FORALL (nzu): -nzu /= zero;

  % Judgement subtype TCC generated (at line 131, column 5) for  nza * nzv
      % expected type  Nz_vector
  nz_nzv: OBLIGATION FORALL (nza, nzv): nza * nzv /= zero;

  % Subtype TCC generated (at line 312, column 34) for  (1 / norm(nzv)) * nzv
      % expected type  Normalized
  caret_TCC1: OBLIGATION
    FORALL (nzv: Nz_vector): norm((1 / norm(nzv)) * nzv) = 1;


body:
  distance_2D: THEORY
  BEGIN

     IMPORTING vectors_2D

     p,p0,p1,p2,u,v,v0,v1,v2: VAR Vect2

     t: VAR posreal

  %  ------- distance function -----

     sq_dist(p1,p2): nnreal = sq(p1`x - p2`x) + sq(p1`y - p2`y)

     dist(p1,p2)   : nnreal = sqrt(sq_dist(p1,p2))


     dist_eq_args : LEMMA  dist(p,p) = 0

     dist_zero_l  : LEMMA  dist(zero,p) = norm(p)
     dist_zero_r  : LEMMA  dist(p,zero) = norm(p)

     dist_sym     : LEMMA  dist(p1,p2) = dist(p2,p1)

     dist_eq_0    : LEMMA  dist(p1,p2) = 0 IFF p1 = p2 

     dist_norm    : LEMMA  dist(u,v) = norm(u-v)

     dist_rel     : LEMMA  dist(p+p1,p+p2) = dist(p1,p2)
    
     sq_dist_is_dist_sq: LEMMA sq_dist(p1,p2) = sq(dist(p1,p2))  

     sq_dist_norm : LEMMA sq_dist(p1,p2) = sq(norm(p1-p2))

     sq_dist_sym  : LEMMA sq_dist(p1,p2) = sq_dist(p2,p1)

     sq_dist_le   : LEMMA sq_dist(v1,v2) <= sq_dist(p1,p2) IMPLIES
                              dist(v1,v2) <= dist(p1,p2)        

     sq_dist_lt   : LEMMA sq_dist(v1,v2) <  sq_dist(p1,p2) IMPLIES
                              dist(v1,v2) <  dist(p1,p2)        

     dist_ge_x    : LEMMA dist(p1,p2) >= abs(p1`x - p2`x)  

     dist_ge_y    : LEMMA dist(p1,p2) >= abs(p1`y - p2`y)  

     sq_dist_dist : LEMMA sq(dist(p2,p0)) = sq(dist(p1,p0)) + sq(dist(p1,p2)) 
                                               - 2*(p1-p0)*(p1-p2) 

     dist_triangle: LEMMA dist(p0,p2) <= dist(p0,p1) + dist(p1,p2) 

     dist_tri_sub: LEMMA abs(dist(p0,p2) - dist(p1,p2)) <= dist(p0,p1)



     AUTO_REWRITE+ dist_eq_args
  %  AUTO_REWRITE+ dist_zero_l  
  %  AUTO_REWRITE+ dist_zero_r  

  %  ------- Predicates

     r: VAR real

     on_circle?(p,r): bool = dist(p,zero) = r   

     on_line?(p1,p2,p): bool = 
                  EXISTS (x : real) : p = p1 + x * (p2 - p1) 

     on_segment?(p1,p2,p): bool = 
                  EXISTS (x : { y: nnreal | y <= 1}) : p = p1 + x * (p2 - p1) 


     on_segment_beg: LEMMA on_segment?(p1,p2,p1)
     on_segment_end: LEMMA on_segment?(p1,p2,p2)
     on_line_beg   : LEMMA on_line?(p1,p2,p1)
     on_line_end   : LEMMA on_line?(p1,p2,p2)


     AUTO_REWRITE+ on_segment_beg
     AUTO_REWRITE+ on_segment_end
     AUTO_REWRITE+ on_line_beg
     AUTO_REWRITE+ on_line_end


     on_segment_on_line: LEMMA on_segment?(p1,p2,p1) IMPLIES on_line?(p1,p2,p1)

  END distance_2D


body:
  lines_2D: THEORY
  %----------------------------------------------------------------------------
  % The traditional way to defines a line L is by specifying two distinct points,
  % P0 and P1, on it.  
  % 
  % A line L can also be defined by a point and a direction.  Let P0 be a
  % point on the line L and let dv be a nonzero vector specifying the direction
  % of the line.  This is equivalent to the two point definition, since we
  % could just put dv=(P1-P0).
   
  % We can also add dynamics to our line.  If we assume a particle is
  % moving in a line with a constant velocity, then we can define
  % this linear motion using the location of the point at time zero,
  % a velocity vector and a time parameter t:
  % 
  %       p0 + t*vel
  % 
  % which provides the location of the particle at time t.
  %
  % Author: Ricky Butler              NASA Langley Research Center
  %----------------------------------------------------------------------------
  BEGIN

     IMPORTING distance_2D
                                       %     Basic        |   Parametric
                                       %------------------|-----------------
     Line : TYPE = [# p: Vect2,        % point on the line| position at time 0
                      v: Nz_vect2 #]   % direction vector | velocity vector
    
     Line2D: TYPE = Line   ;

     -(L: Line): Line = (# p := L`p, v := -L`v #)

     p0 (L: Line): MACRO Vect2 = p(L)  % alternate field names
     vel(L: Line): MACRO Vect2 = v(L)

     vv: VAR [Vect2,Nz_vect2]
     vecpair_to_Line(vv): MACRO Line = (# p := vv`1, v := vv`2 #)

     CONVERSION vecpair_to_Line ;                        %% NEW %%


     p,p1,p2,u,v,v0,v1,v2: VAR Vect2
     t: VAR nzreal


     loc(L: Line)(tt: real): MACRO Vect2 = p(L) + tt*v(L)

  %  ------- generate vector from two points

     vec_from(p1,p2) : MACRO Vect2 = p2 - p1

     line_from(p1,(p2:{v| v /= p1})): Line = (p1,vec_from(p1,p2))

     vec_from_eq_args : LEMMA vec_from(p,p) = zero


  %  ------- generate velocity vector from two points and transport time

     vel_from_tm(p1,p2,t): { v | p2 = p1 + t*v } = 1/t*(p2 - p1)

     line_from_tm(p1,(p2:{v| v /= p1}),t): Line = (p1,vel_from_tm(p1,p2,t))

     vel_from_tm_nz      : LEMMA p1 /= p2 IMPLIES vel_from_tm(p1,p2,t) /= zero

     vel_from_tm_lem     : LEMMA p2 = p1 + t*vel_from_tm(p1,p2,t)

     vel_from_tm_rew     : LEMMA vel_from_tm(p1,p2,t) = 1/t*(p2 - p1)

     vel_from_tm_eq_args : LEMMA vel_from_tm(p,p,t) = zero

     vel_from_tm_length  : LEMMA p1 /= p2 IMPLIES
                                   sq(norm(vel_from_tm(p1,p2,t))) =
                                   sq_dist(p1,p2)/sq(t)

  %  ------- generate velocity vector from two points and speed ------

     s: VAR posreal

     vel_from_spd(p1,p2,s):  Vect2 = IF p1 = p2 then zero
                                     ELSE s/dist(p1,p2)*(p2-p1)
                                     ENDIF
     ps: VAR posreal
     vel_from_spd_lem: LEMMA p1 /= p2 IMPLIES
                       vel_from_spd(p1,p2,ps) = vel_from_tm(p1,p2,dist(p1,p2)/ps)


     vel_from_spd_norm: LEMMA p1 /= p2 IMPLIES
                                 vel_from_spd(p1,p2,s) = s*normalize(p2-p1)

     pt: VAR posreal
     gen_speed(p1,p2,pt): { s1: nnreal | s1 = 1/pt * dist(p1,p2) }


  %  ------- generate velocity vector from a point, heading, speed  ------

  %   IMPORTING trig@trig

  %   hdg: VAR posreal
  %   vel_from_hdg(p1,hdg,s): Vect2 = LET p2 = p1+(cos(hdg),sin(hdg)) IN
  %                                       vel_from_spd(p1,p2,s)


  %  -------------- Line Predicates -----------------

     L,L1,L2: VAR Line

     on_line?(p,L): bool = EXISTS (x : real) : p = p(L) + x * v(L)

     on_segment?(p,L): bool =
                  EXISTS (x : { y: nnreal | y <= 1}) : p = p(L) + x * v(L)

     orthogonal?(L1,L2): bool = ^(v(L1))*^(v(L2)) = 0 

     parallel?(L1,L2)  : bool = abs(^(v(L1))*^(v(L2))) = 1 

     on_line_lem: LEMMA FORALL (p2:{v|v /= p1}): on_line?(p1, line_from(p1,p2)) AND on_line?(p2, line_from(p1,p2))

     on_line_neg: LEMMA on_line?(p, L) IMPLIES on_line?(p, -L)

     on_line_sym: LEMMA FORALL (p2:{v|v /= p1}): on_line?(p, line_from(p1,p2)) IMPLIES on_line?(p, line_from(p2,p1)) 


  %  -------------- Generate Parametric Lines -------

     gen_line_tm(p1,(p2:{v| v /= p1}),t) : Line = (# p := p1,
                                      v := vel_from_tm(p1,p2,t) #)

     gen_line_spd(p1,(p2:{v| v /= p1}),s): Line = (# p := p1,
                                      v := vel_from_spd(p1,p2,s) #)


     test1: LEMMA p1 /= p2 IMPLIES on_line?(p1,gen_line_tm(p1,p2,t))
     test2: LEMMA p1 /= p2 IMPLIES on_line?(p2,gen_line_tm(p1,p2,t))
     test3: LEMMA p1 /= p2 IMPLIES on_line?(p1,gen_line_spd(p1,p2,s))
     test4: LEMMA p1 /= p2 IMPLIES on_line?(p2,gen_line_spd(p1,p2,s))


     vel_from_spd_on_line: LEMMA  LET vv = vel_from_spd(p1,p2,s) IN 
                                    p = p1 + t*vv 
                                      IMPLIES on_line?(p1,p2,p) 



  END lines_2D

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

  % Subtype TCC generated (at line 51, column 35) for  p2 - p1
      % expected type  Nz_vect2
  line_from_TCC1: OBLIGATION
    FORALL (p1: Vect2, (p2: {v | v /= p1})): p2 - p1 /= zero;

  % Subtype TCC generated (at line 60, column 49) for  1 / t * (p2 - p1)
      % expected type  {v | p2 = p1 + t * v}
  vel_from_tm_TCC1: OBLIGATION
    FORALL (p1: Vect2, p2: Vect2, t: nzreal):
      p2 = p1 + t * (1 / t * (p2 - p1));

  % Subtype TCC generated (at line 62, column 52) for  vel_from_tm(p1, p2, t)
      % expected type  Nz_vect2
  line_from_tm_TCC1: OBLIGATION
    FORALL (p1: Vect2, (p2: {v | v /= p1}), t: nzreal):
      vel_from_tm(p1, p2, t) /= zero;

  % Subtype TCC generated (at line 81, column 42) for  dist(p1, p2)
      % expected type  nznum
  vel_from_spd_TCC1: OBLIGATION
    FORALL (p1: Vect2, p2: Vect2): NOT p1 = p2 IMPLIES dist(p1, p2) /= 0;

  % Subtype TCC generated (at line 85, column 64) for  dist(p1, p2) / ps
      % expected type  nzreal
  vel_from_spd_lem_TCC1: OBLIGATION
    FORALL (p1, p2: Vect2, ps: posreal):
      p1 /= p2 IMPLIES dist(p1, p2) / ps /= 0;

  % Subtype TCC generated (at line 89, column 67) for  p2 - p1
      % expected type  Nz_vector
  vel_from_spd_norm_TCC1: OBLIGATION
    FORALL (p1, p2: Vect2): p1 /= p2 IMPLIES p2 - p1 /= zero;

  % Existence TCC generated (at line 92, column 3) for
      % gen_speed(p1, p2, pt): {s1: nnreal | s1 = 1 / pt * dist(p1, p2)}
  gen_speed_TCC1: OBLIGATION
    EXISTS (x:
              [d: [Vect2, Vect2, posreal] ->
                 {s1: nnreal | s1 = 1 / d`3 * dist(d`1, d`2)}]):
      TRUE;

  % Subtype TCC generated (at line 121, column 110) for  p1
      % expected type  {v | v /= p2}
  on_line_sym_TCC1: OBLIGATION
    FORALL (p, p1: Vect2, p2: {v | v /= p1}):
      on_line?(p, line_from(p1, p2)) IMPLIES p1 /= p2;

  % Subtype TCC generated (at line 130, column 41) for
      % vel_from_spd(p1, p2, s)
      % expected type  Nz_vect2
  gen_line_spd_TCC1: OBLIGATION
    FORALL (p1: Vect2, (p2: {v | v /= p1}), s: posreal):
      vel_from_spd(p1, p2, s) /= zero;

  % Subtype TCC generated (at line 133, column 60) for  p2
      % expected type  {v | v /= p1}
  test1_TCC1: OBLIGATION FORALL (p1, p2: Vect2): p1 /= p2 IMPLIES p2 /= p1;


body:
  perpendicular_2D: THEORY
  %----------------------------------------------------------------------------
  %
  %         Q.
  %         .\  .        
  %         . \   .
  %         .  \    .  d                          
  %         .   \     .            .
  %         .    \      .       .                 W  = Q - P0
  %       W .   c \       .  .
  %         .      \       *   P0 + t*v
  %         .       \   .                         del = (t-tp)*v
  %         .        *          
  %         .      .   P0 + tp*v
  %         .   .
  %         ..
  %         P0
  %
  %
  %    determine tp  = intersection of perpendicular line from Q to line (P0,v)
  %                  = perp_pt(Q-P0,nzv) = (W*v)/(v*v)
  %               c  = length of this perpendicular line
  %              del = (t-tp)*v
  %
  %    dist(q,L)     = distance from point q to line defined by perpendicular
  %
  %    perpL(v), perpR(v) = return vector perpendicular to v
  %
  %  Author: Ricky Butler              NASA Langley Research Center
  %
  %----------------------------------------------------------------------------
  BEGIN
   
     IMPORTING vectors_2D

     t,tp: VAR real
     P0,Q,u,v,w,c,d,x,y,del: VAR Vect2

     perpR(v): Vect2 = (v`y,-v`x)     %% RIGHT turn
     perpL(v): Vect2 = (-v`y,v`x)     %% LEFT turn

     neg_perpL : LEMMA
       perpL(-v) = -perpL(v)

     neg_perpR : LEMMA
       perpR(-v) = -perpR(v)
     
     perpL_perpR : LEMMA
       perpL(v) = -perpR(v)

     dot_perpR_eq_0 : LEMMA v*perpR(v) = 0 

     dot_perpL_eq_0 : LEMMA perpL(v)*v = 0

     dot_perpR_scal_eq_0 : LEMMA v*perpR(t*v) = 0 

     dot_perpL_scal_eq_0 : LEMMA perpL(t*v)*v = 0

     sqv_perpR: LEMMA sqv(perpR(v)) = sqv(v)

     sqv_perpL : LEMMA sqv(perpL(v)) = sqv(v)

     perpR_add : LEMMA
       perpR(u+v) = perpR(u)+perpR(v)

     perpR_sub : LEMMA
       perpR(u-v) = perpR(u)-perpR(v)

     perpR_scal : LEMMA
       perpR(t*v) = t*perpR(v)

     perpR_neg : LEMMA
       perpR(-u) = -perpR(u)

     perpR_eq_zero : LEMMA
        perpR(zero) = zero

     perpL_add : LEMMA
       perpL(u+v) = perpL(u)+perpL(v)

     perpL_sub : LEMMA
       perpL(u-v) = perpL(u)-perpL(v)

     perpL_scal : LEMMA
       perpL(t*v) = t*perpL(v)

     perpL_neg : LEMMA
       perpL(-u) = -perpL(u)

     perpL_eq_zero : LEMMA
        perpL(zero) = zero

     perpL_plus_perpR : LEMMA
       perpL(v) + perpR(v) = zero

     perpR_perpR : LEMMA
       perpR(perpR(u)) = -u

     perpR_perpL : LEMMA
       perpR(perpL(u)) = u

     nzv: VAR Nz_vect2

     perpL_nz : JUDGEMENT
       perpL(nzv) HAS_TYPE Nz_vect2

     perpR_nz : JUDGEMENT
       perpR(nzv) HAS_TYPE Nz_vect2

     AUTO_REWRITE+ perpL_eq_zero
     AUTO_REWRITE+ perpR_eq_zero

     perp_pt(Q,P0,nzv): real = (Q-P0)*nzv/(nzv*nzv)

     perp_is_normal: LEMMA tp = perp_pt(Q,P0,nzv) 
                             IMPLIES
                                LET c = (P0 + tp*nzv) - Q,
                                    del = (t-tp)*nzv       IN
                                       del*c = 0


     perp_is_min: LEMMA tp = perp_pt(Q,P0,nzv) 
                        IMPLIES
                            LET d = (P0 + t*nzv) - Q,
                                c = (P0 + tp*nzv) - Q  IN
                              norm(d) >= norm(c) 

     perp_gt_del: LEMMA tp = perp_pt(Q,P0,nzv) 
                         IMPLIES
                            LET d = (P0 + t*nzv) - Q,
                                del = (t-tp)*nzv   IN
                              norm(d) >= norm(del) 


     perp_comps: LEMMA tp = perp_pt(Q,P0,nzv) 
                       IMPLIES
                          LET d = (P0 + t*nzv) - Q,
                              c = (P0 + tp*nzv) - Q,
                              del = (t-tp)*nzv   IN
                       sq(norm(d)) = sq(norm(del)) + sq(norm(c)) 

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

     IMPORTING lines_2D

  %   ----- distance from a point to a line --------

     p,q: VAR Vect2
     L: Var Line


     perp_pt(q,L): real = (q-p(L))*v(L)/(v(L)*v(L))

     dist(q,L): nnreal =  LET tp = perp_pt(q,L) IN
                                 dist(p(L) + tp*v(L),q)

     dist_is_min: THEOREM on_line?(p,L) IMPLIES
                           dist(q,p) >= dist(q,L)

     L1, L2: Var Line
     perpendicular?(L1,L2): bool = orthogonal?(v(L1),v(L2))

     perp_pt_perp: LEMMA q /= p(L) + perp_pt(q,L)*v(L) IMPLIES
                          perpendicular?(L,line_from(q,p(L) 
                                                         + perp_pt(q,L)*v(L)))

  %    perp_pt_parallel_perp: LEMMA LET tp = perp_pt(q,L1), 
  %                                  L2 = line_from(q,p(L1)+tp*v(L1)) IN
  %                                     parallel?(v(L2),perp(v))

  END perpendicular_2D

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

  % Judgement subtype TCC generated (at line 105, column 5) for  perpL(nzv)
      % expected type  Nz_vect2
  perpL_nz: OBLIGATION FORALL (nzv): perpL(nzv) /= zero;

  % Judgement subtype TCC generated (at line 108, column 5) for  perpR(nzv)
      % expected type  Nz_vect2
  perpR_nz: OBLIGATION FORALL (nzv): perpR(nzv) /= zero;

  % Subtype TCC generated (at line 113, column 41) for  (nzv * nzv)
      % expected type  nznum
  perp_pt_TCC1: OBLIGATION FORALL (nzv: Nz_vect2): (nzv * nzv) /= 0;

  % Subtype TCC generated (at line 152, column 39) for  (v(L) * v(L))
      % expected type  nznum
  perp_pt_TCC2: OBLIGATION FORALL (L: Line): (v(L) * v(L)) /= 0;

  % Subtype TCC generated (at line 164, column 53) for
      % p(L) + perp_pt(q, L) * v(L)
      % expected type  {v | v /= q}
  perp_pt_perp_TCC1: OBLIGATION
    FORALL (L: Line, q: Vect2):
      q /= p(L) + perp_pt(q, L) * v(L) IMPLIES
       p(L) + perp_pt(q, L) * v(L) /= q;


body:
  basis_2D: THEORY
  %------------------------------------------------------------------------------
  %     Orthonormal Basis for 2D Vectors      3-4-2010
  %
  %     Authors: Anthony Narkawicz     NASA Langley
  %              Ricky Butler          NASA Langley
  %------------------------------------------------------------------------------

  BEGIN

     IMPORTING vectors_2D

     e1,e2  : VAR Vect2
     w,w1,w2: VAR Vect2
     a1,a2,b1,b2  : VAR real

     orthogonal_basis: LEMMA
       e1 /= zero AND
       e2 /= zero AND
       orthogonal?(e1,e2) IMPLIES
       w = ((w*e1)/sqv(e1))*e1 + ((w*e2)/sqv(e2))*e2

     orthonormal?(e1,e2): bool =  
       orthogonal?(e1,e2) AND e1 /= zero AND norm(e1) = 1 AND
       e2 /= zero AND norm(e2) = 1

     orthonormal_basis: LEMMA FORALL (w:Vect2):
       orthonormal?(e1,e2) IMPLIES
       w = (w*e1)*e1 + (w*e2)*e2

     basis_two_dot_zero: LEMMA
       w /= zero AND e1 /= zero AND w*e1 = 0 AND w*e2 = 0
       IMPLIES
       (EXISTS (c:real): c*e1 = e2)

     basis_add: LEMMA
       %% orthonormal?(e1,e2) AND
       w1 = (w1*e1)*e1 + (w1*e2)*e2 AND
       w2 = (w2*e1)*e1 + (w2*e2)*e2
     IMPLIES 
       w1+w2 = ((w1+w2)*e1)*e1 + ((w1+w2)*e2)*e2

     basis_sub: LEMMA
       %% orthonormal?(e1,e2) AND
       w1 = (w1*e1)*e1 + (w1*e2)*e2 AND
       w2 = (w2*e1)*e1 + (w2*e2)*e2
     IMPLIES 
       w1-w2 = ((w1-w2)*e1)*e1 + ((w1-w2)*e2)*e2

     basis_sqv: LEMMA FORALL (a,b: real,w: Vect2):
       orthonormal?(e1,e2) AND
       w = (a)*e1 + (b)*e2
       IMPLIES
          sqv(w) = sq(a) + sq(b)

     basis_dot: LEMMA  FORALL (a,b,c,d: real):
       orthonormal?(e1,e2) IMPLIES
       LET s = (a)*e1 + (b)*e2,
           v = (c)*e1 + (d)*e2
       IN
          s*v = a*c + b*d

       
     IMPORTING perpendicular_2D

     basis_perpR: LEMMA  FORALL (a,b: real):
       LET e2 = perpR(e1),
           s = (a)*e1 + (b)*e2
       IN
          perpR(s) = (a)*e2 - b*e1

     vh_vp_orthon: LEMMA FORALL (v: Nz_vect2):
       LET
         vh = ^(v),
         vp = perpR(vh)
       IN
        orthonormal?(vh, vp)

    orthogonal_basis_sqv: LEMMA
      orthogonal?(e1,e2) AND
      w = a1*e1 + a2*e2 IMPLIES
      sqv(w) = sq(a1)*sqv(e1) + sq(a2)*sqv(e2)

    orthonormal_basis_sqv: LEMMA
      orthonormal?(e1,e2) AND
      w = a1*e1 + a2*e2 IMPLIES
      sqv(w) = sq(a1) + sq(a2)

    orthogonal_basis_norm: LEMMA
      orthogonal?(e1,e2) AND
      w = a1*e1 + a2*e2 IMPLIES
      norm(w) = sqrt(sq(a1)*sqv(e1) + sq(a2)*sqv(e2))

    orthonormal_basis_norm: LEMMA
      orthonormal?(e1,e2) AND
      w = a1*e1 + a2*e2 IMPLIES
      norm(w) = sqrt(sq(a1) + sq(a2))

    orthogonal_basis_norm_ge: LEMMA
      orthogonal?(e1,e2) AND
      w = a1*e1 + a2*e2 IMPLIES
      norm(w) >= abs(a1)*norm(e1)

    orthonormal_basis_norm_ge: LEMMA
      orthonormal?(e1,e2) AND
      w = a1*e1 + a2*e2 IMPLIES
      norm(w) >= abs(a1)

    orthogonal_basis_dot: LEMMA
      orthogonal?(e1,e2) AND
      w1 = a1*e1 + a2*e2 AND
      w2 = b1*e1 + b2*e2 IMPLIES
      w1*w2 = (a1*b1)*sqv(e1) + (a2*b2)*sqv(e2)

    orthonormal_basis_dot: LEMMA
      orthonormal?(e1,e2) AND
      w1 = a1*e1 + a2*e2 AND
      w2 = b1*e1 + b2*e2 IMPLIES
      w1*w2 = a1*b1 + a2*b2


  END basis_2D

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

  % Subtype TCC generated (at line 21, column 17) for  sqv(e1)
      % expected type  nznum
  orthogonal_basis_TCC1: OBLIGATION
    FORALL (e1, e2: Vect2):
      orthogonal?(e1, e2) AND e2 /= zero AND e1 /= zero IMPLIES sqv(e1) /= 0;

  % Subtype TCC generated (at line 21, column 39) for  sqv(e2)
      % expected type  nznum
  orthogonal_basis_TCC2: OBLIGATION
    FORALL (e1, e2: Vect2):
      orthogonal?(e1, e2) AND e2 /= zero AND e1 /= zero IMPLIES sqv(e2) /= 0;


body:
  det_2D: THEORY
  %------------------------------------------------------------------------------
  %
  % 2-Dimensional Determinant of two vectors (aka 2D-cross product)
  %
  %
  %------------------------------------------------------------------------------
  BEGIN

    IMPORTING vectors_2D,
              perpendicular_2D

    u,v,w   : VAR Vect2
    k       : VAR real
    nzu,nzv : VAR Nz_vect2

    det(u,v): real = u`x*v`y - u`y*v`x

    det_zero_left  : LEMMA det(zero,v) = 0

    det_zero_right : LEMMA det(u,zero) = 0

    det_eq_0       : LEMMA det(u,u) = 0

    det_scal_left  : LEMMA det(k*u,v) = k*det(u,v)
    det_scal_right : LEMMA det(u,k*v) = k*det(u,v)
    
    det_add_left   : LEMMA det(u+v,w) = det(u,w) + det(v,w)
    det_add_right  : LEMMA det(w,u+v) = det(w,u) + det(w,v)

    det_sub_left   : LEMMA det(u-v,w) = det(u,w) - det(v,w)
    det_sub_right  : LEMMA det(w,u-v) = det(w,u) - det(w,v)

    det_symm  : LEMMA det(u,v) = det(-u,-v)
    det_asym  : LEMMA det(u,v) = -det(v,u)

    det_symm_0 : LEMMA det(u,v) = 0 IFF det(v,u) = 0

    sq_det    : LEMMA sq(det(u,v)) = sqv(v)*sqv(u) - sq(u*v)

    det_norm  : LEMMA det(u,v) <= norm(u)*norm(v)

    det_perpR : LEMMA det(u,v) = u*perpR(v)
    det_perpL : LEMMA det(u,v) = perpL(u)*v

    dot_perpR  : LEMMA u*v = -det(u,perpR(v))
    dot_perpL  : LEMMA u*v = -det(perpL(u),v)

    perpR_dot : LEMMA perpR(u)*v = -det(u,v)
    perpL_dot : LEMMA u*perpL(v) = -det(u,v)

    det_dot_0 : LEMMA
      det(nzu,nzv) = 0 IMPLIES nzu*nzv /= 0 

    AUTO_REWRITE+ det_eq_0

  END det_2D


body:
  linear_transformations_2D: THEORY

  %----------------------------------------------------------------------------
  %------------linear transformations over vect2-------------------------------
  %------------Original Date: Dec 15, 2009-------------------------------------
  %----------------------------------------------------------------------------
  %------------Authors: Anthony Narkawicz, NASA--------------------------------
  %----------------------------------------------------------------------------
  %----------------------------------------------------------------------------
  %----------------------------------------------------------------------------

  BEGIN

  IMPORTING vectors_2D, det_2D, basis_2D

     u,v,w     : VAR Vector
     a,b,c     : VAR real
     nza       : VAR nzreal
     L,J	     : VAR [Vector -> Vector] % Linear Transformations
     F,G	     : VAR [Vector -> real] % Linear Functionals


  % LINEAR TRANSFORMATIONS

    linear_transform?(L): bool = 
      FORALL (u,v: Vector): FORALL (a,b: real): L(a*u+b*v) = a*L(u) + b*L(v)

  % Basic Properties

    linear_transform_zero: LEMMA
      linear_transform?(L) IMPLIES L(zero) = zero

    linear_transform_scal: LEMMA
      linear_transform?(L) IMPLIES 
      FORALL (u: Vector, a: real): L(a*u) = a*L(u)

    linear_transform_add: LEMMA
      linear_transform?(L) IMPLIES
      FORALL (u,v: Vector): L(u+v) = L(u) + L(v)

    linear_transform_sub: LEMMA
      linear_transform?(L) IMPLIES
      FORALL (u,v: Vector): L(u-v) = L(u) - L(v)

  % Equivalent Characterizations

    linear_transform_rew: LEMMA linear_transform?(L) IFF
      (FORALL (u,v: Vector): L(u+v) = L(u) + L(v)) AND
      (FORALL (u: Vector, a: real): L(a*u) = a*L(u))

    linear_transform_alt_left: LEMMA linear_transform?(L) IFF
      FORALL (u,v: Vector): FORALL (a: real): L(a*u + v) = a*L(u) + L(v)

    linear_transform_alt_right: LEMMA linear_transform?(L) IFF
      FORALL (u,v: Vector): FORALL (a: real): L(u+a*v) = L(u) + a*L(v)

  % Other Theorems

    linear_transform_perp_unique: LEMMA u /= zero AND v /= zero AND
      linear_transform?(L) AND
      linear_transform?(J) AND
      orthogonal?(u,v) AND
      L(u) = J(u) AND
      L(v) = J(v)
      IMPLIES
      L = J


  % Auto rewrites for linear transformations Vect2 -> Vect2
     AUTO_REWRITE+ linear_transform_zero           % L(zero) = zero



  % LINEAR FUNCTIONALS

    linear_functional?(F): bool = 
      FORALL (u,v: Vector): FORALL (a,b: real): F(a*u+b*v) = a*F(u) + b*F(v)

  % Basic Properties

    linear_functional_zero: LEMMA
      linear_functional?(F) IMPLIES F(zero) = 0

    linear_functional_scal: LEMMA
      linear_functional?(F) IMPLIES 
      FORALL (u: Vector, a: real): F(a*u) = a*F(u)

    linear_functional_add: LEMMA
      linear_functional?(F) IMPLIES
      FORALL (u,v: Vector): F(u+v) = F(u) + F(v)

    linear_functional_sub: LEMMA
      linear_functional?(F) IMPLIES
      FORALL (u,v: Vector): F(u-v) = F(u) - F(v)

    kernel_functional_nonempty: LEMMA
      linear_functional?(F) IMPLIES
      EXISTS (v: Vector): v /= zero AND F(v) = 0

    linear_functional_is_dot: LEMMA
      linear_functional?(F) IMPLIES
      EXISTS (w: Vector): F = (LAMBDA (v: Vector): w*v)

  % Equivalent Characterizations

    linear_functional_rew: LEMMA linear_functional?(F) IFF
      (FORALL (u,v: Vector): F(u+v) = F(u) + F(v)) AND
      (FORALL (u: Vector, a: real): F(a*u) = a*F(u))

    linear_functional_alt_left: LEMMA linear_functional?(F) IFF
      FORALL (u,v: Vector): FORALL (a: real): F(a*u + v) = a*F(u) + F(v)

    linear_functional_alt_right: LEMMA linear_functional?(F) IFF
      FORALL (u,v: Vector): FORALL (a: real): F(u+a*v) = F(u) + a*F(v)

  % Other Theorems

    linear_functional_perp_unique: LEMMA u /= zero AND v /= zero AND
      linear_functional?(F) AND
      linear_functional?(G) AND
      orthogonal?(u,v) AND
      F(u) = G(u) AND
      F(v) = G(v)
      IMPLIES
      F = G

    linear_functional_is_perp_dot: LEMMA
      linear_functional?(F) AND 
      u/=zero AND
      F(u) = 0
      IMPLIES
      (EXISTS (rzk: real): F = (LAMBDA (v: Vector): rzk*det(v,u)))

    linear_functional_perp_signs_unique: LEMMA v /= zero AND
      linear_functional?(F) AND
      linear_functional?(G) AND
      F(u)*G(u) > 0 AND
      F(v) = 0 AND
      G(v) = 0
      IMPLIES
      FORALL (w: Vector): F(w)*G(w) >= 0


  % Auto rewrites for linear functionalations Vect2 -> Vect2
     AUTO_REWRITE+ linear_functional_zero           % F(zero) = zero




  END linear_transformations_2D


body:
  vect3_fun_ops: THEORY
  %---------------------------------------------%
  %  Operations on functions : [Vect3 -> real]  %
  %---------------------------------------------%
  BEGIN
    IMPORTING vectors_3D

    f, f1, f2: VAR [Vect3 -> real]
    f3        : VAR [Vect3 -> nzreal]
    a         : VAR real
    x, y      : VAR Vect3

    const_fun(a) : [Vect3 -> real] = LAMBDA x : a ;

    +(f1, f2) : [Vect3 -> real] = LAMBDA x : f1(x) + f2(x);
   
    -(f1)     : [Vect3 -> real] = LAMBDA x : -f1(x);

    *(f1, f2) : [Vect3 -> real] = LAMBDA x : f1(x) * f2(x);

    *(a, f1)  : [Vect3 -> real] = LAMBDA x : a * f1(x);

    -(f1, f2) : [Vect3 -> real] = LAMBDA x : f1(x) - f2(x);

    /(f1, f3) : [Vect3 -> real] = LAMBDA x : f1(x) / f3(x);

    /(a, f3)  : [Vect3 -> real] = LAMBDA x : a / f3(x);

    inv(f3)   : [Vect3 -> real] = 1 / f3;

    abs(f1)   : [Vect3 -> nnreal] = LAMBDA x : abs(f1(x));

    n: VAR nat
    ^(f,n)    : [Vect3 -> real] =  (LAMBDA (v:Vect3): f(v)^n)

    %------------------
    %  Rewrite rules
    %------------------

    diff_function    : LEMMA f1 - f2 = f1 + (- f2)

    div_function     : LEMMA f1 / f3 = f1 * (1 /f3)

    scal_function    : LEMMA a * f1 = const_fun(a) * f1

    scaldiv_function : LEMMA a / f3 = const_fun(a) / f3

    negneg_function  : LEMMA - (- f1) = f1


  END vect3_fun_ops

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

  % Subtype TCC generated (at line 34, column 57) for  n
      % expected type  {i: int | f(v) /= 0 OR i >= 0}
  caret_TCC1: OBLIGATION
    FORALL (f: [Vect3 -> real], n: nat, v: Vect3): f(v) /= 0 OR n >= 0;


body:
  vect2_fun_ops: THEORY
  %------------------------------------------%
  %  Operations on functions : [Vect2 -> real]  %
  %------------------------------------------%
  BEGIN
    IMPORTING vectors_2D

    f, f1, f2: VAR [Vect2 -> real]
    f3        : VAR [Vect2 -> nzreal]
    a         : VAR real
    x, y      : VAR Vect2

    const_fun(a) : [Vect2 -> real] = LAMBDA x : a ;

    +(f1, f2) : [Vect2 -> real] = LAMBDA x : f1(x) + f2(x);
   
    -(f1)     : [Vect2 -> real] = LAMBDA x : -f1(x);

    *(f1, f2) : [Vect2 -> real] = LAMBDA x : f1(x) * f2(x);

    *(a, f1)  : [Vect2 -> real] = LAMBDA x : a * f1(x);

    -(f1, f2) : [Vect2 -> real] = LAMBDA x : f1(x) - f2(x);

    /(f1, f3) : [Vect2 -> real] = LAMBDA x : f1(x) / f3(x);

    /(a, f3)  : [Vect2 -> real] = LAMBDA x : a / f3(x);

    inv(f3)   : [Vect2 -> real] = 1 / f3;

    abs(f1)   : [Vect2 -> nnreal] = LAMBDA x : abs(f1(x));

    n: VAR nat
    ^(f,n)    : [Vect2 -> real] =  (LAMBDA (v:Vect2): f(v)^n)

    %------------------
    %  Rewrite rules
    %------------------

    diff_function    : LEMMA f1 - f2 = f1 + (- f2)

    div_function     : LEMMA f1 / f3 = f1 * (1 /f3)

    scal_function    : LEMMA a * f1 = const_fun(a) * f1

    scaldiv_function : LEMMA a / f3 = const_fun(a) / f3

    negneg_function  : LEMMA - (- f1) = f1


  END vect2_fun_ops

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

  % Subtype TCC generated (at line 34, column 57) for  n
      % expected type  {i: int | f(v) /= 0 OR i >= 0}
  caret_TCC1: OBLIGATION
    FORALL (f: [Vect2 -> real], n: nat, v: Vect2): f(v) /= 0 OR n >= 0;


body:
  vect_fun_ops[n: posnat]: THEORY
  %----------------------------------------------%
  %  Operations on functions : [Vector -> real]  %
  %----------------------------------------------%
  BEGIN
    IMPORTING vectors[n]

    f, f1, f2: VAR [Vector -> real]
    f3        : VAR [Vector -> nzreal]
    a         : VAR real
    x, y      : VAR Vector

    const_fun(a) : [Vector -> real] = LAMBDA x : a ;

    +(f1, f2) : [Vector -> real] = LAMBDA x : f1(x) + f2(x);
   
    -(f1)     : [Vector -> real] = LAMBDA x : -f1(x);

    *(f1, f2) : [Vector -> real] = LAMBDA x : f1(x) * f2(x);

    *(a, f1)  : [Vector -> real] = LAMBDA x : a * f1(x);

    -(f1, f2) : [Vector -> real] = LAMBDA x : f1(x) - f2(x);

    /(f1, f3) : [Vector -> real] = LAMBDA x : f1(x) / f3(x);

    /(a, f3)  : [Vector -> real] = LAMBDA x : a / f3(x);

    inv(f3)   : [Vector -> real] = 1 / f3;

    abs(f1)   : [Vector -> nnreal] = LAMBDA x : abs(f1(x));

    m: VAR nat
    ^(f,m)    : [Vector -> real] =  (LAMBDA (v:Vector): f(v)^m)

    %------------------
    %  Rewrite rules
    %------------------

    diff_function    : LEMMA f1 - f2 = f1 + (- f2)

    div_function     : LEMMA f1 / f3 = f1 * (1 /f3)

    scal_function    : LEMMA a * f1 = const_fun(a) * f1

    scaldiv_function : LEMMA a / f3 = const_fun(a) / f3

    negneg_function  : LEMMA - (- f1) = f1


  END vect_fun_ops

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

  % Subtype TCC generated (at line 34, column 59) for  m
      % expected type  {i: int | f(v) /= 0 OR i >= 0}
  caret_TCC1: OBLIGATION
    FORALL (f: [Vector[n] -> real], m: nat, v: Vector[n]):
      f(v) /= 0 OR m >= 0;


body:
  ECEF: THEORY
  %----------------------------------------------------------------------------
  %
  % Earth-Centered, Earth-Fixed Cartesian coordinate system
  %
  %----------------------------------------------------------------------------
  BEGIN

    IMPORTING trig@trig_basic,
    	    vectors_3D

    r : VAR posreal % Radius of the Earth
    lat,lon : VAR real

    spherical2xyz(r,lat,lon): Nz_vect3 =   % Convert LatLon to ECEF
      LET theta = pi/2 - lat,
      	phi   = pi-lon,
    	x     = r*sin(theta)*cos(phi),
    	y     = r*sin(theta)*sin(phi),
    	z     = r*cos(theta)
      IN (x,y,z)

    spherical2xyz_norm: LEMMA
      LET vv = spherical2xyz(r,lat,lon) IN norm(vv) = r

  END ECEF

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

  % Subtype TCC generated (at line 16, column 4) for
      % mk_vect3(LET theta = pi / 2 - lat,
      %              phi = pi - lon,
      %              x = r * sin(theta) * cos(phi),
      %              y = r * sin(theta) * sin(phi),
      %              z = r * cos(theta)
      %            IN (x, y, z))
      % expected type  Nz_vect3
  spherical2xyz_TCC1: OBLIGATION
    FORALL (r: posreal, lat: real, lon: real):
      mk_vect3(LET theta = pi / 2 - lat,
                   phi = pi - lon,
                   x = r * sin(theta) * cos(phi),
                   y = r * sin(theta) * sin(phi),
                   z = r * cos(theta)
                 IN (x, y, z))
       /= zero;

  % Subtype TCC generated (at line 8, column 41) for
      % (# x
      %      := (LET theta = pi / 2 - lat,
      %              phi = pi - lon,
      %              x = r * sin(theta) * cos(phi),
      %              y = r * sin(theta) * sin(phi),
      %              z = r * cos(theta)
      %            IN (x, y, z))`1,
      %    y
      %      := (LET theta = pi / 2 - lat,
      %              phi = pi - lon,
      %              x = r * sin(theta) * cos(phi),
      %              y = r * sin(theta) * sin(phi),
      %              z = r * cos(theta)
      %            IN (x, y, z))`2,
      %    z
      %      := (LET theta = pi / 2 - lat,
      %              phi = pi - lon,
      %              x = r * sin(theta) * cos(phi),
      %              y = r * sin(theta) * sin(phi),
      %              z = r * cos(theta)
      %            IN (x, y, z))`3 #)
      % expected type  Nz_vect3
  spherical2xyz_TCC2: OBLIGATION
    FORALL (r: posreal, lat: real, lon: real):
      (# x
           := (LET theta = pi / 2 - lat,
                   phi = pi - lon,
                   x = r * sin(theta) * cos(phi),
                   y = r * sin(theta) * sin(phi),
                   z = r * cos(theta)
                 IN (x, y, z))`1,
         y
           := (LET theta = pi / 2 - lat,
                   phi = pi - lon,
                   x = r * sin(theta) * cos(phi),
                   y = r * sin(theta) * sin(phi),
                   z = r * cos(theta)
                 IN (x, y, z))`2,
         z
           := (LET theta = pi / 2 - lat,
                   phi = pi - lon,
                   x = r * sin(theta) * cos(phi),
                   y = r * sin(theta) * sin(phi),
                   z = r * cos(theta)
                 IN (x, y, z))`3 #)
       /= zero;


body:
  cross_3D: THEORY
  %------------------------------------------------------------------------------
  % 
  %  3D cross-product and mixed product (e.g. a*cross(b,c)) and 
  %  linear independence of two vectors
  %
  %  cross(a,b) =  a x b =  | i     j      k  |
  %                         | a_x   a_y   a_z |
  %                         | b_x   b_y   b_z |
  %
  %  Author: Rick Butler   NASA Langley Research Center
  %                        2-7-2008
  %
  %------------------------------------------------------------------------------
  BEGIN

    IMPORTING vectors_3D

    u,v,w,z : VAR Vect3
    k,k1,k2 : VAR real
    nzu,nzv : VAR Nz_vect3


  % ------------- vector cross product ------------

    cross(u,v): Vector = (u`y*v`z - v`y*u`z,
                          u`z*v`x - v`z*u`x,
                          u`x*v`y - v`x*u`y)

    cross_zero_left  : LEMMA cross(zero,v) = zero

    cross_zero_right : LEMMA cross(v,zero) = zero

    cross_anticomm   : LEMMA cross(u,v) = -cross(v,u)

    cross_scal_left  : LEMMA cross(k*u,v) = k*cross(u,v)

    cross_scal_right : LEMMA cross(u,k*v) = k*cross(u,v)

    cross_dist       : LEMMA cross(u,v+w) = cross(u,v) + cross(u,w)

    Lagrange_Identity: LEMMA cross(u,v)*cross(w,z) = (u*w)*(v*z)-(u*z)*(v*w)

    cross_cross      : LEMMA cross(cross(u,v),w) = (u*w)*v - (v*w)*u 

  %  ------------ linear dependence ------------

     linearly_dependent?(u,v): bool = 
         (EXISTS (k1,k2: real): (k1 /= 0 OR k2 /= 0) AND
                                 k1*u + k2*v = zero)

     linearly_independent?(a,b: Vect3): bool = 
       NOT linearly_dependent?(a,b)

     lin_indep_cross: LEMMA 
       linearly_dependent?(nzu,nzv) IFF cross(nzu,nzv) = zero
   
    % ------------ mixed product ------------
    % ------------ aka triple product, aka determinant of vectors a, b, c

    ;[||](u,v,w): real = u*cross(v,w)

    mixed_prod(u,v,w): MACRO real = [|u,v,w|]

    mixed_prod_perm     : LEMMA [|u,v,w|] = [|v,w,u|]

    mixed_prod_perm2    : LEMMA [|u,v,w|] = [|w,u,v|]

    mixed_prod_perm_neg : LEMMA [|u,v,w|] = -[|v,u,w|]
   
    mixed_prod_scal1    : LEMMA [|k*u,v,w|] = k*[|u,v,w|] 
    mixed_prod_scal2    : LEMMA [|u,k*v,w|] = k*[|u,v,w|] 
    mixed_prod_scal3    : LEMMA [|u,v,k*w|] = k*[|u,v,w|] 

    mixed_prod_dist     : LEMMA [|u+z,v,w|] = [|u,v,w|] + [|z,v,w|]

    cross_cross_mixed   : LEMMA cross(cross(u,v),cross(w,z)) = 
                                [|u,v,z|]*w - [|u,v,w|]*z
  END cross_3D 


body:
  distance_3D: THEORY
  BEGIN

     IMPORTING vectors_3D

     p,p0,p1,p2,u,v,v0,v1,v2: VAR Vect3

     t: VAR posreal

  %  ------- distance function -----

     sq_dist(p1,p2): nnreal = sq(p1`x-p2`x) + sq(p1`y-p2`y) + sq(p1`z-p2`z) 

     dist(p1,p2)   : nnreal = sqrt(sq_dist(p1,p2))


     dist_eq_args : LEMMA  dist(p,p) = 0

     dist_zero_l  : LEMMA  dist(zero,p) = norm(p)
     dist_zero_r  : LEMMA  dist(p,zero) = norm(p)

     dist_sym     : LEMMA  dist(p1,p2) = dist(p2,p1)

     dist_eq_0    : LEMMA  dist(p1,p2) = 0 IFF p1 = p2 

     dist_norm    : LEMMA  dist(u,v) = norm(u-v)

     dist_rel     : LEMMA  dist(p+p1,p+p2) = dist(p1,p2)
    
     sq_dist_is_dist_sq: LEMMA sq_dist(p1,p2) = sq(dist(p1,p2))  

     sq_dist_norm : LEMMA sq_dist(p1,p2) = sq(norm(p1-p2))

     sq_dist_sym  : LEMMA sq_dist(p1,p2) = sq_dist(p2,p1)

     sq_dist_le   : LEMMA sq_dist(v1,v2) <= sq_dist(p1,p2) IMPLIES
                              dist(v1,v2) <= dist(p1,p2)          

     sq_dist_lt   : LEMMA sq_dist(v1,v2) <  sq_dist(p1,p2) IMPLIES
                              dist(v1,v2) <  dist(p1,p2)          

     dist_ge_x    : LEMMA dist(p1,p2) >= abs(p1`x - p2`x)  

     dist_ge_y    : LEMMA dist(p1,p2) >= abs(p1`y - p2`y)  

     dist_ge_z    : LEMMA dist(p1,p2) >= abs(p1`z - p2`z)  

     sq_dist_dist : LEMMA sq(dist(p2,p0)) = sq(dist(p1,p0)) + sq(dist(p1,p2)) 
                                               - 2*(p1-p0)*(p1-p2)

     dist_triangle: LEMMA dist(p0,p2) <= dist(p0,p1) + dist(p1,p2) 

     dist_tri_sub : LEMMA abs(dist(p0,p2) - dist(p1,p2)) <= dist(p0,p1)



     AUTO_REWRITE+ dist_eq_args
  %  AUTO_REWRITE+ dist_zero_l  
  %  AUTO_REWRITE+ dist_zero_r  

  %  ------- Predicates

     r: VAR real

     on_circle?(p,r): bool = dist(p,zero) = r   

     on_line?(p1,p2,p): bool = 
                  EXISTS (x : real) : p = p1 + x * (p2 - p1) 

     on_segment?(p1,p2,p): bool = 
                  EXISTS (x : { y: nnreal | y <= 1}) : p = p1 + x * (p2 - p1) 


     on_segment_beg: LEMMA on_segment?(p1,p2,p1)
     on_segment_end: LEMMA on_segment?(p1,p2,p2)
     on_line_beg   : LEMMA on_line?(p1,p2,p1)
     on_line_end   : LEMMA on_line?(p1,p2,p2)


     AUTO_REWRITE+ on_segment_beg
     AUTO_REWRITE+ on_segment_end
     AUTO_REWRITE+ on_line_beg
     AUTO_REWRITE+ on_line_end


     on_segment_on_line: LEMMA on_segment?(p1,p2,p1) IMPLIES on_line?(p1,p2,p1)

  END distance_3D


body:
  lines_3D: THEORY
  %----------------------------------------------------------------------------
  % The traditional way to defines a line L is by specifying two distinct points,
  % P0 and P1, on it.  
  % 
  % A line L can also be defined by a point and a direction.  Let P0 be a
  % point on the line L and let dv be a nonzero vector specifying the direction
  % of the line.  This is equivalent to the two point definition, since we
  % could just put dv=(P1-P0).
   
  % We can also add dynamics to our line.  If we assume a particle is
  % moving in a line with a constant velocity, then we can define
  % this linear motion using the location of the point at time zero,
  % a velocity vector and a time parameter t:
  % 
  %       p0 + t*vel
  % 
  % which provides the location of the particle at time t.
  %
  % Author: Ricky Butler              NASA Langley Research Center
  %----------------------------------------------------------------------------
  BEGIN

     IMPORTING distance_3D
                                       %     Basic        |   Dynamic
                                       %------------------|-----------------
     Line : Type = [# p: Vect3,        % point on the line| position at time 0
                      v: Nz_vect3 #]   % direction vector | velocity vector

     Line3D: TYPE = Line  ; 

    -(L: Line): Line = (# p := L`p, v := -L`v #)

     p0 (L: Line): MACRO Vect3 = p(L)
     vel(L: Line): MACRO Vect3 = v(L)

     vv: VAR [Vect3,Nz_vect3]
     vecpair_to_Line(vv): MACRO Line = (# p := vv`1, v := vv`2 #)

     CONVERSION vecpair_to_Line ;                        %% NEW %%


     p,p1,p2,u,v,v0,v1,v2: VAR Vect3
     t: VAR nzreal


     loc(L: Line)(tt: real): MACRO Vect3 = p(L) + tt*v(L)

  %  ------- generate vector from two points

     vec_from(p1,p2) : Vect3 = p2 - p1

     line_from(p1,(p2:{v| v /= p1})): Line = (p1,vec_from(p1,p2))

     vec_from_eq_args : LEMMA vec_from(p,p) = zero


  %  ------- generate velocity vector from two points and transport time

     vel_from_tm(p1,p2,t): { v | p2 = p1 + t*v } = 1/t*(p2 - p1)

     line_from_tm(p1,(p2:{v| v /= p1}),t): Line = (p1,vel_from_tm(p1,p2,t))

     vel_from_tm_nz      : LEMMA p1 /= p2 IMPLIES vel_from_tm(p1,p2,t) /= zero

     vel_from_tm_lem     : LEMMA p2 = p1 + t*vel_from_tm(p1,p2,t)

     vel_from_tm_rew     : LEMMA vel_from_tm(p1,p2,t) = 1/t*(p2 - p1)

     vel_from_tm_eq_args : LEMMA vel_from_tm(p,p,t) = zero

     vel_from_tm_length  : LEMMA sq(norm(vel_from_tm(p1,p2,t))) =
                                   sq_dist(p1,p2)/sq(t)

  %  ------- generate velocity vector from two points and speed ------

     s: VAR posreal

     vel_from_spd(p1,p2,s):  Vect3 = IF p1 = p2 then zero
                                     ELSE s/dist(p1,p2)*(p2-p1)
                                     ENDIF
     ps: VAR posreal
     vel_from_spd_lem: LEMMA p1 /= p2 IMPLIES
                       vel_from_spd(p1,p2,ps) = vel_from_tm(p1,p2,dist(p1,p2)/ps)


     vel_from_spd_norm: LEMMA p1 /= p2 IMPLIES
                                 vel_from_spd(p1,p2,s) = s*normalize(p2-p1)

     pt: VAR posreal
     gen_speed(p1,(p2:{v| v /= p1}),pt): { s1: nnreal | s1 = 1/pt * dist(p1,p2) }


  %  ------- generate velocity vector from a point, heading, speed  ------

  %   IMPORTING trig@trig

  %   hdg: VAR posreal
  %   vel_from_hdg(p1,hdg,s): Vect3 = LET p2 = p1+(cos(hdg),sin(hdg)) IN
  %                                       vel_from_spd(p1,p2,s)


  %  -------------- Line Predicates -----------------

     L,L1,L2: VAR Line

     on_line?(p,L): bool = EXISTS (x : real) : p = p(L) + x * v(L)

     on_segment?(p,L): bool =
                  EXISTS (x : { y: nnreal | y <= 1}) : p = p(L) + x * v(L)

     orthogonal?(L1,L2): bool = ^(v(L1))*^(v(L2)) = 0 

     parallel?(L1,L2)  : bool = ^(v(L1))*^(v(L2)) = 1 OR ^(v(L1))*^(v(L2)) = -1 

     on_line_lem: LEMMA FORALL (p2:{v|v /= p1}): on_line?(p1, line_from(p1,p2)) AND on_line?(p2, line_from(p1,p2))

     on_line_neg: LEMMA on_line?(p, L) IMPLIES on_line?(p, -L)

     on_line_sym: LEMMA FORALL (p2:{v|v /= p1}): on_line?(p, line_from(p1,p2)) IMPLIES on_line?(p, line_from(p2,p1)) 

  %  -------------- Generate Dynamic Lines -------

     gen_line_tm(p1,(p2:{v| v /= p1}),t) : Line = (# p := p1,
                                      v := vel_from_tm(p1,p2,t) #)

     gen_line_spd(p1,(p2:{v| v /= p1}),s): Line = (# p := p1,
                                      v := vel_from_spd(p1,p2,s) #)


     test1: LEMMA p1 /= p2 IMPLIES on_line?(p1,gen_line_tm(p1,p2,t))
     test2: LEMMA p1 /= p2 IMPLIES on_line?(p2,gen_line_tm(p1,p2,t))
     test3: LEMMA p1 /= p2 IMPLIES on_line?(p1,gen_line_spd(p1,p2,s))
     test4: LEMMA p1 /= p2 IMPLIES on_line?(p2,gen_line_spd(p1,p2,s))


     vel_from_spd_on_line: LEMMA  LET vv = vel_from_spd(p1,p2,s) IN 
                                    p = p1 + t*vv 
                                      IMPLIES on_line?(p1,p2,p) 



  END lines_3D

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

  % Subtype TCC generated (at line 53, column 47) for  vec_from(p1, p2)
      % expected type  Nz_vect3
  line_from_TCC1: OBLIGATION
    FORALL (p1: Vect3, (p2: {v | v /= p1})): vec_from(p1, p2) /= zero;

  % Subtype TCC generated (at line 60, column 49) for  1 / t * (p2 - p1)
      % expected type  {v | p2 = p1 + t * v}
  vel_from_tm_TCC1: OBLIGATION
    FORALL (p1: Vect3, p2: Vect3, t: nzreal):
      p2 = p1 + t * (1 / t * (p2 - p1));

  % Subtype TCC generated (at line 62, column 52) for  vel_from_tm(p1, p2, t)
      % expected type  Nz_vect3
  line_from_tm_TCC1: OBLIGATION
    FORALL (p1: Vect3, (p2: {v | v /= p1}), t: nzreal):
      vel_from_tm(p1, p2, t) /= zero;

  % Subtype TCC generated (at line 80, column 42) for  dist(p1, p2)
      % expected type  nznum
  vel_from_spd_TCC1: OBLIGATION
    FORALL (p1: Vect3, p2: Vect3): NOT p1 = p2 IMPLIES dist(p1, p2) /= 0;

  % Subtype TCC generated (at line 84, column 64) for  dist(p1, p2) / ps
      % expected type  nzreal
  vel_from_spd_lem_TCC1: OBLIGATION
    FORALL (p1, p2: Vect3, ps: posreal):
      p1 /= p2 IMPLIES dist(p1, p2) / ps /= 0;

  % Subtype TCC generated (at line 88, column 67) for  p2 - p1
      % expected type  Nz_vector
  vel_from_spd_norm_TCC1: OBLIGATION
    FORALL (p1, p2: Vect3): p1 /= p2 IMPLIES p2 - p1 /= zero;

  % Existence TCC generated (at line 91, column 3) for
      % gen_speed(p1, (p2: {v | v /= p1}), pt):
      %       {s1: nnreal | s1 = 1 / pt * dist(p1, p2)}
  gen_speed_TCC1: OBLIGATION
    EXISTS (x:
              [d: [p1: Vect3, {v | v /= p1}, posreal] ->
                 {s1: nnreal | s1 = 1 / d`3 * dist(d`1, d`2)}]):
      TRUE;

  % Subtype TCC generated (at line 120, column 110) for  p1
      % expected type  {v | v /= p2}
  on_line_sym_TCC1: OBLIGATION
    FORALL (p, p1: Vect3, p2: {v | v /= p1}):
      on_line?(p, line_from(p1, p2)) IMPLIES p1 /= p2;

  % Subtype TCC generated (at line 128, column 41) for
      % vel_from_spd(p1, p2, s)
      % expected type  Nz_vect3
  gen_line_spd_TCC1: OBLIGATION
    FORALL (p1: Vect3, (p2: {v | v /= p1}), s: posreal):
      vel_from_spd(p1, p2, s) /= zero;

  % Subtype TCC generated (at line 131, column 60) for  p2
      % expected type  {v | v /= p1}
  test1_TCC1: OBLIGATION FORALL (p1, p2: Vect3): p1 /= p2 IMPLIES p2 /= p1;


body:
  perpendicular_3D: THEORY
  %----------------------------------------------------------------------------
  %
  %         Q.
  %         .\  .        
  %         . \   .
  %         .  \    .  d                          
  %         .   \     .            .
  %         .    \      .       .                 W  = Q - P0
  %       W .   c \       .  .
  %         .      \       *   P0 + t*v
  %         .       \   .                         del = (t-tp)*v
  %         .        *          
  %         .      .   P0 + tp*v
  %         .   .
  %         ..
  %         P0
  %
  %
  %    determine tp  = intersection of perpendicular line from Q to line (P0,v)
  %                  = perp_pt(Q-P0,nzv) = (W*v)/(v*v)
  %               c  = length of this perpendicular line
  %              del = (t-tp)*v
  %
  %    dist(q,L)     = distance from point q to line defined by perpendicular
  %
  %  Author: Ricky Butler              NASA Langley Research Center
  %
  %----------------------------------------------------------------------------
  BEGIN
   
      IMPORTING distance_3D

      t,tp: VAR real
      P0,Q,v,w,c,d,x,y,del: VAR Vect3

  %  In three dimensions, there are an infinite number of vectors perpendicular to a given vector
  %  but given a line and a point (not on line), the perpendicular line is uniquely determined.

      nzv: VAR Nz_vect3
      perp_pt(Q,P0,nzv): real = (Q-P0)*nzv/(nzv*nzv)

      perp_is_normal: LEMMA tp = perp_pt(Q,P0,nzv) 
                             IMPLIES
                                LET c = (P0 + tp*nzv) - Q,
                                    del = (t-tp)*nzv       IN
                                       del*c = 0


      perp_is_min: LEMMA tp = perp_pt(Q,P0,nzv) 
                         IMPLIES
                             LET d = (P0 + t*nzv) - Q,
                                 c = (P0 + tp*nzv) - Q  IN
                               norm(d) >= norm(c) 

      perp_gt_del: LEMMA tp = perp_pt(Q,P0,nzv) 
                          IMPLIES
                             LET d = (P0 + t*nzv) - Q,
                                 del = (t-tp)*nzv   IN
                               norm(d) >= norm(del) 


      perp_comps: LEMMA tp = perp_pt(Q, P0,nzv) 
                        IMPLIES
                           LET d = (P0 + t*nzv) - Q,
                               c = (P0 + tp*nzv) - Q,
                               del = (t-tp)*nzv   IN
                        sq(norm(d)) = sq(norm(del)) + sq(norm(c)) 

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

      IMPORTING lines_3D

  %   ----- distance from a point to a line --------

      p,q: VAR Vect3
      L: Var Line


      perp_pt(q,L): real = (q-p(L))*v(L)/(v(L)*v(L))

      dist(q,L): nnreal =  LET tp = perp_pt(q,L) IN
                                  dist(p(L) + tp*v(L),q)

      dist_is_min: THEOREM on_line?(p,L) IMPLIES
                            dist(q,p) >= dist(q,L)

      L1, L2: Var Line
      perpendicular?(L1,L2): bool = orthogonal?(v(L1),v(L2))

      perp_pt_perp: LEMMA q /= p(L) + perp_pt(q,L)*v(L) IMPLIES
                             perpendicular?(L,line_from(q,p(L) 
                                                         + perp_pt(q,L)*v(L)))

  %    perp_pt_parallel_perp: LEMMA LET tp = perp_pt(q,L1), 
  %                                  L2 = line_from(q,p(L1)+tp*v(L1)) IN
  %                                     parallel?(v(L2),perp(v))

  END perpendicular_3D

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

  % Subtype TCC generated (at line 41, column 42) for  (nzv * nzv)
      % expected type  nznum
  perp_pt_TCC1: OBLIGATION FORALL (nzv: Nz_vect3): (nzv * nzv) /= 0;

  % Subtype TCC generated (at line 80, column 40) for  (v(L) * v(L))
      % expected type  nznum
  perp_pt_TCC2: OBLIGATION FORALL (L: Line): (v(L) * v(L)) /= 0;

  % Subtype TCC generated (at line 92, column 56) for
      % p(L) + perp_pt(q, L) * v(L)
      % expected type  {v | v /= q}
  perp_pt_perp_TCC1: OBLIGATION
    FORALL (L: Line, q: Vect3):
      q /= p(L) + perp_pt(q, L) * v(L) IMPLIES
       p(L) + perp_pt(q, L) * v(L) /= q;


body:
  vect3_basis: THEORY
  %----------------------------------------------------------------------------
  % Given one vector of norm 1, this gives an orthonormal basis containing that vector
  %
  %----------------------------------------------------------------------------
  BEGIN
   
      IMPORTING perpendicular_3D, cross_3D

      t,tp: VAR real
      P0,Q,v,w,u,c,d,x,y,del: VAR Vect3
      nzv,nzw,nzu: VAR Nz_vect3
      R : VAR posreal % Radius of the sphere to be rotated and planed

     vect3_orthog_tox(v): Vect3 = v

     vect3_orthog_toy(v): Vect3 =
        IF v`x/=0 OR v`y /=0 THEN (v`y,-v`x,0)
        ELSE (1,0,0) ENDIF

     vect3_orthog_toy_def: LEMMA v/=zero IMPLIES orthogonal?(v,vect3_orthog_toy(v))

     vect3_orthog_toz(v): Vect3 = cross(v,vect3_orthog_toy(v))

     vect3_orthog_toz_def: LEMMA orthogonal?(v,vect3_orthog_toz(v))
     			       AND
  			       orthogonal?(vect3_orthog_toy(v),vect3_orthog_toz(v))


     %%%%%%% The normalized basis %%%%%%%

     vect3_orthonorm_tox(nzv): Normalized = ^(nzv)

     vect3_orthonorm_toy(nzv): Normalized = ^(vect3_orthog_toy(nzv))

     vect3_orthonorm_toz(nzv): Normalized = ^(vect3_orthog_toz(nzv))

     vect3_orthonorm_basis: LEMMA
       LET v = vect3_orthonorm_tox(nzv),
           u = vect3_orthonorm_toy(nzv),
  	 w = vect3_orthonorm_toz(nzv)
       IN
           orthogonal?(v,u) AND orthogonal?(u,w) AND orthogonal?(w,v)

    %%%%%%% Rotation to Equator %%%%%%%

    %%%%%%% A distance preserving map... %%%%%%%

    Equator_map(nzv)(w): Vect3 =
      LET xmult: Vect3 = vect3_orthonorm_tox(nzv),
          ymult: Vect3 = vect3_orthonorm_toy(nzv),
  	zmult: Vect3 = vect3_orthonorm_toz(nzv)
      IN
          (xmult*w,ymult*w,zmult*w)

    Equator_map_def: LEMMA normalized?(nzv) IMPLIES
      Equator_map(nzv)(nzv) = (1,0,0)

    transpose_Equator_map(nzv): [Vect3,Vect3,Vect3] =
      LET xvect: Vect3 = vect3_orthonorm_tox(nzv),
          yvect: Vect3 = vect3_orthonorm_toy(nzv),
  	zvect: Vect3 = vect3_orthonorm_toz(nzv),
  	xmultinv: Vect3 = (xvect`x,yvect`x,zvect`x),
  	ymultinv: Vect3 = (xvect`y,yvect`y,zvect`y),
  	zmultinv: Vect3 = (xvect`z,yvect`z,zvect`z)
      IN  (xmultinv,ymultinv,zmultinv)

    Equator_map_inv(nzv)(w): Vect3 =
      LET xvect: Vect3 = vect3_orthonorm_tox(nzv),
          yvect: Vect3 = vect3_orthonorm_toy(nzv),
  	zvect: Vect3 = vect3_orthonorm_toz(nzv),
  	xmultinv: Vect3 = (xvect`x,yvect`x,zvect`x),
  	ymultinv: Vect3 = (xvect`y,yvect`y,zvect`y),
  	zmultinv: Vect3 = (xvect`z,yvect`z,zvect`z)
      IN
          (xmultinv*w,ymultinv*w,zmultinv*w)

    Equator_map_inv_def: LEMMA
      Equator_map(nzv)(Equator_map_inv(nzv)(w)) = w


    %%%%%%% Translating to 2D Plane %%%%%%%

    sphere_to_2D_plane(nzv)(w): Vect2 =
      LET xmult: Vect3 = vect3_orthonorm_tox(nzv),
          ymult: Vect3 = vect3_orthonorm_toy(nzv),
  	zmult: Vect3 = vect3_orthonorm_toz(nzv)
      IN
          (ymult*w,zmult*w)

  END vect3_basis

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

  % Subtype TCC generated (at line 34, column 44) for  vect3_orthog_toy(nzv)
      % expected type  Nz_vector
  vect3_orthonorm_toy_TCC1: OBLIGATION
    FORALL (nzv: Nz_vect3): vect3_orthog_toy(nzv) /= zero;

  % Subtype TCC generated (at line 36, column 44) for  vect3_orthog_toz(nzv)
      % expected type  Nz_vector
  vect3_orthonorm_toz_TCC1: OBLIGATION
    FORALL (nzv: Nz_vect3): vect3_orthog_toz(nzv) /= zero;


body:
  angles_2D_scaf: THEORY
  BEGIN

     IMPORTING vectors_2D, trig@trig_inverses, trig@trig_extra,
               reals@abs_lems

     a: VAR real
     u: VAR Nz_vect2

     trig_prop2: LEMMA 
       cos(a) /= 0 AND u`x /= 0 AND sin(a) / cos(a) = u`y / u`x 
       IMPLIES
         sq(u`x) = sq(norm(u))*sq(cos(a))  AND 
         sq(u`y) = sq(norm(u))*sq(sin(a))  

     trig_prop: LEMMA 
       cos(a) /= 0 AND u`x /= 0 AND sin(a) / cos(a) = u`y / u`x 
       IMPLIES
         sin(a) = u`y/norm(u) AND cos(a) = u`x/norm(u) OR
         sin(a) = -u`y/norm(u) AND cos(a) = -u`x/norm(u) 

     alpha,beta : VAR nnreal_lt_2pi
     pa,pb      : VAR posreal

     sin_cos_angle: LEMMA 
       (pa*cos(alpha),pa*sin(alpha)) =(pb*cos(beta),pb*sin(beta)) 
       IMPLIES
         pa = pb AND alpha = beta 

  END angles_2D_scaf


body:
  angles_2D: THEORY
  %------------------------------------------------------------------------------
  %
  %    Provides:
  %        vfrom(a): Vect2   returns a unit vector given an angle
  %        vfrom(a,k): Vect2 returns a vector given an angle and a magnitude
  %
  %        angle(u): nnreal_lt_2pi returns an angle between 0,2*pi given a vector
  %        Angle(u): nnreal_lt_2pi returns an angle between 0,2*pi given a vector
  %                                    (defined used atan2)
  %        See angle_Angle which proves equivalence
  %
  %    Author:
  %        Rick Butler            NASA Langley Research Center
  %
  %    EXPERIMENTAL
  %
  %------------------------------------------------------------------------------
  BEGIN

     IMPORTING vectors_2D, trig@trig_inverses,
               reals@abs_lems, angles_2D_scaf, 
               trig@trig_values,
               trig@trig_inverses,
               trig@atan2

     Angle: NONEMPTY_TYPE = nnreal_lt_2pi

     a,b,c : VAR real
     alpha : VAR Angle
     k     : VAR posreal
     v     : VAR Vect2
     u     : VAR Nz_vect2

  %  -------- Vector from an angle -------------

     v_from(a: real): Vect2 = (# x := cos(a), y := sin(a) #)

     v_from(a: real, k: posreal): Vect2 = (# x := k*cos(a), y := k*sin(a) #)

     v_from_k_1: LEMMA v_from(a,1) = v_from(a)

     norm_v_from: LEMMA norm(v_from(a,k)) = k

     angle_exists_x: LEMMA  (EXISTS (a: real): u`x = norm(u) * cos(a) AND
                                               u`y = norm(u) * sin(a))

  %  -------- Angle from a vector -------------

     vec_from(a: Angle, k: posreal): MACRO Vect2 = v_from(a,k)
     
     norm_vec_from : LEMMA norm(vec_from(alpha,k)) = k

     vec_from_inj  : LEMMA injective?(vec_from)

     angle_exists: LEMMA  (EXISTS (alpha: Angle): 
                                u`x = norm(u) * cos(alpha) AND
                                u`y = norm(u) * sin(alpha))

     angle(u: Nz_vect2): {alpha: Angle | u = vec_from(alpha, norm(u))} 
                         = choose({alpha: Angle | u = vec_from(alpha, norm(u))})

     vec_from_angle   : LEMMA vec_from(angle(u),norm(u)) = u

     angle_vec_from : LEMMA angle(vec_from(alpha,k)) = alpha

     Angle(u: Nz_vect2): Angle = atan2(u`x,u`y)

     angle_Angle: LEMMA angle(u) = Angle(u)

     vec_from_Angle: LEMMA vec_from(Angle(u), norm(u)) = u

  %  -------- Special Values -----------

     x: VAR posreal
     angle_x0: LEMMA angle(mk_vect2(x,0)) = 0
     angle_0x: LEMMA angle(mk_vect2(0,x)) = pi/2
     angle_xx: LEMMA angle(mk_vect2(x,x)) = pi/4

     ngr: VAR negreal
     angle_n0: LEMMA angle(mk_vect2(ngr,0)) = pi
     angle_0n: LEMMA angle(mk_vect2(0,ngr)) = 3*pi/2

     angle_nx: LEMMA angle(mk_vect2(-x,x)) = 3*pi/4
     angle_xn: LEMMA angle(mk_vect2(x,-x)) = 7*pi/4
     angle_nn: LEMMA angle(mk_vect2(-x,-x)) = 5*pi/4

  %  --------- Properties ------------------

     vfrom_sub          : LEMMA v_from(a-b) = (cos(a-b),sin(a-b))  

     v_from_dot         : LEMMA v_from(a)*v_from(b) = cos(a-b)  

     ka,kb: VAR posreal
     v_from_dot_k       : LEMMA v_from(a,ka)*v_from(b,kb) = ka*kb*cos(a-b)  

     dot_prod_angles    : LEMMA LET s = v_from(c),
                                    nv = v_from(a),
                                    v = v_from(b) IN
                               s*(nv-v) = cos(a-c) - cos(b-c) 


  END angles_2D

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

  % Subtype TCC generated (at line 61, column 32) for
      % {alpha: Angle | u = v_from(alpha, norm(u))}
      % expected type  p: (nonempty?[Angle])
  angle_TCC1: OBLIGATION
    FORALL (u: Nz_vect2):
      nonempty?[Angle]({alpha: Angle | u = v_from(alpha, norm(u))});

  % Subtype TCC generated (at line 50, column 49) for  v_from(alpha, k)
      % expected type  u: Nz_vect2
  angle_vec_from_TCC1: OBLIGATION
    FORALL (alpha: Angle, k: posreal): v_from(alpha, k) /= zero;

  % Subtype TCC generated (at line 67, column 41) for  u`y
      % expected type  {z: real | u`x = 0 => z /= 0}
  Angle_TCC1: OBLIGATION FORALL (u: Nz_vect2): u`x = 0 => u`y /= 0;

  % Subtype TCC generated (at line 6, column 38) for  (# x := x, y := 0 #)
      % expected type  u: Nz_vect2
  angle_x0_TCC1: OBLIGATION FORALL (x: posreal): (# x := x, y := 0 #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := 0, y := x #)
      % expected type  u: Nz_vect2
  angle_0x_TCC1: OBLIGATION FORALL (x: posreal): (# x := 0, y := x #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := x, y := x #)
      % expected type  u: Nz_vect2
  angle_xx_TCC1: OBLIGATION FORALL (x: posreal): (# x := x, y := x #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := ngr, y := 0 #)
      % expected type  u: Nz_vect2
  angle_n0_TCC1: OBLIGATION
    FORALL (ngr: negreal): (# x := ngr, y := 0 #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := 0, y := ngr #)
      % expected type  u: Nz_vect2
  angle_0n_TCC1: OBLIGATION
    FORALL (ngr: negreal): (# x := 0, y := ngr #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := -x, y := x #)
      % expected type  u: Nz_vect2
  angle_nx_TCC1: OBLIGATION
    FORALL (x: posreal): (# x := -x, y := x #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := x, y := -x #)
      % expected type  u: Nz_vect2
  angle_xn_TCC1: OBLIGATION
    FORALL (x: posreal): (# x := x, y := -x #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := -x, y := -x #)
      % expected type  u: Nz_vect2
  angle_nn_TCC1: OBLIGATION
    FORALL (x: posreal): (# x := -x, y := -x #) /= zero;


body:
  between_2D: THEORY
  %------------------------------------------------------------------------------
  %
  %    Provides:
  %       between?(v1,v2)(xx)  -- true iff xx is between? v1 and v2 (within 180 of each other)
  %       betw?(v1,v2)(xx)     -- true iff xx is between? v1 and v2
  %
  %    Author:
  %        Rick Butler            NASA Langley Research Center
  %
  %    VERY EXPERIMENTAL !!!!
  %
  %------------------------------------------------------------------------------
  BEGIN

     %% --------- between? assuming v1 and v2 are within 180 of each other ----------

     IMPORTING vectors_2D, trig@trig_basic, trig@trig_ineq, angles_2D

     between?(v1,v2: Vect2)(xx: Vect2): bool =
         LET k1 = norm(v1),
             k2 = norm(v2),
             kx = norm(xx) IN
            v1*(kx*v2-k2*xx) <= 0 AND
            v2*(kx*v1-k1*xx) <= 0 

     a1,a2,a3: VAR real
     v,v1,v2,v3: VAR Vect2
     k: VAR posreal
     k1,k2,k3: VAR posreal

     between_sym: LEMMA between?(v1,v3)(v2) IFF between?(v3,v1)(v2) 


     between_cos: LEMMA LET v1 = v_from(a1,k1),
                            v2 = v_from(a2,k2),
                            v3 = v_from(a3,k3) IN
                        between?(v1,v3)(v2) IFF
                            ( cos(a3 - a1) <= cos(a3 - a2) AND
                              cos(a3 - a1) <= cos(a2 - a1) )

     is_between: LEMMA  a1 <= a2 AND a2 <= a3 AND
                        a3 - a1 <= pi AND a2 - a1 <= pi
                     IMPLIES
                        LET v1 = v_from(a1,k1),
                            v2 = v_from(a2,k2),
                            v3 = v_from(a3,k3) IN
                          between?(v1,v3)(v2)


     is_between2: COROLLARY 0 <= a1 AND a1 <= a2 AND a2 <= a3 AND a3 <= pi IMPLIES
                      LET v1 = v_from(a1,k1),
                          v2 = v_from(a2,k2),
                          v3 = v_from(a3,k3) IN
                      between?(v1,v3)(v2)


     between_lem: LEMMA LET v1 = v_from(a1,k1),
                         v2 = v_from(a2,k2),
                         v3 = v_from(a3,k3) IN
                      0 <= a1 AND a1 <= pi AND
                      0 <= a2 AND a2 <= pi AND
                      0 <= a3 AND a3 <= pi AND
                      a1 <= a3 AND
                      between?(v1,v3)(v2)
                          IMPLIES (a1 <= a2 AND a2 <= a3) 


     between_thm: THEOREM LET v1 = v_from(a1,k1),
                         v2 = v_from(a2,k2),
                         v3 = v_from(a3,k3) IN
                      0 <= a1 AND a1 <= pi AND
                      0 <= a2 AND a2 <= pi AND
                      0 <= a3 AND a3 <= pi AND
                      between?(v1,v3)(v2)
                          IMPLIES (a1 <= a2 AND a2 <= a3) OR
                                  (a3 <= a2 AND a2 <= a1)


  %% ------------ betw ----------------

     betw?(v1,v2: Nz_vect2)(xx: Nz_vect2): bool =
             angle(v1) <= angle(xx) AND angle(xx) <= angle(v2)


     betw_between: LEMMA FORALL (v1,v2,xx: Nz_vect2):
                            angle(v2) - angle(v1) <= pi AND 
                            angle(xx) - angle(v1) <= pi AND
                            betw?(v1,v2)(xx) IMPLIES between?(v1,v2)(xx)

     between_betw: LEMMA FORALL (v1,v2,xx: Nz_vect2):
                         angle(v1) <= pi AND angle(xx) <= pi AND angle(v2) <= pi AND
                         angle(v1) <= angle(v2) AND
                         between?(v1,v2)(xx) IMPLIES betw?(v1,v2)(xx) 

  END between_2D


body:
  trackAngles_scaf: THEORY
  %------------------------------------------------------------------------------
  %
  %    Provides:
  %        vfrom(a): Vect2   returns a unit vector given a real number
  %        vfrom(a,k): Vect2 returns a vector given an track and a magnitude
  %
  %    Author:
  %        Rick Butler            NASA Ltracky Research Center
  %
  %    EXPERIMENTAL
  %
  %------------------------------------------------------------------------------
  BEGIN

     IMPORTING vectors_2D, 
               reals@abs_lems, 
               trig@trig_values,
               trig@trig_inverses,
               trig@atan2, angles_2D_scaf

     Track: NONEMPTY_TYPE = nnreal_lt_2pi

     a,b,c : VAR real
     alpha : VAR Track
     k     : VAR posreal
     v     : VAR Vect2
     u     : VAR Nz_vect2


     track_exists_x: LEMMA  (EXISTS (a: real): u`x = norm(u) * sin(a) AND
                                               u`y = norm(u) * cos(a))

     track_exists  : LEMMA  (EXISTS (alpha: Track): 
                                u`x = norm(u) * sin(alpha) AND
                                u`y = norm(u) * cos(alpha))




  END trackAngles_scaf


body:
  trackAngles_2D: THEORY
  %------------------------------------------------------------------------------
  %
  %    Provides:
  %        vec_from(a,k): Vect2 returns a vector given an track and a magnitude
  %
  %        track(u): Track returns an track angle between 0,2*pi given a vector
  %                                    (defined used atan2)
  % 
  %        trk(u): atan2(u`y,u`x) is equivalent
  %
  %    Author:
  %        Rick Butler            NASA Langley Research Center
  %
  %    EXPERIMENTAL
  %
  %------------------------------------------------------------------------------
  BEGIN

     IMPORTING trackAngles_scaf

     a,b,c : VAR real
     alpha : VAR Track
     k     : VAR posreal
     v     : VAR Vect2
     u     : VAR Nz_vect2

  %  -------- Vector from an track angle 0 to 2 PI

     v_from(a: real, k: posreal): MACRO Nz_vect2 = (# x := k*sin(a), y := k*cos(a) #)

     vec_from(a: Track, k: posreal): Vect2 = v_from(a,k)

     trk(u: Nz_vect2)  : Track = atan2(u`y,u`x)

  %%   sqrt_scal      : LEMMA FORALL (x: nnreal): abs(a)*sqrt(x) = sqrt(sq(a)*x)

     track(u: Nz_vect2): {alpha: Track | u = vec_from(alpha, norm(u))} 

     norm_v_from    : LEMMA norm(v_from(a,k)) = k

     vec_from_nz    : LEMMA vec_from(alpha,k) /= zero

     norm_vec_from  : LEMMA norm(vec_from(alpha,k)) = k
   
     vec_from_inj   : LEMMA injective?(vec_from)

     vec_from_track : LEMMA vec_from(track(u),norm(u)) = u

     track_vec_from : LEMMA track(vec_from(alpha,k)) = alpha

     track_trk      : LEMMA track(u) = trk(u)

     vec_from_trk   : LEMMA vec_from(trk(u), norm(u)) = u

  %  -------- Special Values ------------------

     x: VAR posreal
     track_x0: LEMMA track(mk_vect2(x,0)) = pi/2
     track_0x: LEMMA track(mk_vect2(0,x)) = 0
     track_xx: LEMMA track(mk_vect2(x,x)) = pi/4

     ngr: VAR negreal
     track_n0: LEMMA track(mk_vect2(ngr,0)) = 3*pi/2
     track_0n: LEMMA track(mk_vect2(0,ngr)) = pi

     track_nx: LEMMA track(mk_vect2(-x,x)) = 7*pi/4
     track_xn: LEMMA track(mk_vect2(x,-x)) = 3*pi/4
     track_nn: LEMMA track(mk_vect2(-x,-x)) = 5*pi/4


  %  -------- Properties of v_from -------------

     vfrom_sub          : LEMMA v_from(a-b,1) = (sin(a-b),cos(a-b))  

     v_from_dot         : LEMMA v_from(a,1)*v_from(b,1) = cos(a-b)  

     ka,kb: VAR posreal
     v_from_dot_k       : LEMMA v_from(a,ka)*v_from(b,kb) = ka*kb*cos(a-b)  

     dot_prod_tracks    : LEMMA LET s = v_from(c,1),
                                    nv = v_from(a,1),
                                    v = v_from(b,1) IN
                               s*(nv-v) = cos(a-c) - cos(b-c) 


  END trackAngles_2D

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

  % Subtype TCC generated (at line 30, column 49) for
      % (# x := k * sin(a), y := k * cos(a) #)
      % expected type  Nz_vect2
  v_from_TCC1: OBLIGATION
    FORALL (a: real, k: posreal):
      (# x := k * sin(a), y := k * cos(a) #) /= zero;

  % Subtype TCC generated (at line 34, column 41) for  u`x
      % expected type  {z: real | u`y = 0 => z /= 0}
  trk_TCC1: OBLIGATION FORALL (u: Nz_vect2): u`y = 0 => u`x /= 0;

  % Existence TCC generated (at line 38, column 3) for
      % track(u: Nz_vect2): {alpha: Track | u = vec_from(alpha, norm(u))}
  track_TCC1: OBLIGATION
    EXISTS (x:
              [u: Nz_vect2 ->
                 {alpha: Track | u = vec_from(alpha, norm(u))}]):
      TRUE;

  % Subtype TCC generated (at line 50, column 32) for  vec_from(alpha, k)
      % expected type  u: Nz_vect2
  track_vec_from_TCC1: OBLIGATION
    FORALL (alpha: Track, k: posreal): vec_from(alpha, k) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := x, y := 0 #)
      % expected type  u: Nz_vect2
  track_x0_TCC1: OBLIGATION FORALL (x: posreal): (# x := x, y := 0 #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := 0, y := x #)
      % expected type  u: Nz_vect2
  track_0x_TCC1: OBLIGATION FORALL (x: posreal): (# x := 0, y := x #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := x, y := x #)
      % expected type  u: Nz_vect2
  track_xx_TCC1: OBLIGATION FORALL (x: posreal): (# x := x, y := x #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := ngr, y := 0 #)
      % expected type  u: Nz_vect2
  track_n0_TCC1: OBLIGATION
    FORALL (ngr: negreal): (# x := ngr, y := 0 #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := 0, y := ngr #)
      % expected type  u: Nz_vect2
  track_0n_TCC1: OBLIGATION
    FORALL (ngr: negreal): (# x := 0, y := ngr #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := -x, y := x #)
      % expected type  u: Nz_vect2
  track_nx_TCC1: OBLIGATION
    FORALL (x: posreal): (# x := -x, y := x #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := x, y := -x #)
      % expected type  u: Nz_vect2
  track_xn_TCC1: OBLIGATION
    FORALL (x: posreal): (# x := x, y := -x #) /= zero;

  % Subtype TCC generated (at line 6, column 38) for  (# x := -x, y := -x #)
      % expected type  u: Nz_vect2
  track_nn_TCC1: OBLIGATION
    FORALL (x: posreal): (# x := -x, y := -x #) /= zero;


body:
  parallel_3D: THEORY
  BEGIN
    IMPORTING cross_3D, reals@abs_lems

    nzu,nzv     : VAR Nz_vector

    abs_cross_par : LEMMA
      abs(^(nzu)*^(nzv)) = 1 
      IFF
      cross(nzu,nzv) = zero

    parallel_dot_1: LEMMA 
      parallel?(nzu,nzv) IFF abs(^(nzu)*^(nzv)) = 1 

    parallel_cross_zero: LEMMA 
      parallel?(nzu,nzv) IFF cross(nzu,nzv) = zero

  END parallel_3D


body:
  parallel_2D: THEORY
  BEGIN
    IMPORTING det_2D

    nzu,nzv     : VAR Nz_vector

    abs_det_par : LEMMA
      abs(^(nzu)*^(nzv)) = 1 
      IFF
      det(nzu,nzv) = 0

    parallel_dot_1: LEMMA 
      parallel?(nzu,nzv) IFF abs(^(nzu)*^(nzv)) = 1 

    parallel_det_0: LEMMA 
      parallel?(nzu,nzv) IFF det(nzu,nzv) = 0

    dot_perpL_parallel: LEMMA nzu*nzv = 0 IMPLIES
                             parallel?(perpL(nzu),nzv)


    dot_perpR_parallel: LEMMA nzu*nzv = 0 IMPLIES
                             parallel?(perpR(nzu),nzv)

  END parallel_2D


body:
  vectors_4D_def : THEORY
  BEGIN
    
    IMPORTING vectors_3D_def

    Vect4 : TYPE = Vect3 WITH [#  t: real  #]
    
    mk_vect4(x,y,z,t: real) : MACRO Vect4 =  (# x := x, y := y, z := z, t := t #) 

    CONVERSION mk_vect4
    
  END vectors_4D_def


body:
  vectors_4D: THEORY
  %----------------------------------------------------------------------------
  %
  %  The Vect4 type is a record [#  x, y, z, t: real  #]
  %  but the vect4 conversion allows one to write (x,y,z,t) 
  %
  %----------------------------------------------------------------------------
  BEGIN

     IMPORTING reals@sqrt, vectors_4D_def

     Vector   : TYPE = Vect4
     u,v,w    : VAR Vector
     a,b,c,d  : VAR real
     nza      : VAR nzreal 

  %  ----------- Special vectors ---------------------------------------------

     zero: Vector =  (0,0,0,0)
     const_vec(a): Vector = (a,a,a,a) ;

  %  ----------- Vector Operations -------------------------------------------

     -(v)  : Vector = ( -v`x, -v`y, -v`z, -v`t ) ;

     +(u,v): Vector = ( u`x + v`x, u`y + v`y, u`z + v`z, u`t + v`t ) ;

     -(u,v): Vector = ( u`x - v`x, u`y - v`y, u`z - v`z, u`t - v`t) ;

     *(u,v): real  =  u`x * v`x + u`y * v`y + u`z * v`z + u`t * v`t ;       % dot product

     *(a,v): Vector = ( a * v`x, a * v`y,  a * v`z, a * v`t ) ;

  %  ----------- Vector Functions  -------------------------------------------

     sqv(v): nnreal = v*v

     sos(v): nnreal = sq(v`x)+sq(v`y)+sq(v`z)+sq(v`t)   

     sqv_rew        : LEMMA v*v = sqv(v)

     sqv_sos        : LEMMA sqv(v) = sos(v)

     norm(v): nnreal = sqrt(sqv(v))

     zero_vector?(v): MACRO bool =
       v = zero

     nz_vector?(v): MACRO bool = 
       v /= zero

     zero_vect4? : MACRO PRED[Vector] = zero_vector?
     nz_vect4?   : MACRO PRED[Vector] = nz_vector?

     normalized?(v): MACRO bool = 
       norm(v) = 1
   
     Nz_vector   : TYPE = (nz_vector?)
     Nz_vect4    : TYPE = Nz_vector
     Normalized  : TYPE = (normalized?)

     iv: Vector = (1,0,0,0)
     jv: Vector = (0,1,0,0)
     kv: Vector = (0,0,1,0)
     lv: Vector = (0,0,0,1)

     nzu,nzv     : VAR Nz_vector

  %  ----------- Vector Component Lemmas

     basis          : LEMMA a*iv + b*jv +c*kv + d*lv  = (a,b,c,d)

     vx_distr_add   : LEMMA (v + w)`x = v`x + w`x  
     vy_distr_add   : LEMMA (v + w)`y = v`y + w`y  
     vz_distr_add   : LEMMA (v + w)`z = v`z + w`z  
     vt_distr_add   : LEMMA (v + w)`t = v`t + w`t  

     vx_distr_sub   : LEMMA (v - w)`x = v`x - w`x  
     vy_distr_sub   : LEMMA (v - w)`y = v`y - w`y  
     vz_distr_sub   : LEMMA (v - w)`z = v`z - w`z  
     vt_distr_sub   : LEMMA (v - w)`t = v`t - w`t  

     vx_scal        : LEMMA (a*v)`x = a*v`x                       
     vy_scal        : LEMMA (a*v)`y = a*v`y                       
     vz_scal        : LEMMA (a*v)`z = a*v`z                       
     vt_scal        : LEMMA (a*v)`t = a*v`t                       

     vx_neg         : LEMMA (-v)`x = -v`x
     vy_neg         : LEMMA (-v)`y = -v`y
     vz_neg         : LEMMA (-v)`z = -v`z
     vt_neg         : LEMMA (-v)`t = -v`t

     comp_eq_x      : LEMMA u = w IMPLIES u`x = w`x       
     comp_eq_y      : LEMMA u = w IMPLIES u`y = w`y       
     comp_eq_z      : LEMMA u = w IMPLIES u`z = w`z       
     comp_eq_t      : LEMMA u = w IMPLIES u`t = w`t       

     comps_eq       : LEMMA u = w IFF u`x = w`x AND u`y = w`y AND u`z = w`z AND u`t = w`t       

     comp_zero_x    : LEMMA zero`x = 0
     comp_zero_y    : LEMMA zero`y = 0
     comp_zero_z    : LEMMA zero`z = 0
     comp_zero_t    : LEMMA zero`t = 0

     norm_xyz_eq_0  : LEMMA norm(v) = 0 IFF v`x =0 AND v`y=0 AND v`z=0 AND v`t=0
     
     norm_sqv_eq_0  : LEMMA norm(v) = 0 IFF sqv(v) = 0

     norm_eq_0      : LEMMA norm(v) = 0 IFF v = zero

     norm_zero      : LEMMA norm(zero) = 0 

     sqv_zero       : LEMMA sqv(zero) = 0

     sqv_eq_0       : LEMMA sqv(v) = 0 IFF v = zero

     v_neq_zero     : LEMMA v /= zero IFF sqv(v) > 0

     sq_dot_eq_0    : LEMMA v*v = 0 IFF v = zero

     nzv_xyz_neq_0  : LEMMA nz_vector?(v) IFF v`x /= 0 OR v`y /= 0 OR v`z /= 0 OR v`t /= 0

  %  ----------- JUDGEMENTS -------------------------------------

     nz_norm_gt_0 : JUDGEMENT 
       norm(nzu) HAS_TYPE posreal

     nz_sqv_gt_0 : JUDGEMENT 
       sqv(nzu) HAS_TYPE posreal

     nz_nvz_left : JUDGEMENT
       mk_vect4(nza,b,c,d) HAS_TYPE Nz_vector

     nz_nvz_middle : JUDGEMENT
       mk_vect4(b,nza,c,d) HAS_TYPE Nz_vector

     nz_nvz_right : JUDGEMENT
       mk_vect4(b,c,nza,d) HAS_TYPE Nz_vector

     nz_nvz_time : JUDGEMENT
       mk_vect4(b,c,d,nza) HAS_TYPE Nz_vector

     normalized_nz : JUDGEMENT
       Normalized SUBTYPE_OF Nz_vector

     neg_nzv : JUDGEMENT
       -(nzu) HAS_TYPE Nz_vector

     nz_nzv : JUDGEMENT
       *(nza,nzv) HAS_TYPE Nz_vector

  %  ----------- Vector Operation Lemmas -------------------------------------
     
     neg_zero         : LEMMA -zero = zero

     add_zero_left    : LEMMA zero + v = v

     add_zero_right   : LEMMA v + zero = v

     add_comm         : LEMMA u+v = v+u

     add_assoc        : LEMMA u+(v+w) = (u+v)+w

     add_move_left    : LEMMA u + w = v IFF w = v - u   

     add_move_right   : LEMMA u + w = v IFF u = v - w

     add_move_both    : LEMMA v = u + w IFF u = v - w

     add_neg_sub      : LEMMA v + -u = v - u

     add_cancel       : LEMMA v + w - v = w
     
     add_cancel_neg   : LEMMA -v + w + v = w

     add_cancel2      : LEMMA w - v + v = w
     
     add_cancel_neg2  : LEMMA w + v - v = w

     add_cancel_left  : LEMMA u + v = u + w IMPLIES v = w  

     add_cancel_right : LEMMA u + v = w + v IMPLIES u = w  

     add_eq_zero      : LEMMA u + v = zero IFF u = -v
   
     neg_shift        : LEMMA u = -v IFF -u = v


     sub_cancel_left  : LEMMA u - v = u - w IMPLIES v = w  

     sub_cancel_right : LEMMA u - v = w - v IMPLIES u = w 

     sub_zero_left    : LEMMA zero - v = -v

     sub_zero_right   : LEMMA v - zero = v

     sub_eq_args      : LEMMA v - v = zero

     sub_eq_zero      : LEMMA u - v = zero IFF u = v

     sub_cancel       : LEMMA v - w - v = -w

     sub_cancel_neg   : LEMMA -v - w + v = -w


     neg_add_left     : LEMMA -v + v = zero

     neg_add_right    : LEMMA v + -v = zero

     neg_distr_sub    : LEMMA -(v - u) = u - v

     neg_neg          : LEMMA --v = v

     neg_distr_add    : LEMMA -(u + v) = -u - v

     dot_neg_left     : LEMMA (-u)*w = -(u*w)

     dot_neg_right    : LEMMA u*(-w) = -(u*w)

     neg_dot_neg      : LEMMA (-u)*(-v) = u*v 

     dot_zero_left    : LEMMA zero * v = 0

     dot_zero_right   : LEMMA v * zero  = 0

     dot_comm         : LEMMA u*v = v*u

     dot_assoc        : LEMMA a*(v*w) = (a*v)*w

     dot_eq_args_ge   : LEMMA u*u >= 0

     add_comm_assoc_left : LEMMA (u+v)+w = (u+w)+v   

     add_comm_assoc_right: LEMMA u+(v+w) = v+(u+w)   

     dot_add_right  : LEMMA u*(v+w) = u*v + u*w

     dot_add_left : LEMMA (v+w)*u = v*u + w*u

     dot_sub_right  : LEMMA u*(v-w) = u*v - u*w

     dot_sub_left : LEMMA (v-w)*u = v*u - w*u

     dot_divby           : LEMMA nza*u = nza*v IMPLIES u = v   

     dot_scal_left       : LEMMA (a*u)*v = a*(u*v)

     dot_scal_right      : LEMMA u*(a*v) = a*(u*v)

     dot_scal_comm_assoc : LEMMA (a*u)*v = (a*v)*u  

     scal_comm_assoc     : LEMMA a*(b*u) = b*(a*u)  

     dot_scal_canon      : LEMMA (a*u)*(b*v) = (a*b)*(u*v)      

     scal_add_left  : LEMMA (a+b)*u = a*u + b*u 

     scal_sub_left  : LEMMA (a-b)*u = a*u - b*u 

     scal_add_right      : LEMMA a*(u+v) = a*u + a*v 

     scal_sub_right      : LEMMA a*(u-v) = a*u - a*v 

     scal_assoc     : LEMMA a*(b*u) = (a*b)*u  

     scal_neg       : LEMMA a*(-v) = (-a)*v  

     scal_cross     : LEMMA (1/nza) * v = w IFF v = nza*w 

     scal_zero      : LEMMA a * zero = zero

     scal_0         : LEMMA 0 * v = zero

     scal_1         : LEMMA 1 * v = v 

     scal_neg_1     : LEMMA -1 * v = -v

     scal_cancel    : LEMMA a*nzv = b*nzv IMPLIES a = b    

     scal_div_mult_left  : LEMMA (a/nza)*u = v IFF a*u = nza*v   %%%

     scal_div_mult_right : LEMMA u = (a/nza)*v IFF nza*u = a*v   %%%

     scal_eq_zero   : LEMMA c*v = zero IMPLIES c = 0 OR v = zero 

     dot_ge_dist    : LEMMA w*u >= w*v IMPLIES w*(u-v) >= 0 

     dot_gt_dist    : LEMMA w*u > w*v  IMPLIES w*(u-v) > 0 

     idem_right     : LEMMA a * v = v IFF (a = 1 OR v = zero)

     sqv_neg        : LEMMA sqv(-v) = sqv(v)

     sqv_add        : LEMMA sqv(u+v) = sqv(u) + sqv(v) + 2*u*v

     sqv_scal       : LEMMA sqv(a*v) = sq(a)*sqv(v)

     sqv_sub        : LEMMA sqv(u-v) = sqv(u) + sqv(v) - 2*u*v

     sqv_sub_scal    : LEMMA sqv(u-a*v) = sqv(u) - 2*a*u*v + sq(a)*sqv(v) 

     sqv_sym        : LEMMA sqv(u-v) = sqv(v-u)   

     sqrt_sqv_sq    : LEMMA sqrt(sqv(v)) * sqrt(sqv(v)) = sqv(v)

     norm_sym       : LEMMA norm(u-v) = norm(v-u)

     norm_neg       : LEMMA norm(-u)  = norm(u)

     dot_sq_norm    : LEMMA u*u = sq(norm(u))

     sq_norm        : LEMMA sq(norm(u)) = sqv(u)

     sqrt_sqv_norm  : LEMMA sqrt(sqv(v)) = norm(v)

     norms_eq_sqv   : LEMMA norm(u) = norm(v) IFF sqv(u) = sqv(v)

     norms_eq_sos   : LEMMA norm(u) = norm(v) IFF sos(u) = sos(v)

     norm_le_sqv    : LEMMA norm(u) <= norm(v) IFF sqv(u) <= sqv(v)

     norm_lt_sqv    : LEMMA norm(u) < norm(v) IFF sqv(u) < sqv(v)

     norm_scal      : LEMMA norm(a*v) = abs(a)*norm(v) ;

     ^(nzv)         : Normalized = (1/norm(nzv))*nzv              

     normalize(nzv) : MACRO Normalized = ^(nzv)

     norm_normalize : LEMMA
       norm(^(nzv)) = 1     

     dot_normalize  : LEMMA 
       ^(nzu) * ^(nzv) = nzu*nzv/(norm(nzu)*norm(nzv))

     normalize_normalize: LEMMA ^(^(nzv)) = ^(nzv)      

     normalized_id  : LEMMA norm(nzv)*^(nzv) = nzv

     normalize_scal : LEMMA ^(nza*nzv) = sign(nza)*^(nzv)

     cauchy_schwarz : LEMMA sq(u*v) <= sqv(u)*sqv(v)

     dot_norm        : LEMMA -norm(u)*norm(v) <= u*v AND u*v <= norm(u)*norm(v)

     schwartz        : LEMMA abs(u*v) <= norm(u)*norm(v)

     schwartz_cor    : LEMMA sqrt(sqv(u+v)) <= sqrt(sqv(u)) + sqrt(sqv(v))

     norm_triangle   : LEMMA norm(u-w) <= norm(u-v) + norm(v-w) 

     norm_add_le     : LEMMA norm(u+v) <= norm(u) + norm(v)

     norm_sub_le     : LEMMA norm(u-v) <= norm(u) + norm(v)

     norm_sub_ge     : LEMMA norm(u-v) >= norm(u) - norm(v)

     norm_ge_comps   : LEMMA norm(u) >= abs(u`x) AND
                             norm(u) >= abs(u`y) AND               
                             norm(u) >= abs(u`z) AND                      
                             norm(u) >= abs(u`t)

     v0,v1,v2  : VAR Vect4
     sq_norm_dist   : LEMMA LET a = v1-v0, b = v1-v2, c = v2-v0 IN    
                               sq(norm(c)) = sq(norm(a)) + sq(norm(b)) - 2*a*b

  % ---------- Predicates over vectors ---------

    parallel?(u,v): bool = 
      EXISTS (nzk:nzreal):  u = nzk*v 

    dir_parallel?(u,v): bool =  
      EXISTS (pk:posreal):  u = pk*v 

    parallel_refl : LEMMA
      parallel?(u,u)

    parallel_symm : LEMMA
      parallel?(u,v) IFF parallel?(v,u)

    parallel_trans : LEMMA
      parallel?(u,v) AND parallel?(v,w) IMPLIES
      parallel?(u,w)

    parallel_zero : LEMMA
      parallel?(u,zero) IFF u = zero

    dir_parallel : LEMMA
      dir_parallel?(u,v) IMPLIES parallel?(u,v) 

    orthogonal?(u,v): bool =  u * v = 0 

    pythagorean : LEMMA
      orthogonal?(u,v) IMPLIES
      sqv(u+v) = sqv(u) + sqv(v)

    norm_add_ge_left : LEMMA
      orthogonal?(u,v) IMPLIES
      norm(u+v) >= norm(u) 

    norm_add_ge_right : LEMMA
      orthogonal?(u,v) IMPLIES
      norm(u+v) >= norm(v)

  % ---------- Auto Rewrites  -----------------------

     AUTO_REWRITE+ neg_zero
     AUTO_REWRITE+ add_zero_left  
     AUTO_REWRITE+ add_zero_right 
     AUTO_REWRITE+ sub_zero_left  
     AUTO_REWRITE+ sub_zero_right 
     AUTO_REWRITE+ sub_eq_args    
     AUTO_REWRITE+ neg_add_left   
     AUTO_REWRITE+ neg_add_right  
     AUTO_REWRITE+ dot_zero_left  
     AUTO_REWRITE+ dot_zero_right 
     AUTO_REWRITE+ scal_zero      
     AUTO_REWRITE+ scal_0         
     AUTO_REWRITE+ scal_1 
     AUTO_REWRITE+ scal_neg_1        
     AUTO_REWRITE+ sqv_zero
     AUTO_REWRITE+ norm_zero      
     AUTO_REWRITE+ add_neg_sub    
     AUTO_REWRITE+ neg_neg        
     AUTO_REWRITE+ dot_scal_left      
     AUTO_REWRITE+ dot_scal_right     
     AUTO_REWRITE+ dot_scal_canon                 
     AUTO_REWRITE+ scal_assoc     
     AUTO_REWRITE+ sqv_neg        
     AUTO_REWRITE+ sqrt_sqv_sq
     AUTO_REWRITE+ norm_neg 
     AUTO_REWRITE+ norm_normalize      
     AUTO_REWRITE+ comp_zero_x
     AUTO_REWRITE+ comp_zero_y
     AUTO_REWRITE+ comp_zero_z
     AUTO_REWRITE+ add_cancel
     AUTO_REWRITE+ sub_cancel
     AUTO_REWRITE+ add_cancel_neg
     AUTO_REWRITE+ sub_cancel_neg
     AUTO_REWRITE+ add_cancel2
     AUTO_REWRITE+ add_cancel_neg2

  %  ---- Turn off dangerous and unhelpful rewrites for auto-rewrite-theory --

     AUTO_REWRITE-    add_comm          % LEMMA u+v = v+u
     AUTO_REWRITE-    dot_comm          % LEMMA u*v = v*u
     AUTO_REWRITE-    dot_assoc         % LEMMA a*(v*w) = (a*v)*w   
     AUTO_REWRITE-    sqv_sym           % LEMMA sqv(u-v) = sqv(v-u) 
     AUTO_REWRITE-    norm_sym          % LEMMA norm(u-v) = norm(v-u)
     AUTO_REWRITE-    dot_sq_norm       % LEMMA u*u = sq(norm(u))

  END vectors_4D

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

  % Subtype TCC generated (at line 36, column 20) for  v * v
      % expected type  nnreal
  sqv_TCC1: OBLIGATION FORALL (v: Vector): v * v >= 0;

  % Judgement subtype TCC generated (at line 126, column 5) for  norm(nzu)
      % expected type  posreal
  nz_norm_gt_0: OBLIGATION FORALL (nzu): norm(nzu) > 0;

  % Judgement subtype TCC generated (at line 129, column 5) for  sqv(nzu)
      % expected type  posreal
  nz_sqv_gt_0: OBLIGATION FORALL (nzu): sqv(nzu) > 0;

  % Judgement subtype TCC generated (at line 8, column 43) for
      % (# x := nza, y := b, z := c, t := d #)
      % expected type  Nz_vector
  nz_nvz_left: OBLIGATION
    FORALL (b, c, d, nza): (# x := nza, y := b, z := c, t := d #) /= zero;

  % Judgement subtype TCC generated (at line 8, column 43) for
      % (# x := b, y := nza, z := c, t := d #)
      % expected type  Nz_vector
  nz_nvz_middle: OBLIGATION
    FORALL (b, c, d, nza): (# x := b, y := nza, z := c, t := d #) /= zero;

  % Judgement subtype TCC generated (at line 8, column 43) for
      % (# x := b, y := c, z := nza, t := d #)
      % expected type  Nz_vector
  nz_nvz_right: OBLIGATION
    FORALL (b, c, d, nza): (# x := b, y := c, z := nza, t := d #) /= zero;

  % Judgement subtype TCC generated (at line 8, column 43) for
      % (# x := b, y := c, z := d, t := nza #)
      % expected type  Nz_vector
  nz_nvz_time: OBLIGATION
    FORALL (b, c, d, nza): (# x := b, y := c, z := d, t := nza #) /= zero;

  % Judgement subtype TCC generated (at line 144, column 5) for  x
      % expected type  Nz_vector
  normalized_nz: OBLIGATION FORALL (x: Normalized): x /= zero;

  % Judgement subtype TCC generated (at line 147, column 5) for  -nzu
      % expected type  Nz_vector
  neg_nzv: OBLIGATION FORALL (nzu): -nzu /= zero;

  % Judgement subtype TCC generated (at line 150, column 5) for  nza * nzv
      % expected type  Nz_vector
  nz_nzv: OBLIGATION FORALL (nza, nzv): nza * nzv /= zero;

  % Subtype TCC generated (at line 326, column 33) for  (1 / norm(nzv)) * nzv
      % expected type  Normalized
  caret_TCC1: OBLIGATION
    FORALL (nzv: Nz_vector): norm((1 / norm(nzv)) * nzv) = 1;


body:
  vect_4D_3D_2D: THEORY
  BEGIN

    IMPORTING vectors_2D, vectors_3D, vectors_4D

    vect2(v:Vect4): Vect2 = (v`x,v`y)
    vect3(v:Vect4): Vect3 = (v`x,v`y,v`z)

    CONVERSION vect2
    CONVERSION vect3

    v2      : VAR Vect2
    v3      : VAR Vect3
    v,w     : VAR Vect4
    a,vz,vt : VAR real
    
    vect2_add : LEMMA 
      vect2(v+w) = vect2(v) + vect2(w)

    vect2_sub   : LEMMA 
      vect2(v-w) = vect2(v) - vect2(w)

    vect2_scal : LEMMA 
      vect2(a*v) = a*vect2(v)
   
    vect2_neg : LEMMA 
      vect2(-v)  = -vect2(v) 

    vect2_zero  : LEMMA 
      vect2(zero) = zero

    vect2_eq : LEMMA
       vect2(v WITH [z := vz]) = vect2(v)

    vect2_eq_ext : LEMMA
       vect2(v2 WITH [z |-> vz] WITH [t |-> vt]) = v2

    vect2_ext_id :LEMMA
      vect2(v) WITH [z |-> v`z] WITH [t |-> v`t] = v

    AUTO_REWRITE+ vect2_zero
    AUTO_REWRITE+ vect2_eq
    AUTO_REWRITE+ vect2_eq_ext
    AUTO_REWRITE+ vect2_ext_id

    vect3_add : LEMMA 
      vect3(v+w) = vect3(v) + vect3(w)

    vect3_sub   : LEMMA 
      vect3(v-w) = vect3(v) - vect3(w)

    vect3_scal : LEMMA 
      vect3(a*v) = a*vect3(v)
   
    vect3_neg : LEMMA 
      vect3(-v)  = -vect3(v) 

    vect3_zero  : LEMMA 
      vect3(zero) = zero

    vect3_eq : LEMMA
       vect3(v WITH [t := vt]) = vect3(v)

    vect3_eq_ext : LEMMA
       vect3(v3 WITH [t |-> vt]) = v3

    vect3_ext_id :LEMMA
      vect3(v) WITH [t |-> v`t] = v

    AUTO_REWRITE+ vect3_zero
    AUTO_REWRITE+ vect3_eq
    AUTO_REWRITE+ vect3_eq_ext
    AUTO_REWRITE+ vect3_ext_id

  END vect_4D_3D_2D


body:
  vect_3D_2D: THEORY
  BEGIN

    IMPORTING vectors_2D, vectors_3D

    vect2(v:Vect3): Vect2 = (v`x,v`y)

    CONVERSION vect2

    v2   : VAR Vect2
    v,w  : VAR Vect3
    a,vz : VAR real
    
    vect2_add : LEMMA 
      vect2(v+w) = vect2(v) + vect2(w)

    vect2_sub   : LEMMA 
      vect2(v-w) = vect2(v) - vect2(w)

    vect2_scal : LEMMA 
      vect2(a*v) = a*vect2(v)
   
    vect2_neg : LEMMA 
      vect2(-v)  = -vect2(v) 

    vect2_zero  : LEMMA 
      vect2(zero) = zero

    vect2_eq : LEMMA
       vect2(v WITH [z := vz]) = vect2(v)

    vect2_eq_ext : LEMMA
       vect2(v2 WITH [z |-> vz]) = v2

    vect2_ext_id :LEMMA
      vect2(v) WITH [z |-> v`z] = v

    AUTO_REWRITE+ vect2_zero
    AUTO_REWRITE+ vect2_eq
    AUTO_REWRITE+ vect2_eq_ext
    AUTO_REWRITE+ vect2_ext_id

  END vect_3D_2D


body:
  fseqs_ops_vect3: THEORY
  %------------------------------------------------------------------------
  %
  %  Defines some convenient operations over finite sequences of Vect3
  %
  %  EXPERIMENTAL
  %
  %------------------------------------------------------------------------
  BEGIN


    IMPORTING vectors_3D, structures@fseqs_ops[Vect3]

    fs,gs: VAR fseq[Vect3]
    nefs: VAR ne_fseq[Vect3]
    i,n: VAR nat
    x: VAR real

  % ------------ pointwise addition, subtraction of a sequence of vectors

    mmin(m,n:nat): MACRO nat = IF m > n THEN n ELSE m ENDIF ;

    +(fs,gs): fseq[Vect3] = LET len = mmin(l(fs),l(gs)) IN
                      (# length := len,
                        seq := (LAMBDA n: IF n < len THEN fs(n) + gs(n) 
                                          ELSE default
                                          ENDIF)
                      #) ;


    -(fs,gs): fseq[Vect3] = LET len = mmin(l(fs),l(gs)) IN
                      (# length := len,
                        seq := (LAMBDA n: IF n < len THEN fs(n) + gs(n) 
                                          ELSE default
                                          ENDIF)
                      #) ;


  % ---------- scalar product of a sequence of reals with a sequence of vectors

    IMPORTING structures@fseqs_ops_real

    c: VAR fseq[real]

    *(c,gs): fseq[Vect3] = (# length := l(gs),
                        seq := (LAMBDA n: IF n < l(gs) THEN c(n) * gs(n) 
                                          ELSE default
                                          ENDIF)
                      #) ;

  END fseqs_ops_vect3

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

  % Subtype TCC generated (at line 25, column 30) for
      % (LAMBDA n: IF n < len THEN fs`seq(n) + gs`seq(n) ELSE default ENDIF)
      % expected type  barray[Vect3](len)
  plus_TCC1: OBLIGATION
    FORALL (fs: fseq[Vect3], gs: fseq[Vect3], len: nat):
      len = IF fs`length > gs`length THEN gs`length ELSE fs`length ENDIF
       IMPLIES
       (FORALL (i: nat):
          i >= len IMPLIES
           IF i < len THEN fs`seq(i) + gs`seq(i) ELSE default[Vect3] ENDIF =
            default[Vect3]);

  % Subtype TCC generated (at line 46, column 30) for
      % (LAMBDA n:
      %    IF n < gs`length THEN c`seq(n) * gs`seq(n) ELSE default ENDIF)
      % expected type  barray[Vect3](gs`length)
  times_TCC1: OBLIGATION
    FORALL (c: fseq[real], gs: fseq[Vect3]):
      FORALL (i: nat):
        i >= gs`length IMPLIES
         IF i < gs`length THEN c`seq(i) * gs`seq(i) ELSE default[Vect3] ENDIF
          = default[Vect3];


body:
  sigma_3D[T: TYPE FROM int]: THEORY
  %------------------------------------------------------------------------------
  %
  % Summation over Vector-valued Functions
  %
  % The summations theory introduces and defines properties of the sigma 
  % function that sums an arbitrary function F: [T -> vector] over a range
  % from low to high
  %
  %  		          high
  %		          ----
  %  sigma(low, high, F) =  \     F(j)
  %		          /
  %		          ----
  %		         j = low
  %
  %  AUTHORS:
  %
  %    Rick Butler     NASA Langley Research Center           
  %    Paul Miner      NASA Langley Research Center           
  %
  %------------------------------------------------------------------------------

  BEGIN

    ASSUMING

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

    ENDASSUMING

    IMPORTING vectors_3D

    T_low?: MACRO set[int] = {i:int | EXISTS (j:T): j <= i}
    T_low  : TYPE = {i:int | T_pred(i) OR T_low?(i)}

    T_high?: MACRO set[int] = {i:int | EXISTS (j:T): i <= j}
    T_high : TYPE = {i:int | T_pred(i) OR T_high?(i)}

    low       : VAR T_low
    high      : VAR T_high 
    l,h,n,m,i : VAR T
    rng, nn   : VAR nat
    pn        : VAR posnat
    z         : VAR int
    a,x,B     : VAR real
    v         : VAR Vector

    T_pred_lem : LEMMA low <= z AND z <= high IMPLIES T_pred(z)

    high_low_rewrite: LEMMA
     (FORALL (p: pred[[T_high, T_low]]):
       (FORALL (high: T_high), (low: T_low):
        IF high < low THEN p(high, low) 
        ELSE (FORALL (n: subrange(low, high)): p(n, low))
        ENDIF)
      IMPLIES
        (FORALL high, low:  p(high, low)))


    F, G: VAR function[T -> Vector]  

    sigma(low, high, F): RECURSIVE Vector
        = IF low > high THEN zero
          ELSE  F(high) + sigma(low, high-1, F)
          ENDIF                            
     MEASURE (LAMBDA low, high, F: abs(high+1-low))

    % provides one unfolding analogous to old definition -- useful for upgrade
    sigma_rew : LEMMA sigma(low, high, F) = IF low > high THEN zero
                                            ELSIF high = low THEN F(low) 
                                            ELSE  F(high) + sigma(low, high-1, F)
                                            ENDIF

    sigma_spl     : THEOREM T_pred(low + nn + rng) IMPLIES 
                             sigma(low, low+nn+rng, F) = 
                                sigma(low,low+nn,F) + sigma(low+nn+1,low+nn+rng,F)

    sigma_split   : THEOREM low - 1 <= z AND z <= high IMPLIES 
                              sigma(low, high, F) = 
                                       sigma(low, z, F) + sigma(z+1, high, F)

    sigma_diff    : THEOREM low - 1 <= z AND z <= high IMPLIES
                      sigma(low, high, F) - sigma(low, z, F) = sigma(z+1, high, F)

    sigma_diff_neg: THEOREM low - 1 <= z AND z <= high IMPLIES
                    sigma(low, z, F) - sigma(low, high, F) = - sigma(z+1, high, F)
   		 
    sigma_eq_arg  : THEOREM sigma(m, m, F) = F(m)

    sigma_first   : THEOREM high >= low IMPLIES 
                             sigma(low, high, F) = F(low) + sigma(low+1, high, F)

    sigma_last    : THEOREM high >= low IMPLIES 
                            sigma(low, high, F) = sigma(low, high-1, F) + F(high)

    sigma_middle : THEOREM high >= i AND i >= low IMPLIES
                            sigma(low, high, F) = sigma(low, i-1, F) + F(i) +
                                                  sigma(i+1, high, F) 

    sigma_const   : THEOREM sigma(low, high, (LAMBDA i: const_vec(x))) = 
                             IF high >= low THEN (high-low+1) * const_vec(x) 
                             ELSE zero ENDIF


    sigma_zero    : THEOREM sigma(low, high, (LAMBDA i: zero)) = zero
   		 
    sigma_scal    : THEOREM sigma(low, high, (LAMBDA i: a * F(i)))
                               = a * sigma(low, high, F)

  % Lack of an order prevents proof of the following
  %	 
  %   sigma_bound   : THEOREM low - 1 <= high AND
  %                          (FORALL i: i >= low AND i <= high IMPLIES F(i) <= B)
  %                             IMPLIES sigma(low, high, F) <= B*(high-low+1) 
  %
  %   sigma_abs     : THEOREM abs(sigma(low, high, F)) <= 
  %                               sigma(low, high, LAMBDA (n: T): abs(F(n)))
  %
  %   sigma_ge_0    : THEOREM (FORALL (n: subrange(low,high)): F(n) >= 0)
  %                                 IMPLIES sigma(low,high,F) >= 0
  %
  %   sigma_gt_0    : THEOREM low <= high AND 
  %                           (FORALL (n: subrange(low,high)): F(n) > 0)
  %                                IMPLIES sigma(low,high,F) > 0


    sigma_shift_T : THEOREM (FORALL (i:T): T_pred(i+z)) IMPLIES 
  			         sigma(low+z,high+z,F) = 
                                      sigma(low,high, (LAMBDA (i:T): F(i+z)))

    sigma_shift_T2 : THEOREM T_pred(low+z) AND T_pred(high+z) IMPLIES 
  			         sigma(low+z,high+z,F) = 
                   sigma(low,high, (LAMBDA (i:T): IF T_pred(i+z) THEN F(i+z)
                                                  ELSE zero ENDIF))


  % ------------------ Summation Involving Two Functions ------------------

    sigma_sum     : THEOREM sigma(low, high, F) + sigma(low, high, G)
                               = sigma(low, high, (LAMBDA i: F(i) + G(i)))

    sigma_minus   : THEOREM sigma(low, high, F) - sigma(low, high, G)
                               = sigma(low, high, (LAMBDA i: F(i) - G(i)))

  % Lack of an order prevents proof of the following
  %	 
  %   sigma_abs_bnd  : THEOREM (FORALL (i: subrange(low,high)): abs(F(i)) <= G(i))
  %                        IMPLIES sigma(low, high, LAMBDA (n: T): abs(F(n))) <=
  %                                        sigma(low, high, G)

    restrict(F, low, high): function[T -> Vector] = 
       (LAMBDA i: IF i < low OR i > high THEN zero ELSE F(i) ENDIF )

    sigma_restrict   : THEOREM l <= low AND h >= high IMPLIES	
                              sigma(low,high,F) = sigma(low,high,restrict(F,l,h))


    sigma_restrict_to: THEOREM sigma(low,high,F) = 
                                  sigma(low,high,restrict(F,low,high))

    sigma_restrict_eq: THEOREM restrict(F,low,high) = restrict(G,low,high) 
                                  IMPLIES sigma(low,high,F) = sigma(low,high,G) 


    sigma_eq         : THEOREM (FORALL (n: subrange(low,high)): F(n) = G(n))
                                  IMPLIES sigma(low,high,F) = sigma(low,high,G) 

  % Lack of an order prevents proof of the following
  %	 
  %   sigma_le         : THEOREM (FORALL (n: subrange(low,high)): F(n) <= G(n))
  %                                 IMPLIES sigma(low,high,F) <= sigma(low,high,G) 
  %
  %   sigma_lt         : THEOREM low <= high AND
  %                              (FORALL (n: subrange(low,high)): F(n) < G(n))
  %                                 IMPLIES sigma(low,high,F) < sigma(low,high,G) 


    sigma_with       : THEOREM low <= i AND i <= high AND
                               F = G WITH [i := v] IMPLIES
                            sigma(low, high,F) = sigma(low,high,G) - G(i) + v


  % ------------------------ Special Arguments --------------------------------
  %
  %   sigma_nonneg     : THEOREM (FORALL i: F(i) >= 0) 
  %                                  IMPLIES sigma(low, high, F) >= 0
  % 
  %   sigma_nonpos     : THEOREM (FORALL i: F(i) <= 0) 
  %                                  IMPLIES sigma(low, high, F) <= 0
  %
  %
  %   Fnnr: VAR function[T -> nonneg_real]
  %   Fnpr: VAR function[T -> nonpos_real]
  %   Fnat: VAR function[T -> nat]
  %   Fnpi: VAR function[T -> nonpos_int]
  %   Fposnat: VAR function[T -> posnat]
  %
  %
  %   sigma_Fnnr        : JUDGEMENT sigma(low,high,Fnnr) HAS_TYPE nonneg_real
  %
  %   sigma_nonpos_real : JUDGEMENT sigma(low,high,Fnpr) HAS_TYPE nonpos_real
  %
  %   sigma_nat         : JUDGEMENT sigma(low,high,Fnat) HAS_TYPE nat
  %
  %   sigma_nonpos_int  : JUDGEMENT sigma(low,high,Fnpi) HAS_TYPE nonpos_int
  %
  %   sigma_posnat      : LEMMA low <= high IMPLIES sigma(low,high,Fposnat) > 0
  %
  %   sigma_nonneg_eq_0 : THEOREM sigma(low,high,Fnnr) = 0 
  %                               AND low <= i AND i <= high IMPLIES Fnnr(i) = 0
  %
  %   sigma_nn_ge_comps : THEOREM low <= i AND i <= high IMPLIES 
  %                                   sigma(low,high,Fnnr) >= Fnnr(i) 
  % Lack of an order prevents proof of the following
  %	 


  % ------------------- Iterative Summation (tail recursion) ------------

     sum_it_def(low, high, F,v): RECURSIVE Vector
        = IF low > high THEN v
          ELSE  sum_it_def(low+1,high,F,v+F(low))
          ENDIF
     MEASURE (LAMBDA low, high, F, v: abs(high+1-low))

     sum_it(low,high,F) : Vector = sum_it_def(low,high,F,zero)

     sum_it_prop : LEMMA
       low - 1 <= i AND i <= high =>
       sum_it_def(i+1,high,F,sigma(low,i,F)) = sigma(low,high,F)

     sum_it_sigma: LEMMA sum_it(low,high,F) = sigma(low,high,F)

  END sigma_3D

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

  % Subtype TCC generated (at line 56, column 47) for  n
      % expected type  T_high
  high_low_rewrite_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low):
      NOT high < low IMPLIES
       (FORALL (n: subrange(low, high)):
          T_pred(n) OR (EXISTS (j: T): n <= j));

  % Subtype TCC generated (at line 66, column 16) for  high
      % expected type  T
  sigma_TCC1: OBLIGATION
    FORALL (low: T_low, high: T_high): NOT low > high IMPLIES T_pred(high);

  % Subtype TCC generated (at line 66, column 35) for  high - 1
      % expected type  T_high
  sigma_TCC2: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES
       T_pred(high - 1) OR (EXISTS (j: T): high - 1 <= j);

  % Termination TCC generated (at line 66, column 24) for
      % sigma(low, high - 1, F)
  sigma_TCC3: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES abs(high - 1 + 1 - low) < abs(high + 1 - low);

  % Subtype TCC generated (at line 72, column 66) for  low
      % expected type  T
  sigma_rew_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low):
      NOT low > high AND high = low IMPLIES T_pred(low);

  % Subtype TCC generated (at line 77, column 38) for  low + nn + rng
      % expected type  T_high
  sigma_spl_TCC1: OBLIGATION
    FORALL (low: T_low, nn, rng: nat):
      T_pred(low + nn + rng) IMPLIES
       T_pred(low + nn + rng) OR (EXISTS (j: T): low + nn + rng <= j);

  % Subtype TCC generated (at line 78, column 40) for  low + nn
      % expected type  T_high
  sigma_spl_TCC2: OBLIGATION
    FORALL (low: T_low, nn, rng: nat):
      T_pred(low + nn + rng) IMPLIES
       T_pred(low + nn) OR (EXISTS (j: T): low + nn <= j);

  % Subtype TCC generated (at line 78, column 58) for  low + nn + 1
      % expected type  T_low
  sigma_spl_TCC3: OBLIGATION
    FORALL (low: T_low, nn, rng: nat):
      T_pred(low + nn + rng) IMPLIES
       T_pred(low + nn + 1) OR (EXISTS (j: T): j <= low + nn + 1);

  % Subtype TCC generated (at line 82, column 48) for  z
      % expected type  T_high
  sigma_split_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      z <= high AND low - 1 <= z IMPLIES T_pred(z) OR (EXISTS (j: T): z <= j);

  % Subtype TCC generated (at line 82, column 62) for  z + 1
      % expected type  T_low
  sigma_split_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      z <= high AND low - 1 <= z IMPLIES
       T_pred(z + 1) OR (EXISTS (j: T): j <= z + 1);

  % Subtype TCC generated (at line 93, column 51) for  low
      % expected type  T
  sigma_first_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low): high >= low IMPLIES T_pred(low);

  % Subtype TCC generated (at line 93, column 64) for  low + 1
      % expected type  T_low
  sigma_first_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low):
      high >= low IMPLIES T_pred(low + 1) OR (EXISTS (j: T): j <= low + 1);

  % Subtype TCC generated (at line 96, column 59) for  high - 1
      % expected type  T_high
  sigma_last_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low):
      high >= low IMPLIES T_pred(high - 1) OR (EXISTS (j: T): high - 1 <= j);

  % Subtype TCC generated (at line 96, column 74) for  high
      % expected type  T
  sigma_last_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low): high >= low IMPLIES T_pred(high);

  % Subtype TCC generated (at line 99, column 59) for  i - 1
      % expected type  T_high
  sigma_middle_TCC1: OBLIGATION
    FORALL (high: T_high, i: T, low: T_low):
      i >= low AND high >= i IMPLIES
       T_pred(i - 1) OR (EXISTS (j: T): i - 1 <= j);

  % Subtype TCC generated (at line 100, column 54) for  i + 1
      % expected type  T_low
  sigma_middle_TCC2: OBLIGATION
    FORALL (high: T_high, i: T, low: T_low):
      i >= low AND high >= i IMPLIES
       T_pred(i + 1) OR (EXISTS (j: T): j <= i + 1);

  % Subtype TCC generated (at line 130, column 18) for  low + z
      % expected type  T_low
  sigma_shift_T_TCC1: OBLIGATION
    FORALL (low: T_low, z: int):
      (FORALL (i: T): T_pred(i + z)) IMPLIES
       T_pred(low + z) OR (EXISTS (j: T): j <= low + z);

  % Subtype TCC generated (at line 130, column 24) for  high + z
      % expected type  T_high
  sigma_shift_T_TCC2: OBLIGATION
    FORALL (high: T_high, z: int):
      (FORALL (i: T): T_pred(i + z)) IMPLIES
       T_pred(high + z) OR (EXISTS (j: T): high + z <= j);

  % Subtype TCC generated (at line 131, column 69) for  i + z
      % expected type  T
  sigma_shift_T_TCC3: OBLIGATION
    FORALL (z: int):
      (FORALL (i: T): T_pred(i + z)) IMPLIES (FORALL (i1: T): T_pred(i1 + z));

  % Subtype TCC generated (at line 134, column 18) for  low + z
      % expected type  T_low
  sigma_shift_T2_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      T_pred(high + z) AND T_pred(low + z) IMPLIES
       T_pred(low + z) OR (EXISTS (j: T): j <= low + z);

  % Subtype TCC generated (at line 134, column 24) for  high + z
      % expected type  T_high
  sigma_shift_T2_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      T_pred(high + z) AND T_pred(low + z) IMPLIES
       T_pred(high + z) OR (EXISTS (j: T): high + z <= j);

  % Subtype TCC generated (at line 167, column 64) for  n
      % expected type  T
  sigma_eq_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, n: subrange(low, high)): T_pred(n);

  % Subtype TCC generated (at line 224, column 25) for  low + 1
      % expected type  T_low
  sum_it_def_TCC1: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES T_pred(low + 1) OR (EXISTS (j: T): j <= low + 1);

  % Subtype TCC generated (at line 224, column 42) for  low
      % expected type  T
  sum_it_def_TCC2: OBLIGATION
    FORALL (low: T_low, high: T_high): NOT low > high IMPLIES T_pred(low);

  % Termination TCC generated (at line 224, column 14) for
      % sum_it_def(low + 1, high, F, v + F(low))
  sum_it_def_TCC3: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES abs(high + 1 - (low + 1)) < abs(high + 1 - low);

  % Subtype TCC generated (at line 232, column 16) for  i + 1
      % expected type  T_low
  sum_it_prop_TCC1: OBLIGATION
    FORALL (high: T_high, i: T, low: T_low):
      i <= high AND low - 1 <= i IMPLIES
       T_pred(i + 1) OR (EXISTS (j: T): j <= i + 1);


body:
  sigma_fseq_3D: THEORY
  %------------------------------------------------------------------------------
  % The summations theory provides properties of the sigma 
  % function that sums up sequence of vectors, e.g. fseq[Vect3].
  %
  %  		           l(fs)
  %		           ----
  %             sigma(fs) =  \     fs`seq(j)
  %		           /
  %		           ----
  %		          j = 0
  %

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


  BEGIN

    IMPORTING sigma_3D, structures@fseqs[Vector]

    fs: VAR fseq[Vector]

    sigma(fs): Vector = sigma(0,l(fs)-1,(LAMBDA (n: nat): fs`seq(n)))
   
                                                
  END sigma_fseq_3D

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

  % Subtype TCC generated (at line 23, column 28) for  0
      % expected type  T_low[nat]
  sigma_TCC1: OBLIGATION
    FORALL (fs: fseq[Vector]): 0 >= 0 OR (EXISTS (j: nat): j <= 0);

  % Subtype TCC generated (at line 23, column 30) for  fs`length - 1
      % expected type  T_high[nat]
  sigma_TCC2: OBLIGATION
    FORALL (fs: fseq[Vector]):
      fs`length - 1 >= 0 OR (EXISTS (j: nat): fs`length - 1 <= j);

  % Assuming TCC generated (at line 19, column 12) for  sigma_3D[nat]
      % generated from assumption sigma_3D.connected_domain
  sigma_TCC3: OBLIGATION
    FORALL (fs: fseq[Vector]):
      (FORALL (x, y: nat), (z: integer): x <= z AND z <= y IMPLIES z >= 0);


body:
  sigma_2D[T: TYPE FROM int]: THEORY
  %------------------------------------------------------------------------------
  %
  % Summation over Vector-valued Functions
  %
  % The summations theory introduces and defines properties of the sigma 
  % function that sums an arbitrary function F: [T -> vector] over a range
  % from low to high
  %
  %  		          high
  %		          ----
  %  sigma(low, high, F) =  \     F(j)
  %		          /
  %		          ----
  %		         j = low
  %
  %  AUTHORS:
  %
  %    Rick Butler     NASA Langley Research Center           
  %    Paul Miner      NASA Langley Research Center           
  %
  %------------------------------------------------------------------------------

  BEGIN

    ASSUMING

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

    ENDASSUMING

    IMPORTING vectors_2D

    T_low?: MACRO set[int] = {i:int | EXISTS (j:T): j <= i}
    T_low  : TYPE = {i:int | T_pred(i) OR T_low?(i)}

    T_high?: MACRO set[int] = {i:int | EXISTS (j:T): i <= j}
    T_high : TYPE = {i:int | T_pred(i) OR T_high?(i)}

    low       : VAR T_low
    high      : VAR T_high 
    l,h,n,m,i : VAR T
    rng, nn   : VAR nat
    pn        : VAR posnat
    z         : VAR int
    a,x,B     : VAR real
    v         : VAR Vector

    T_pred_lem : LEMMA low <= z AND z <= high IMPLIES T_pred(z)

    high_low_rewrite: LEMMA
     (FORALL (p: pred[[T_high, T_low]]):
       (FORALL (high: T_high), (low: T_low):
        IF high < low THEN p(high, low) 
        ELSE (FORALL (n: subrange(low, high)): p(n, low))
        ENDIF)
      IMPLIES
        (FORALL high, low:  p(high, low)))


    F, G: VAR function[T -> Vector]   

    sigma(low, high, F): RECURSIVE Vector
        = IF low > high THEN zero
          ELSE  F(high) + sigma(low, high-1, F)
          ENDIF                            
     MEASURE (LAMBDA low, high, F: abs(high+1-low))

    % provides one unfolding analogous to old definition -- useful for upgrade
    sigma_rew : LEMMA sigma(low, high, F) = IF low > high THEN zero
                                            ELSIF high = low THEN F(low) 
                                            ELSE  F(high) + sigma(low, high-1, F)
                                            ENDIF

    sigma_spl     : THEOREM T_pred(low + nn + rng) IMPLIES 
                             sigma(low, low+nn+rng, F) = 
                                sigma(low,low+nn,F) + sigma(low+nn+1,low+nn+rng,F)

    sigma_split   : THEOREM low - 1 <= z AND z <= high IMPLIES 
                              sigma(low, high, F) = 
                                       sigma(low, z, F) + sigma(z+1, high, F)

    sigma_diff    : THEOREM low - 1 <= z AND z <= high IMPLIES
                      sigma(low, high, F) - sigma(low, z, F) = sigma(z+1, high, F)

    sigma_diff_neg: THEOREM low - 1 <= z AND z <= high IMPLIES
                    sigma(low, z, F) - sigma(low, high, F) = - sigma(z+1, high, F)
   		 
    sigma_eq_arg  : THEOREM sigma(m, m, F) = F(m)

    sigma_first   : THEOREM high >= low IMPLIES 
                             sigma(low, high, F) = F(low) + sigma(low+1, high, F)

    sigma_last    : THEOREM high >= low IMPLIES 
                            sigma(low, high, F) = sigma(low, high-1, F) + F(high)

    sigma_middle : THEOREM high >= i AND i >= low IMPLIES
                            sigma(low, high, F) = sigma(low, i-1, F) + F(i) +
                                                  sigma(i+1, high, F) 

    sigma_const   : THEOREM sigma(low, high, (LAMBDA i: const_vec(x))) = 
                             IF high >= low THEN (high-low+1) * const_vec(x) 
                             ELSE zero ENDIF


    sigma_zero    : THEOREM sigma(low, high, (LAMBDA i: zero)) = zero
   		 
    sigma_scal    : THEOREM sigma(low, high, (LAMBDA i: a * F(i)))
                               = a * sigma(low, high, F)

  % Lack of an order prevents proof of the following
  %	 
  %   sigma_bound   : THEOREM low - 1 <= high AND
  %                          (FORALL i: i >= low AND i <= high IMPLIES F(i) <= B)
  %                             IMPLIES sigma(low, high, F) <= B*(high-low+1) 
  %
  %   sigma_abs     : THEOREM abs(sigma(low, high, F)) <= 
  %                               sigma(low, high, LAMBDA (n: T): abs(F(n)))
  %
  %   sigma_ge_0    : THEOREM (FORALL (n: subrange(low,high)): F(n) >= 0)
  %                                 IMPLIES sigma(low,high,F) >= 0
  %
  %   sigma_gt_0    : THEOREM low <= high AND 
  %                           (FORALL (n: subrange(low,high)): F(n) > 0)
  %                                IMPLIES sigma(low,high,F) > 0


    sigma_shift_T : THEOREM (FORALL (i:T): T_pred(i+z)) IMPLIES 
  			         sigma(low+z,high+z,F) = 
                                      sigma(low,high, (LAMBDA (i:T): F(i+z)))

    sigma_shift_T2 : THEOREM T_pred(low+z) AND T_pred(high+z) IMPLIES 
  			         sigma(low+z,high+z,F) = 
                   sigma(low,high, (LAMBDA (i:T): IF T_pred(i+z) THEN F(i+z)
                                                  ELSE zero ENDIF))


  % ------------------ Summation Involving Two Functions ------------------

    sigma_sum     : THEOREM sigma(low, high, F) + sigma(low, high, G)
                               = sigma(low, high, (LAMBDA i: F(i) + G(i)))

    sigma_minus   : THEOREM sigma(low, high, F) - sigma(low, high, G)
                               = sigma(low, high, (LAMBDA i: F(i) - G(i)))

  % Lack of an order prevents proof of the following
  %	 
  %   sigma_abs_bnd  : THEOREM (FORALL (i: subrange(low,high)): abs(F(i)) <= G(i))
  %                        IMPLIES sigma(low, high, LAMBDA (n: T): abs(F(n))) <=
  %                                        sigma(low, high, G)

    restrict(F, low, high): function[T -> Vector] = 
       (LAMBDA i: IF i < low OR i > high THEN zero ELSE F(i) ENDIF )

    sigma_restrict   : THEOREM l <= low AND h >= high IMPLIES	
                              sigma(low,high,F) = sigma(low,high,restrict(F,l,h))


    sigma_restrict_to: THEOREM sigma(low,high,F) = 
                                  sigma(low,high,restrict(F,low,high))

    sigma_restrict_eq: THEOREM restrict(F,low,high) = restrict(G,low,high) 
                                  IMPLIES sigma(low,high,F) = sigma(low,high,G) 


    sigma_eq         : THEOREM (FORALL (n: subrange(low,high)): F(n) = G(n))
                                  IMPLIES sigma(low,high,F) = sigma(low,high,G) 

  % Lack of an order prevents proof of the following
  %	 
  %   sigma_le         : THEOREM (FORALL (n: subrange(low,high)): F(n) <= G(n))
  %                                 IMPLIES sigma(low,high,F) <= sigma(low,high,G) 
  %
  %   sigma_lt         : THEOREM low <= high AND
  %                              (FORALL (n: subrange(low,high)): F(n) < G(n))
  %                                 IMPLIES sigma(low,high,F) < sigma(low,high,G) 


    sigma_with       : THEOREM low <= i AND i <= high AND
                               F = G WITH [i := v] IMPLIES
                            sigma(low, high,F) = sigma(low,high,G) - G(i) + v


  % ------------------------ Special Arguments --------------------------------
  %
  %   sigma_nonneg     : THEOREM (FORALL i: F(i) >= 0) 
  %                                  IMPLIES sigma(low, high, F) >= 0
  % 
  %   sigma_nonpos     : THEOREM (FORALL i: F(i) <= 0) 
  %                                  IMPLIES sigma(low, high, F) <= 0
  %
  %
  %   Fnnr: VAR function[T -> nonneg_real]
  %   Fnpr: VAR function[T -> nonpos_real]
  %   Fnat: VAR function[T -> nat]
  %   Fnpi: VAR function[T -> nonpos_int]
  %   Fposnat: VAR function[T -> posnat]
  %
  %
  %   sigma_Fnnr        : JUDGEMENT sigma(low,high,Fnnr) HAS_TYPE nonneg_real
  %
  %   sigma_nonpos_real : JUDGEMENT sigma(low,high,Fnpr) HAS_TYPE nonpos_real
  %
  %   sigma_nat         : JUDGEMENT sigma(low,high,Fnat) HAS_TYPE nat
  %
  %   sigma_nonpos_int  : JUDGEMENT sigma(low,high,Fnpi) HAS_TYPE nonpos_int
  %
  %   sigma_posnat      : LEMMA low <= high IMPLIES sigma(low,high,Fposnat) > 0
  %
  %   sigma_nonneg_eq_0 : THEOREM sigma(low,high,Fnnr) = 0 
  %                               AND low <= i AND i <= high IMPLIES Fnnr(i) = 0
  %
  %   sigma_nn_ge_comps : THEOREM low <= i AND i <= high IMPLIES 
  %                                   sigma(low,high,Fnnr) >= Fnnr(i) 
  % Lack of an order prevents proof of the following
  %	 


  % ------------------- Iterative Summation (tail recursion) ------------

     sum_it_def(low, high, F,v): RECURSIVE Vector
        = IF low > high THEN v
          ELSE  sum_it_def(low+1,high,F,v+F(low))
          ENDIF
     MEASURE (LAMBDA low, high, F, v: abs(high+1-low))

     sum_it(low,high,F) : Vector = sum_it_def(low,high,F,zero)

     sum_it_prop : LEMMA
       low - 1 <= i AND i <= high =>
       sum_it_def(i+1,high,F,sigma(low,i,F)) = sigma(low,high,F)

     sum_it_sigma: LEMMA sum_it(low,high,F) = sigma(low,high,F)

  END sigma_2D

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

  % Subtype TCC generated (at line 56, column 47) for  n
      % expected type  T_high
  high_low_rewrite_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low):
      NOT high < low IMPLIES
       (FORALL (n: subrange(low, high)):
          T_pred(n) OR (EXISTS (j: T): n <= j));

  % Subtype TCC generated (at line 66, column 16) for  high
      % expected type  T
  sigma_TCC1: OBLIGATION
    FORALL (low: T_low, high: T_high): NOT low > high IMPLIES T_pred(high);

  % Subtype TCC generated (at line 66, column 35) for  high - 1
      % expected type  T_high
  sigma_TCC2: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES
       T_pred(high - 1) OR (EXISTS (j: T): high - 1 <= j);

  % Termination TCC generated (at line 66, column 24) for
      % sigma(low, high - 1, F)
  sigma_TCC3: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES abs(high - 1 + 1 - low) < abs(high + 1 - low);

  % Subtype TCC generated (at line 72, column 66) for  low
      % expected type  T
  sigma_rew_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low):
      NOT low > high AND high = low IMPLIES T_pred(low);

  % Subtype TCC generated (at line 77, column 38) for  low + nn + rng
      % expected type  T_high
  sigma_spl_TCC1: OBLIGATION
    FORALL (low: T_low, nn, rng: nat):
      T_pred(low + nn + rng) IMPLIES
       T_pred(low + nn + rng) OR (EXISTS (j: T): low + nn + rng <= j);

  % Subtype TCC generated (at line 78, column 40) for  low + nn
      % expected type  T_high
  sigma_spl_TCC2: OBLIGATION
    FORALL (low: T_low, nn, rng: nat):
      T_pred(low + nn + rng) IMPLIES
       T_pred(low + nn) OR (EXISTS (j: T): low + nn <= j);

  % Subtype TCC generated (at line 78, column 58) for  low + nn + 1
      % expected type  T_low
  sigma_spl_TCC3: OBLIGATION
    FORALL (low: T_low, nn, rng: nat):
      T_pred(low + nn + rng) IMPLIES
       T_pred(low + nn + 1) OR (EXISTS (j: T): j <= low + nn + 1);

  % Subtype TCC generated (at line 82, column 48) for  z
      % expected type  T_high
  sigma_split_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      z <= high AND low - 1 <= z IMPLIES T_pred(z) OR (EXISTS (j: T): z <= j);

  % Subtype TCC generated (at line 82, column 62) for  z + 1
      % expected type  T_low
  sigma_split_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      z <= high AND low - 1 <= z IMPLIES
       T_pred(z + 1) OR (EXISTS (j: T): j <= z + 1);

  % Subtype TCC generated (at line 93, column 51) for  low
      % expected type  T
  sigma_first_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low): high >= low IMPLIES T_pred(low);

  % Subtype TCC generated (at line 93, column 64) for  low + 1
      % expected type  T_low
  sigma_first_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low):
      high >= low IMPLIES T_pred(low + 1) OR (EXISTS (j: T): j <= low + 1);

  % Subtype TCC generated (at line 96, column 59) for  high - 1
      % expected type  T_high
  sigma_last_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low):
      high >= low IMPLIES T_pred(high - 1) OR (EXISTS (j: T): high - 1 <= j);

  % Subtype TCC generated (at line 96, column 74) for  high
      % expected type  T
  sigma_last_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low): high >= low IMPLIES T_pred(high);

  % Subtype TCC generated (at line 99, column 59) for  i - 1
      % expected type  T_high
  sigma_middle_TCC1: OBLIGATION
    FORALL (high: T_high, i: T, low: T_low):
      i >= low AND high >= i IMPLIES
       T_pred(i - 1) OR (EXISTS (j: T): i - 1 <= j);

  % Subtype TCC generated (at line 100, column 54) for  i + 1
      % expected type  T_low
  sigma_middle_TCC2: OBLIGATION
    FORALL (high: T_high, i: T, low: T_low):
      i >= low AND high >= i IMPLIES
       T_pred(i + 1) OR (EXISTS (j: T): j <= i + 1);

  % Subtype TCC generated (at line 130, column 18) for  low + z
      % expected type  T_low
  sigma_shift_T_TCC1: OBLIGATION
    FORALL (low: T_low, z: int):
      (FORALL (i: T): T_pred(i + z)) IMPLIES
       T_pred(low + z) OR (EXISTS (j: T): j <= low + z);

  % Subtype TCC generated (at line 130, column 24) for  high + z
      % expected type  T_high
  sigma_shift_T_TCC2: OBLIGATION
    FORALL (high: T_high, z: int):
      (FORALL (i: T): T_pred(i + z)) IMPLIES
       T_pred(high + z) OR (EXISTS (j: T): high + z <= j);

  % Subtype TCC generated (at line 131, column 69) for  i + z
      % expected type  T
  sigma_shift_T_TCC3: OBLIGATION
    FORALL (z: int):
      (FORALL (i: T): T_pred(i + z)) IMPLIES (FORALL (i1: T): T_pred(i1 + z));

  % Subtype TCC generated (at line 134, column 18) for  low + z
      % expected type  T_low
  sigma_shift_T2_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      T_pred(high + z) AND T_pred(low + z) IMPLIES
       T_pred(low + z) OR (EXISTS (j: T): j <= low + z);

  % Subtype TCC generated (at line 134, column 24) for  high + z
      % expected type  T_high
  sigma_shift_T2_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      T_pred(high + z) AND T_pred(low + z) IMPLIES
       T_pred(high + z) OR (EXISTS (j: T): high + z <= j);

  % Subtype TCC generated (at line 167, column 64) for  n
      % expected type  T
  sigma_eq_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, n: subrange(low, high)): T_pred(n);

  % Subtype TCC generated (at line 224, column 25) for  low + 1
      % expected type  T_low
  sum_it_def_TCC1: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES T_pred(low + 1) OR (EXISTS (j: T): j <= low + 1);

  % Subtype TCC generated (at line 224, column 42) for  low
      % expected type  T
  sum_it_def_TCC2: OBLIGATION
    FORALL (low: T_low, high: T_high): NOT low > high IMPLIES T_pred(low);

  % Termination TCC generated (at line 224, column 14) for
      % sum_it_def(low + 1, high, F, v + F(low))
  sum_it_def_TCC3: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES abs(high + 1 - (low + 1)) < abs(high + 1 - low);

  % Subtype TCC generated (at line 232, column 16) for  i + 1
      % expected type  T_low
  sum_it_prop_TCC1: OBLIGATION
    FORALL (high: T_high, i: T, low: T_low):
      i <= high AND low - 1 <= i IMPLIES
       T_pred(i + 1) OR (EXISTS (j: T): j <= i + 1);


body:
  linear_independence_3D: THEORY
  %------------------------------------------------------------------------------
  % 
  %  EXPERIMENTAL
  %
  %  Author: Rick Butler    NASA Langley
  %
  %------------------------------------------------------------------------------
  BEGIN

     IMPORTING vectors_3D

     IMPORTING fseqs_ops_vect3, sigma_fseq_3D


     linearly_dependent?(av: fseq[Vect3]): bool = 
          EXISTS (rk: fseq[real]): length(rk) = length(av) AND
                         EXISTS (jj: nat): jj < length(rk) AND rk(jj) /= 0 AND
                 sigma(rk*av) = zero
    
     linearly_independent?(av: fseq[Vect3]): bool =  NOT linearly_dependent?(av)         

     IMPORTING cross_3D


     get_around_bug: LEMMA (FORALL (n: int): 0 <= n AND n < 2 
                             IMPLIES n = 0 OR n = 1)

     av: VAR fseq[Vect3]
     test2: LEMMA l(av) = 2 IMPLIES   %% PVS BUG %%
          (linearly_dependent?(av) IFF linearly_dependent?(av(0),av(1)))

  % ------------ The following in cross_3D ------------
  %
  %    linearly_dependent?(a,b: Vect3): bool = 
  %        (EXISTS (k1,k2: real): (k1 /= 0 OR k2 /= 0) AND
  %                                k1*a + k2*b = zero)
  %
  %    linearly_independent?(a,b: Vect3): bool = NOT linearly_dependent?(a,b)
  %
  %     a,b: VAR Nz_vect3
  %     lin_indep_cross: LEMMA linearly_dependent?(a,b) IFF
  %                               cross(a,b) = zero
   


  END linear_independence_3D


body:
  vect_trig_3D: THEORY
  BEGIN

    IMPORTING vectors_3D

    u,v : VAR Nz_vector

    cos(u,v): real = u*v/(norm(u)*norm(v))

    trig_range  : TYPE = {x:real | -1 <= x AND x <= 1}

    cos_range   : JUDGEMENT cos(u,v) HAS_TYPE trig_range

    cos_symm : LEMMA cos(u,v) = cos(v,u)

  END vect_trig_3D

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

  % Judgement subtype TCC generated (at line 12, column 26) for  cos(u, v)
      % expected type  trig_range
  cos_range: OBLIGATION FORALL (u, v): -1 <= cos(u, v) AND cos(u, v) <= 1;


body:
  vect_trig_2D: THEORY
  BEGIN

    IMPORTING det_2D

    u,v : VAR Nz_vector

    % sin(u,v) provides the sin of the angle from u to v (counter-clockwise)
    % cos(u,v) provides the cos of the angle from u to v (any direction) 

    sin(u,v): real = det(u,v)/(norm(u)*norm(v))

    cos(u,v): real = u*v/(norm(u)*norm(v))

    trig_range  : TYPE = {x:real | -1 <= x AND x <= 1}

    sin_range   : JUDGEMENT sin(u,v) HAS_TYPE trig_range

    cos_range   : JUDGEMENT cos(u,v) HAS_TYPE trig_range

    sin2_cos2: THEOREM sq(sin(u,v)) + sq(cos(u,v)) = 1

    sin_asym: LEMMA sin(u,v) = -sin(v,u)
   
    cos_symm: LEMMA cos(u,v) = cos(v,u)

  END vect_trig_2D

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

  % Judgement subtype TCC generated (at line 17, column 26) for  sin(u, v)
      % expected type  trig_range
  sin_range: OBLIGATION FORALL (u, v): -1 <= sin(u, v) AND sin(u, v) <= 1;

  % Judgement subtype TCC generated (at line 19, column 26) for  cos(u, v)
      % expected type  trig_range
  cos_range: OBLIGATION FORALL (u, v): -1 <= cos(u, v) AND cos(u, v) <= 1;


body:
  vect3D : THEORY
  %------------------------------------------------------------------------------
  %
  % This theory creates a special 3D version of vectors from the generic vectors
  % library by importing vectors[3].  Note that this is nearly equivalent
  % to the vectors_3D library.  Since lemma names are the same this theory
  % it is hoped that switching between them will be seemless.  This theory
  % seeks to bridge the gap between the generic vectors type:
  %
  %    Index     : TYPE = below(3) 
  %    Vector    : TYPE = [Index -> real]
  %
  %   and the record structure of vectors_3D:
  %
  %      Vect3: TYPE = [#  x, y, z: real  #]
  %
  %------------------------------------------------------------------------------

  BEGIN
    IMPORTING vectors[3]

    Vect3 : TYPE = Vector
    x,y,z : VAR real  
    u,v   : VAR Vect3

    vect3(x,y,z) : Vect3 =  LAMBDA(i:Index):
                              IF  i=0 THEN x ELSIF i=1 THEN y ELSE z  ENDIF

    put_x(v,x)   : Vect3 = v WITH [`0 := x]

    put_y(v,y)   : Vect3 = v WITH [`1 := y]

    put_z(v,z)   : Vect3 = v WITH [`2 := z]

    x(v)         : MACRO real = v(0)
    y(v)         : MACRO real = v(1)
    z(v)         : MACRO real = v(2)

  % --------- Basis vectors

    iv  : Vect3 = vect3(1,0,0)
    jv  : Vect3 = vect3(0,1,0)
    kv  : Vect3 = vect3(0,0,1)



  % ----------- Equality

    eq3D?(u,v): bool=  x(u)=x(v) AND y(u) = y(v) AND z(u)=z(v)

    Eq3D     : LEMMA   eq3D?(u,v) IFF u = v

    vect3D_0 : LEMMA vect3(x,y,z)(0) = x

    vect3D_1 : LEMMA vect3(x,y,z)(1) = y

    vect3D_2 : LEMMA vect3(x,y,z)(2) = z

    pp3D(v)  :[real,real,real] = (x(v),y(v),z(v))

  END vect3D


body:
  vect2D : THEORY
  %------------------------------------------------------------------------------
  %
  % This theory creates a special 2D version of vectors from the generic vectors
  % library by importing vectors[2].  Note that this is nearly equivalent
  % to the vectors_2D library.  Since lemma names are the same this theory
  % it is hoped that switching between them will be seemless.  This theory
  % seeks to bridge the gap between the generic vectors type:
  %
  %    Index     : TYPE = below(2) 
  %    Vector    : TYPE = [Index -> real]
  %
  %   and the record structure of vectors_2D:
  %
  %      Vect2: TYPE = [#  x, y: real  #]
  %
  %------------------------------------------------------------------------------
  BEGIN
    IMPORTING vectors[2]

    Vect2 : TYPE = Vector
    x,y   : VAR real  
    u,v   : VAR Vect2

    vect2(x,y): Vect2 = LAMBDA(i:Index): IF i=0 THEN x ELSE y ENDIF  

    put_x(v,x): Vect2 =  v WITH [`0 := x]

    put_y(v,y): Vect2 =  v WITH [`1 := y]

    x(v)      : MACRO real = v(0)
    y(v)      : MACRO real = v(1)

    iv  : Vect2 = vect2(1,0)
    jv  : Vect2 = vect2(0,1)

    vect2D_0   : LEMMA vect2(x,y)(0) = x

    vect2D_1   : LEMMA vect2(x,y)(1) = y

    eq2D?(u,v): bool =  x(u)=x(v) AND y(u) = y(v)

    Eq2D      : LEMMA  eq2D?(u,v) IFF u = v
   
    pp2D(v)   :[real,real] = (x(v),y(v))

  END vect2D


body:
  matrices : THEORY
  BEGIN
    
    IMPORTING vect2D,vect3D

    Mat3 : TYPE = ARRAY[[below(3),below(3)]->real]

    Mat2 : TYPE = {m:Mat3|m(2,0)=0 AND m(2,1)=0 AND m(2,2)=1}

    m,n,l        : VAR Mat3
    v,w          : VAR Vect3
    x00,x01,x02,
    x10,x11,x12,
    x20,x21,x22,
    k            : VAR real

    mat3(x00,x01,x02,x10,x11,x12,x20,x21,x22): Mat3 =
        					       LAMBDA(x,y:below(3)):
        					  	 IF    (x=0 AND y=0) THEN x00
        					  	 ELSIF (x=0 AND y=1) THEN x01
        					  	 ELSIF (x=0 AND y=2) THEN x02
        					  	 ELSIF (x=1 AND y=0) THEN x10
        					  	 ELSIF (x=1 AND y=1) THEN x11
        					  	 ELSIF (x=1 AND y=2) THEN x12
        					  	 ELSIF (x=2 AND y=0) THEN x20
        					  	 ELSIF (x=2 AND y=1) THEN x21
        					  	 ELSIF (x=2 AND y=2) THEN x22
        					  	 ELSE 0
        					  	 ENDIF  
      
    putAt(m:Mat3, i, j:below(3),r:real): Mat3 =  m WITH [(i,j) := r]

    id: Mat3 = mat3(1,0,0,
                    0,1,0,
                    0,0,1)

    row(m:Mat3, i:below(3)): Vect3 = vect3(m(i,0),m(i,1),m(i,2))

    col(m:Mat3, i:below(3)): Vect3 = vect3(m(0,i),m(1,i),m(2,i))

  % ------- Determinant

    det(m): real = m(0,0)*m(1,1)*m(2,2) +
      		 m(0,1)*m(1,2)*m(2,0) +
      		 m(0,2)*m(1,0)*m(2,1) -
      		 m(0,2)*m(1,1)*m(2,0) -
      		 m(0,0)*m(1,2)*m(2,1) -
      		 m(0,1)*m(1,0)*m(2,2)

    singular?(m): bool = (det(m) = 0)

    NonSingular  : TYPE = {m: Mat3 | NOT singular?(m)} 
    ns           : VAR NonSingular

    det_id : LEMMA  det(id) = 1
      
  % ------- Transposed

    T(m): Mat3 =  mat3(m(0,0),m(1,0),m(2,0),
                       m(0,1),m(1,1),m(2,1),
                       m(0,2),m(1,2),m(2,2)) 

    det_T: LEMMA det(m) = det(T(m));
   
  % ------ Products

    *(k,m): Mat3 =    mat3(k*m(0,0),k*m(0,1),k*m(0,2),
                           k*m(1,0),k*m(1,1),k*m(1,2),
                           k*m(2,0),k*m(2,1),k*m(2,2));

    *(v,m): Vect3 =   vect3(v*col(m,0),v*col(m,1),v*col(m,2));

    *(m,v): Vect3 =   vect3(row(m,0)*v,row(m,1)*v,row(m,2)*v);
     
    *(m,n): Mat3 =    mat3(row(m,0)*col(n,0),row(m,0)*col(n,1),row(m,0)*col(n,2),
                           row(m,1)*col(n,0),row(m,1)*col(n,1),row(m,1)*col(n,2),
                           row(m,2)*col(n,0),row(m,2)*col(n,1),row(m,2)*col(n,2))
    
    id_left1 : LEMMA id*m = m

    id_right1: LEMMA m*id = m

    id_left2 : LEMMA id*v = v

    id_right2: LEMMA v*id = v

    associativity_1    : LEMMA (m*n)*l = m*(n*l)

    associativity_2    : LEMMA (m*n)*v = m*(n*v)

    associativity_3    : LEMMA (v*m)*n = v*(m*n)

    distribution_minus : LEMMA m*(v-w) = (m*v)-(m*w)

    distribution_add   : LEMMA  m*(v+w) = (m*v)+(m*w)

  % ------ Mat2

    mat2(x00,x01,x10,x11): Mat2 =  mat3(x00,x01,0,x10,x11,0,0,0,1)

    det_mat2 : LEMMA  det(mat2(x00,x01,x10,x11)) = x00*x11 - x01*x10

    cofactor_ij(m:Mat3, i,j:below(3)): Mat3 = LAMBDA(a,b:below(3)):
        					     IF    (a=i AND b=j) THEN 1
        					     ELSIF (a=i OR  b=j) THEN 0
        					     ELSE  m(a,b)
        					     ENDIF
                               
    cofactor(m:Mat3): Mat3 =   LAMBDA(i,j:below(3)): det(cofactor_ij(m,i,j))

  % ------ Inverse

    inv(ns): Mat3 = (1/det(ns))*T(cofactor(ns))

    inv_id    : LEMMA inv(id) = id

    inv_left  : LEMMA inv(ns)*ns = id

    inv_right : LEMMA ns*inv(ns) = id

  % ------ pp: Mat3 -> (Vect3,Vect3,Vect3) 

    pp(m):[Vect3,Vect3,Vect3]= (row(m,0),row(m,1),row(m,2))

  % ------ System of equations
  % ------ Ax=B

    sol_eqs(A:NonSingular,B:Vect3):Vect3 = inv(A)*B

    sol_eqs_correctness : LEMMA ns*sol_eqs(ns,v) = v

  % ------ 2 equations 2 variables

    system2(v,u:Vect2): MACRO Mat2 =  mat2(x(v),y(v),x(u),y(u))

  % ------ 3 equations 3 variables

    system3(v,u,w:Vect3): MACRO Mat3 =
                           mat3(x(v),y(v),z(v),x(u),y(u),z(u),x(w),y(w),z(w))
    
  END matrices

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

  % Subtype TCC generated (at line 99, column 33) for
      % mat3(x00, x01, 0, x10, x11, 0, 0, 0, 1)
      % expected type  Mat2
  mat2_TCC1: OBLIGATION
    FORALL (x00: real, x01: real, x10: real, x11: real):
      mat3(x00, x01, 0, x10, x11, 0, 0, 0, 1)(2, 0) = 0 AND
       mat3(x00, x01, 0, x10, x11, 0, 0, 0, 1)(2, 1) = 0 AND
        mat3(x00, x01, 0, x10, x11, 0, 0, 0, 1)(2, 2) = 1;

  % Subtype TCC generated (at line 113, column 21) for  det(ns)
      % expected type  nznum
  inv_TCC1: OBLIGATION FORALL (ns: NonSingular): det(ns) /= 0;

  % Subtype TCC generated (at line 115, column 24) for  id
      % expected type  NonSingular
  inv_id_TCC1: OBLIGATION NOT singular?(id);


body:
  intersections_2D: THEORY
  %--------------------------------------------------------------------------
  %
  %  Derived from paper "Intersection of Linear and Circular Components in 2D"
  %  by David Eberly. Available at:
  %
  %    www.magic-software.com
  %
  %  Author: Ricky Butler              NASA Langley Research Center
  %
  %--------------------------------------------------------------------------
  BEGIN

     IMPORTING distance_2D,
               det_2D,
               lines_2D, parallel_2D

     p,p0,p1,p2,pnot,u,v,v0,v1,v2: VAR Vect2

     s,t,t1,t2: VAR real

     nza: VAR nzreal

     cross(p0,p1): MACRO real = det(p0,p1)
   
  %                                     |     Basic        |   Parametric
  %                                     |------------------|-----------------
  %   Line : TYPE = [# p: Vect2,        | point on the line| position at time 0
  %                    v: Nz_vect2 #]   | direction vector | velocity vector


  %  Let L0 = p0 + s*v  == L0`p + s*L0`v
  %  Let L1 = p0 + s*v1 == L1`p + s*L1`v


     L0,L1: VAR Line2D

     det_line: LEMMA LET DELTA = L1`p - L0`p IN
                       L0`p + s*L0`v =  L1`p + t*L1`v IMPLIES
                          det(L0`v,L1`v)*s = det(DELTA,L1`v) AND
                          det(L0`v,L1`v)*t = det(DELTA,L0`v)

  %  Three cases
  %      intersecting :   det(L0`v,L1`v) /= 0 
  %      parallel     :   det(L0`v,L1`v) =  0 AND det(DELTA,L0`v) /= 0
  %      same_line    :   det(L0`v,L1`v) =  0 AND det(DELTA,L0`v) = 0


     intersect?(L0,L1): bool = det(L0`v,L1`v) /= 0 

     same_line?(L0,L1): bool = LET DELTA = L1`p - L0`p IN  
                                 det(L0`v,L1`v) = 0 AND det(DELTA,L0`v) = 0
  %  ----------- function to return intersection point --------------

      intersect_pt(L0:Line2D,L1: Line2D | det(L0`v,L1`v) /= 0): Vect2 =
                                 LET DELTA = L1`p - L0`p,
                                     ss = det(DELTA,L1`v)/det(L0`v,L1`v) IN 
                                     L0`p + ss*L0`v

  %  ----------- basic properties ---------------

     IMPORTING parallel_2D

     same_line_sym: LEMMA same_line?(L0,L1) IMPLIES same_line?(L1,L0)  

     intersect_not_parallel: LEMMA intersect?(L0,L1) IMPLIES
                                     NOT parallel?(L0`v,L1`v)

     intersection_lem      : LEMMA det(L0`v,L1`v) /= 0 IMPLIES
                                      LET DELTA = L1`p - L0`p,
                                         ss = det(DELTA,L1`v)/det(L0`v,L1`v),
                                         tt = det(DELTA,L0`v)/det(L0`v,L1`v)
                                      IN
                                L0`p + ss*L0`v =  L1`p + tt*L1`v

     lines_intersection(so:Vect2,vo:Nz_vect2,si:Vect2,vi:Nz_vect2|det(vo,vi) /= 0) : [real,real] =
       LET ns = si-so,
           d = det(vo,vi) IN
       (det(ns,vi)/d, det(ns,vo)/d)

     lines_intersection_sound : LEMMA
       FORALL(so:Vect2,vo:Nz_vect2,si:Vect2,vi:Nz_vect2|det(vo,vi) /= 0):
         LET (ko,ki) = lines_intersection(so,vo,si,vi) IN
         so+ko*vo = si+ki*vi

      pt_intersect          : LEMMA on_line?(p,L0) AND on_line?(p,L1) AND
                                   NOT same_line?(L0,L1) IMPLIES
                                       intersect?(L0,L1) 


     intersect_pt_unique   : LEMMA intersect?(L0,L1) IMPLIES
                                   pnot /= intersect_pt(L0,L1) AND
                                   on_line?(pnot,L0)  
                                IMPLIES
                                   NOT on_line?(pnot,L1)

     same_line_lem         : LEMMA p0 /= p1 AND
                                  ( on_line?(p0,L0) AND on_line?(p0,L1) AND
                                    on_line?(p1,L0) AND on_line?(p1,L1) )
                                       IMPLIES same_line?(L0,L1)
          
     not_same_line         : LEMMA on_line?(p,L0) AND NOT on_line?(p,L1) IMPLIES
                                   NOT same_line?(L0,L1)
                           
   
     intersect_pt_lem      : LEMMA NOT same_line?(L0,L1) AND
                                   on_line?(pnot,L0)  AND
                                   on_line?(pnot,L1)  
                                IMPLIES
                                    intersect_pt(L0,L1) = pnot 
                         
  END intersections_2D

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

  % Subtype TCC generated (at line 57, column 56) for  det(L0`v, L1`v)
      % expected type  nznum
  intersect_pt_TCC1: OBLIGATION
    FORALL (L0: Line2D, L1: Line2D | det(L0`v, L1`v) /= 0, DELTA: Vector):
      DELTA = L1`p - L0`p IMPLIES det(L0`v, L1`v) /= 0;

  % Subtype TCC generated (at line 79, column 17) for  d
      % expected type  nznum
  lines_intersection_TCC1: OBLIGATION
    FORALL (so: Vect2, vo: Nz_vect2, si: Vect2,
            vi: Nz_vect2 | det(vo, vi) /= 0, ns: Vector):
      ns = si - so IMPLIES (FORALL (d: real): d = det(vo, vi) IMPLIES d /= 0);

  % Subtype TCC generated (at line 92, column 57) for  L1
      % expected type  {L1: Line2D | det(L0`v, L1`v) /= 0}
  intersect_pt_unique_TCC1: OBLIGATION
    FORALL (L0, L1: Line2D): intersect?(L0, L1) IMPLIES det(L0`v, L1`v) /= 0;

  % Subtype TCC generated (at line 110, column 50) for  L1
      % expected type  {L1: Line2D | det(L0`v, L1`v) /= 0}
  intersect_pt_lem_TCC1: OBLIGATION
    FORALL (L0, L1: Line2D, pnot: Vect2):
      on_line?(pnot, L1) AND on_line?(pnot, L0) AND NOT same_line?(L0, L1)
       IMPLIES det(L0`v, L1`v) /= 0;


body:
  closest_approach_3D: THEORY
  %----------------------------------------------------------------------------
  %  We compute the closest point of approach (CPA) between two
  %  points that are dynamically moving in a straight line.  This is 
  %  an important computation in collision detection. For example,
  %  to calculate the time and distance of two planes (represented as 
  %  line vectors) when they are at their closest point.
  %  
  %  We use time-parametric equations to represent the paths of the
  %  two planes:
  %  
  %     p(t) = p0 + t*u      q(t) = q0 + t*v     
  %  
  %  Minimum separation occurs at:
  %
  %      t_cpa = -w0*(u-v)/sq(norm(u-v))  
  %
  %  where w0 = p0 - q0
  %
  %    dist(L1,L2,t): MACRO nnreal = dist(loc(L1)(t),loc(L2)(t))
  %    dist(L1,L2): nnreal = dist(L1,L2,t_cpa(L1,L2))
  %
  % We also introduce the following convenient predicates
  %
  %   divergent?(p0,q0,u,v): bool = 
  %     FORALL (t: posreal): dist(p0,q0) < dist(p0+t*u,q0+t*v)
  %
  %   dot_prop?(p0,q0,u,v): bool = (p0-q0)*(u-v) >= 0
  %
  % and we prove there equivalence when u /= v. See "dot_prop_divergent".
   
  %
  %  See
  %     http://geometryalgorithms.com/Archive/algorithm_0106/algorithm_0106.htm
  %  
  %  for a very nice discussion.
  %
  %  Author: Ricky Butler              NASA Langley Research Center
  %
  %----------------------------------------------------------------------------
  BEGIN
   
    IMPORTING distance_3D, 
              reals@quad_minmax

    t,t0,t1,t2     : VAR real
    a,b,c          : VAR real
    p0,q0,u,v,w0,wt: VAR Vect3


    sq_dist_lem: LEMMA LET p(t) = p0 + t*u, q(t) = q0 + t*v,
                           w0 = p0 - q0,
                           w(t) = w0 + t*(u-v) IN
                         sq_dist(p(t),q(t)) = w(t)*w(t)



  %  --- distance between two moving points is a quadratic function ----

    sq_dist_quad: LEMMA w0 = p0 - q0 AND
                        a = (u-v)*(u-v) AND
                        b = 2*w0*(u-v) AND
                        c = w0*w0
                        IMPLIES sq_dist(p0+t*u,q0+t*v) = a*sq(t) + b*t + c


  %  -----  p(t) = p0 + t*u      q(t) = q0 + t*v  -----  


    dist_eq_vel   : LEMMA dist(p0 + t*v, q0 + t*v) = dist(p0,q0)

    norm_diff_eq_0: LEMMA norm(u-v) = 0 IMPLIES
                          dist(p0+t1*u, q0+t1*v) = dist(p0+t2*u, q0+t2*v)


  %  ----- time of closest point of approach --------

    time_closest(p0,q0,u,v): real = IF norm(u-v) = 0 THEN  % parallel, eq speed
                                       0
                                    ELSE
                                       -((p0-q0)*(u-v))/sq(norm(u-v))
                                    ENDIF 

    time_closest_lem: LEMMA norm(u-v) /= 0 AND
                            a = (u-v)*(u-v) AND
                            b = 2*(p0-q0)*(u-v) 
                            IMPLIES
                              time_closest(p0,q0,u,v) = -b/(2*a)

  %  ----- time of closest point of approach between p(t) and q0

    time_closest(p0,q0,u): MACRO real = time_closest(p0,q0,u,zero)

  %  ----- distance at time of closest point of approach

    dist_closest(p0,q0,u,v): MACRO nnreal = 
      LET t_cpa=time_closest(p0,q0,u,v) IN
         dist(p0+t_cpa*u, q0+t_cpa*v)

  %  ----- distance at time of closest point of approach between p(t) and q0 

    dist_closest(p0,q0,u): MACRO nnreal = 
       dist_closest(p0,q0,u,zero)

  %  ----- distance at closest point is indeed a minimum -------

    t_cpa: VAR real
    d_cpa: VAR nnreal

    cpa_prep_mono: LEMMA w0 = p0 - q0 AND
                      a = (u-v)*(u-v) AND
                      b = 2*w0*(u-v) AND
                      c = w0*w0 AND
                      t_cpa = time_closest(p0,q0,u,v) AND
                      norm(u-v) /= 0 AND
                      t_cpa <= t1 AND t1 < t2 
                   IMPLIES
                      LET D2 = (LAMBDA t: sq_dist(p0+t*u,q0+t*v)) IN
                          D2(t1) < D2(t2)

    time_cpa: LEMMA t_cpa = time_closest(p0,q0,u,v) 
                 IMPLIES
                    is_minimum?(t_cpa,(LAMBDA t: sq_dist(p0+t*u,q0+t*v))) 
                    
    dist_cpa: LEMMA 
               dist_closest(p0,q0,u,v) <= dist(p0+t*u, q0+t*v)

    dist_cpa_lt: LEMMA t_cpa = time_closest(p0,q0,u,v) AND
                       norm(u-v) /= 0 AND
                       t_cpa <= t1 AND t1 < t2 
                 IMPLIES
                      LET D2 = (LAMBDA t: sq_dist(p0+t*u,q0+t*v)) IN
                          D2(t1) < D2(t2)

    dist_min: LEMMA LET p(t) = p0 + t*u,      
                        q(t) = q0 + t*v IN
                    t_cpa = time_closest(p0,q0,u,v) 
                IMPLIES
                    dist(p(t_cpa),q(t_cpa)) <= dist(p(t),q(t))

  %  ------ points diverge from point of closest approach ------

    tt: VAR real
    dist_diverges: LEMMA  LET p(t) = p0 + t*u,      
                              q(t) = q0 + t*v IN
                          t_cpa = time_closest(p0,q0,u,v) AND
                          t_cpa <= t1 AND t1 < t2 AND
                          norm(u-v) /= 0 
                IMPLIES
                    dist(p(t1),q(t1)) < dist(p(t2),q(t2))

    dist_parallel_lines: LEMMA  LET p(t) = p0 + t*u,      
                                    q(t) = q0 + t*v IN
                                norm(u-v) = 0
                             IMPLIES
                                dist(p(t1),q(t1)) = dist(p(t2),q(t2))
   
  %  ------ Relation between positive dot product and tcpa


    dot_nneg_tca_npos : LEMMA 
      (p0-q0)*(u-v) >= 0 IMPLIES 
        time_closest(p0,q0,u,v) <= 0

    divergent?(p0,q0,u,v): bool = 
      FORALL (t: posreal): dist(p0,q0) < dist(p0+t*u,q0+t*v)

    dot_prop?(p0,q0,u,v): bool = (p0-q0)*(u-v) >= 0

    divergent_u_neq_v : LEMMA
      divergent?(p0,q0,u,v) IMPLIES
        u /= v

    dot_nneg_divergent : THEOREM 
      (p0-q0)*(u-v) >= 0 AND u /= v IMPLIES 
        divergent?(p0,q0,u,v)   

    divergent_dot_nneg : THEOREM 
      divergent?(p0,q0,u,v) IMPLIES 
        (p0-q0)*(u-v) >= 0 
   
    divergent_t1_lt_t2 : LEMMA
      divergent?(p0,q0,u,v) IFF
        FORALL (t1,t2): 0 <= t1 AND t1 < t2 
          IMPLIES dist(p0+t1*u,q0+t1*v) <  dist(p0+t2*u,q0+t2*v)

    dot_prop_divergent: THEOREM u /= v IMPLIES 
                                (dot_prop?(p0,q0,u,v) IFF divergent?(p0,q0,u,v))



  %  ------ Intersection of dynamic line and a sphere -----

    s:              VAR Vect3

    % The first lemma states that if t1 and t2 are the intersection
    % points with a sphere of radius D, then the distance for all times
    % between t1 and t2 is less than D 

    t1_lt_t2_lt_D : LEMMA FORALL (t,t1,t2,D:real):
        	     	     v*v /= 0 AND
        	     	     t1 < t2 AND
        	     	     (s+t1*v)*(s+t1*v) = D AND
        	     	     (s+t2*v)*(s+t2*v) = D AND
        	     	     t1 < t AND t < t2 IMPLIES
        	     	     (s+t*v)*(s+t*v) < D

    % The second lemma is the reciprocal of the previous lemma. It states that
    % if the distance at time t is less than D, then t is between t1 and
    % t2.
   
    lt_D_t1_lt_t2 : LEMMA FORALL (t,t1,t2,D:real):
        		      	   v*v /= 0 AND
        		      	   t1 < t2 AND
        	     	           (s+t1*v)*(s+t1*v) = D AND
        	     	           (s+t2*v)*(s+t2*v) = D AND
        	     	           (s+t*v)*(s+t*v) < D IMPLIES
        		      	   t1 < t AND t < t2 


    % The third lemma states that if there are no intersection points with
    % a sphere of radius D then the distance at any time is greater than D.

    discr_le_0 : LEMMA FORALL (t,discrm,D:real): 
                          sos(v) /= 0 AND
                          discr(sos(v),2*(s*v),sos(s) - D) <= 0
        		  	IMPLIES
        		  	  (s+t*v)*(s+t*v) >= D 



  END closest_approach_3D

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

  % Subtype TCC generated (at line 81, column 54) for  sq(norm(u - v))
      % expected type  nznum
  time_closest_TCC1: OBLIGATION
    FORALL (u: Vect3, v: Vect3):
      NOT norm(u - v) = 0 IMPLIES sq(norm(u - v)) /= 0;

  % Subtype TCC generated (at line 88, column 58) for  (2 * a)
      % expected type  nznum
  time_closest_lem_TCC1: OBLIGATION
    FORALL (a, b: real, p0, q0, u, v: Vect3):
      b = 2 * (p0 - q0) * (u - v) AND
       a = (u - v) * (u - v) AND norm(u - v) /= 0
       IMPLIES (2 * a) /= 0;


body:
  closest_approach_2D: THEORY
  %----------------------------------------------------------------------------
  %  We compute the closest point of approach (CPA) between two
  %  points that are dynamically moving in a straight line.  This is 
  %  an important computation in collision detection. For example,
  %  to calculate the time and distance of two planes (represented as 
  %  line vectors) when they are at their closest point.
  %  
  %  We use time-parametric equations to represent the paths of the
  %  two planes:
  %  
  %     p(t) = p0 + t*u      q(t) = q0 + t*v     
  %  
  %  Distance between D(t) is given by:
  %
  %     D(t) = (u-v)*(u-v) t^2 + 2 * w0 * (u-v) t + w0*w0 
  %
  %  where w0 = p0 - q0.  This is a quadratic equation with
  %
  %       a = (u-v)*(u-v) AND
  %       b = 2*w0*(u-v) AND
  %       c = w0*w0 AND
  %
  % which has a minimum at -b/2a.
  %  
  %  Minimum separation occurs at:
  %
  %      t_cpa = -w0*(u-v)/sq(norm(u-v))  
  %
  %  where w0 = p0 - q0
  %
  %    dist(L1,L2,t): MACRO nnreal = dist(loc(L1)(t),loc(L2)(t))
  %    dist(L1,L2): nnreal = dist(L1,L2,t_cpa(L1,L2))
  %
  % We also introduce the following convenient predicates
  %
  %   divergent?(p0,q0,u,v): bool = 
  %     FORALL (t: posreal): dist(p0,q0) < dist(p0+t*u,q0+t*v)
  %
  %   dot_prop?(p0,q0,u,v): bool = (p0-q0)*(u-v) >= 0
  %
  % and we prove there equivalence when u /= v. See "dot_prop_divergent".
  %
  %  See
  %     http://geometryalgorithms.com/Archive/algorithm_0106/algorithm_0106.htm
  %  
  %  for a very nice discussion.
  %
  %  Author: Ricky Butler              NASA Langley Research Center
  %
  %----------------------------------------------------------------------------
  BEGIN
   
    IMPORTING distance_2D, 
              reals@quad_minmax

    t,t0,t1,t2      : VAR real
    a,b,c           : VAR real
    p0,q0,u,v,w0,wt : VAR Vect2


    sq_dist_lem: LEMMA LET p(t) = p0 + t*u, q(t) = q0 + t*v,
                           w0 = p0 - q0,
                           w(t) = w0 + t*(u-v) IN
                         sq_dist(p(t),q(t)) = w(t)*w(t)



  %  --- distance between two moving points is a quadratic function ----

    sq_dist_quad: LEMMA w0 = p0 - q0 AND
                        a = (u-v)*(u-v) AND
                        b = 2*w0*(u-v) AND
                        c = w0*w0
                        IMPLIES sq_dist(p0+t*u,q0+t*v) = a*sq(t) + b*t + c


  %  -----  p(t) = p0 + t*u      q(t) = q0 + t*v  -----  


    dist_eq_vel   : LEMMA dist(p0 + t*v, q0 + t*v) = dist(p0,q0)

    norm_diff_eq_0: LEMMA norm(u-v) = 0 IMPLIES
                          dist(p0+t1*u, q0+t1*v) = dist(p0+t2*u, q0+t2*v)


  %  ----- time of closest point of approach --------

    time_closest(p0,q0,u,v): real = IF norm(u-v) = 0 THEN  % parallel, eq speed
                                       0
                                    ELSE
                                       -((p0-q0)*(u-v))/sq(norm(u-v))
                                    ENDIF 

    time_closest_lem: LEMMA norm(u-v) /= 0 AND
                            a = (u-v)*(u-v) AND
                            b = 2*(p0-q0)*(u-v) 
                            IMPLIES
                              time_closest(p0,q0,u,v) = -b/(2*a)

  %  ----- distance at time of closest point of approach

    dist_closest(p0,q0,u,v): MACRO nnreal = 
      LET t_cpa=time_closest(p0,q0,u,v) IN
         dist(p0+t_cpa*u, q0+t_cpa*v)

  %  ----- distance at closest point is indeed a minimum -------

    t_cpa: VAR real
    d_cpa: VAR nnreal

    cpa_prep_mono: LEMMA w0 = p0 - q0 AND
                      a = (u-v)*(u-v) AND
                      b = 2*w0*(u-v) AND
                      c = w0*w0 AND
                      t_cpa = time_closest(p0,q0,u,v) AND
                      norm(u-v) /= 0 AND
                      t_cpa <= t1 AND t1 < t2 
                   IMPLIES
                      LET D2 = (LAMBDA t: sq_dist(p0+t*u,q0+t*v)) IN
                          D2(t1) < D2(t2)

    time_cpa: LEMMA t_cpa = time_closest(p0,q0,u,v) 
                 IMPLIES
                    is_minimum?(t_cpa,(LAMBDA t: sq_dist(p0+t*u,q0+t*v))) 
                    
    dist_cpa: LEMMA 
                dist_closest(p0,q0,u,v) <= dist(p0+t*u, q0+t*v)

    dist_cpa_lt: LEMMA t_cpa = time_closest(p0,q0,u,v) AND
                       norm(u-v) /= 0 AND
                       t_cpa <= t1 AND t1 < t2 
                 IMPLIES
                      LET D2 = (LAMBDA t: sq_dist(p0+t*u,q0+t*v)) IN
                          D2(t1) < D2(t2)


    dist_min: LEMMA LET p(t) = p0 + t*u,      
                        q(t) = q0 + t*v IN
                    t_cpa = time_closest(p0,q0,u,v) 
                IMPLIES
                     dist(p(t_cpa),q(t_cpa)) <= dist(p(t),q(t))


  %  ------ points diverge from point of closest approach ------

    tt: VAR real
    dist_diverges: LEMMA  LET p(t) = p0 + t*u,      
                              q(t) = q0 + t*v IN
                          t_cpa = time_closest(p0,q0,u,v) AND
                          t_cpa <= t1 AND t1 < t2 AND
                          norm(u-v) /= 0 
                IMPLIES
                    dist(p(t1),q(t1)) < dist(p(t2),q(t2))

    dist_parallel_lines: LEMMA  LET p(t) = p0 + t*u,      
                                    q(t) = q0 + t*v IN
                                norm(u-v) = 0
                             IMPLIES
                                dist(p(t1),q(t1)) = dist(p(t2),q(t2))
   
  %  ------ Relation between positive dot product and tcpa

    dot_nneg_tca_npos : LEMMA 
      (p0-q0)*(u-v) >= 0 IMPLIES 
        time_closest(p0,q0,u,v) <= 0

    divergent?(p0,q0,u,v): bool = 
      FORALL (t: posreal): dist(p0,q0) < dist(p0+t*u,q0+t*v)

    dot_prop?(p0,q0,u,v): bool = (p0-q0)*(u-v) >= 0

    divergent_u_neq_v : LEMMA
      divergent?(p0,q0,u,v) IMPLIES 
        u /= v

    dot_nneg_divergent : THEOREM 
      (p0-q0)*(u-v) >= 0 AND u /= v IMPLIES 
        divergent?(p0,q0,u,v)   

    divergent_dot_nneg : THEOREM 
      divergent?(p0,q0,u,v) IMPLIES
        (p0-q0)*(u-v) >= 0 

    divergent_t1_lt_t2 : LEMMA
      divergent?(p0,q0,u,v) IFF
        FORALL (t1,t2): 0 <= t1 AND t1 < t2 
          IMPLIES dist(p0+t1*u,q0+t1*v) <  dist(p0+t2*u,q0+t2*v)

    dot_prop_divergent: THEOREM 
      u /= v IMPLIES 
      (dot_prop?(p0,q0,u,v) IFF divergent?(p0,q0,u,v))

    pos_dot_divergent: THEOREM 
      (p0-q0)*(u-v) > 0 IMPLIES divergent?(p0,q0,u,v)


  %  ------ Intersection of dynamic line and a circle -----
  %
  %  See reals@circles_and_lines for similar lemmas

    s:              VAR Vect2

    % The first lemma states that if t1 and t2 are the intersection
    % points with a circle of radius D, then the distance for all times
    % between t1 and t2 is less than D 

    t1_lt_t2_lt_D : LEMMA FORALL (t,t1,t2,D:real):
        	     	     sqv(v) /= 0 AND
        	     	     t1 < t2 AND
        	     	     sqv(s+t1*v) = D AND
        	     	     sqv(s+t2*v) = D AND
        	     	     t1 < t AND t < t2 IMPLIES
        	     	     sqv(s+t*v) < D

    % The second lemma is the reciprocal of the previous lemma. It states that
    % if the distance at time t is less than D, then t is between t1 and
    % t2.
   
    lt_D_t1_lt_t2 : LEMMA FORALL (t,t1,t2,D:real):
        		      	   sqv(v) /= 0 AND
        		      	   t1 < t2 AND
        	     	           sqv(s+t1*v) = D AND
        	     	           sqv(s+t2*v) = D AND
        	     	           sqv(s+t*v) < D IMPLIES
        		      	   t1 < t AND t < t2 

    % The third lemma states that if there are no intersection points with
    % a circle of radius D then the distance at any time is greater than D.

    discr_le_0 : LEMMA FORALL (t,D:real): 
        		  	sqv(v) /= 0  AND
                          discr(sqv(v),2*(s*v),sqv(s) - D) <= 0 
        		  	IMPLIES
        		  	  sqv(s+t*v) >= D 



    gt_D_t1_lt_t2 : LEMMA FORALL (t,t1,t2,t3,D:real):
       sqv(v) /= 0 AND
       t1 <= t AND t < t2 AND t2 < t3 AND
       sqv(s+t1*v) > D AND
       sqv(s+t2*v) = D AND
       sqv(s+t3*v) < D
       IMPLIES
           sqv(s+t*v) > D 

    cpa_sqvs_lt: LEMMA 0 <= t1 AND t1 < t2 AND s*v > 0 IMPLIES
       sqv(s+t1*v) < sqv(s+t2*v)



  END closest_approach_2D

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

  % Subtype TCC generated (at line 92, column 54) for  sq(norm(u - v))
      % expected type  nznum
  time_closest_TCC1: OBLIGATION
    FORALL (u: Vect2, v: Vect2):
      NOT norm(u - v) = 0 IMPLIES sq(norm(u - v)) /= 0;

  % Subtype TCC generated (at line 99, column 58) for  (2 * a)
      % expected type  nznum
  time_closest_lem_TCC1: OBLIGATION
    FORALL (a, b: real, p0, q0, u, v: Vect2):
      b = 2 * (p0 - q0) * (u - v) AND
       a = (u - v) * (u - v) AND norm(u - v) /= 0
       IMPLIES (2 * a) /= 0;


body:
  closest_approach_relative_2D: THEORY
  %------------------------------------------------------------------------------
  %
  % The closest approach of approach (cpa) only depends upon the relative position and
  % relative velocity between two trajectories.   Therefore it is convenient
  % to cast the cpa theory in terms of relative vectors:
  %
  %     s = po - qo
  %
  %     v = v - u
  %
  %  Author: Ricky Butler              NASA Langley Research Center
  %
  %------------------------------------------------------------------------------
  BEGIN

    IMPORTING closest_approach_2D

    s,v,
    so,si,
    vo,vi,
    nvo,nvi : VAR Vect2
    t,t1,t2 : VAR real
    nzv : VAR Nz_vect2

    dot_pos?(s,v): bool = s * v > 0 

    dot_nneg?(s,v): bool = s * v >= 0 

    divergent?(s,v): MACRO bool =
      divergent?(s,zero,v,zero)

    divergent_lem: LEMMA 
        divergent?(s,v) IFF (FORALL (t: posreal): norm(s) < norm(s+t*v))

    dot_pos_comm : LEMMA
      dot_pos?(s,v) IFF dot_pos?(-s,-v)

    dot_pos_divergent : LEMMA 
      dot_pos?(s,v) IMPLIES divergent?(s,v)

    sq_dist_at(s,v,t) : nnreal = 
      sq_dist(s+t*v,zero)

    divergent_lt : LEMMA
      divergent?(s,v) IFF
        FORALL(t1,t2:real): 
          0 <= t1 AND t1 < t2 IMPLIES
          sq_dist_at(s,v,t1) < sq_dist_at(s,v,t2)

    divergent_dot_pos: LEMMA 
       divergent?(s,v) IMPLIES (dot_pos?(s,v) OR s*v = 0)

    diverg_dot_nneg : LEMMA 
       divergent?(s,v) IMPLIES dot_nneg?(s,v)

    divergent_v_neq_0 : LEMMA
      divergent?(s,v) IMPLIES v /= zero

    dot_nneg_divergent_nzv: THEOREM 
      dot_nneg?(s,nzv) IFF divergent?(s,nzv)

    % Time of closest approach
    
    tau_2D(s,nzv) : real =  -(s*nzv)/sqv(nzv) 

    tau(s,v): real = IF v = zero THEN 0
                     ELSE -(s*v)/sqv(v) 
                     ENDIF

    tau_is_min: LEMMA LET Tau = tau_2D(s,nzv) IN
                    is_minimum?(Tau,(LAMBDA t: sq(norm(s+t*nzv))))

    dist_tau(s,v): real = norm(s+tau(s,v)*v)

    dist_tau_min: LEMMA dist_tau(s,v) <= norm(s+t*v)

    tau_sqv_min : LEMMA sqv(s+tau(s,v)*v) <= sqv(s+t*v)


  END closest_approach_relative_2D

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

  % Subtype TCC generated (at line 68, column 31) for  sqv(v)
      % expected type  nznum
  tau_TCC1: OBLIGATION FORALL (v: Vect2): NOT v = zero IMPLIES sqv(v) /= 0;


body:
  distance[n: posnat]: THEORY
  BEGIN

     IMPORTING vectors

     p,p0,p1,p2,u,v,v0,v1,v2: VAR Vector[n]

     t: VAR posreal
     i: VAR Index[n]

  %  ------- distance function -----


     sq_dist(p1,p2): nnreal = sigma(0,n-1, LAMBDA i: sq(p1(i)-p2(i)))

     dist(p1,p2)   : nnreal = sqrt(sq_dist(p1,p2))


     dist_eq_args : LEMMA  dist(p,p) = 0

     dist_zero_l  : LEMMA  dist(zero,p) = norm(p)
     dist_zero_r  : LEMMA  dist(p,zero) = norm(p)

     dist_sym     : LEMMA  dist(p1,p2) = dist(p2,p1)

     dist_eq_0    : LEMMA  dist(p1,p2) = 0 IFF p1 = p2 

     dist_norm    : LEMMA  dist(u,v) = norm(u-v)

     dist_rel     : LEMMA  dist(p+p1,p+p2) = dist(p1,p2)
    
     sq_dist_is_dist_sq: LEMMA sq_dist(p1,p2) = sq(dist(p1,p2))  

     sq_dist_norm : LEMMA sq_dist(p1,p2) = sq(norm(p1-p2))

     sq_dist_sym  : LEMMA sq_dist(p1,p2) = sq_dist(p2,p1)

     sq_dist_le   : LEMMA sq_dist(v1,v2) <= sq_dist(p1,p2) IMPLIES
                              dist(v1,v2) <= dist(p1,p2)             %% NEW %%

     sq_dist_lt   : LEMMA sq_dist(v1,v2) <  sq_dist(p1,p2) IMPLIES
                              dist(v1,v2) <  dist(p1,p2)             %% NEW %%

     dist_gt_comp : LEMMA (FORALL i: dist(v1,v2) >= abs(v1(i) - v2(i)))  %% NEW %

     sq_dist_dist : LEMMA sq(dist(p2,p0)) = sq(dist(p1,p0)) + sq(dist(p1,p2)) 
                                               - 2*(p1-p0)*(p1-p2) %% NEW %% 

  %   dist_triangle: LEMMA dist(p0,p2) <= dist(p0,p1) + dist(p1,p2) 
  %
  %   dist_tri_sub: LEMMA abs(dist(p0,p2) - dist(p1,p2)) <= dist(p0,p1)

     AUTO_REWRITE+ dist_eq_args
  %  AUTO_REWRITE+ dist_zero_l  
  %  AUTO_REWRITE+ dist_zero_r  

  %  ------- Predicates

     r: VAR real

     on_circle?(p,r): bool = dist(p,zero) = r   

     on_line?(p1,p2,p): bool = 
                  EXISTS (x : real) : p = p1 + x * (p2 - p1) 

     on_segment?(p1,p2,p): bool = 
                  EXISTS (x : { y: nnreal | y <= 1}) : p = p1 + x * (p2 - p1) 


     on_segment_beg: LEMMA on_segment?(p1,p2,p1)
     on_segment_end: LEMMA on_segment?(p1,p2,p2)
     on_line_beg   : LEMMA on_line?(p1,p2,p1)
     on_line_end   : LEMMA on_line?(p1,p2,p2)


     AUTO_REWRITE+ on_segment_beg
     AUTO_REWRITE+ on_segment_end
     AUTO_REWRITE+ on_line_beg
     AUTO_REWRITE+ on_line_end


     on_segment_on_line: LEMMA on_segment?(p1,p2,p1) IMPLIES on_line?(p1,p2,p1)

  END distance

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

  % Subtype TCC generated (at line 14, column 34) for  0
      % expected type  T_low[Index[n]]
  sq_dist_TCC1: OBLIGATION 0 >= 0 AND 0 < n OR (EXISTS (j: Index[n]): j <= 0);

  % Subtype TCC generated (at line 14, column 36) for  n - 1
      % expected type  T_high[Index[n]]
  sq_dist_TCC2: OBLIGATION
    n - 1 >= 0 AND n - 1 < n OR (EXISTS (j: Index[n]): n - 1 <= j);

  % Assuming TCC generated (at line 21, column 12) for  reals@sigma[Index[n]]
      % generated from assumption sigma.connected_domain
  sq_dist_TCC3: OBLIGATION
    (FORALL (x, y: Index[n]), (z: integer):
       x <= z AND z <= y IMPLIES z >= 0 AND z < n);


body:
   closest_approach[n: posnat]: THEORY
  %----------------------------------------------------------------------------
  %  We compute the closest point of approach (CPA) between two
  %  points that are dynamically moving in a straight line.  This is 
  %  an important computation in collision detection. For example,
  %  to calculate the time and distance of two planes (represented as 
  %  line vectors) when they are at their closest point.
  %  
  %  We use time-parametric equations to represent the paths of the
  %  two planes:
  %  
  %     p(t) = p0 + t*u      q(t) = q0 + t*v    
  %
  %  Distance between D(t) is given by:
  %
  %     D(t) = (u-v)*(u-v) t^2 + 2 * w0 * (u-v) t + w0*w0 
  %
  %  where w0 = p0 - q0.  This is a quadratic equation which has a minimum at -b/2a.
  %  
  %  Minimum separation therefore occurs at:
  %
  %      t_cpa = -w0*(u-v)/sq(norm(u-v))  
  %
  %  where w0 = p0 - q0
  %
  %    dist(L1,L2,t): MACRO nnreal = dist(loc(L1)(t),loc(L2)(t))
  %    dist(L1,L2): nnreal = dist(L1,L2,t_cpa(L1,L2))
  %
  % We also introduce the following convenient predicates
  %
  %   divergent?(p0,q0,u,v): bool = 
  %     FORALL (t: posreal): dist(p0,q0) < dist(p0+t*u,q0+t*v)
  %
  %   dot_prop?(p0,q0,u,v): bool = (p0-q0)*(u-v) >= 0
  %
  % and we prove there equivalence when u /= v. See "dot_prop_divergent".
  %
  %  See
  %     http://geometryalgorithms.com/Archive/algorithm_0106/algorithm_0106.htm
  %  
  %  for a very nice discussion.
  %
  %  Author: Ricky Butler              NASA Langley Research Center
  %
  %----------------------------------------------------------------------------
  BEGIN
   
    IMPORTING distance[n],
              reals@quad_minmax

    t,t0,t1,t2     : VAR real
    a,b,c          : VAR real
    p0,q0,u,v,w0,wt: VAR Vector[n]


    sq_dist_lem: LEMMA LET p(t) = p0 + t*u, q(t) = q0 + t*v,  
                           w0 = p0 - q0,
                           w(t) = w0 + t*(u-v) IN
                         sq_dist(p(t),q(t)) = w(t)*w(t)



  %  --- distance between two moving points is a quadratic function ----

    sq_dist_quad: LEMMA w0 = p0 - q0 AND              	    
                        a = (u-v)*(u-v) AND
                        b = 2*w0*(u-v) AND
                        c = w0*w0
                        IMPLIES sq_dist(p0+t*u,q0+t*v) = a*sq(t) + b*t + c


  %  -----  p(t) = p0 + t*u      q(t) = q0 + t*v  -----  


    dist_eq_vel   : LEMMA dist(p0 + t*v, q0 + t*v) = dist(p0,q0)

    norm_diff_eq_0: LEMMA norm(u-v) = 0 IMPLIES
                          dist(p0+t1*u, q0+t1*v) = dist(p0+t2*u, q0+t2*v)


  %  ----- time of closest point of approach --------

    time_closest(p0,q0,u,v): real = IF norm(u-v) = 0 THEN  % parallel, eq speed
                                       0
                                    ELSE
                                       -((p0-q0)*(u-v))/sq(norm(u-v))
                                    ENDIF 

    time_closest_lem: LEMMA norm(u-v) /= 0 AND
                            a = (u-v)*(u-v) AND
                            b = 2*(p0-q0)*(u-v) 
                            IMPLIES
                              time_closest(p0,q0,u,v) = -b/(2*a)

  %  ----- time of closest point of approach between p(t) and q0 

    time_closest(p0,q0,u): MACRO real = time_closest(p0,q0,u,zero)


    dist_closest(p0,q0,u,v): MACRO nnreal = 
      LET t_cpa=time_closest(p0,q0,u,v) IN
         dist(p0+t_cpa*u, q0+t_cpa*v)

  %  ----- distance at closest point is indeed a minimum -------

    t_cpa: VAR real
    d_cpa: VAR nnreal

    cpa_prep_mono: LEMMA w0 = p0 - q0 AND
                      a = (u-v)*(u-v) AND
                      b = 2*w0*(u-v) AND
                      c = w0*w0 AND
                      t_cpa = time_closest(p0,q0,u,v) AND
                      norm(u-v) /= 0 AND
                      t_cpa <= t1 AND t1 < t2 
                   IMPLIES
                      LET D2 = (LAMBDA t: sq_dist(p0+t*u,q0+t*v)) IN
                          D2(t1) < D2(t2)


    time_cpa: LEMMA t_cpa = time_closest(p0,q0,u,v) 
                 IMPLIES
                    is_minimum?(t_cpa,(LAMBDA t: sq_dist(p0+t*u,q0+t*v))) 

    dist_cpa: LEMMA 
                dist_closest(p0,q0,u,v) <= dist(p0+t*u, q0+t*v)


    dist_cpa_lt: LEMMA t_cpa = time_closest(p0,q0,u,v) AND
                       norm(u-v) /= 0 AND
                       t_cpa <= t1 AND t1 < t2 
                 IMPLIES
                      LET D2 = (LAMBDA t: sq_dist(p0+t*u,q0+t*v)) IN
                          D2(t1) < D2(t2)

    dist_min: LEMMA LET p(t) = p0 + t*u,      
                        q(t) = q0 + t*v IN
                    t_cpa = time_closest(p0,q0,u,v) 
                IMPLIES
                    dist(p(t_cpa),q(t_cpa)) <= dist(p(t),q(t))

  %  ------ points diverge from point of closest approach ------

    tt: VAR real
    dist_diverges: LEMMA  LET p(t) = p0 + t*u,      
                              q(t) = q0 + t*v IN
                          t_cpa = time_closest(p0,q0,u,v) AND
                          t_cpa <= t1 AND t1 < t2 AND
                          norm(u-v) /= 0 
                IMPLIES
                    dist(p(t1),q(t1)) < dist(p(t2),q(t2))

    dist_parallel_lines: LEMMA  LET p(t) = p0 + t*u,      
                                    q(t) = q0 + t*v IN
                                norm(u-v) = 0
                             IMPLIES
                                dist(p(t1),q(t1)) = dist(p(t2),q(t2))
   
  %  ------ Relation between positive dot product and tcpa

    dot_nneg_tca_npos : LEMMA 
      (p0-q0)*(u-v) >= 0 IMPLIES 
        time_closest(p0,q0,u,v) <= 0

    divergent?(p0,q0,u,v): bool = 
      FORALL (t: posreal): dist(p0,q0) < dist(p0+t*u,q0+t*v)

    dot_prop?(p0,q0,u,v): bool = (p0-q0)*(u-v) >= 0

    divergent_u_neq_v : LEMMA
      divergent?(p0,q0,u,v) IMPLIES 
        u /= v

    dot_nneg_divergent : THEOREM 
      (p0-q0)*(u-v) >= 0 AND u /= v IMPLIES 
        divergent?(p0,q0,u,v)   

    divergent_dot_nneg : THEOREM 
      divergent?(p0,q0,u,v) IMPLIES 
        (p0-q0)*(u-v) >= 0 
   
    divergent_t1_lt_t2 : LEMMA
      divergent?(p0,q0,u,v) IFF
        FORALL (t1,t2): 0 <= t1 AND t1 < t2 
          IMPLIES dist(p0+t1*u,q0+t1*v) <  dist(p0+t2*u,q0+t2*v)

    dot_prop_divergent: THEOREM u /= v IMPLIES 
                                (dot_prop?(p0,q0,u,v) IFF divergent?(p0,q0,u,v))


  END closest_approach

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

  % Subtype TCC generated (at line 86, column 54) for  sq(norm(u - v))
      % expected type  nznum
  time_closest_TCC1: OBLIGATION
    FORALL (u: Vector[n], v: Vector[n]):
      NOT norm(u - v) = 0 IMPLIES sq(norm[n]((-[n])(u, v))) /= 0;

  % Subtype TCC generated (at line 93, column 58) for  (2 * a)
      % expected type  nznum
  time_closest_lem_TCC1: OBLIGATION
    FORALL (a, b: real, p0, q0, u, v: Vector[n]):
      b = 2 * (p0 - q0) * (u - v) AND
       a = (u - v) * (u - v) AND norm(u - v) /= 0
       IMPLIES (2 * a) /= 0;


body:
  law_cos_pos_3D: THEORY
  BEGIN

  %                                      v2
  %                                      .
  %                                     / \
  %                                   /    \
  %                                 /       \
  %                               /          \
  %                      c      /             \
  %                           /                \    b
  %                         /                   \
  %                       /                      \
  %                     /                         \
  %                   /                            \
  %                 /                           ab  \
  %               /                                  \
  %               ------------------------------------ 
  %               v0                a                   v1


    IMPORTING trig@trig_basic,
              distance_3D


    v0,v1,v2: VAR Vect3

    ab: VAR real

    law_cosines   : LEMMA
                       LET a = dist(v1,v0),
                           b = dist(v2,v1),
                           c = dist(v2,v0)
                       IN
                        a*b*cos(ab) = (v1-v0)*(v1-v2)
                          IMPLIES
                             sq(c) = sq(a) + sq(b) - 2*a*b*cos(ab)


    law_cosines_alt   : LEMMA
                        LET a = dist(v1,v0),
                            b = dist(v2,v1),
                            c = dist(v2,v0)
                        IN
                            sq(c) = sq(a) + sq(b) - 2*(v1-v0)*(v1-v2)

    IMPORTING trig@trig_inverses

    angle_exists: LEMMA (EXISTS ab:  LET  a = dist(v1,v0),
                                          b = dist(v2,v1) IN
                                a*b*cos(ab) = (v1-v0)*(v1-v2))


    angle_between(u,v:Nz_vect3): real = arccos(u*v/(norm(u)*norm(v)))


    law_cosines_bnd : LEMMA
                       LET a = dist(v1,v0),
                           b = dist(v2,v1),
                           c = dist(v2,v0)
                       IN
                           sq(c) >= sq(a-b)

    law_cosines_bnd_abs : LEMMA
                          LET a = dist(v1,v0),
                              b = dist(v2,v1),
                              c = dist(v2,v0)
                          IN
                              c >= abs(a-b)


    law_cosines_le : LEMMA LET  a = dist(v1,v0),
                                b = dist(v2,v1),
                                c = dist(v2,v0)
                           IN
                                   c <= a + b
   


  END law_cos_pos_3D

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

  % Subtype TCC generated (at line 54, column 45) for
      % u * v / (norm(u) * norm(v))
      % expected type  y: real_abs_le1
  angle_between_TCC1: OBLIGATION
    FORALL (u, v: Nz_vect3):
      -1 <= u * v / (norm(u) * norm(v)) AND u * v / (norm(u) * norm(v)) <= 1;


body:
  law_cos_pos_2D: THEORY
  BEGIN

  %                                      v2
  %                                      .
  %                                     / \
  %                                   /    \
  %                                 /       \
  %                               /          \
  %                      c      /             \
  %                           /                \    b
  %                         /                   \
  %                       /                      \
  %                     /                         \
  %                   /                            \
  %                 /                           ab  \
  %               /                                  \
  %               ------------------------------------ 
  %               v0                a                   v1


    IMPORTING trig@trig_basic,
              distance_2D


    v0,v1,v2: VAR Vect2

    ab: VAR real

    law_cosines   : LEMMA
                       LET a = dist(v1,v0),
                           b = dist(v2,v1),
                           c = dist(v2,v0)
                       IN
                        a*b*cos(ab) = (v1-v0)*(v1-v2)
                          IMPLIES
                             sq(c) = sq(a) + sq(b) - 2*a*b*cos(ab)


    law_cosines_alt   : LEMMA
                        LET a = dist(v1,v0),
                            b = dist(v2,v1),
                            c = dist(v2,v0)
                        IN
                            sq(c) = sq(a) + sq(b) - 2*(v1-v0)*(v1-v2)

    IMPORTING trig@trig_inverses

    angle_exists: LEMMA (EXISTS ab:  LET  a = dist(v1,v0),
                                          b = dist(v2,v1) IN
                                a*b*cos(ab) = (v1-v0)*(v1-v2))


    angle_between(u,v:Nz_vect2): real = arccos(u*v/(norm(u)*norm(v)))


    law_cosines_bnd : LEMMA
                       LET a = dist(v1,v0),
                           b = dist(v2,v1),
                           c = dist(v2,v0)
                       IN
                           sq(c) >= sq(a-b)

    law_cosines_bnd_abs : LEMMA
                          LET a = dist(v1,v0),
                              b = dist(v2,v1),
                              c = dist(v2,v0)
                          IN
                              c >= abs(a-b)


    law_cosines_le : LEMMA LET  a = dist(v1,v0),
                                b = dist(v2,v1),
                                c = dist(v2,v0)
                           IN
                                   c <= a + b
   


  END law_cos_pos_2D

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

  % Subtype TCC generated (at line 54, column 45) for
      % u * v / (norm(u) * norm(v))
      % expected type  y: real_abs_le1
  angle_between_TCC1: OBLIGATION
    FORALL (u, v: Nz_vect2):
      -1 <= u * v / (norm(u) * norm(v)) AND u * v / (norm(u) * norm(v)) <= 1;


body:
  lines[n: posnat]: THEORY
  %----------------------------------------------------------------------------
  % The traditional way to defines a line L is by specifying two distinct points,
  % P0 and P1, on it.  
  % 
  % A line L can also be defined by a point and a direction.  Let P0 be a
  % point on the line L and let dv be a nonzero vector specifying the direction
  % of the line.  This is equivalent to the two point definition, since we
  % could just put dv=(P1-P0).
   
  % We can also add dynamics to our line.  If we assume a particle is
  % moving in a line with a constant velocity, then we can define
  % this linear motion using the location of the point at time zero,
  % a velocity vector and a time parameter t:
  % 
  %       p0 + t*vel
  % 
  % which provides the location of the particle at time t.
  %
  % Author: Ricky Butler              NASA Langley Research Center
  %----------------------------------------------------------------------------
  BEGIN

     IMPORTING distance
                                          %     Basic        |   Parametric
                                          %------------------|-----------------
     Line : TYPE = [# p: Vector[n],       % point on the line| position at time 0
                      v: Nz_vector[n] #]  % direction vector | velocity vector
    
     LineND: TYPE = Line   

     p0 (L: Line): MACRO Vector[n] = p(L)  % alternate field names
     vel(L: Line): MACRO Vector[n] = v(L)

     vv: VAR [Vector[n],Nz_vector[n]]
     vecpair_to_Line(vv): MACRO Line = (# p := vv`1, v := vv`2 #)

     CONVERSION vecpair_to_Line 

     p,p1,p2,u,v,v0,v1,v2: VAR Vector[n]
     t: VAR nzreal


     loc(L: Line)(tt: real): MACRO Vector[n] = p(L) + tt*v(L)

  %  ------- generate vector from two points

     vec_from(p1,p2) : Vector[n] = p2 - p1

     line_from(p1,(p2:{v| v /= p1})): Line = (p1,vec_from(p1,p2))

     vec_from_eq_args : LEMMA vec_from(p,p) = zero


  %  ------- generate velocity vector from two points and transport time

     vel_from_tm(p1,p2,t): { v | p2 = p1 + t*v } = 1/t*(p2 - p1)

     line_from_tm(p1,(p2:{v| v /= p1}),t): Line = (p1,vel_from_tm(p1,p2,t))

     vel_from_tm_nz      : LEMMA p1 /= p2 IMPLIES vel_from_tm(p1,p2,t) /= zero

     vel_from_tm_lem     : LEMMA p2 = p1 + t*vel_from_tm(p1,p2,t)

     vel_from_tm_rew     : LEMMA vel_from_tm(p1,p2,t) = 1/t*(p2 - p1)

     vel_from_tm_eq_args : LEMMA vel_from_tm(p,p,t) = zero

     vel_from_tm_length  : LEMMA sq(norm(vel_from_tm(p1,p2,t))) =
                                      sq_dist(p1,p2)/sq(t)

  %  ------- generate velocity vector from two points and speed ------

     s: VAR posreal

     vel_from_spd(p1,p2,s):  Vector[n] = IF p1 = p2 then zero
                                     ELSE s/dist(p1,p2)*(p2-p1)
                                     ENDIF
     ps: VAR posreal
     vel_from_spd_lem: LEMMA p1 /= p2 IMPLIES
                       vel_from_spd(p1,p2,ps) = vel_from_tm(p1,p2,dist(p1,p2)/ps)


     vel_from_spd_norm: LEMMA p1 /= p2 IMPLIES
                                 vel_from_spd(p1,p2,s) = s*normalize(p2-p1)

     pt: VAR posreal
     gen_speed(p1,p2,pt): { s1: nnreal | s1 = 1/pt * dist(p1,p2) }


  %  ------- generate velocity vector from a point, heading, speed  ------

  %   IMPORTING trig@trig

  %   hdg: VAR posreal
  %   vel_from_hdg(p1,hdg,s): Vector[n] = LET p2 = p1+(cos(hdg),sin(hdg)) IN
  %                                       vel_from_spd(p1,p2,s)


  %  -------------- Line Predicates -----------------

     L,L1,L2: VAR Line

     on_line?(p,L): bool = EXISTS (x : real) : p = p(L) + x * v(L)

     on_segment?(p,L): bool =
                  EXISTS (x : { y: nnreal | y <= 1}) : p = p(L) + x * v(L)

     orthogonal?(L1,L2): bool = ^(v(L1))*^(v(L2)) = 0 

     parallel?(L1,L2)  : bool = ^(v(L1))*^(v(L2)) = 1 OR ^(v(L1))*^(v(L2)) = -1 


  %  -------------- Generate Parametric Lines -------

     gen_line_tm(p1,(p2:{v| v /= p1}),t) : Line = (# p := p1,
                                      v := vel_from_tm(p1,p2,t) #)

     gen_line_spd(p1,(p2:{v| v /= p1}),s): Line = (# p := p1,
                                      v := vel_from_spd(p1,p2,s) #)


     test1: LEMMA p1 /= p2 IMPLIES on_line?(p1,gen_line_tm(p1,p2,t))
     test2: LEMMA p1 /= p2 IMPLIES on_line?(p2,gen_line_tm(p1,p2,t))
     test3: LEMMA p1 /= p2 IMPLIES on_line?(p1,gen_line_spd(p1,p2,s))
     test4: LEMMA p1 /= p2 IMPLIES on_line?(p2,gen_line_spd(p1,p2,s))


     vel_from_spd_on_line: LEMMA  LET vv = vel_from_spd(p1,p2,s) IN 
                                    p = p1 + t*vv 
                                      IMPLIES on_line?(p1,p2,p) 



  END lines

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

  % Subtype TCC generated (at line 50, column 47) for  vec_from(p1, p2)
      % expected type  Nz_vector[n]
  line_from_TCC1: OBLIGATION
    FORALL (p1: Vector[n], (p2: {v | v /= p1})): vec_from(p1, p2) /= zero[n];

  % Subtype TCC generated (at line 57, column 49) for  1 / t * (p2 - p1)
      % expected type  {v | p2 = p1 + t * v}
  vel_from_tm_TCC1: OBLIGATION
    FORALL (p1: Vector[n], p2: Vector[n], t: nzreal):
      p2 = (+[n])(p1, *[n](t, *[n](1 / t, ((-[n])(p2, p1)))));

  % Subtype TCC generated (at line 59, column 52) for  vel_from_tm(p1, p2, t)
      % expected type  Nz_vector[n]
  line_from_tm_TCC1: OBLIGATION
    FORALL (p1: Vector[n], (p2: {v | v /= p1}), t: nzreal):
      vel_from_tm(p1, p2, t) /= zero[n];

  % Subtype TCC generated (at line 77, column 42) for  dist(p1, p2)
      % expected type  nznum
  vel_from_spd_TCC1: OBLIGATION
    FORALL (p1: Vector[n], p2: Vector[n]):
      NOT p1 = p2 IMPLIES dist[n](p1, p2) /= 0;

  % Subtype TCC generated (at line 81, column 64) for  dist(p1, p2) / ps
      % expected type  nzreal
  vel_from_spd_lem_TCC1: OBLIGATION
    FORALL (p1, p2: Vector[n], ps: posreal):
      p1 /= p2 IMPLIES dist[n](p1, p2) / ps /= 0;

  % Subtype TCC generated (at line 85, column 67) for  p2 - p1
      % expected type  Nz_vector[n]
  vel_from_spd_norm_TCC1: OBLIGATION
    FORALL (p1, p2: Vector[n]): p1 /= p2 IMPLIES (-[n])(p2, p1) /= zero[n];

  % Existence TCC generated (at line 88, column 3) for
      % gen_speed(p1, p2, pt): {s1: nnreal | s1 = 1 / pt * dist(p1, p2)}
  gen_speed_TCC1: OBLIGATION
    EXISTS (x:
              [d: [Vector[n], Vector[n], posreal] ->
                 {s1: nnreal | s1 = 1 / d`3 * dist[n](d`1, d`2)}]):
      TRUE;

  % Subtype TCC generated (at line 120, column 41) for
      % vel_from_spd(p1, p2, s)
      % expected type  Nz_vector[n]
  gen_line_spd_TCC1: OBLIGATION
    FORALL (p1: Vector[n], (p2: {v | v /= p1}), s: posreal):
      vel_from_spd(p1, p2, s) /= zero[n];

  % Subtype TCC generated (at line 123, column 60) for  p2
      % expected type  {v | v /= p1}
  test1_TCC1: OBLIGATION
    FORALL (p1, p2: Vector[n]): p1 /= p2 IMPLIES p2 /= p1;


body:
  vectors_3D_cos: THEORY
  BEGIN

  %                                      
  %                                      .
  %                                     / \
  %                                   /    \
  %                                 /       \
  %                               /          \
  %                      vc     /             \
  %                           /                \    vb
  %                         /                   \
  %                       /                      \
  %                     /                         \
  %                   /                            \
  %                 /                           ab  \
  %               /                                  \
  %               ------------------------------------ 
  %                               va                   

    IMPORTING vectors_3D, 
              trig@trig_basic

    va,vb,vc,v0,v1,v2: VAR Vect3

    ab: VAR real

    cosines_law   : LEMMA
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                        vc = va - vb AND
                        a*b*cos(ab) = va*vb
                          IMPLIES
                             sq(c) = sq(a) + sq(b) - 2*a*b*cos(ab)


    IMPORTING trig@trig_inverses

    angle_exists: LEMMA (EXISTS ab:  LET  a = norm(va),
                                          b = norm(vb) IN
                                a*b*cos(ab) = va*vb)


    angle_between(u,v:Nz_vect3): real = arccos(u*v/(norm(u)*norm(v)))


    cosines_law_bnd : LEMMA
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                           vc = va - vb IMPLIES
                              sq(c) >= sq(a-b)

    cosines_law_ge : LEMMA
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                           vc = va - vb IMPLIES
                              c >= abs(a-b)


    cosines_law_le : LEMMA 
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                           vc = va - vb IMPLIES
                                   c <= a + b
   


  END vectors_3D_cos

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

  % Subtype TCC generated (at line 46, column 45) for
      % u * v / (norm(u) * norm(v))
      % expected type  y: real_abs_le1
  angle_between_TCC1: OBLIGATION
    FORALL (u, v: Nz_vect3):
      -1 <= u * v / (norm(u) * norm(v)) AND u * v / (norm(u) * norm(v)) <= 1;


body:
  vectors_2D_cos: THEORY
  BEGIN

  %                                      
  %                                      .
  %                                     / \
  %                                   /    \
  %                                 /       \
  %                               /          \
  %                      vc     /             \
  %                           /                \    vb
  %                         /                   \
  %                       /                      \
  %                     /                         \
  %                   /                            \
  %                 /                           ab  \
  %               /                                  \
  %               ------------------------------------ 
  %                               va                   

  %  trig: LIBRARY = "../trig"

    IMPORTING vectors_2D, trig@trig_basic

    va,vb,vc,v0,v1,v2: VAR Vect2

    ab: VAR real

    cosines_law   : LEMMA
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                        vc = va - vb AND
                        a*b*cos(ab) = va*vb
                          IMPLIES
                             sq(c) = sq(a) + sq(b) - 2*a*b*cos(ab)


    IMPORTING trig@trig_inverses

    angle_exists: LEMMA (EXISTS ab:  LET  a = norm(va),
                                          b = norm(vb) IN
                                a*b*cos(ab) = va*vb)


    angle_between(u,v:Nz_vect2): real = arccos(u*v/(norm(u)*norm(v)))


    cosines_law_bnd : LEMMA
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                           vc = va - vb IMPLIES
                              sq(c) >= sq(a-b)

    cosines_law_ge : LEMMA
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                           vc = va - vb IMPLIES
                              c >= abs(a-b)


    cosines_law_le : LEMMA 
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                           vc = va - vb IMPLIES
                                   c <= a + b
   


  END vectors_2D_cos

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

  % Subtype TCC generated (at line 47, column 45) for
      % u * v / (norm(u) * norm(v))
      % expected type  y: real_abs_le1
  angle_between_TCC1: OBLIGATION
    FORALL (u, v: Nz_vect2):
      -1 <= u * v / (norm(u) * norm(v)) AND u * v / (norm(u) * norm(v)) <= 1;


body:
  vectors_cos[n: posnat]: THEORY
  BEGIN

  %                                      
  %                                      .
  %                                     / \
  %                                   /    \
  %                                 /       \
  %                               /          \
  %                      vc     /             \
  %                           /                \    vb
  %                         /                   \
  %                       /                      \
  %                     /                         \
  %                   /                            \
  %                 /                           ab  \
  %               /                                  \
  %               ------------------------------------ 
  %                               va                   

    IMPORTING vectors, trig@trig_basic

    va,vb,vc,v0,v1,v2: VAR Vector[n]

    ab: VAR real

    cosines_law   : LEMMA
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                        vc = va - vb AND
                        a*b*cos(ab) = va*vb
                          IMPLIES
                             sq(c) = sq(a) + sq(b) - 2*a*b*cos(ab)


    IMPORTING trig@trig_inverses

    angle_exists: LEMMA (EXISTS ab:  LET  a = norm(va),
                                          b = norm(vb) IN
                                a*b*cos(ab) = va*vb)



    angle_between(u,v:Nz_vector[n]): real = arccos(u*v/(norm(u)*norm(v)))


    cosines_law_bnd : LEMMA
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                           vc = va - vb IMPLIES
                              sq(c) >= sq(a-b)

    cosines_law_ge : LEMMA
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                           vc = va - vb IMPLIES
                              c >= abs(a-b)


    cosines_law_le : LEMMA 
                       LET a = norm(va),
                           b = norm(vb),
                           c = norm(vc)
                       IN
                           vc = va - vb IMPLIES
                                   c <= a + b
   


  END vectors_cos

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

  % Subtype TCC generated (at line 46, column 49) for
      % u * v / (norm(u) * norm(v))
      % expected type  y: real_abs_le1
  angle_between_TCC1: OBLIGATION
    FORALL (u, v: Nz_vector[n]):
      -1 <= *[n](u, v) / (norm[n](u) * norm[n](v)) AND
       *[n](u, v) / (norm[n](u) * norm[n](v)) <= 1;


body:
  vectors_3D_rew : THEORY

  %
  % NOTE:  USE "auto_rewrite_theory "vectors_3D_rew"
  %        If want distributed property applied also USE
  %             "auto_rewrite_theory "vectors_dist"

  BEGIN

    IMPORTING vectors_3D

    u,v,w    : VAR Vect3
    a,b      : VAR real


    AUTO_REWRITE+ vx_distr_add
    AUTO_REWRITE+ vy_distr_add
    AUTO_REWRITE+ vz_distr_add
    AUTO_REWRITE+ vx_distr_sub
    AUTO_REWRITE+ vy_distr_sub
    AUTO_REWRITE+ vz_distr_sub

    AUTO_REWRITE+ vx_scal                %% NEW %%
    AUTO_REWRITE+ vy_scal                %% NEW %%
    AUTO_REWRITE+ vz_scal                %% NEW %%

    AUTO_REWRITE+ sqv_scal
    AUTO_REWRITE+ norm_scal

    AUTO_REWRITE+ neg_distr_sub  
    AUTO_REWRITE+ neg_distr_add  
    AUTO_REWRITE+ dot_add_right  
    AUTO_REWRITE+ dot_add_left 
    AUTO_REWRITE+ dot_sub_right  
    AUTO_REWRITE+ dot_sub_left 
    AUTO_REWRITE+ scal_add_left      
    AUTO_REWRITE+ scal_sub_left  
    AUTO_REWRITE+ scal_add_right
    AUTO_REWRITE+ scal_sub_right


  %  AUTO_REWRITE+  sqv_add        
  %  AUTO_REWRITE+  sqv_sub        


  END vectors_3D_rew


body:
  vectors_2D_rew : THEORY

  %
  %   Additional more aggressive rewrites

  BEGIN

    IMPORTING vectors_2D

    u,v,w    : VAR Vect2
    a,b      : VAR real

    AUTO_REWRITE+ vx_distr_add
    AUTO_REWRITE+ vy_distr_add
    AUTO_REWRITE+ vx_distr_sub
    AUTO_REWRITE+ vy_distr_sub
    AUTO_REWRITE+ vx_scal                %% NEW %%
    AUTO_REWRITE+ vy_scal                %% NEW %%

    AUTO_REWRITE+ sqv_scal
    AUTO_REWRITE+ norm_scal

    AUTO_REWRITE+ neg_distr_sub  
    AUTO_REWRITE+ neg_distr_add  
    AUTO_REWRITE+ dot_add_right  
    AUTO_REWRITE+ dot_add_left 
    AUTO_REWRITE+ dot_sub_right  
    AUTO_REWRITE+ dot_sub_left 
    AUTO_REWRITE+ scal_add_left      
    AUTO_REWRITE+ scal_sub_left  
    AUTO_REWRITE+ scal_add_right
    AUTO_REWRITE+ scal_sub_right


  %  AUTO_REWRITE+  sqv_add        
  %  AUTO_REWRITE+  sqv_sub        

  END vectors_2D_rew


body:
  nvectors: THEORY
  %----------------------------------------------------------------------------
  % N-dimensional vectors of reals and operations (zero-based)
  %----------------------------------------------------------------------------
  BEGIN
     
  %   reals: LIBRARY = "../reals"

     IMPORTING reals@sigma_nat, reals@sqrt
     IMPORTING structures@fseqs_def[real,0]

     n: VAR posnat

     Vector : TYPE = {s: fseq | s`length > 0}
     Vect(n): TYPE = {v: Vector | v`length = n}

     a,b,c     : VAR real
     nza       : VAR nzreal
     u,v,w,z   : VAR Vector

  %  ----------- Vector Operations -------------------------------------------


     -(v): Vect(v`length) = 
         (# length := v`length,
            seq    := LAMBDA (i: nat): -v(i) 
         #) ;

     +(u: Vector, v: Vect(u`length)): Vect(u`length) = 
       (# length := u`length,
          seq := (LAMBDA (i: nat): u`seq(i) + v`seq(i))
        #) ;

     -(u: Vector, v: Vect(u`length)): Vect(u`length) = u + -v ;

     *(u: Vector, v: Vect(u`length)): real =
         sigma(0, u`length-1, LAMBDA (i: nat):u(i)*v(i)); % Dot Product

     *(a,v): Vect(v`length) =
         (# length := v`length,
            seq := LAMBDA (i: nat): a*v(i) 
         #)
      

  %  ^(nzv): Normalized = (1/norm(nzv))*nzv              % defined ahead

  %  ----------- Vector Functions  -------------------------------------------

     sqv(v): nnreal = v*v

     sq(v): nnreal = sigma(0,v`length-1,LAMBDA (i: nat): sq(v(i)))

     norm(v): nnreal = sqrt(sqv(v))

     zero_vector?(v) : MACRO bool = (norm(v) = 0)
     nz_vector?(v)   : MACRO bool = (norm(v) /= 0)  
     normalized?(v)  : MACRO bool = (norm(v) = 1)

     zero_vect?(n)(v: Vect(n)) : MACRO bool = (norm(v) = 0)
     nz_vect?(n)(v: Vect(n))  : MACRO bool = (norm(v) /= 0)  
     normalized_vect?(n)(v: Vect(n)) : MACRO bool = (norm(v) = 1)
   
     Zero_vector : TYPE = (zero_vector?)
     Nz_vector   : TYPE = (nz_vector?)
     Normalized  : TYPE = (normalized?)

     Zero_vect(n)  : TYPE = (zero_vect?(n))
     Nz_vect(n) : TYPE = (nz_vect?(n))
     Normalized_vect(n) : TYPE = (normalized_vect?(n))

     nzu,nzv     : VAR Nz_vector

  %  normalize(nzv) : Normalized = (1/norm(nzv))*nzv

  %  ----------- Special vectors ---------------------------------------------

     zero(n) : Zero_vect(n) = (# length := n, seq := LAMBDA (i: nat): 0 #)

     unity(n)(i: below(n)): Normalized_vect(n) =
        zero(n) WITH [`seq(i) := 1]

     const_vec(n)(a): Vect(n)  = const_seq(n,a)

  %  ----------- Vector Component Lemmas -------------------------------------

     comp_distr_add  : LEMMA
       FORALL (v: Vector, w: Vect(v`length), i: nat): i < v`length IMPLIES
         (v + w)`seq(i) = v`seq(i) + w`seq(i)  

     comp_distr_sub  : LEMMA
       FORALL (v: Vector, w: Vect(v`length), i: nat): i < v`length IMPLIES
         (v - w)`seq(i) = v`seq(i) - w`seq(i)  

     comp_distr_scal : LEMMA 
       FORALL (v: Vector, i: nat): i < v`length IMPLIES
         (a*v)`seq(i) = a*(v`seq(i))                %% NEW %%

     comp_zero : LEMMA FORALL (i: below(n)): zero(n)`seq(i) = 0

     comp_eq : LEMMA
       FORALL (u, (w: Vect(u`length))):
          u = w IFF FORALL (i: below(u`length)): u(i) = w(i)   %%%% NEW %%%%

  %  ----------- Vector Operation Lemmas -------------------------------------

     add_zero_left  : LEMMA FORALL (v: Vect(n)): zero(n) + v = v

     add_zero_right : LEMMA FORALL (v: Vect(n)): v + zero(n) = v

     add_comm       : LEMMA FORALL (u: Vector, v: Vect(u`length)): u+v = v+u

     add_assoc      : LEMMA
       FORALL (u: Vector, v, w: Vect(u`length)): u+(v+w) = (u+v)+w

     add_move_right : LEMMA
       FORALL (u: Vector, v, w: Vect(u`length)): u + w = v IFF u = v - w

     add_move_both  : LEMMA
       FORALL (u: Vector, v, w: Vect(u`length)): v = u + w IFF u = v - w

     add_neg_sub    : LEMMA
       FORALL (u: Vector, v: Vect(u`length)): v + -u = v - u

     add_cancel     : LEMMA
       FORALL (v: Vector, w: Vect(v`length)): v + w - v = w
     
     add_cancel_neg : LEMMA
       FORALL (v: Vector, w: Vect(v`length)): -v + w + v = w

     add_cancel2    : LEMMA
       FORALL (v: Vector, w: Vect(v`length)): w - v + v = w
     
     add_cancel_neg2 : LEMMA
       FORALL (v: Vector, w: Vect(v`length)): w + v - v = w


     sub_zero_left  : LEMMA FORALL (v: Vect(n)): zero(n) - v = -v

     sub_zero_right : LEMMA FORALL (v: Vect(n)): v - zero(n) = v

     sub_eq_args    : LEMMA FORALL (v: Vect(n)): v - v = zero(n)

     sub_eq_zero    : LEMMA FORALL (u, v: Vect(n)):
        u - v = zero(n) IFF u = v

     sub_cancel     : LEMMA
        FORALL (v: Vector, w: Vect(v`length)): v - w - v = -w

     sub_cancel_neg : LEMMA
        FORALL (v: Vector, w: Vect(v`length)): -v - w + v = -w


     neg_add_left   : LEMMA FORALL (v: Vect(n)): -v + v = zero(n)

     neg_add_right  : LEMMA FORALL (v: Vect(n)): v + -v = zero(n)

     neg_distr_sub  : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): -(v - u) = u - v

     neg_neg        : LEMMA --v = v

     neg_distr_add  : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): -(u + v) = -u - v


     dot_neg_left        : LEMMA
        FORALL (u: Vector, w: Vect(u`length)): (-u)*w = -(u*w)

     dot_neg_right       : LEMMA
        FORALL (u: Vector, w: Vect(u`length)): u*(-w) = -(u*w)

     dot_neg_sq          : LEMMA (-v)*(-v) = v*v 

     dot_zero_left       : LEMMA zero(v`length) * v = 0

     dot_zero_right      : LEMMA v * zero(v`length)  = 0

     dot_comm            : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): u*v = v*u

     dot_assoc           : LEMMA
        FORALL (w: Vect(v`length)): a*(v*w) = (a*v)*w

     dot_eq_args_ge      : LEMMA u*u >= 0

     dot_distr_add_left  : LEMMA
        FORALL (u: Vector, v, w: Vect(u`length)): u*(v+w) = u*v + u*w

     dot_distr_add_right : LEMMA
        FORALL (u: Vector, v, w: Vect(u`length)): (v+w)*u = v*u + w*u

     dot_distr_sub_left  : LEMMA
        FORALL (u: Vector, v, w: Vect(u`length)): u*(v-w) = u*v - u*w

     dot_distr_sub_right : LEMMA
        FORALL (u: Vector, v, w: Vect(u`length)): (v-w)*u = v*u - w*u

     dot_divby           : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): nza*u = nza*v IMPLIES u = v   %%%% NEW %%%%


     dot_scal_left       : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): (a*u)*v = a*(u*v)

     dot_scal_right      : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): u*(a*v) = a*(u*v)

     dot_scal_assoc      : LEMMA a*(b*u) = (a*b)*u 

     dot_scal_canon      : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): (a*u)*(b*v) = (a*b)*(u*v)      %% NEW %%x

     dot_scal_distr_add  : LEMMA (a+b)*u = a*u + b*u 

     dot_scal_distr_sub  : LEMMA (a-b)*u = a*u - b*u 

     scal_add_distr      : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): a*(u+v) = a*u + a*v 

     scal_sub_distr      : LEMMA 
        FORALL (u, (v: Vect(u`length))): a*(u-v) = a*u - a*v 


     scal_zero      : LEMMA a * zero(n) = zero(n)

     scal_0         : LEMMA 0 * v = zero(v`length)

     scal_1         : LEMMA 1 * v = v

     scal_cancel    : LEMMA a*nzv = b*nzv IMPLIES a = b    %% NEW %%


     scal_dot_eq_0  : LEMMA
        FORALL (v: Vect(n)): c*v = zero(n) IMPLIES c = 0 OR v = zero(n) %%%% NEW %%%%

     dot_ge_dist    : LEMMA
        FORALL (u: Vector, v, w: Vect(u`length)): w*u >= w*v IMPLIES w*(u-v) >= 0 

     dot_gt_dist    : LEMMA 
        FORALL (u: Vector, v, w: Vect(u`length)): w*u > w*v IMPLIES w*(u-v) > 0 

     sq_dot_eq      : LEMMA
        v*v = 0 IFF v = zero(v`length)

     sqv_sq         : LEMMA sqv(v) = sq(v)

     sq_sqv         : LEMMA sq(v) = sqv(v)

     sq_lem         : LEMMA
        sq(v) = sigma(0,v`length-1,LAMBDA (i: nat): sq(v(i)))

     sqv_lem        : LEMMA
        sqv(u) = sigma(0,u`length-1,(LAMBDA (i: nat): sq(u(i))))

     sqv_zero       : LEMMA sqv(zero(n)) = 0

     sqv_eq_0       : LEMMA sqv(v) = 0 IFF v = zero(v`length)

     sqv_neg        : LEMMA sqv(-v) = sqv(v)

     sqv_add        : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): sqv(u+v) = sqv(u) + sqv(v) + 2*u*v

     sqv_sub        : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): sqv(u-v) = sqv(u) + sqv(v) - 2*u*v

     sqv_sym        : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): sqv(u-v) = sqv(v-u)   

     sqv_scal       : LEMMA sqv(a*v) = sq(a)*sqv(v)

     sqrt_sqv_sq    : LEMMA sqrt(sqv(v)) * sqrt(sqv(v)) = sqv(v)


     norm_sym       : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): norm(u-v) = norm(v-u)

     norm_neg       : LEMMA norm(-u)  = norm(u)

     dot_sq_norm    : LEMMA u*u = sq(norm(u))

     sq_norm        : LEMMA sq(norm(u)) = u*u

     sqrt_sqv_norm  : LEMMA sqrt(sqv(v)) = norm(v)


     norm_eq_0      : LEMMA
        norm(v) = 0 IFF v = zero(v`length)

     norms_eq_sqv   : LEMMA
        FORALL (u: Vector, v: Vect(u`length)): norm(u) = norm(v) IFF sqv(u) = sqv(v)

     norm_scal      : LEMMA norm(a*v) = abs(a)*norm(v) 

     idem_right     : LEMMA
        a * v = v IFF (a = 1 OR v = zero(v`length)) ;

     ^(nzv)         : Normalized = (1/norm(nzv))*nzv              %% NEW %%
     normalize(nzv) : MACRO Normalized = ^(nzv)


     dot_normalize  : LEMMA
         FORALL (nzv: Nz_vect(nzu`length)): ^(nzu) * ^(nzv) %% NEW %%
                                 = nzu*nzv/(norm(nzu)*norm(nzv))

     normalize_normalize: LEMMA ^(^(nzv)) = ^(nzv)      %%%% NEW %%%%%%%


     sqv_minus_dot   : LEMMA
         FORALL (u: Vector, v: Vect(u`length)): sqv(u-a*v) = sqv(u) - 2*a*u*v + sq(a)*sqv(v)

     cauchy_schwarz : LEMMA
         FORALL (u: Vector, v: Vect(u`length)): sq(u*v) <= sqv(u)*sqv(v)

     dot_norm        : LEMMA
         FORALL (u: Vector, v: Vect(u`length)): -norm(u)*norm(v) <= u*v AND u*v <= norm(u)*norm(v)

     norm_add_le     : LEMMA
         FORALL (u: Vector, v: Vect(u`length)): norm(u+v) <= norm(u) + norm(v)

     norm_sub_le     : LEMMA
         FORALL (u: Vector, v: Vect(u`length)): norm(u-v) <= norm(u) + norm(v)

     norm_sub_ge     : LEMMA
         FORALL (u: Vector, v: Vect(u`length)): norm(u-v) >= norm(u) - norm(v)


     norm_ge_comps   : LEMMA
         FORALL (i: nat): norm(u) >= abs(u`seq(i)) %% NEW %%

     v0,v1,v2 : VAR Vector
     norm_triangle   : LEMMA
        FORALL (v0: Vector, v1, v2: Vect(v0`length)):
          LET a = v1-v0, b = v1-v2, c = v2-v0 IN    %% NEW %%
              sq(norm(c)) = sq(norm(a)) + sq(norm(b)) - 2*a*b

     nzvec_has_nz    : LEMMA (EXISTS (i: below(nzv`length)): nzv`seq(i) /= 0)      %% NEW %%

     nzvec_neq_zero  : LEMMA nzv /= zero(nzv`length) %% NEW %%


     v_neq_0        : LEMMA v /= zero(v`length) IFF sigma(0,v`length-1,(LAMBDA (i: nat): sq(v(i)))) > 0

  % ---------- Predicates over vectors ---------

    parallel?(nzu, (nzv: Nz_vect(nzu`length))): bool =
          ^(nzu)*^(nzv) = 1 OR ^(nzu)*^(nzv) = -1  %% NEW %%

    orthogonal?(u,(v: Vect(u`length))): bool =  u * v = 0 ;

  %  parallel_lem: LEMMA parallel?(nzu,nzv) IFF (EXISTS (k:nzreal):  nzu = k*nzv)

  % ---------- Auto Rewrites ------------------------------------


     AUTO_REWRITE+ add_zero_left  
     AUTO_REWRITE+ add_zero_right 
     AUTO_REWRITE+ sub_zero_left  
     AUTO_REWRITE+ sub_zero_right 
     AUTO_REWRITE+ sub_eq_zero                       %% NEW %%

     AUTO_REWRITE+ sub_eq_args    
     AUTO_REWRITE+ neg_add_left   
     AUTO_REWRITE+ neg_add_right  
     AUTO_REWRITE+ dot_zero_left  
     AUTO_REWRITE+ dot_zero_right 
     AUTO_REWRITE+ scal_zero      
     AUTO_REWRITE+ scal_0         
     AUTO_REWRITE+ sqv_zero       
     AUTO_REWRITE+ add_neg_sub    
     AUTO_REWRITE+ neg_neg        
     AUTO_REWRITE+ dot_scal_left      
     AUTO_REWRITE+ dot_scal_right     
     AUTO_REWRITE+ dot_scal_assoc     
     AUTO_REWRITE+ dot_scal_canon                 %% NEW %%
     AUTO_REWRITE+ sqv_neg        
     AUTO_REWRITE+ sqrt_sqv_sq
     AUTO_REWRITE+ norm_neg       
     AUTO_REWRITE+ comp_zero
     AUTO_REWRITE+ add_cancel
     AUTO_REWRITE+ sub_cancel
     AUTO_REWRITE+ add_cancel_neg
     AUTO_REWRITE+ sub_cancel_neg
     AUTO_REWRITE+ add_cancel2
     AUTO_REWRITE+ add_cancel_neg2

  %  ---- Turn off dangerous and unhelpful rewrites for auto-rewrite-theory --

     AUTO_REWRITE-    add_comm          % LEMMA u+v = v+u
     AUTO_REWRITE-    dot_comm          % LEMMA u*v = v*u
     AUTO_REWRITE-    dot_assoc         % LEMMA a*(v*w) = (a*v)*w   
     AUTO_REWRITE-    sqv_lem           % LEMMA sqv(u) = u*u
     AUTO_REWRITE-    sqv_sym           % LEMMA sqv(u-v) = sqv(v-u) 
     AUTO_REWRITE-    norm_sym          % LEMMA norm(u-v) = norm(v-u)
     AUTO_REWRITE-    dot_sq_norm       % LEMMA u*u = sq(norm(u))

  END nvectors

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

  % Subtype TCC generated (at line 24, column 14) for  v`length
      % expected type  posnat
  difference_TCC1: OBLIGATION FORALL (v): v`length > 0;

  % Subtype TCC generated (at line 26, column 20) for
      % LAMBDA (i: nat): -v`seq(i)
      % expected type  barray[real, 0](v`length)
  difference_TCC2: OBLIGATION
    FORALL (v: Vector):
      FORALL (i_1: nat): i_1 >= v`length IMPLIES -v`seq(i_1) = 0;

  % Subtype TCC generated (at line 31, column 16) for
      % (LAMBDA (i: nat): u`seq(i) + v`seq(i))
      % expected type  barray[real, 0](u`length)
  plus_TCC1: OBLIGATION
    FORALL (u: Vector, v: Vect(u`length)):
      FORALL (i_1: nat): i_1 >= u`length IMPLIES u`seq(i_1) + v`seq(i_1) = 0;

  % Subtype TCC generated (at line 30, column 5) for
      % (# length := u`length,
      %    seq := (LAMBDA (i: nat): u`seq(i) + v`seq(i)) #)
      % expected type  Vect(u`length)
  plus_TCC2: OBLIGATION FORALL (u: Vector, v: Vect(u`length)): u`length > 0;

  % Subtype TCC generated (at line 34, column 57) for  -v
      % expected type  Vect(u`length)
  difference_TCC3: OBLIGATION
    FORALL (u: Vector, v: Vect(u`length)): (-v)`length = u`length;

  % Subtype TCC generated (at line 37, column 16) for  u`length - 1
      % expected type  T_high[nat]
  times_TCC1: OBLIGATION
    FORALL (u: Vector, v: Vect(u`length)):
      u`length - 1 >= 0 OR (EXISTS (j: nat): u`length - 1 <= j);

  % Subtype TCC generated (at line 41, column 17) for
      % LAMBDA (i: nat): a * v`seq(i)
      % expected type  barray[real, 0](v`length)
  times_TCC2: OBLIGATION
    FORALL (a: real, v: Vector):
      FORALL (i_1: nat): i_1 >= v`length IMPLIES a * v`seq(i_1) = 0;

  % Subtype TCC generated (at line 49, column 20) for  v * v
      % expected type  nnreal
  sqv_TCC1: OBLIGATION FORALL (v: Vector): v * v >= 0;

  % Subtype TCC generated (at line 51, column 27) for  v`length - 1
      % expected type  T_high[nat]
  sq_TCC1: OBLIGATION
    FORALL (v: Vector):
      v`length - 1 >= 0 OR (EXISTS (j: nat): v`length - 1 <= j);

  % Subtype TCC generated (at line 77, column 51) for  LAMBDA (i: nat): 0
      % expected type  barray[real, 0](n)
  zero_TCC1: OBLIGATION FORALL (i_1: nat): TRUE;

  % Subtype TCC generated (at line 77, column 28) for
      % (# length := n, seq := LAMBDA (i: nat): 0 #)
      % expected type  Zero_vect(n)
  zero_TCC2: OBLIGATION
    FORALL (n: posnat):
      n > 0 AND (norm((# length := n, seq := LAMBDA (i: nat): 0 #)) = 0);

  % Subtype TCC generated (at line 80, column 6) for
      % zero(n) WITH [`seq(i) := 1]
      % expected type  Normalized_vect(n)
  unity_TCC1: OBLIGATION
    FORALL (n: posnat, i: below(n)):
      zero(n)`length > 0 AND
       zero(n)`length = n AND (norm((zero(n) WITH [`seq(i) := 1])) = 1);

  % Subtype TCC generated (at line 82, column 31) for  const_seq(n, a)
      % expected type  Vect(n)
  const_vec_TCC1: OBLIGATION
    FORALL (n: posnat, a: real):
      const_seq[real, 0](n, a)`length > 0 AND
       const_seq[real, 0](n, a)`length = n;

  % Subtype TCC generated (at line 106, column 57) for  v
      % expected type  Vect(zero(n)`length)
  add_zero_left_TCC1: OBLIGATION
    FORALL (n: posnat, v: Vect(n)): v`length = zero(n)`length;

  % Subtype TCC generated (at line 108, column 51) for  zero(n)
      % expected type  Vect(v`length)
  add_zero_right_TCC1: OBLIGATION
    FORALL (n: posnat, v: Vect(n)): zero(n)`length = v`length;

  % Subtype TCC generated (at line 110, column 73) for  u
      % expected type  Vect(v`length)
  add_comm_TCC1: OBLIGATION
    FORALL (u: Vector, v: Vect(u`length)): u`length = v`length;

  % Subtype TCC generated (at line 113, column 52) for  w
      % expected type  Vect(v`length)
  add_assoc_TCC1: OBLIGATION
    FORALL (u: Vector, v, w: Vect(u`length)): w`length = v`length;

  % Subtype TCC generated (at line 113, column 50) for  (v + w)
      % expected type  Vect(u`length)
  add_assoc_TCC2: OBLIGATION
    FORALL (u: Vector, v, w: Vect(u`length)): (v + w)`length = u`length;

  % Subtype TCC generated (at line 113, column 63) for  w
      % expected type  Vect((u + v)`length)
  add_assoc_TCC3: OBLIGATION
    FORALL (u: Vector, v, w: Vect(u`length)): w`length = (u + v)`length;

  % Subtype TCC generated (at line 122, column 48) for  -u
      % expected type  Vect(v`length)
  add_neg_sub_TCC1: OBLIGATION
    FORALL (u: Vector, v: Vect(u`length)): (-u)`length = v`length;

  % Subtype TCC generated (at line 125, column 52) for  v
      % expected type  Vect((v + w)`length)
  add_cancel_TCC1: OBLIGATION
    FORALL (v: Vector, w: Vect(v`length)): v`length = (v + w)`length;

  % Subtype TCC generated (at line 128, column 49) for  w
      % expected type  Vect((-v)`length)
  add_cancel_neg_TCC1: OBLIGATION
    FORALL (v: Vector, w: Vect(v`length)): w`length = (-v)`length;

  % Subtype TCC generated (at line 128, column 53) for  v
      % expected type  Vect((-v + w)`length)
  add_cancel_neg_TCC2: OBLIGATION
    FORALL (v: Vector, w: Vect(v`length)): v`length = (-v + w)`length;

  % Subtype TCC generated (at line 131, column 52) for  v
      % expected type  Vect((w - v)`length)
  add_cancel2_TCC1: OBLIGATION
    FORALL (v: Vector, w: Vect(v`length)): v`length = (w - v)`length;

  % Subtype TCC generated (at line 134, column 52) for  v
      % expected type  Vect((w + v)`length)
  add_cancel_neg2_TCC1: OBLIGATION
    FORALL (v: Vector, w: Vect(v`length)): v`length = (w + v)`length;

  % Subtype TCC generated (at line 144, column 10) for  v
      % expected type  Vect(u`length)
  sub_eq_zero_TCC1: OBLIGATION
    FORALL (n: posnat, u, v: Vect(n)): v`length = u`length;

  % Subtype TCC generated (at line 147, column 53) for  v
      % expected type  Vect((v - w)`length)
  sub_cancel_TCC1: OBLIGATION
    FORALL (v: Vector, w: Vect(v`length)): v`length = (v - w)`length;

  % Subtype TCC generated (at line 150, column 54) for  v
      % expected type  Vect((-v - w)`length)
  sub_cancel_neg_TCC1: OBLIGATION
    FORALL (v: Vector, w: Vect(v`length)): v`length = (-v - w)`length;

  % Subtype TCC generated (at line 153, column 52) for  v
      % expected type  Vect((-v)`length)
  neg_add_left_TCC1: OBLIGATION
    FORALL (n: posnat, v: Vect(n)): v`length = (-v)`length;

  % Subtype TCC generated (at line 163, column 61) for  v
      % expected type  Vect((-u)`length)
  neg_distr_add_TCC1: OBLIGATION
    FORALL (u: Vector, v: Vect(u`length)): v`length = (-u)`length;

  % Subtype TCC generated (at line 174, column 48) for  v
      % expected type  Vect(zero(v`length)`length)
  dot_zero_left_TCC1: OBLIGATION
    FORALL (v: Vector): v`length = zero(v`length)`length;

  % Subtype TCC generated (at line 182, column 50) for  w
      % expected type  Vect((a * v)`length)
  dot_assoc_TCC1: OBLIGATION
    FORALL (a: real, v: Vector, w: Vect(v`length)): w`length = (a * v)`length;

  % Subtype TCC generated (at line 190, column 54) for  u
      % expected type  Vect((v + w)`length)
  dot_distr_add_right_TCC1: OBLIGATION
    FORALL (u: Vector, v, w: Vect(u`length)): u`length = (v + w)`length;

  % Subtype TCC generated (at line 190, column 66) for  u
      % expected type  Vect(w`length)
  dot_distr_add_right_TCC2: OBLIGATION
    FORALL (u: Vector, v, w: Vect(u`length)): u`length = w`length;

  % Subtype TCC generated (at line 193, column 51) for  (v - w)
      % expected type  Vect(u`length)
  dot_distr_sub_left_TCC1: OBLIGATION
    FORALL (u: Vector, v, w: Vect(u`length)): (v - w)`length = u`length;

  % Subtype TCC generated (at line 196, column 54) for  u
      % expected type  Vect((v - w)`length)
  dot_distr_sub_right_TCC1: OBLIGATION
    FORALL (u: Vector, v, w: Vect(u`length)): u`length = (v - w)`length;

  % Subtype TCC generated (at line 203, column 51) for  v
      % expected type  Vect((a * u)`length)
  dot_scal_left_TCC1: OBLIGATION
    FORALL (a: real, u: Vector, v: Vect(u`length)): v`length = (a * u)`length;

  % Subtype TCC generated (at line 206, column 48) for  (a * v)
      % expected type  Vect(u`length)
  dot_scal_right_TCC1: OBLIGATION
    FORALL (a: real, u: Vector, v: Vect(u`length)): (a * v)`length = u`length;

  % Subtype TCC generated (at line 211, column 52) for  (b * v)
      % expected type  Vect((a * u)`length)
  dot_scal_canon_TCC1: OBLIGATION
    FORALL (a, b: real, u: Vector, v: Vect(u`length)):
      (b * v)`length = (a * u)`length;

  % Subtype TCC generated (at line 213, column 47) for  b * u
      % expected type  Vect((a * u)`length)
  dot_scal_distr_add_TCC1: OBLIGATION
    FORALL (a, b: real, u: Vector): (b * u)`length = (a * u)`length;

  % Subtype TCC generated (at line 218, column 61) for  a * v
      % expected type  Vect((a * u)`length)
  scal_add_distr_TCC1: OBLIGATION
    FORALL (a: real, u: Vector, v: Vect(u`length)):
      (a * v)`length = (a * u)`length;

  % Subtype TCC generated (at line 237, column 57) for  v
      % expected type  Vect(w`length)
  dot_ge_dist_TCC1: OBLIGATION
    FORALL (u: Vector, v, w: Vect(u`length)): v`length = w`length;

  % Subtype TCC generated (at line 237, column 70) for  (u - v)
      % expected type  Vect(w`length)
  dot_ge_dist_TCC2: OBLIGATION
    FORALL (u: Vector, v, w: Vect(u`length)):
      w * u >= w * v IMPLIES (u - v)`length = w`length;

  % Subtype TCC generated (at line 240, column 69) for  (u - v)
      % expected type  Vect(w`length)
  dot_gt_dist_TCC1: OBLIGATION
    FORALL (u: Vector, v, w: Vect(u`length)):
      w * u > w * v IMPLIES (u - v)`length = w`length;

  % Subtype TCC generated (at line 262, column 78) for  v
      % expected type  Vect((2 * u)`length)
  sqv_add_TCC1: OBLIGATION
    FORALL (u: Vector, v: Vect(u`length)): v`length = (2 * u)`length;

  % Subtype TCC generated (at line 298, column 36) for  norm(nzv)
      % expected type  nznum
  caret_TCC1: OBLIGATION FORALL (nzv: Nz_vector): norm(nzv) /= 0;

  % Subtype TCC generated (at line 298, column 33) for  (1 / norm(nzv)) * nzv
      % expected type  Normalized
  caret_TCC2: OBLIGATION
    FORALL (nzv: Nz_vector): (norm((1 / norm(nzv)) * nzv) = 1);

  % Subtype TCC generated (at line 303, column 51) for  ^(nzv)
      % expected type  Vect(^(nzu)`length)
  dot_normalize_TCC1: OBLIGATION
    FORALL (nzu: Nz_vector, nzv: Nz_vect(nzu`length)):
      ^(nzv)`length = ^(nzu)`length;

  % Subtype TCC generated (at line 304, column 42) for
      % (norm(nzu) * norm(nzv))
      % expected type  nznum
  dot_normalize_TCC2: OBLIGATION
    FORALL (nzu: Nz_vector, nzv: Nz_vect(nzu`length)):
      (norm(nzu) * norm(nzv)) /= 0;

  % Subtype TCC generated (at line 306, column 32) for  ^(nzv)
      % expected type  Nz_vector
  normalize_normalize_TCC1: OBLIGATION
    FORALL (nzv: Nz_vector): (norm(^(nzv)) /= 0);

  % Subtype TCC generated (at line 310, column 74) for  v
      % expected type  Vect((2 * a * u)`length)
  sqv_minus_dot_TCC1: OBLIGATION
    FORALL (a: real, u: Vector, v: Vect(u`length)):
      v`length = (2 * a * u)`length;

  % Subtype TCC generated (at line 335, column 58) for  b
      % expected type  Vect((2 * a)`length)
  norm_triangle_TCC1: OBLIGATION
    FORALL (v0: Vector, v1, v2: Vect(v0`length), a: Vect(v1`length)):
      a = v1 - v0 IMPLIES
       (FORALL (b: Vect(v1`length)):
          b = v1 - v2 IMPLIES
           (FORALL (c: Vect(v2`length)):
              c = v2 - v0 IMPLIES b`length = (2 * a)`length));

  % Subtype TCC generated (at line 339, column 39) for  nzv`length
      % expected type  n: posnat
  nzvec_neq_zero_TCC1: OBLIGATION FORALL (nzv: Nz_vector): nzv`length > 0;


body:
  %------------------------------------------------------------------------------
  % Top for the While Language
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  % The Programming Language "while" has been parameterized over the type of
  % variables (V); this is so that variable renaming can be made easier when
  % needed.
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  top[V:TYPE+]: THEORY

  BEGIN

    IMPORTING
      list_props_aux, % Extras for prelude library


      State[V],       % States and assignment
      AExp[V],        % Arithmetic Expressions and their evaluation function
      BExp[V],        % Boolean Expressions and their evaluation function
      Stm[V],         % Statements of While and structural induction principle
      Cont[V],        % Partial functions from State to State, and their order
      direct[V],      % A direct denotational semantics for While
      continuation[V],% A continuation semantics for While
      congruence[V],  % An equivalence proof (direct & continuation)
      sos[V],         % A Structural Operational Semantics
      direct_sos[V],  % An equivalence proof (direct & sos)
      compiler[V],    % A compiler
      Instruction[V], % Instruction set for an abstract machine
      am[V],          % An abstract machine
      bisimulation[V],% An equivalence proof (sos & am/compiler)
      axiomatic[V],   % An Axiomatic Semantics (Sound and Complete rwt sos)
      natural[V]      % A natural semantics and its equivalence to sos

  END top


body:
  %------------------------------------------------------------------------------
  % States
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  State[V:TYPE+]: THEORY

  BEGIN

    x,y: VAR V
    z:   VAR int

    State: TYPE+ = [V->int] CONTAINING (LAMBDA x: 0)

    s:   VAR State
    f:   VAR [State->int]

    assign(x,z)(s):State = (LAMBDA y: IF y = x THEN z ELSE s(y) ENDIF)
    assign(x,f)(s):State = assign(x,f(s))(s)

  END State


body:
  %------------------------------------------------------------------------------
  % Continuations
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  Cont[V:TYPE+]: THEORY

  BEGIN

    IMPORTING State[V],
              orders@lift_props[State],
              scott@partial_function_props[State,State]

    s,s1,s2: VAR State

    Cont: TYPE+ = LiftPartialFunction[State,State] CONTAINING (LAMBDA s: bottom)

    x:       VAR V
    f:       VAR [State->int]
    c,c1,c2: VAR Cont
    p:       VAR pred[State]

    sq_le(c1,c2):bool = FORALL (s1,s2): c1(s1) = up(s2) IMPLIES c2(s1) = up(s2)

    sq_le_def: LEMMA sq_le(c1,c2) IFF
                     subset?[[State,State]](graph(c1),graph(c2))      % NN 4.8

    partial_order_sq_le: JUDGEMENT sq_le HAS_TYPE (partial_order?[Cont])

    IMPORTING orders@directed_orders[Cont],
              orders@bounded_order_props[Cont,(sq_le)]

    D: VAR set[Cont]

    lub_graph: LEMMA empty?(D) OR directed?(sq_le)(D) IMPLIES
       least_upper_bound?(from_graph(Union(image(graph,D))),D,sq_le)

    sq_le_dcpo:  JUDGEMENT
                  sq_le HAS_TYPE (directed_complete_partial_order?[Cont])
    sq_le_pdcpo: JUDGEMENT
                  sq_le HAS_TYPE (pointed_directed_complete_partial_order?[Cont])

    sq_le_bottom: LEMMA sq_le((LAMBDA s: bottom),c)

    sq_le_least:  LEMMA least?(fullset[Cont],sq_le)(LAMBDA s: bottom)

    conditional(p,c1,c2):Cont
      = (LAMBDA s: IF p(s) THEN c1(s) ELSE c2(s) ENDIF)

    sq_le_conditional: LEMMA sq_le(c,conditional(p,c1,c2)) IFF
      (FORALL s1,s2: (    p(s1) AND c(s1) = up(s2) IMPLIES c1(s1) = up(s2)) AND
                     (NOT p(s1) AND c(s1) = up(s2) IMPLIES c2(s1) = up(s2)))

    assign(x,f):Cont = (LAMBDA s: up(assign(x,f)(s)))

    IMPORTING scott@scott_continuity[Cont,Cont,(sq_le),(sq_le)]

    apply_continuous: LEMMA scott_continuous?(LAMBDA c: c o c1)

  END Cont

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

  % Judgement subtype TCC generated (at line 35, column 33) for  sq_le
      % expected type  (partial_order?[Cont])
  partial_order_sq_le: OBLIGATION partial_order?[Cont](sq_le);

  % Subtype TCC generated (at line 42, column 49) for  D
      % expected type  (nonempty?[Cont])
  lub_graph_TCC1: OBLIGATION
    FORALL (D: set[Cont]): NOT empty?(D) IMPLIES nonempty?[Cont](D);

  % Subtype TCC generated (at line 43, column 35) for  Union(image(graph, D))
      % expected type  (graph?)
  lub_graph_TCC2: OBLIGATION
    FORALL (D: set[Cont]):
      empty?(D) OR directed?(sq_le)(D) IMPLIES
       graph?[State, State]
           (Union[[State[V], State[V]]]
                (image
                     [LiftPartialFunction[State, State],
                      set[[State[V], State[V]]]]
                     (graph[State, State], D)));

  % Judgement subtype TCC generated (at line 46, column 16) for  sq_le
      % expected type  (directed_complete_partial_order?[Cont])
  sq_le_dcpo: OBLIGATION directed_complete_partial_order?[Cont](sq_le);

  % Judgement subtype TCC generated (at line 48, column 16) for  sq_le
      % expected type  (pointed_directed_complete_partial_order?[Cont])
  sq_le_pdcpo: OBLIGATION
    pointed_directed_complete_partial_order?[Cont](sq_le);


body:
  %------------------------------------------------------------------------------
  % Arithmetic Expressions
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  AExp[V:TYPE+]: THEORY

  BEGIN

    IMPORTING State[V]

    AExp: DATATYPE  
    BEGIN
      N(n:int)        : N?
      V(x:V)          : V?
      Add(a1,a2:AExp) : Add?
      Sub(a1,a2:AExp) : Sub?
      Mul(a1,a2:AExp) : Mul?
    END AExp

    s: VAR State

    A(a:AExp) : RECURSIVE [State->int] =
      LAMBDA s: cases a of
                        N(n) : n,
                        V(x) : s(x),
                        Add(a1,a2) : A(a1)(s) + A(a2)(s),
                        Sub(a1,a2) : A(a1)(s) - A(a2)(s),
                        Mul(a1,a2) : A(a1)(s) * A(a2)(s)
                      endcases
                      MEASURE a by <<

  END AExp

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

  AExp_ord_defaxiom: AXIOM
         (FORALL (n: int): AExp_ord(N(n)) = 0)
     AND (FORALL (x: V): AExp_ord(V(x)) = 1)
     AND (FORALL (a1: AExp, a2: AExp): AExp_ord(Add(a1, a2)) = 2)
     AND (FORALL (a1: AExp, a2: AExp): AExp_ord(Sub(a1, a2)) = 3)
     AND (FORALL (a1: AExp, a2: AExp): AExp_ord(Mul(a1, a2)) = 4);

  AExp_N_extensionality: AXIOM
    FORALL (N?_var: (N?), N?_var2: (N?)):
      n(N?_var) = n(N?_var2) IMPLIES N?_var = N?_var2;

  AExp_N_eta: AXIOM FORALL (N?_var: (N?)): N(n(N?_var)) = N?_var;

  AExp_V_extensionality: AXIOM
    FORALL (V?_var: (V?), V?_var2: (V?)):
      x(V?_var) = x(V?_var2) IMPLIES V?_var = V?_var2;

  AExp_V_eta: AXIOM FORALL (V?_var: (V?)): V(x(V?_var)) = V?_var;

  AExp_Add_extensionality: AXIOM
    FORALL (Add?_var: (Add?), Add?_var2: (Add?)):
      a1(Add?_var) = a1(Add?_var2) AND a2(Add?_var) = a2(Add?_var2) IMPLIES
       Add?_var = Add?_var2;

  AExp_Add_eta: AXIOM
    FORALL (Add?_var: (Add?)): Add(a1(Add?_var), a2(Add?_var)) = Add?_var;

  AExp_Sub_extensionality: AXIOM
    FORALL (Sub?_var: (Sub?), Sub?_var2: (Sub?)):
      a1(Sub?_var) = a1(Sub?_var2) AND a2(Sub?_var) = a2(Sub?_var2) IMPLIES
       Sub?_var = Sub?_var2;

  AExp_Sub_eta: AXIOM
    FORALL (Sub?_var: (Sub?)): Sub(a1(Sub?_var), a2(Sub?_var)) = Sub?_var;

  AExp_Mul_extensionality: AXIOM
    FORALL (Mul?_var: (Mul?), Mul?_var2: (Mul?)):
      a1(Mul?_var) = a1(Mul?_var2) AND a2(Mul?_var) = a2(Mul?_var2) IMPLIES
       Mul?_var = Mul?_var2;

  AExp_Mul_eta: AXIOM
    FORALL (Mul?_var: (Mul?)): Mul(a1(Mul?_var), a2(Mul?_var)) = Mul?_var;

  AExp_n_N: AXIOM FORALL (N1_var: int): n(N(N1_var)) = N1_var;

  AExp_x_V: AXIOM FORALL (V1_var: V): x(V(V1_var):: (V?)) = V1_var;

  AExp_a1_Add: AXIOM
    FORALL (Add1_var: AExp, Add2_var: AExp):
      a1(Add(Add1_var, Add2_var)) = Add1_var;

  AExp_a2_Add: AXIOM
    FORALL (Add1_var: AExp, Add2_var: AExp):
      a2(Add(Add1_var, Add2_var)) = Add2_var;

  AExp_a1_Sub: AXIOM
    FORALL (Sub1_var: AExp, Sub2_var: AExp):
      a1(Sub(Sub1_var, Sub2_var)) = Sub1_var;

  AExp_a2_Sub: AXIOM
    FORALL (Sub1_var: AExp, Sub2_var: AExp):
      a2(Sub(Sub1_var, Sub2_var)) = Sub2_var;

  AExp_a1_Mul: AXIOM
    FORALL (Mul1_var: AExp, Mul2_var: AExp):
      a1(Mul(Mul1_var, Mul2_var)) = Mul1_var;

  AExp_a2_Mul: AXIOM
    FORALL (Mul1_var: AExp, Mul2_var: AExp):
      a2(Mul(Mul1_var, Mul2_var)) = Mul2_var;

  AExp_inclusive: AXIOM
    FORALL (AExp_var: AExp):
          N?(AExp_var) OR V?(AExp_var) OR Add?(AExp_var) OR Sub?(AExp_var)
       OR Mul?(AExp_var);

  AExp_induction: AXIOM
    FORALL (p: [AExp -> boolean]):
      (     FORALL (N1_var: int): p(N(N1_var))
        AND FORALL (V1_var: V): p(V(V1_var))
        AND FORALL (Add1_var: AExp, Add2_var: AExp):
              p(Add1_var) AND p(Add2_var) IMPLIES p(Add(Add1_var, Add2_var))
        AND FORALL (Sub1_var: AExp, Sub2_var: AExp):
              p(Sub1_var) AND p(Sub2_var) IMPLIES p(Sub(Sub1_var, Sub2_var))
        AND FORALL (Mul1_var: AExp, Mul2_var: AExp):
              p(Mul1_var) AND p(Mul2_var) IMPLIES p(Mul(Mul1_var, Mul2_var)))
       IMPLIES (FORALL (AExp_var: AExp): p(AExp_var));

  AExp_well_founded: AXIOM strict_well_founded?[AExp](<<);

  AExp: TYPE

  N?: [AExp -> boolean]

  V?: [AExp -> boolean]

  Add?: [AExp -> boolean]

  Sub?: [AExp -> boolean]

  Mul?: [AExp -> boolean]

  n: [(N?) -> int]

  x: [(V?) -> V]

  a1: [{x: AExp | Add?(x) OR Sub?(x) OR Mul?(x)} -> AExp]

  a2: [{x: AExp | Add?(x) OR Sub?(x) OR Mul?(x)} -> AExp]

  N: [int -> (N?)]

  V: [V -> (V?)]

  Add: [[AExp, AExp] -> (Add?)]

  Sub: [[AExp, AExp] -> (Sub?)]

  Mul: [[AExp, AExp] -> (Mul?)]

  AExp_ord: [AExp -> upto(4)]

  ord(x1: AExp): [AExp -> upto(4)] =
      CASES x1
        OF N(N1_var): 0,
           V(V1_var): 1,
           Add(Add1_var, Add2_var): 2,
           Sub(Sub1_var, Sub2_var): 3,
           Mul(Mul1_var, Mul2_var): 4
        ENDCASES

  subterm(x1: AExp, y: AExp):  boolean =
      x1 = y OR
       CASES y
         OF N(N1_var): FALSE,
            V(V1_var): FALSE,
            Add(Add1_var, Add2_var):
              subterm(x1, Add1_var) OR subterm(x1, Add2_var),
            Sub(Sub1_var, Sub2_var):
              subterm(x1, Sub1_var) OR subterm(x1, Sub2_var),
            Mul(Mul1_var, Mul2_var):
              subterm(x1, Mul1_var) OR subterm(x1, Mul2_var)
         ENDCASES;

  reduce_nat(N?_fun: [int -> nat], V?_fun: [V -> nat],
             Add?_fun: [[nat, nat] -> nat], Sub?_fun: [[nat, nat] -> nat],
             Mul?_fun: [[nat, nat] -> nat]):
        [AExp -> nat] =
      LAMBDA (AExp_adtvar: AExp):
        LET red: [AExp -> nat] =
              reduce_nat(N?_fun, V?_fun, Add?_fun, Sub?_fun, Mul?_fun)
          IN
          CASES AExp_adtvar
            OF N(N1_var): N?_fun(N1_var),
               V(V1_var): V?_fun(V1_var),
               Add(Add1_var, Add2_var):
                 Add?_fun(red(Add1_var), red(Add2_var)),
               Sub(Sub1_var, Sub2_var):
                 Sub?_fun(red(Sub1_var), red(Sub2_var)),
               Mul(Mul1_var, Mul2_var):
                 Mul?_fun(red(Mul1_var), red(Mul2_var))
            ENDCASES;

  REDUCE_nat(N?_fun: [[int, AExp] -> nat], V?_fun: [[V, AExp] -> nat],
             Add?_fun: [[nat, nat, AExp] -> nat],
             Sub?_fun: [[nat, nat, AExp] -> nat],
             Mul?_fun: [[nat, nat, AExp] -> nat]):
        [AExp -> nat] =
      LAMBDA (AExp_adtvar: AExp):
        LET red: [AExp -> nat] =
              REDUCE_nat(N?_fun, V?_fun, Add?_fun, Sub?_fun, Mul?_fun)
          IN
          CASES AExp_adtvar
            OF N(N1_var): N?_fun(N1_var, AExp_adtvar),
               V(V1_var): V?_fun(V1_var, AExp_adtvar),
               Add(Add1_var, Add2_var):
                 Add?_fun(red(Add1_var), red(Add2_var), AExp_adtvar),
               Sub(Sub1_var, Sub2_var):
                 Sub?_fun(red(Sub1_var), red(Sub2_var), AExp_adtvar),
               Mul(Mul1_var, Mul2_var):
                 Mul?_fun(red(Mul1_var), red(Mul2_var), AExp_adtvar)
            ENDCASES;

  reduce_ordinal(N?_fun: [int -> ordinal], V?_fun: [V -> ordinal],
                 Add?_fun: [[ordinal, ordinal] -> ordinal],
                 Sub?_fun: [[ordinal, ordinal] -> ordinal],
                 Mul?_fun: [[ordinal, ordinal] -> ordinal]):
        [AExp -> ordinal] =
      LAMBDA (AExp_adtvar: AExp):
        LET red: [AExp -> ordinal] =
              reduce_ordinal(N?_fun, V?_fun, Add?_fun, Sub?_fun, Mul?_fun)
          IN
          CASES AExp_adtvar
            OF N(N1_var): N?_fun(N1_var),
               V(V1_var): V?_fun(V1_var),
               Add(Add1_var, Add2_var):
                 Add?_fun(red(Add1_var), red(Add2_var)),
               Sub(Sub1_var, Sub2_var):
                 Sub?_fun(red(Sub1_var), red(Sub2_var)),
               Mul(Mul1_var, Mul2_var):
                 Mul?_fun(red(Mul1_var), red(Mul2_var))
            ENDCASES;

  REDUCE_ordinal(N?_fun: [[int, AExp] -> ordinal],
                 V?_fun: [[V, AExp] -> ordinal],
                 Add?_fun: [[ordinal, ordinal, AExp] -> ordinal],
                 Sub?_fun: [[ordinal, ordinal, AExp] -> ordinal],
                 Mul?_fun: [[ordinal, ordinal, AExp] -> ordinal]):
        [AExp -> ordinal] =
      LAMBDA (AExp_adtvar: AExp):
        LET red: [AExp -> ordinal] =
              REDUCE_ordinal(N?_fun, V?_fun, Add?_fun, Sub?_fun, Mul?_fun)
          IN
          CASES AExp_adtvar
            OF N(N1_var): N?_fun(N1_var, AExp_adtvar),
               V(V1_var): V?_fun(V1_var, AExp_adtvar),
               Add(Add1_var, Add2_var):
                 Add?_fun(red(Add1_var), red(Add2_var), AExp_adtvar),
               Sub(Sub1_var, Sub2_var):
                 Sub?_fun(red(Sub1_var), red(Sub2_var), AExp_adtvar),
               Mul(Mul1_var, Mul2_var):
                 Mul?_fun(red(Mul1_var), red(Mul2_var), AExp_adtvar)
            ENDCASES;

  <<:  (strict_well_founded?[AExp]) =
      LAMBDA (x1, y: AExp):
        CASES y
          OF N(N1_var): FALSE,
             V(V1_var): FALSE,
             Add(Add1_var, Add2_var):
               (x1 = Add1_var OR x1 << Add1_var) OR
                x1 = Add2_var OR x1 << Add2_var,
             Sub(Sub1_var, Sub2_var):
               (x1 = Sub1_var OR x1 << Sub1_var) OR
                x1 = Sub2_var OR x1 << Sub2_var,
             Mul(Mul1_var, Mul2_var):
               (x1 = Mul1_var OR x1 << Mul1_var) OR
                x1 = Mul2_var OR x1 << Mul2_var
          ENDCASES;

  % Termination TCC generated (at line 34, column 35) for  A(a1)
  A_TCC1: OBLIGATION
    FORALL (a: AExp, a1: AExp, a2: AExp): a = Add(a1, a2) IMPLIES a1 << a;

  % Termination TCC generated (at line 34, column 46) for  A(a2)
  A_TCC2: OBLIGATION
    FORALL (a: AExp, a1: AExp, a2: AExp): a = Add(a1, a2) IMPLIES a2 << a;

  % Termination TCC generated (at line 35, column 35) for  A(a1)
  A_TCC3: OBLIGATION
    FORALL (a: AExp, a1: AExp, a2: AExp): a = Sub(a1, a2) IMPLIES a1 << a;

  % Termination TCC generated (at line 35, column 46) for  A(a2)
  A_TCC4: OBLIGATION
    FORALL (a: AExp, a1: AExp, a2: AExp): a = Sub(a1, a2) IMPLIES a2 << a;

  % Termination TCC generated (at line 36, column 35) for  A(a1)
  A_TCC5: OBLIGATION
    FORALL (a: AExp, a1: AExp, a2: AExp): a = Mul(a1, a2) IMPLIES a1 << a;

  % Termination TCC generated (at line 36, column 46) for  A(a2)
  A_TCC6: OBLIGATION
    FORALL (a: AExp, a1: AExp, a2: AExp): a = Mul(a1, a2) IMPLIES a2 << a;


body:
  %------------------------------------------------------------------------------
  % Boolean Expressions
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  BExp[V:TYPE+]: THEORY

  BEGIN

    IMPORTING State[V], AExp[V]

    s:     VAR State

    BExp: DATATYPE  
    BEGIN
      TT               : TT?
      FF               : FF?
      Eq(a1,a2:AExp)   : Eq?
      Le(a1,a2:AExp)   : Le?
      Neg(b:BExp)      : Neg?
      Band(b1,b2:BExp) : Band?
    END BExp

    B(b:BExp) : RECURSIVE [State->bool] =
      LAMBDA s: cases b of
                        TT         : True,
                        FF         : False,
                        Eq(a1,a2)  : A(a1)(s) =  A(a2)(s),
                        Le(a1,a2)  : A(a1)(s) <= A(a2)(s),
                        Neg(b)     : NOT (B(b)(s)),
                        Band(b1,b2): B(b1)(s) AND B(b2)(s)
                      endcases
                      MEASURE b by <<

  END BExp

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

  BExp_ord_defaxiom: AXIOM
         BExp_ord(TT) = 0 AND BExp_ord(FF) = 1
     AND (FORALL (a1: AExp, a2: AExp): BExp_ord(Eq(a1, a2)) = 2)
     AND (FORALL (a1: AExp, a2: AExp): BExp_ord(Le(a1, a2)) = 3)
     AND (FORALL (b: BExp): BExp_ord(Neg(b)) = 4)
     AND (FORALL (b1: BExp, b2: BExp): BExp_ord(Band(b1, b2)) = 5);

  BExp_TT_extensionality: AXIOM
    FORALL (TT?_var: (TT?), TT?_var2: (TT?)): TT?_var = TT?_var2;

  BExp_FF_extensionality: AXIOM
    FORALL (FF?_var: (FF?), FF?_var2: (FF?)): FF?_var = FF?_var2;

  BExp_Eq_extensionality: AXIOM
    FORALL (Eq?_var: (Eq?), Eq?_var2: (Eq?)):
      a1(Eq?_var) = a1(Eq?_var2) AND a2(Eq?_var) = a2(Eq?_var2) IMPLIES
       Eq?_var = Eq?_var2;

  BExp_Eq_eta: AXIOM
    FORALL (Eq?_var: (Eq?)): Eq(a1(Eq?_var), a2(Eq?_var)) = Eq?_var;

  BExp_Le_extensionality: AXIOM
    FORALL (Le?_var: (Le?), Le?_var2: (Le?)):
      a1(Le?_var) = a1(Le?_var2) AND a2(Le?_var) = a2(Le?_var2) IMPLIES
       Le?_var = Le?_var2;

  BExp_Le_eta: AXIOM
    FORALL (Le?_var: (Le?)): Le(a1(Le?_var), a2(Le?_var)) = Le?_var;

  BExp_Neg_extensionality: AXIOM
    FORALL (Neg?_var: (Neg?), Neg?_var2: (Neg?)):
      b(Neg?_var) = b(Neg?_var2) IMPLIES Neg?_var = Neg?_var2;

  BExp_Neg_eta: AXIOM FORALL (Neg?_var: (Neg?)): Neg(b(Neg?_var)) = Neg?_var;

  BExp_Band_extensionality: AXIOM
    FORALL (Band?_var: (Band?), Band?_var2: (Band?)):
      b1(Band?_var) = b1(Band?_var2) AND b2(Band?_var) = b2(Band?_var2)
       IMPLIES Band?_var = Band?_var2;

  BExp_Band_eta: AXIOM
    FORALL (Band?_var: (Band?)):
      Band(b1(Band?_var), b2(Band?_var)) = Band?_var;

  BExp_a1_Eq: AXIOM
    FORALL (Eq1_var: AExp, Eq2_var: AExp): a1(Eq(Eq1_var, Eq2_var)) = Eq1_var;

  BExp_a2_Eq: AXIOM
    FORALL (Eq1_var: AExp, Eq2_var: AExp): a2(Eq(Eq1_var, Eq2_var)) = Eq2_var;

  BExp_a1_Le: AXIOM
    FORALL (Le1_var: AExp, Le2_var: AExp): a1(Le(Le1_var, Le2_var)) = Le1_var;

  BExp_a2_Le: AXIOM
    FORALL (Le1_var: AExp, Le2_var: AExp): a2(Le(Le1_var, Le2_var)) = Le2_var;

  BExp_b_Neg: AXIOM FORALL (Neg1_var: BExp): b(Neg(Neg1_var)) = Neg1_var;

  BExp_b1_Band: AXIOM
    FORALL (Band1_var: BExp, Band2_var: BExp):
      b1(Band(Band1_var, Band2_var)) = Band1_var;

  BExp_b2_Band: AXIOM
    FORALL (Band1_var: BExp, Band2_var: BExp):
      b2(Band(Band1_var, Band2_var)) = Band2_var;

  BExp_inclusive: AXIOM
    FORALL (BExp_var: BExp):
          TT?(BExp_var) OR FF?(BExp_var) OR Eq?(BExp_var) OR Le?(BExp_var)
       OR Neg?(BExp_var) OR Band?(BExp_var);

  BExp_induction: AXIOM
    FORALL (p: [BExp -> boolean]):
      (     p(TT) AND p(FF)
        AND FORALL (Eq1_var: AExp, Eq2_var: AExp): p(Eq(Eq1_var, Eq2_var))
        AND FORALL (Le1_var: AExp, Le2_var: AExp): p(Le(Le1_var, Le2_var))
        AND FORALL (Neg1_var: BExp): p(Neg1_var) IMPLIES p(Neg(Neg1_var))
        AND FORALL (Band1_var: BExp, Band2_var: BExp):
              p(Band1_var) AND p(Band2_var) IMPLIES
               p(Band(Band1_var, Band2_var)))
       IMPLIES (FORALL (BExp_var: BExp): p(BExp_var));

  BExp_well_founded: AXIOM strict_well_founded?[BExp](<<);

  BExp: TYPE

  TT?: [BExp -> boolean]

  FF?: [BExp -> boolean]

  Eq?: [BExp -> boolean]

  Le?: [BExp -> boolean]

  Neg?: [BExp -> boolean]

  Band?: [BExp -> boolean]

  a1: [{x: BExp | Eq?(x) OR Le?(x)} -> AExp[V]]

  a2: [{x: BExp | Eq?(x) OR Le?(x)} -> AExp[V]]

  b: [(Neg?) -> BExp]

  b1: [(Band?) -> BExp]

  b2: [(Band?) -> BExp]

  Eq: [[AExp[V], AExp[V]] -> (Eq?)]

  Le: [[AExp[V], AExp[V]] -> (Le?)]

  Neg: [BExp -> (Neg?)]

  Band: [[BExp, BExp] -> (Band?)]

  BExp_ord: [BExp -> upto(5)]

  ord(x: BExp): [BExp -> upto(5)] =
      CASES x
        OF TT: 0,
           FF: 1,
           Eq(Eq1_var, Eq2_var): 2,
           Le(Le1_var, Le2_var): 3,
           Neg(Neg1_var): 4,
           Band(Band1_var, Band2_var): 5
        ENDCASES

  subterm(x: BExp, y: BExp):  boolean =
      x = y OR
       CASES y
         OF TT: FALSE,
            FF: FALSE,
            Eq(Eq1_var, Eq2_var): FALSE,
            Le(Le1_var, Le2_var): FALSE,
            Neg(Neg1_var): subterm(x, Neg1_var),
            Band(Band1_var, Band2_var):
              subterm(x, Band1_var) OR subterm(x, Band2_var)
         ENDCASES;

  reduce_nat(TT?_fun: nat, FF?_fun: nat,
             Eq?_fun: [[AExp[V], AExp[V]] -> nat],
             Le?_fun: [[AExp[V], AExp[V]] -> nat], Neg?_fun: [nat -> nat],
             Band?_fun: [[nat, nat] -> nat]):
        [BExp -> nat] =
      LAMBDA (BExp_adtvar: BExp):
        LET red: [BExp -> nat] =
              reduce_nat(TT?_fun, FF?_fun, Eq?_fun, Le?_fun, Neg?_fun,
                         Band?_fun)
          IN
          CASES BExp_adtvar
            OF TT: TT?_fun,
               FF: FF?_fun,
               Eq(Eq1_var, Eq2_var): Eq?_fun(Eq1_var, Eq2_var),
               Le(Le1_var, Le2_var): Le?_fun(Le1_var, Le2_var),
               Neg(Neg1_var): Neg?_fun(red(Neg1_var)),
               Band(Band1_var, Band2_var):
                 Band?_fun(red(Band1_var), red(Band2_var))
            ENDCASES;

  REDUCE_nat(TT?_fun: [BExp -> nat], FF?_fun: [BExp -> nat],
             Eq?_fun: [[AExp[V], AExp[V], BExp] -> nat],
             Le?_fun: [[AExp[V], AExp[V], BExp] -> nat],
             Neg?_fun: [[nat, BExp] -> nat],
             Band?_fun: [[nat, nat, BExp] -> nat]):
        [BExp -> nat] =
      LAMBDA (BExp_adtvar: BExp):
        LET red: [BExp -> nat] =
              REDUCE_nat(TT?_fun, FF?_fun, Eq?_fun, Le?_fun, Neg?_fun,
                         Band?_fun)
          IN
          CASES BExp_adtvar
            OF TT: TT?_fun(BExp_adtvar),
               FF: FF?_fun(BExp_adtvar),
               Eq(Eq1_var, Eq2_var): Eq?_fun(Eq1_var, Eq2_var, BExp_adtvar),
               Le(Le1_var, Le2_var): Le?_fun(Le1_var, Le2_var, BExp_adtvar),
               Neg(Neg1_var): Neg?_fun(red(Neg1_var), BExp_adtvar),
               Band(Band1_var, Band2_var):
                 Band?_fun(red(Band1_var), red(Band2_var), BExp_adtvar)
            ENDCASES;

  reduce_ordinal(TT?_fun: ordinal, FF?_fun: ordinal,
                 Eq?_fun: [[AExp[V], AExp[V]] -> ordinal],
                 Le?_fun: [[AExp[V], AExp[V]] -> ordinal],
                 Neg?_fun: [ordinal -> ordinal],
                 Band?_fun: [[ordinal, ordinal] -> ordinal]):
        [BExp -> ordinal] =
      LAMBDA (BExp_adtvar: BExp):
        LET red: [BExp -> ordinal] =
              reduce_ordinal(TT?_fun, FF?_fun, Eq?_fun, Le?_fun, Neg?_fun,
                             Band?_fun)
          IN
          CASES BExp_adtvar
            OF TT: TT?_fun,
               FF: FF?_fun,
               Eq(Eq1_var, Eq2_var): Eq?_fun(Eq1_var, Eq2_var),
               Le(Le1_var, Le2_var): Le?_fun(Le1_var, Le2_var),
               Neg(Neg1_var): Neg?_fun(red(Neg1_var)),
               Band(Band1_var, Band2_var):
                 Band?_fun(red(Band1_var), red(Band2_var))
            ENDCASES;

  REDUCE_ordinal(TT?_fun: [BExp -> ordinal], FF?_fun: [BExp -> ordinal],
                 Eq?_fun: [[AExp[V], AExp[V], BExp] -> ordinal],
                 Le?_fun: [[AExp[V], AExp[V], BExp] -> ordinal],
                 Neg?_fun: [[ordinal, BExp] -> ordinal],
                 Band?_fun: [[ordinal, ordinal, BExp] -> ordinal]):
        [BExp -> ordinal] =
      LAMBDA (BExp_adtvar: BExp):
        LET red: [BExp -> ordinal] =
              REDUCE_ordinal(TT?_fun, FF?_fun, Eq?_fun, Le?_fun, Neg?_fun,
                             Band?_fun)
          IN
          CASES BExp_adtvar
            OF TT: TT?_fun(BExp_adtvar),
               FF: FF?_fun(BExp_adtvar),
               Eq(Eq1_var, Eq2_var): Eq?_fun(Eq1_var, Eq2_var, BExp_adtvar),
               Le(Le1_var, Le2_var): Le?_fun(Le1_var, Le2_var, BExp_adtvar),
               Neg(Neg1_var): Neg?_fun(red(Neg1_var), BExp_adtvar),
               Band(Band1_var, Band2_var):
                 Band?_fun(red(Band1_var), red(Band2_var), BExp_adtvar)
            ENDCASES;

  TT: (TT?)

  FF: (FF?)

  <<:  (strict_well_founded?[BExp]) =
      LAMBDA (x, y: BExp):
        CASES y
          OF TT: FALSE,
             FF: FALSE,
             Eq(Eq1_var, Eq2_var): FALSE,
             Le(Le1_var, Le2_var): FALSE,
             Neg(Neg1_var): x = Neg1_var OR x << Neg1_var,
             Band(Band1_var, Band2_var):
               (x = Band1_var OR x << Band1_var) OR
                x = Band2_var OR x << Band2_var
          ENDCASES;

  % Termination TCC generated (at line 37, column 40) for  B(b)
  B_TCC1: OBLIGATION FORALL (b: BExp, b1: BExp): b = Neg(b1) IMPLIES b1 << b;

  % Termination TCC generated (at line 38, column 35) for  B(b1)
  B_TCC2: OBLIGATION
    FORALL (b: BExp, b1: BExp, b2: BExp): b = Band(b1, b2) IMPLIES b1 << b;

  % Termination TCC generated (at line 38, column 48) for  B(b2)
  B_TCC3: OBLIGATION
    FORALL (b: BExp, v: [{z: BExp | z << b} -> [State[V] -> bool]], s,
            b1: BExp, b2: BExp):
      v(b1)(s) AND b = Band(b1, b2) IMPLIES b2 << b;


body:
  %------------------------------------------------------------------------------
  % Statements
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  Stm[V:TYPE+]: THEORY

  BEGIN

    IMPORTING AExp[V], BExp[V]

    Stm: DATATYPE  
    BEGIN
      Assign(x:V,a:AExp)            : Assign?
      Skip                          : Skip?
      Sequence(S1,S2:Stm)           : Sequence?
      Conditional(b:BExp,S1,S2:Stm) : Conditional?
      While(b:BExp,S1:Stm)          : While?
    END Stm

    x:       VAR V
    p:       VAR pred[Stm]
    a:       VAR AExp
    b:       VAR BExp
    S,S1,S2: VAR Stm

    Stm_measure(S): RECURSIVE nat =
       cases S of
         Assign(x,a)          : 0,
         Skip                 : 0,
         Sequence(S1,S2)      : max(Stm_measure(S1),Stm_measure(S2))+1,
         Conditional(b,S1,S2) : max(Stm_measure(S1),Stm_measure(S2))+1,
         While(b,S1)          : Stm_measure(S1)+1
       endcases
       MEASURE S by <<

    IMPORTING measure_induction[Stm,nat,Stm_measure,<]

    structural_induction: LEMMA
                 (FORALL x,a:                        p(Assign(x,a)))          AND
                                                     p(Skip)                  AND
                 (FORALL S1,S2:   p(S1) AND p(S2) => p(Sequence(S1,S2)))      AND
                 (FORALL b,S1,S2: p(S1) AND p(S2) => p(Conditional(b,S1,S2))) AND
                 (FORALL b,S1:    p(S1)           => p(While(b,S1)))
      IMPLIES
                 (FORALL S: p(S))

  END Stm

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

  Stm_ord_defaxiom: AXIOM
         (FORALL (x: V, a: AExp): Stm_ord(Assign(x, a)) = 0)
     AND Stm_ord(Skip) = 1
     AND (FORALL (S1: Stm, S2: Stm): Stm_ord(Sequence(S1, S2)) = 2)
     AND (FORALL (b: BExp, S1: Stm, S2: Stm):
            Stm_ord(Conditional(b, S1, S2)) = 3)
     AND (FORALL (b: BExp, S1: Stm): Stm_ord(While(b, S1)) = 4);

  Stm_Assign_extensionality: AXIOM
    FORALL (Assign?_var: (Assign?), Assign?_var2: (Assign?)):
      x(Assign?_var) = x(Assign?_var2) AND a(Assign?_var) = a(Assign?_var2)
       IMPLIES Assign?_var = Assign?_var2;

  Stm_Assign_eta: AXIOM
    FORALL (Assign?_var: (Assign?)):
      Assign(x(Assign?_var), a(Assign?_var)) = Assign?_var;

  Stm_Skip_extensionality: AXIOM
    FORALL (Skip?_var: (Skip?), Skip?_var2: (Skip?)): Skip?_var = Skip?_var2;

  Stm_Sequence_extensionality: AXIOM
    FORALL (Sequence?_var: (Sequence?), Sequence?_var2: (Sequence?)):
      S1(Sequence?_var) = S1(Sequence?_var2) AND
       S2(Sequence?_var) = S2(Sequence?_var2)
       IMPLIES Sequence?_var = Sequence?_var2;

  Stm_Sequence_eta: AXIOM
    FORALL (Sequence?_var: (Sequence?)):
      Sequence(S1(Sequence?_var), S2(Sequence?_var)) = Sequence?_var;

  Stm_Conditional_extensionality: AXIOM
    FORALL (Conditional?_var: (Conditional?),
            Conditional?_var2: (Conditional?)):
      b(Conditional?_var) = b(Conditional?_var2) AND
       S1(Conditional?_var) = S1(Conditional?_var2) AND
        S2(Conditional?_var) = S2(Conditional?_var2)
       IMPLIES Conditional?_var = Conditional?_var2;

  Stm_Conditional_eta: AXIOM
    FORALL (Conditional?_var: (Conditional?)):
      Conditional(b(Conditional?_var), S1(Conditional?_var),
                  S2(Conditional?_var))
       = Conditional?_var;

  Stm_While_extensionality: AXIOM
    FORALL (While?_var: (While?), While?_var2: (While?)):
      b(While?_var) = b(While?_var2) AND S1(While?_var) = S1(While?_var2)
       IMPLIES While?_var = While?_var2;

  Stm_While_eta: AXIOM
    FORALL (While?_var: (While?)):
      While(b(While?_var), S1(While?_var)) = While?_var;

  Stm_x_Assign: AXIOM
    FORALL (Assign1_var: V, Assign2_var: AExp):
      x(Assign(Assign1_var, Assign2_var)) = Assign1_var;

  Stm_a_Assign: AXIOM
    FORALL (Assign1_var: V, Assign2_var: AExp):
      a(Assign(Assign1_var, Assign2_var)) = Assign2_var;

  Stm_S1_Sequence: AXIOM
    FORALL (Sequence1_var: Stm, Sequence2_var: Stm):
      S1(Sequence(Sequence1_var, Sequence2_var)) = Sequence1_var;

  Stm_S2_Sequence: AXIOM
    FORALL (Sequence1_var: Stm, Sequence2_var: Stm):
      S2(Sequence(Sequence1_var, Sequence2_var)) = Sequence2_var;

  Stm_b_Conditional: AXIOM
    FORALL (Conditional1_var: BExp, Conditional2_var: Stm,
            Conditional3_var: Stm):
      b(Conditional(Conditional1_var, Conditional2_var, Conditional3_var)) =
       Conditional1_var;

  Stm_S1_Conditional: AXIOM
    FORALL (Conditional1_var: BExp, Conditional2_var: Stm,
            Conditional3_var: Stm):
      S1(Conditional(Conditional1_var, Conditional2_var, Conditional3_var)) =
       Conditional2_var;

  Stm_S2_Conditional: AXIOM
    FORALL (Conditional1_var: BExp, Conditional2_var: Stm,
            Conditional3_var: Stm):
      S2(Conditional(Conditional1_var, Conditional2_var, Conditional3_var)) =
       Conditional3_var;

  Stm_b_While: AXIOM
    FORALL (While1_var: BExp, While2_var: Stm):
      b(While(While1_var, While2_var)) = While1_var;

  Stm_S1_While: AXIOM
    FORALL (While1_var: BExp, While2_var: Stm):
      S1(While(While1_var, While2_var)) = While2_var;

  Stm_inclusive: AXIOM
    FORALL (Stm_var: Stm):
          Assign?(Stm_var) OR Skip?(Stm_var) OR Sequence?(Stm_var)
       OR Conditional?(Stm_var) OR While?(Stm_var);

  Stm_induction: AXIOM
    FORALL (p: [Stm -> boolean]):
      (     FORALL (Assign1_var: V, Assign2_var: AExp):
              p(Assign(Assign1_var, Assign2_var))
        AND p(Skip)
        AND FORALL (Sequence1_var: Stm, Sequence2_var: Stm):
              p(Sequence1_var) AND p(Sequence2_var) IMPLIES
               p(Sequence(Sequence1_var, Sequence2_var))
        AND FORALL (Conditional1_var: BExp, Conditional2_var: Stm,
                    Conditional3_var: Stm):
              p(Conditional2_var) AND p(Conditional3_var) IMPLIES
               p(Conditional(Conditional1_var, Conditional2_var,
                             Conditional3_var))
        AND FORALL (While1_var: BExp, While2_var: Stm):
              p(While2_var) IMPLIES p(While(While1_var, While2_var)))
       IMPLIES (FORALL (Stm_var: Stm): p(Stm_var));

  Stm_well_founded: AXIOM strict_well_founded?[Stm](<<);

  Stm: TYPE

  Assign?: [Stm -> boolean]

  Skip?: [Stm -> boolean]

  Sequence?: [Stm -> boolean]

  Conditional?: [Stm -> boolean]

  While?: [Stm -> boolean]

  x: [(Assign?) -> V]

  a: [(Assign?) -> AExp[V]]

  S1: [{x: Stm | Sequence?(x) OR Conditional?(x) OR While?(x)} -> Stm]

  S2: [{x: Stm | Sequence?(x) OR Conditional?(x)} -> Stm]

  b: [{x: Stm | Conditional?(x) OR While?(x)} -> BExp[V]]

  Assign: [[V, AExp[V]] -> (Assign?)]

  Sequence: [[Stm, Stm] -> (Sequence?)]

  Conditional: [[BExp[V], Stm, Stm] -> (Conditional?)]

  While: [[BExp[V], Stm] -> (While?)]

  Stm_ord: [Stm -> upto(4)]

  ord(x1: Stm): [Stm -> upto(4)] =
      CASES x1
        OF Assign(Assign1_var, Assign2_var): 0,
           Skip: 1,
           Sequence(Sequence1_var, Sequence2_var): 2,
           Conditional(Conditional1_var, Conditional2_var, Conditional3_var):
             3,
           While(While1_var, While2_var): 4
        ENDCASES

  subterm(x1: Stm, y: Stm):  boolean =
      x1 = y OR
       CASES y
         OF Assign(Assign1_var, Assign2_var): FALSE,
            Skip: FALSE,
            Sequence(Sequence1_var, Sequence2_var):
              subterm(x1, Sequence1_var) OR subterm(x1, Sequence2_var),
            Conditional(Conditional1_var, Conditional2_var,
                        Conditional3_var):
              subterm(x1, Conditional2_var) OR subterm(x1, Conditional3_var),
            While(While1_var, While2_var): subterm(x1, While2_var)
         ENDCASES;

  reduce_nat(Assign?_fun: [[V, AExp[V]] -> nat], Skip?_fun: nat,
             Sequence?_fun: [[nat, nat] -> nat],
             Conditional?_fun: [[BExp[V], nat, nat] -> nat],
             While?_fun: [[BExp[V], nat] -> nat]):
        [Stm -> nat] =
      LAMBDA (Stm_adtvar: Stm):
        LET red: [Stm -> nat] =
              reduce_nat(Assign?_fun, Skip?_fun, Sequence?_fun,
                         Conditional?_fun, While?_fun)
          IN
          CASES Stm_adtvar
            OF Assign(Assign1_var, Assign2_var):
                 Assign?_fun(Assign1_var, Assign2_var),
               Skip: Skip?_fun,
               Sequence(Sequence1_var, Sequence2_var):
                 Sequence?_fun(red(Sequence1_var), red(Sequence2_var)),
               Conditional(Conditional1_var, Conditional2_var,
                           Conditional3_var):
                 Conditional?_fun(Conditional1_var, red(Conditional2_var),
                                  red(Conditional3_var)),
               While(While1_var, While2_var):
                 While?_fun(While1_var, red(While2_var))
            ENDCASES;

  REDUCE_nat(Assign?_fun: [[V, AExp[V], Stm] -> nat],
             Skip?_fun: [Stm -> nat],
             Sequence?_fun: [[nat, nat, Stm] -> nat],
             Conditional?_fun: [[BExp[V], nat, nat, Stm] -> nat],
             While?_fun: [[BExp[V], nat, Stm] -> nat]):
        [Stm -> nat] =
      LAMBDA (Stm_adtvar: Stm):
        LET red: [Stm -> nat] =
              REDUCE_nat(Assign?_fun, Skip?_fun, Sequence?_fun,
                         Conditional?_fun, While?_fun)
          IN
          CASES Stm_adtvar
            OF Assign(Assign1_var, Assign2_var):
                 Assign?_fun(Assign1_var, Assign2_var, Stm_adtvar),
               Skip: Skip?_fun(Stm_adtvar),
               Sequence(Sequence1_var, Sequence2_var):
                 Sequence?_fun(red(Sequence1_var), red(Sequence2_var),
                               Stm_adtvar),
               Conditional(Conditional1_var, Conditional2_var,
                           Conditional3_var):
                 Conditional?_fun(Conditional1_var, red(Conditional2_var),
                                  red(Conditional3_var), Stm_adtvar),
               While(While1_var, While2_var):
                 While?_fun(While1_var, red(While2_var), Stm_adtvar)
            ENDCASES;

  reduce_ordinal(Assign?_fun: [[V, AExp[V]] -> ordinal], Skip?_fun: ordinal,
                 Sequence?_fun: [[ordinal, ordinal] -> ordinal],
                 Conditional?_fun: [[BExp[V], ordinal, ordinal] -> ordinal],
                 While?_fun: [[BExp[V], ordinal] -> ordinal]):
        [Stm -> ordinal] =
      LAMBDA (Stm_adtvar: Stm):
        LET red: [Stm -> ordinal] =
              reduce_ordinal(Assign?_fun, Skip?_fun, Sequence?_fun,
                             Conditional?_fun, While?_fun)
          IN
          CASES Stm_adtvar
            OF Assign(Assign1_var, Assign2_var):
                 Assign?_fun(Assign1_var, Assign2_var),
               Skip: Skip?_fun,
               Sequence(Sequence1_var, Sequence2_var):
                 Sequence?_fun(red(Sequence1_var), red(Sequence2_var)),
               Conditional(Conditional1_var, Conditional2_var,
                           Conditional3_var):
                 Conditional?_fun(Conditional1_var, red(Conditional2_var),
                                  red(Conditional3_var)),
               While(While1_var, While2_var):
                 While?_fun(While1_var, red(While2_var))
            ENDCASES;

  REDUCE_ordinal(Assign?_fun: [[V, AExp[V], Stm] -> ordinal],
                 Skip?_fun: [Stm -> ordinal],
                 Sequence?_fun: [[ordinal, ordinal, Stm] -> ordinal],
                 Conditional?_fun:
                   [[BExp[V], ordinal, ordinal, Stm] -> ordinal],
                 While?_fun: [[BExp[V], ordinal, Stm] -> ordinal]):
        [Stm -> ordinal] =
      LAMBDA (Stm_adtvar: Stm):
        LET red: [Stm -> ordinal] =
              REDUCE_ordinal(Assign?_fun, Skip?_fun, Sequence?_fun,
                             Conditional?_fun, While?_fun)
          IN
          CASES Stm_adtvar
            OF Assign(Assign1_var, Assign2_var):
                 Assign?_fun(Assign1_var, Assign2_var, Stm_adtvar),
               Skip: Skip?_fun(Stm_adtvar),
               Sequence(Sequence1_var, Sequence2_var):
                 Sequence?_fun(red(Sequence1_var), red(Sequence2_var),
                               Stm_adtvar),
               Conditional(Conditional1_var, Conditional2_var,
                           Conditional3_var):
                 Conditional?_fun(Conditional1_var, red(Conditional2_var),
                                  red(Conditional3_var), Stm_adtvar),
               While(While1_var, While2_var):
                 While?_fun(While1_var, red(While2_var), Stm_adtvar)
            ENDCASES;

  Skip: (Skip?)

  <<:  (strict_well_founded?[Stm]) =
      LAMBDA (x1, y: Stm):
        CASES y
          OF Assign(Assign1_var, Assign2_var): FALSE,
             Skip: FALSE,
             Sequence(Sequence1_var, Sequence2_var):
               (x1 = Sequence1_var OR x1 << Sequence1_var) OR
                x1 = Sequence2_var OR x1 << Sequence2_var,
             Conditional(Conditional1_var, Conditional2_var,
                         Conditional3_var):
               (x1 = Conditional2_var OR x1 << Conditional2_var) OR
                x1 = Conditional3_var OR x1 << Conditional3_var,
             While(While1_var, While2_var):
               x1 = While2_var OR x1 << While2_var
          ENDCASES;

  % Termination TCC generated (at line 38, column 34) for  Stm_measure(S1)
  Stm_measure_TCC1: OBLIGATION
    FORALL (S: Stm, S1: Stm, S2: Stm): S = Sequence(S1, S2) IMPLIES S1 << S;

  % Termination TCC generated (at line 38, column 50) for  Stm_measure(S2)
  Stm_measure_TCC2: OBLIGATION
    FORALL (S: Stm, S1: Stm, S2: Stm): S = Sequence(S1, S2) IMPLIES S2 << S;

  % Termination TCC generated (at line 39, column 34) for  Stm_measure(S1)
  Stm_measure_TCC3: OBLIGATION
    FORALL (S: Stm, b: BExp[V], S1: Stm, S2: Stm):
      S = Conditional(b, S1, S2) IMPLIES S1 << S;

  % Termination TCC generated (at line 39, column 50) for  Stm_measure(S2)
  Stm_measure_TCC4: OBLIGATION
    FORALL (S: Stm, b: BExp[V], S1: Stm, S2: Stm):
      S = Conditional(b, S1, S2) IMPLIES S2 << S;

  % Termination TCC generated (at line 40, column 30) for  Stm_measure(S1)
  Stm_measure_TCC5: OBLIGATION
    FORALL (S: Stm, b: BExp[V], S1: Stm): S = While(b, S1) IMPLIES S1 << S;

  % Subtype TCC generated (at line 44, column 50) for
      % restrict[[real, real], [nat, nat], boolean](<)
      % expected type  (well_founded?[nat])
  IMP_measure_induction_TCC1: OBLIGATION
    well_founded?[nat](restrict[[real, real], [nat, nat], boolean](<));


body:
  %------------------------------------------------------------------------------
  % A Continuation Semantics for the While Language
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  continuation[V:TYPE+]: THEORY

  BEGIN

    IMPORTING AExp[V], BExp[V], State[V], Stm[V], Cont[V],
              scott@partial_function_props[State,State],
              scott@scott_continuity[Cont,Cont,(sq_le),(sq_le)],
              scott@scott_identity_continuity[Cont,(sq_le)],
              scott@scott_composition_continuity[Cont,Cont,Cont,
                                                (sq_le),(sq_le),(sq_le)],
              scott@pointwise_orders_aux[Cont,Cont],
              scott@fixpoints[scott_continuous[Cont,Cont,(sq_le),(sq_le)],
                              continuous_pointwise(sq_le,sq_le)]

    s:       VAR State
    a:       VAR AExp
    b:       VAR BExp
    c,c1,c2: VAR Cont
    f,g:     VAR scott_continuous[Cont,Cont,(sq_le),(sq_le)]
    x:       VAR V
    S:       VAR Stm

    identity_continuous:    LEMMA scott_continuous?(I[Cont])
    composition_continuous: LEMMA scott_continuous?(f o g)
    assign_continuous:      LEMMA
                      scott_continuous?(LAMBDA c: LAMBDA s: c(assign(x,A(a))(s)))
    conditional_continuous: LEMMA
                         scott_continuous?(LAMBDA c: conditional(B(b),f(c),g(c)))

    composition_conditional: LEMMA
      conditional(B(b),c o c1, c o c2) = c o conditional(B(b),c1,c2)

    SS(S) : RECURSIVE (scott_continuous?[Cont,Cont,(sq_le),(sq_le)]) =
      cases S of
        Assign(x,a)          : (LAMBDA c: LAMBDA s: c(assign(x,A(a))(s))),
        Skip                 : I[Cont],
        Sequence(S1,S2)      : SS(S1) o SS(S2),
        Conditional(b,S1,S2) : LAMBDA c: conditional(B(b),SS(S1)(c),SS(S2)(c)),
        While(b,S1)          :
                 fix(LAMBDA g: LAMBDA c: conditional(B(b),SS(S1)(g(c)), c))
      endcases MEASURE S by <<

  END continuation

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

  % Existence TCC generated (at line 24, column 12) for
      % scott@fixpoints
      %     [scott_continuous[Cont, Cont, (sq_le), (sq_le)],
      %      continuous_pointwise(sq_le, sq_le)]
  IMP_fixpoints_TCC1: OBLIGATION
    EXISTS (x: scott_continuous[Cont[V], Cont[V], (sq_le[V]), (sq_le[V])]):
      TRUE;

  % Subtype TCC generated (at line 47, column 30) for
      % (LAMBDA c: LAMBDA s: c(assign(x, A(a))(s)))
      % expected type  (scott_continuous?[Cont, Cont, (sq_le), (sq_le)])
  SS_TCC1: OBLIGATION
    FORALL (S: Stm[V], x: V, a: AExp[V]):
      S = Assign(x, a) IMPLIES
       scott_continuous?[Cont[V], Cont[V], (sq_le[V]), (sq_le[V])]
           ((LAMBDA c: LAMBDA s: c(assign[V](x, A[V](a))(s))));

  % Termination TCC generated (at line 49, column 29) for  SS(S1)
  SS_TCC2: OBLIGATION
    FORALL (S: Stm[V], S1: Stm[V], S2: Stm[V]):
      S = Sequence(S1, S2) IMPLIES <<[V](S1, S);

  % Termination TCC generated (at line 49, column 38) for  SS(S2)
  SS_TCC3: OBLIGATION
    FORALL (S: Stm[V], S1: Stm[V], S2: Stm[V]):
      S = Sequence(S1, S2) IMPLIES <<[V](S2, S);

  % Termination TCC generated (at line 50, column 56) for  SS(S1)
  SS_TCC4: OBLIGATION
    FORALL (S: Stm[V], b: BExp[V], S1: Stm[V], S2: Stm[V]):
      S = Conditional(b, S1, S2) IMPLIES <<[V](S1, S);

  % Termination TCC generated (at line 50, column 66) for  SS(S2)
  SS_TCC5: OBLIGATION
    FORALL (S: Stm[V], b: BExp[V], S1: Stm[V], S2: Stm[V]):
      S = Conditional(b, S1, S2) IMPLIES <<[V](S2, S);

  % Subtype TCC generated (at line 50, column 29) for
      % LAMBDA c: conditional(B(b), SS(S1)(c), SS(S2)(c))
      % expected type  (scott_continuous?[Cont, Cont, (sq_le), (sq_le)])
  SS_TCC6: OBLIGATION
    FORALL (S: Stm[V],
            v:
              [{z: Stm[V] | z << S} ->
                 (scott_continuous?[Cont, Cont, (sq_le), (sq_le)])],
            b: BExp[V], S1: Stm[V], S2: Stm[V]):
      S = Conditional(b, S1, S2) IMPLIES
       scott_continuous?[Cont[V], Cont[V], (sq_le[V]), (sq_le[V])]
           (LAMBDA c: conditional[V](B[V](b), v(S1)(c), v(S2)(c)));

  % Termination TCC generated (at line 52, column 56) for  SS(S1)
  SS_TCC7: OBLIGATION
    FORALL (S: Stm[V], b: BExp[V], S1: Stm[V]):
      S = While(b, S1) IMPLIES <<[V](S1, S);

  % Subtype TCC generated (at line 52, column 29) for
      % LAMBDA c: conditional(B(b), SS(S1)(g(c)), c)
      % expected type  scott_continuous[Cont, Cont, (sq_le), (sq_le)]
  SS_TCC8: OBLIGATION
    FORALL (S: Stm[V],
            v:
              [{z: Stm[V] | z << S} ->
                 (scott_continuous?[Cont, Cont, (sq_le), (sq_le)])],
            b: BExp[V], S1: Stm[V]):
      S = While(b, S1) IMPLIES
       (FORALL (g):
          (scott_continuous?[Cont, Cont, (sq_le), (sq_le)])
              (LAMBDA c: conditional[V](B[V](b), v(S1)(g(c)), c)));

  % Subtype TCC generated (at line 52, column 19) for
      % LAMBDA g: LAMBDA c: conditional(B(b), SS(S1)(g(c)), c)
      % expected type  (increasing?)
  SS_TCC9: OBLIGATION
    FORALL (S: Stm[V],
            v:
              [{z: Stm[V] | z << S} ->
                 (scott_continuous?[Cont, Cont, (sq_le), (sq_le)])],
            b: BExp[V], S1: Stm[V]):
      S = While(b, S1) IMPLIES
       increasing?
           [scott_continuous[Cont, Cont, (sq_le), (sq_le)],
            scott_continuous[Cont, Cont, (sq_le), (sq_le)],
            continuous_pointwise(sq_le, sq_le),
            continuous_pointwise(sq_le, sq_le)]
           (LAMBDA g: LAMBDA c: conditional[V](B[V](b), v(S1)(g(c)), c));


body:
  %------------------------------------------------------------------------------
  % A Structural Operational Semantics
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  sos[V:TYPE+]: THEORY

  BEGIN

    IMPORTING State[V], AExp[V], BExp[V], Stm[V], Cont[V]

    S,S0,S1,S2: VAR Stm
    a: VAR AExp
    b: VAR BExp
    s,s0,s1,s2: VAR State
    i,j: VAR int
    x: VAR V
    n,k,k0,k1,k2: VAR nat

    Config: DATATYPE
    BEGIN
      I(S:Stm,s:State) : I?
      T(s1:State)      : T?
    END Config

    c,c0,c1,c2: VAR Config

    step(S,s): RECURSIVE [Config]
      = CASES S OF
          Assign(x,a)          : T(assign(x,A(a))(s)),
          Skip                 : T(s),
          Sequence(S1,S2)      : CASES step(S1,s) OF
                                   I(S11,s1) : I(Sequence(S11,S2),s1),
                                   T(s1)     : I(S2,s1) ENDCASES,
          Conditional(b,S1,S2) : IF B(b)(s) THEN I(S1,s) ELSE I(S2,s) ENDIF,
          While(b,S1)          : I(Conditional(b,Sequence(S1,S),Skip),s)
        ENDCASES MEASURE S BY <<

    terminal?(c):bool = T?(c)
    intermediate?(c):bool = I?(c)

    TConfig: TYPE = (terminal?)
    IConfig: TYPE = (intermediate?)

    TConfig_is_Config: JUDGEMENT TConfig SUBTYPE_OF Config
    IConfig_is_Config: JUDGEMENT IConfig SUBTYPE_OF Config

    tr(n)(c0,c): RECURSIVE bool
      = IF n=0 THEN c0=c
        ELSE I?(c0) AND CASES c0 OF I(S,s): tr(n-1)(step(S,s),c) ENDCASES ENDIF
        MEASURE n

    tr_add: LEMMA tr(k1+k2)(c0,c2) IFF EXISTS c1: tr(k1)(c0,c1) AND tr(k2)(c1,c2)
    tr_eq:  LEMMA tr(k)(c0,c1) AND tr(k)(c0,c2) => c1 = c2

    tr_split: LEMMA                                                    % N&N 2.19
       tr(k)(I(Sequence(S1,S2),s0),T(s2)) =>
       EXISTS s1,k1,k2:
         tr(k1)(I(S1,s0),T(s1)) AND tr(k2)(I(S2,s1),T(s2)) AND k1+k2=k

    tr_partial: LEMMA                                                  % N&N 2.21
       tr(k)(I(S1,s0),T(s1)) => tr(k)(I(Sequence(S1,S2),s0),I(S2,s1))

    tr_deterministic: LEMMA
       (tr(k1)(c,T(s1)) AND tr(k2)(c,T(s2))) => (k1 = k2 AND s1 = s2)

    SS(S) : Cont
      = lambda s:
          IF EXISTS n,s1: tr(n)(I(S,s),T(s1))
          THEN up(choose({s1 | EXISTS n: tr(n)(I(S,s),T(s1))}))
          ELSE bottom ENDIF

    SS_deterministic: LEMMA (EXISTS n: tr(n)(I(S,s),T(s1))) IFF SS(S)(s) = up(s1)
                                                                       % N&N 2.22

  END sos

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

  Config_ord_defaxiom: AXIOM
    (FORALL (S: Stm, s: State): Config_ord(I(S, s)) = 0) AND
     (FORALL (s1: State): Config_ord(T(s1)) = 1);

  Config_I_extensionality: AXIOM
    FORALL (I?_var: (I?), I?_var2: (I?)):
      S(I?_var) = S(I?_var2) AND s(I?_var) = s(I?_var2) IMPLIES
       I?_var = I?_var2;

  Config_I_eta: AXIOM FORALL (I?_var: (I?)): I(S(I?_var), s(I?_var)) = I?_var;

  Config_T_extensionality: AXIOM
    FORALL (T?_var: (T?), T?_var2: (T?)):
      s1(T?_var) = s1(T?_var2) IMPLIES T?_var = T?_var2;

  Config_T_eta: AXIOM FORALL (T?_var: (T?)): T(s1(T?_var)) = T?_var;

  Config_S_I: AXIOM
    FORALL (I1_var: Stm, I2_var: State): S(I(I1_var, I2_var)) = I1_var;

  Config_s_I: AXIOM
    FORALL (I1_var: Stm, I2_var: State): s(I(I1_var, I2_var)) = I2_var;

  Config_s1_T: AXIOM FORALL (T1_var: State): s1(T(T1_var)) = T1_var;

  Config_inclusive: AXIOM
    FORALL (Config_var: Config): I?(Config_var) OR T?(Config_var);

  Config_induction: AXIOM
    FORALL (p: [Config -> boolean]):
      ((FORALL (I1_var: Stm, I2_var: State): p(I(I1_var, I2_var))) AND
        (FORALL (T1_var: State): p(T(T1_var))))
       IMPLIES (FORALL (Config_var: Config): p(Config_var));

  Config_well_founded: AXIOM strict_well_founded?[Config](<<);

  Config: TYPE

  I?: [Config -> boolean]

  T?: [Config -> boolean]

  S: [(I?) -> Stm[V]]

  s: [(I?) -> [V -> int]]

  s1: [(T?) -> [V -> int]]

  I: [[Stm[V], [V -> int]] -> (I?)]

  T: [[V -> int] -> (T?)]

  Config_ord: [Config -> upto(1)]

  ord(x: Config): [Config -> upto(1)] =
      CASES x OF I(I1_var, I2_var): 0, T(T1_var): 1 ENDCASES

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

  reduce_nat(I?_fun: [[Stm[V], State[V]] -> nat],
             T?_fun: [State[V] -> nat]):
        [Config -> nat] =
      LAMBDA (Config_adtvar: Config):
        LET red: [Config -> nat] = reduce_nat(I?_fun, T?_fun) IN
          CASES Config_adtvar
            OF I(I1_var, I2_var): I?_fun(I1_var, I2_var),
               T(T1_var): T?_fun(T1_var)
            ENDCASES;

  REDUCE_nat(I?_fun: [[Stm[V], State[V], Config] -> nat],
             T?_fun: [[State[V], Config] -> nat]):
        [Config -> nat] =
      LAMBDA (Config_adtvar: Config):
        LET red: [Config -> nat] = REDUCE_nat(I?_fun, T?_fun) IN
          CASES Config_adtvar
            OF I(I1_var, I2_var): I?_fun(I1_var, I2_var, Config_adtvar),
               T(T1_var): T?_fun(T1_var, Config_adtvar)
            ENDCASES;

  reduce_ordinal(I?_fun: [[Stm[V], State[V]] -> ordinal],
                 T?_fun: [State[V] -> ordinal]):
        [Config -> ordinal] =
      LAMBDA (Config_adtvar: Config):
        LET red: [Config -> ordinal] = reduce_ordinal(I?_fun, T?_fun) IN
          CASES Config_adtvar
            OF I(I1_var, I2_var): I?_fun(I1_var, I2_var),
               T(T1_var): T?_fun(T1_var)
            ENDCASES;

  REDUCE_ordinal(I?_fun: [[Stm[V], State[V], Config] -> ordinal],
                 T?_fun: [[State[V], Config] -> ordinal]):
        [Config -> ordinal] =
      LAMBDA (Config_adtvar: Config):
        LET red: [Config -> ordinal] = REDUCE_ordinal(I?_fun, T?_fun) IN
          CASES Config_adtvar
            OF I(I1_var, I2_var): I?_fun(I1_var, I2_var, Config_adtvar),
               T(T1_var): T?_fun(T1_var, Config_adtvar)
            ENDCASES;

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

  % Termination TCC generated (at line 39, column 37) for  step(S1, s)
  step_TCC1: OBLIGATION
    FORALL (S: Stm[V], S1: Stm[V], S2: Stm[V]):
      S = Sequence(S1, S2) IMPLIES <<[V](S1, S);

  % Subtype TCC generated (at line 57, column 45) for  n - 1
      % expected type  nat
  tr_TCC1: OBLIGATION
    FORALL (n: nat, c0: Config):
      I?(c0) AND NOT n = 0 IMPLIES
       (FORALL (S: Stm[V], s: State[V]): c0 = I(S, s) IMPLIES n - 1 >= 0);

  % Termination TCC generated (at line 57, column 42) for  tr(n - 1)
  tr_TCC2: OBLIGATION
    FORALL (n: nat, c0: Config):
      I?(c0) AND NOT n = 0 IMPLIES
       (FORALL (S: Stm[V], s: State[V]): c0 = I(S, s) IMPLIES n - 1 < n);

  % Cases TCC generated (at line 57, column 28) for  c0
      % for missing ELSE of CASES expression over datatype Config
  tr_TCC3: OBLIGATION
    FORALL (n: nat, c0: Config): I?(c0) AND NOT n = 0 IMPLIES NOT T?(c0);

  % Subtype TCC generated (at line 77, column 23) for
      % {s1 | EXISTS n: tr(n)(I(S, s), T(s1))}
      % expected type  p: (nonempty?[State[V]])
  SS_TCC1: OBLIGATION
    FORALL (S: Stm[V], s):
      (EXISTS n, s1: tr(n)(I(S, s), T(s1))) IMPLIES
       nonempty?[State[V]]({s1 | EXISTS n: tr(n)(I(S, s), T(s1))});


body:
  %------------------------------------------------------------------------------
  % A Natural Semantics and its Equivalence to a Structural Operational Semantics
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  natural[V:TYPE+]: THEORY

  BEGIN

    IMPORTING State[V], AExp[V], BExp[V], Stm[V], Cont[V]

    tree: DATATYPE
    BEGIN
      leaf(d:[Stm,State,State])               : leaf?
      branch1(d:[Stm,State,State],t1:tree)    : branch1?
      branch2(d:[Stm,State,State],t1,t2:tree) : branch2?
    END tree

    depth(t:tree): RECURSIVE nat =
      CASES t OF
        leaf(d)          : 0,
        branch1(d,t1)    : depth(t1)+1,
        branch2(d,t1,t2) : max(depth(t1),depth(t2))+1
      ENDCASES MEASURE t by <<

    x: VAR V
    s,s0,s1: VAR State
    S: VAR Stm

    S(d:[Stm,State,State]):  Stm   = d`1
    s0(d:[Stm,State,State]): State = d`2
    s1(d:[Stm,State,State]): State = d`3

    S(t:tree):  Stm   = S(d(t))
    s0(t:tree): State = s0(d(t))
    s1(t:tree): State = s1(d(t))

    derivation_tree?(t:tree): RECURSIVE bool =
      CASES t OF
        leaf(d):
                 (Assign?(S(d)) AND s1(d)= assign(x(S(d)),A(a(S(d))))(s0(d))) OR
                 (Skip?(S(d))   AND s1(d)= s0(d)) OR
                 (While?(S(d)) AND (NOT B(b(S(d)))(s0(d))) AND s1(d) = s0(d)),
        branch2(d,t1,t2):
                 derivation_tree?(t1) AND derivation_tree?(t2) AND
                 ((Sequence?(S(d)) AND
                  S1(S(d)) = S(t1) AND S2(S(d)) = S(t2) AND
                  s0(t1) = s0(d) AND s1(t1) = s0(t2) AND s1(t) = s1(t2)) OR
                 (While?(S(d)) AND B(b(S(d)))(s0(d)) AND
                  S1(S(d)) = S(t1) AND S(t2) = S(d) AND
                  s0(t1) = s0(d) AND s1(t1) = s0(t2) AND s1(t) = s1(t2))),
        branch1(d,t1):
                 Conditional?(S(d)) AND derivation_tree?(t1) AND
                 s0(t1) = s0(d) AND s1(t1) = s1(d) AND
                 ((B(b(S(d)))(s0(d)) AND S1(S(d)) = S(t1)) OR
                  ((NOT B(b(S(d)))(s0(d))) AND S2(S(d)) = S(t1)))
      ENDCASES MEASURE t by <<

    derivation_tree: TYPE+ = (derivation_tree?)
                             CONTAINING leaf((Skip,lambda x: 0,lambda x: 0))

    d,d1,d2: VAR derivation_tree

    dt_eq: LEMMA S(d1) = S(d2) AND s0(d1) = s0(d2) => d1 = d2

    SS(S): Cont
      = lambda s:
          IF EXISTS d: S(d) = S AND s0(d) = s
          THEN up(choose({s1 | EXISTS d: S(d) = S AND s0(d) = s AND s1(d) = s1}))
          ELSE bottom ENDIF

    SS_deterministic: LEMMA (EXISTS d: S(d) = S AND s0(d) = s AND s1(d) = s1)
                            IFF SS(S)(s) = up(s1)                       % N%N 2.9

    IMPORTING sos, continuation

    natural_le_sos: LEMMA sq_le(SS(S),sos.SS(S))                       % N&N 2.27

    sos_le_natural: LEMMA sq_le(sos.SS(S),SS(S))                       % N&N 2.28

    natural_eq_sos: LEMMA SS(S) = sos.SS(S)                            % N&N 2.26

  END natural

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

  tree_ord_defaxiom: AXIOM
    (FORALL (d: [Stm, State, State]): tree_ord(leaf(d)) = 0) AND
     (FORALL (d: [Stm, State, State], t1: tree):
        tree_ord(branch1(d, t1)) = 1)
      AND
      (FORALL (d: [Stm, State, State], t1: tree, t2: tree):
         tree_ord(branch2(d, t1, t2)) = 2);

  tree_leaf_extensionality: AXIOM
    FORALL (leaf?_var: (leaf?), leaf?_var2: (leaf?)):
      d(leaf?_var) = d(leaf?_var2) IMPLIES leaf?_var = leaf?_var2;

  tree_leaf_eta: AXIOM
    FORALL (leaf?_var: (leaf?)): leaf(d(leaf?_var)) = leaf?_var;

  tree_branch1_extensionality: AXIOM
    FORALL (branch1?_var: (branch1?), branch1?_var2: (branch1?)):
      d(branch1?_var) = d(branch1?_var2) AND
       t1(branch1?_var) = t1(branch1?_var2)
       IMPLIES branch1?_var = branch1?_var2;

  tree_branch1_eta: AXIOM
    FORALL (branch1?_var: (branch1?)):
      branch1(d(branch1?_var), t1(branch1?_var)) = branch1?_var;

  tree_branch2_extensionality: AXIOM
    FORALL (branch2?_var: (branch2?), branch2?_var2: (branch2?)):
      d(branch2?_var) = d(branch2?_var2) AND
       t1(branch2?_var) = t1(branch2?_var2) AND
        t2(branch2?_var) = t2(branch2?_var2)
       IMPLIES branch2?_var = branch2?_var2;

  tree_branch2_eta: AXIOM
    FORALL (branch2?_var: (branch2?)):
      branch2(d(branch2?_var), t1(branch2?_var), t2(branch2?_var)) =
       branch2?_var;

  tree_d_leaf: AXIOM
    FORALL (leaf1_var: [Stm, State, State]): d(leaf(leaf1_var)) = leaf1_var;

  tree_d_branch1: AXIOM
    FORALL (branch11_var: [Stm, State, State], branch12_var: tree):
      d(branch1(branch11_var, branch12_var)) = branch11_var;

  tree_t1_branch1: AXIOM
    FORALL (branch11_var: [Stm, State, State], branch12_var: tree):
      t1(branch1(branch11_var, branch12_var)) = branch12_var;

  tree_d_branch2: AXIOM
    FORALL (branch21_var: [Stm, State, State], branch22_var: tree,
            branch23_var: tree):
      d(branch2(branch21_var, branch22_var, branch23_var)) = branch21_var;

  tree_t1_branch2: AXIOM
    FORALL (branch21_var: [Stm, State, State], branch22_var: tree,
            branch23_var: tree):
      t1(branch2(branch21_var, branch22_var, branch23_var)) = branch22_var;

  tree_t2_branch2: AXIOM
    FORALL (branch21_var: [Stm, State, State], branch22_var: tree,
            branch23_var: tree):
      t2(branch2(branch21_var, branch22_var, branch23_var)) = branch23_var;

  tree_inclusive: AXIOM
    FORALL (tree_var: tree):
      leaf?(tree_var) OR branch1?(tree_var) OR branch2?(tree_var);

  tree_induction: AXIOM
    FORALL (p: [tree -> boolean]):
      ((FORALL (leaf1_var: [Stm, State, State]):
          TRUE IMPLIES p(leaf(leaf1_var)))
        AND
        (FORALL (branch11_var: [Stm, State, State], branch12_var: tree):
           TRUE AND p(branch12_var) IMPLIES
            p(branch1(branch11_var, branch12_var)))
         AND
         (FORALL (branch21_var: [Stm, State, State], branch22_var: tree,
                  branch23_var: tree):
            TRUE AND p(branch22_var) AND p(branch23_var) IMPLIES
             p(branch2(branch21_var, branch22_var, branch23_var))))
       IMPLIES (FORALL (tree_var: tree): p(tree_var));

  tree_well_founded: AXIOM strict_well_founded?[tree](<<);

  tree: TYPE

  leaf?: [tree -> boolean]

  branch1?: [tree -> boolean]

  branch2?: [tree -> boolean]

  d: [tree -> [Stm[V], [V -> int], [V -> int]]]

  t1: [{x: tree | branch1?(x) OR branch2?(x)} -> tree]

  t2: [(branch2?) -> tree]

  leaf: [[Stm[V], [V -> int], [V -> int]] -> (leaf?)]

  branch1: [[[Stm[V], [V -> int], [V -> int]], tree] -> (branch1?)]

  branch2: [[[Stm[V], [V -> int], [V -> int]], tree, tree] -> (branch2?)]

  tree_ord: [tree -> upto(2)]

  ord(x: tree): [tree -> upto(2)] =
      CASES x
        OF leaf(leaf1_var): 0,
           branch1(branch11_var, branch12_var): 1,
           branch2(branch21_var, branch22_var, branch23_var): 2
        ENDCASES

  subterm(x: tree, y: tree):  boolean =
      x = y OR
       CASES y
         OF leaf(leaf1_var): FALSE,
            branch1(branch11_var, branch12_var): subterm(x, branch12_var),
            branch2(branch21_var, branch22_var, branch23_var):
              subterm(x, branch22_var) OR subterm(x, branch23_var)
         ENDCASES;

  reduce_nat(leaf?_fun: [[Stm[V], State[V], State[V]] -> nat],
             branch1?_fun: [[[Stm[V], State[V], State[V]], nat] -> nat],
             branch2?_fun:
               [[[Stm[V], State[V], State[V]], nat, nat] -> nat]):
        [tree -> nat] =
      LAMBDA (tree_adtvar: tree):
        LET red: [tree -> nat] =
              reduce_nat(leaf?_fun, branch1?_fun, branch2?_fun)
          IN
          CASES tree_adtvar
            OF leaf(leaf1_var): leaf?_fun(leaf1_var),
               branch1(branch11_var, branch12_var):
                 branch1?_fun(branch11_var, red(branch12_var)),
               branch2(branch21_var, branch22_var, branch23_var):
                 branch2?_fun(branch21_var, red(branch22_var),
                              red(branch23_var))
            ENDCASES;

  REDUCE_nat(leaf?_fun: [[[Stm[V], State[V], State[V]], tree] -> nat],
             branch1?_fun:
               [[[Stm[V], State[V], State[V]], nat, tree] -> nat],
             branch2?_fun:
               [[[Stm[V], State[V], State[V]], nat, nat, tree] -> nat]):
        [tree -> nat] =
      LAMBDA (tree_adtvar: tree):
        LET red: [tree -> nat] =
              REDUCE_nat(leaf?_fun, branch1?_fun, branch2?_fun)
          IN
          CASES tree_adtvar
            OF leaf(leaf1_var): leaf?_fun(leaf1_var, tree_adtvar),
               branch1(branch11_var, branch12_var):
                 branch1?_fun(branch11_var, red(branch12_var), tree_adtvar),
               branch2(branch21_var, branch22_var, branch23_var):
                 branch2?_fun(branch21_var, red(branch22_var),
                              red(branch23_var), tree_adtvar)
            ENDCASES;

  reduce_ordinal(leaf?_fun: [[Stm[V], State[V], State[V]] -> ordinal],
                 branch1?_fun:
                   [[[Stm[V], State[V], State[V]], ordinal] -> ordinal],
                 branch2?_fun:
                   [[[Stm[V], State[V], State[V]], ordinal, ordinal] ->
                      ordinal]):
        [tree -> ordinal] =
      LAMBDA (tree_adtvar: tree):
        LET red: [tree -> ordinal] =
              reduce_ordinal(leaf?_fun, branch1?_fun, branch2?_fun)
          IN
          CASES tree_adtvar
            OF leaf(leaf1_var): leaf?_fun(leaf1_var),
               branch1(branch11_var, branch12_var):
                 branch1?_fun(branch11_var, red(branch12_var)),
               branch2(branch21_var, branch22_var, branch23_var):
                 branch2?_fun(branch21_var, red(branch22_var),
                              red(branch23_var))
            ENDCASES;

  REDUCE_ordinal(leaf?_fun:
                   [[[Stm[V], State[V], State[V]], tree] -> ordinal],
                 branch1?_fun:
                   [[[Stm[V], State[V], State[V]], ordinal, tree] ->
                      ordinal],
                 branch2?_fun:
                   [[[Stm[V], State[V], State[V]], ordinal, ordinal, tree] ->
                      ordinal]):
        [tree -> ordinal] =
      LAMBDA (tree_adtvar: tree):
        LET red: [tree -> ordinal] =
              REDUCE_ordinal(leaf?_fun, branch1?_fun, branch2?_fun)
          IN
          CASES tree_adtvar
            OF leaf(leaf1_var): leaf?_fun(leaf1_var, tree_adtvar),
               branch1(branch11_var, branch12_var):
                 branch1?_fun(branch11_var, red(branch12_var), tree_adtvar),
               branch2(branch21_var, branch22_var, branch23_var):
                 branch2?_fun(branch21_var, red(branch22_var),
                              red(branch23_var), tree_adtvar)
            ENDCASES;

  <<:  (strict_well_founded?[tree]) =
      LAMBDA (x, y: tree):
        CASES y
          OF leaf(leaf1_var): FALSE,
             branch1(branch11_var, branch12_var):
               x = branch12_var OR x << branch12_var,
             branch2(branch21_var, branch22_var, branch23_var):
               (x = branch22_var OR x << branch22_var) OR
                x = branch23_var OR x << branch23_var
          ENDCASES;

  % Termination TCC generated (at line 29, column 25) for  depth(t1)
  depth_TCC1: OBLIGATION
    FORALL (t: tree, d: [Stm[V], State[V], State[V]], t1: tree):
      t = branch1(d, t1) IMPLIES t1 << t;

  % Termination TCC generated (at line 30, column 29) for  depth(t1)
  depth_TCC2: OBLIGATION
    FORALL (t: tree, d: [Stm[V], State[V], State[V]], t1: tree, t2: tree):
      t = branch2(d, t1, t2) IMPLIES t1 << t;

  % Termination TCC generated (at line 30, column 39) for  depth(t2)
  depth_TCC3: OBLIGATION
    FORALL (t: tree, d: [Stm[V], State[V], State[V]], t1: tree, t2: tree):
      t = branch2(d, t1, t2) IMPLIES t2 << t;

  % Subtype TCC generated (at line 50, column 42) for  S(d)
      % expected type  {x: Stm[V] | Conditional?(x) OR While?(x)}
  derivation_tree?_TCC1: OBLIGATION
    FORALL (t: tree, d: [Stm[V], State[V], State[V]]):
      While?(S(d)) AND
       NOT (Skip?(S(d)) AND s1(d) = s0(d)) AND
        NOT (Assign?(S(d)) AND s1(d) = assign(x(S(d)), A(a(S(d))))(s0(d)))
         AND t = leaf(d)
       IMPLIES Conditional?[V](S(d)) OR While?[V](S(d));

  % Subtype TCC generated (at line 54, column 19) for  S(d)
      % expected type  {x: Stm[V] |
                     %          Sequence?[V](x) OR
                     %           Conditional?(x) OR While?(x)}
  derivation_tree?_TCC2: OBLIGATION
    FORALL (t: tree, v: [{z: tree | z << t} -> bool],
            d: [Stm[V], State[V], State[V]], t1: tree, t2: tree):
      Sequence?(S(d)) AND v(t2) AND v(t1) AND t = branch2(d, t1, t2) IMPLIES
       Sequence?[V](S(d)) OR Conditional?[V](S(d)) OR While?[V](S(d));

  % Subtype TCC generated (at line 54, column 40) for  S(d)
      % expected type  {x: Stm[V] | Sequence?[V](x) OR Conditional?(x)}
  derivation_tree?_TCC3: OBLIGATION
    FORALL (t: tree, v: [{z: tree | z << t} -> bool],
            d: [Stm[V], State[V], State[V]], t1: tree, t2: tree):
           S1(S(d)) = S(t1) AND Sequence?(S(d)) AND v(t2) AND v(t1)
       AND t = branch2(d, t1, t2)
       IMPLIES Sequence?[V](S(d)) OR Conditional?[V](S(d));

  % Subtype TCC generated (at line 56, column 37) for  S(d)
      % expected type  {x: Stm[V] | Conditional?(x) OR While?(x)}
  derivation_tree?_TCC4: OBLIGATION
    FORALL (t: tree, v: [{z: tree | z << t} -> bool],
            d: [Stm[V], State[V], State[V]], t1: tree, t2: tree):
           While?(S(d))
       AND NOT (     Sequence?(S(d)) AND S1(S(d)) = S(t1) AND S2(S(d)) = S(t2)
                 AND s0(t1) = s0(d) AND s1(t1) = s0(t2) AND s1(t) = s1(t2))
       AND v(t2) AND v(t1) AND t = branch2(d, t1, t2)
       IMPLIES Conditional?[V](S(d)) OR While?[V](S(d));

  % Subtype TCC generated (at line 62, column 21) for  S(d)
      % expected type  {x: Stm[V] | Conditional?(x) OR While?(x)}
  derivation_tree?_TCC5: OBLIGATION
    FORALL (t: tree, v: [{z: tree | z << t} -> bool],
            d: [Stm[V], State[V], State[V]], t1: tree):
           s1(t1) = s1(d) AND s0(t1) = s0(d) AND v(t1) AND Conditional?(S(d))
       AND t = branch1(d, t1)
       IMPLIES Conditional?[V](S(d)) OR While?[V](S(d));

  % Subtype TCC generated (at line 63, column 48) for  S(d)
      % expected type  {x: Stm[V] | Sequence?[V](x) OR Conditional?(x)}
  derivation_tree?_TCC6: OBLIGATION
    FORALL (t: tree, v: [{z: tree | z << t} -> bool],
            d: [Stm[V], State[V], State[V]], t1: tree):
           (NOT B(b(S(d)))(s0(d)))
       AND NOT (B(b(S(d)))(s0(d)) AND S1(S(d)) = S(t1)) AND s1(t1) = s1(d)
       AND s0(t1) = s0(d) AND v(t1) AND Conditional?(S(d))
       AND t = branch1(d, t1)
       IMPLIES Sequence?[V](S(d)) OR Conditional?[V](S(d));

  % Subtype TCC generated (at line 67, column 38) for
      % leaf(Skip, LAMBDA x: 0, LAMBDA x: 0)
      % expected type  derivation_tree
  derivation_tree_TCC1: OBLIGATION
    derivation_tree?(leaf(Skip[V], LAMBDA x: 0, LAMBDA x: 0));

  % Subtype TCC generated (at line 76, column 23) for
      % {s1 | EXISTS d: S(d) = S AND s0(d) = s AND s1(d) = s1}
      % expected type  p: (nonempty?[State[V]])
  SS_TCC1: OBLIGATION
    FORALL (S: Stm[V], s):
      (EXISTS d: S(d) = S AND s0(d) = s) IMPLIES
       nonempty?[State[V]]
           ({s1 | EXISTS d: S(d) = S AND s0(d) = s AND s1(d) = s1});


body:
  %------------------------------------------------------------------------------
  % An Axiomatic (Hoare) Semantics and its Soundness and Completeness
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  axiomatic[V:TYPE+]: THEORY

  BEGIN

    IMPORTING State[V], AExp[V], BExp[V], Stm[V]

    Predicate: TYPE+ = pred[State]
    Hoare:     TYPE+ = [Predicate,Stm,Predicate]

    s,s1: VAR State
    x: VAR V
    a: VAR AExp
    b: VAR BExp

    assign(x,a)(P:Predicate)(s):bool = P(assign(x,A(a))(s))

  ;
    &(P,Q:Predicate)(s):bool  = P(s) AND Q(s);
    |>(P,Q:Predicate):bool    = FORALL s: P(s) => Q(s);
    ~(P:Predicate)(s):bool    = NOT P(s);

    tree: DATATYPE
    BEGIN
      ass(h:Hoare)             : ass?
      skip(h:Hoare)            : skip?
      comp(h:Hoare,t1,t2:tree) : comp?
      iif(h:Hoare,t1,t2:tree)  : iif? 
      while(h:Hoare,t:tree)    : while?
      cons(h:Hoare,t:tree)     : cons?
    END tree

    H(t:tree): RECURSIVE Hoare = 
      CASES t OF
        ass(h)        : h,
        skip(h)       : h,
        comp(h,t1,t2) : h,
        iif(h,t1,t2)  : h,
        while(h,t)    : h,
        cons(h,t)     : h
      ENDCASES MEASURE (lambda (t:tree): 1)

    P(h:Hoare): Predicate = h`1
    S(h:Hoare): Stm       = h`2
    Q(h:Hoare): Predicate = h`3

    inference_tree?(t:tree): RECURSIVE bool =
      CASES t OF
        ass(h)        : Assign?(S(h)) AND assign(x(S(h)),a(S(h)))(Q(h)) = P(h),
        skip(h)       : Skip?(S(h)) AND P(h) = Q(h),
        comp(h,t1,t2) : Sequence?(S(h)) AND
                        S1(S(h)) = S(H(t1)) AND S2(S(h)) = S(H(t2)) AND
                        inference_tree?(t1) AND inference_tree?(t2) AND
                        P(H(t1)) = P(h)     AND
                        Q(H(t1)) = P(H(t2)) AND
                        Q(H(t2)) = Q(h),
        iif(h,t1,t2)  : Conditional?(S(h))  AND
                        S1(S(h)) = S(H(t1)) AND S2(S(h)) = S(H(t2)) AND
                        inference_tree?(t1) AND inference_tree?(t2) AND
                        P(H(t1)) = (B(b(S(h))) & P(h))     AND
                        P(H(t2)) = (~B(b(S(h))) & P(h))     AND
                        Q(H(t1)) = Q(h) AND
                        Q(H(t2)) = Q(h),
        while(h,t)    : While?(S(h)) AND inference_tree?(t) AND
                        P(H(t)) = (B(b(S(h))) & P(h)) AND
                        Q(H(t)) = P(h)                  AND
                        Q(h)    = (~B(b(S(h))) & P(h))AND
                        S1(S(h)) = S(H(t)),
        cons(h,t)     : inference_tree?(t) AND S(h) = S(H(t)) AND
                        P(h) |> P(H(t)) AND Q(H(t)) |> Q(h)
      ENDCASES MEASURE t by <<

    inference_tree:TYPE+ = (inference_tree?)
                           CONTAINING skip((lambda s: TRUE,Skip,lambda s: TRUE))

    IMPORTING sos[V]

    t:   VAR inference_tree
    P,Q: VAR Predicate
    S:   VAR Stm

  ;
    |-(P,S,Q):bool = EXISTS t: H(t) = (P,S,Q);
    |=(P,S,Q):bool = FORALL s,s1: P(s) AND SS(S)(s) = up(s1) => Q(s1)

    wlp(S,Q)(s):bool = FORALL s1: SS(S)(s) = up(s1) => Q(s1)

    wlp_is_precondition: LEMMA |=(wlp(S,Q),S,Q)                        % N&N 6.20
    wlp_is_weakest:      LEMMA |=(P,S,Q) => P |> wlp(S,Q)              % N&N 6.20

    soundness:    LEMMA |-(P,S,Q) => |=(P,S,Q)                         % N&N 6.17
    completeness: LEMMA |=(P,S,Q) => |-(P,S,Q)                         % N&N 6.23

    sound_and_complete: THEOREM |=(P,S,Q) IFF |-(P,S,Q)                % N&N 6.16

  END axiomatic

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

  tree_ord_defaxiom: AXIOM
         (FORALL (h: Hoare): tree_ord(ass(h)) = 0)
     AND (FORALL (h: Hoare): tree_ord(skip(h)) = 1)
     AND (FORALL (h: Hoare, t1: tree, t2: tree):
            tree_ord(comp(h, t1, t2)) = 2)
     AND (FORALL (h: Hoare, t1: tree, t2: tree): tree_ord(iif(h, t1, t2)) = 3)
     AND (FORALL (h: Hoare, t: tree): tree_ord(while(h, t)) = 4)
     AND (FORALL (h: Hoare, t: tree): tree_ord(cons(h, t)) = 5);

  tree_ass_extensionality: AXIOM
    FORALL (ass?_var: (ass?), ass?_var2: (ass?)):
      h(ass?_var) = h(ass?_var2) IMPLIES ass?_var = ass?_var2;

  tree_ass_eta: AXIOM FORALL (ass?_var: (ass?)): ass(h(ass?_var)) = ass?_var;

  tree_skip_extensionality: AXIOM
    FORALL (skip?_var: (skip?), skip?_var2: (skip?)):
      h(skip?_var) = h(skip?_var2) IMPLIES skip?_var = skip?_var2;

  tree_skip_eta: AXIOM
    FORALL (skip?_var: (skip?)): skip(h(skip?_var)) = skip?_var;

  tree_comp_extensionality: AXIOM
    FORALL (comp?_var: (comp?), comp?_var2: (comp?)):
      h(comp?_var) = h(comp?_var2) AND
       t1(comp?_var) = t1(comp?_var2) AND t2(comp?_var) = t2(comp?_var2)
       IMPLIES comp?_var = comp?_var2;

  tree_comp_eta: AXIOM
    FORALL (comp?_var: (comp?)):
      comp(h(comp?_var), t1(comp?_var), t2(comp?_var)) = comp?_var;

  tree_iif_extensionality: AXIOM
    FORALL (iif?_var: (iif?), iif?_var2: (iif?)):
      h(iif?_var) = h(iif?_var2) AND
       t1(iif?_var) = t1(iif?_var2) AND t2(iif?_var) = t2(iif?_var2)
       IMPLIES iif?_var = iif?_var2;

  tree_iif_eta: AXIOM
    FORALL (iif?_var: (iif?)):
      iif(h(iif?_var), t1(iif?_var), t2(iif?_var)) = iif?_var;

  tree_while_extensionality: AXIOM
    FORALL (while?_var: (while?), while?_var2: (while?)):
      h(while?_var) = h(while?_var2) AND t(while?_var) = t(while?_var2)
       IMPLIES while?_var = while?_var2;

  tree_while_eta: AXIOM
    FORALL (while?_var: (while?)):
      while(h(while?_var), t(while?_var)) = while?_var;

  tree_cons_extensionality: AXIOM
    FORALL (cons?_var: (cons?), cons?_var2: (cons?)):
      h(cons?_var) = h(cons?_var2) AND t(cons?_var) = t(cons?_var2) IMPLIES
       cons?_var = cons?_var2;

  tree_cons_eta: AXIOM
    FORALL (cons?_var: (cons?)): cons(h(cons?_var), t(cons?_var)) = cons?_var;

  tree_h_ass: AXIOM FORALL (ass1_var: Hoare): h(ass(ass1_var)) = ass1_var;

  tree_h_skip: AXIOM
    FORALL (skip1_var: Hoare): h(skip(skip1_var)) = skip1_var;

  tree_h_comp: AXIOM
    FORALL (comp1_var: Hoare, comp2_var: tree, comp3_var: tree):
      h(comp(comp1_var, comp2_var, comp3_var)) = comp1_var;

  tree_t1_comp: AXIOM
    FORALL (comp1_var: Hoare, comp2_var: tree, comp3_var: tree):
      t1(comp(comp1_var, comp2_var, comp3_var)) = comp2_var;

  tree_t2_comp: AXIOM
    FORALL (comp1_var: Hoare, comp2_var: tree, comp3_var: tree):
      t2(comp(comp1_var, comp2_var, comp3_var)) = comp3_var;

  tree_h_iif: AXIOM
    FORALL (iif1_var: Hoare, iif2_var: tree, iif3_var: tree):
      h(iif(iif1_var, iif2_var, iif3_var)) = iif1_var;

  tree_t1_iif: AXIOM
    FORALL (iif1_var: Hoare, iif2_var: tree, iif3_var: tree):
      t1(iif(iif1_var, iif2_var, iif3_var)) = iif2_var;

  tree_t2_iif: AXIOM
    FORALL (iif1_var: Hoare, iif2_var: tree, iif3_var: tree):
      t2(iif(iif1_var, iif2_var, iif3_var)) = iif3_var;

  tree_h_while: AXIOM
    FORALL (while1_var: Hoare, while2_var: tree):
      h(while(while1_var, while2_var)) = while1_var;

  tree_t_while: AXIOM
    FORALL (while1_var: Hoare, while2_var: tree):
      t(while(while1_var, while2_var)) = while2_var;

  tree_h_cons: AXIOM
    FORALL (cons1_var: Hoare, cons2_var: tree):
      h(cons(cons1_var, cons2_var)) = cons1_var;

  tree_t_cons: AXIOM
    FORALL (cons1_var: Hoare, cons2_var: tree):
      t(cons(cons1_var, cons2_var)) = cons2_var;

  tree_inclusive: AXIOM
    FORALL (tree_var: tree):
          ass?(tree_var) OR skip?(tree_var) OR comp?(tree_var)
       OR iif?(tree_var) OR while?(tree_var) OR cons?(tree_var);

  tree_induction: AXIOM
    FORALL (p: [tree -> boolean]):
      (     FORALL (ass1_var: Hoare): TRUE IMPLIES p(ass(ass1_var))
        AND FORALL (skip1_var: Hoare): TRUE IMPLIES p(skip(skip1_var))
        AND FORALL (comp1_var: Hoare, comp2_var: tree, comp3_var: tree):
              TRUE AND p(comp2_var) AND p(comp3_var) IMPLIES
               p(comp(comp1_var, comp2_var, comp3_var))
        AND FORALL (iif1_var: Hoare, iif2_var: tree, iif3_var: tree):
              TRUE AND p(iif2_var) AND p(iif3_var) IMPLIES
               p(iif(iif1_var, iif2_var, iif3_var))
        AND FORALL (while1_var: Hoare, while2_var: tree):
              TRUE AND p(while2_var) IMPLIES p(while(while1_var, while2_var))
        AND FORALL (cons1_var: Hoare, cons2_var: tree):
              TRUE AND p(cons2_var) IMPLIES p(cons(cons1_var, cons2_var)))
       IMPLIES (FORALL (tree_var: tree): p(tree_var));

  tree_well_founded: AXIOM strict_well_founded?[tree](<<);

  tree: TYPE

  ass?: [tree -> boolean]

  skip?: [tree -> boolean]

  comp?: [tree -> boolean]

  iif?: [tree -> boolean]

  while?: [tree -> boolean]

  cons?: [tree -> boolean]

  h: [tree -> [[[V -> int] -> boolean], Stm[V], [[V -> int] -> boolean]]]

  t1: [{x: tree | comp?(x) OR iif?(x)} -> tree]

  t2: [{x: tree | comp?(x) OR iif?(x)} -> tree]

  t: [{x: tree | while?(x) OR cons?(x)} -> tree]

  ass: [[[[V -> int] -> boolean], Stm[V], [[V -> int] -> boolean]] -> (ass?)]

  skip:
        [[[[V -> int] -> boolean], Stm[V], [[V -> int] -> boolean]] ->
           (skip?)]

  comp:
        [[[[[V -> int] -> boolean], Stm[V], [[V -> int] -> boolean]], tree,
          tree] ->
           (comp?)]

  iif:
        [[[[[V -> int] -> boolean], Stm[V], [[V -> int] -> boolean]], tree,
          tree] ->
           (iif?)]

  while:
        [[[[[V -> int] -> boolean], Stm[V], [[V -> int] -> boolean]],
          tree] ->
           (while?)]

  cons:
        [[[[[V -> int] -> boolean], Stm[V], [[V -> int] -> boolean]],
          tree] ->
           (cons?)]

  tree_ord: [tree -> upto(5)]

  ord(x: tree): [tree -> upto(5)] =
      CASES x
        OF ass(ass1_var): 0,
           skip(skip1_var): 1,
           comp(comp1_var, comp2_var, comp3_var): 2,
           iif(iif1_var, iif2_var, iif3_var): 3,
           while(while1_var, while2_var): 4,
           cons(cons1_var, cons2_var): 5
        ENDCASES

  subterm(x: tree, y: tree):  boolean =
      x = y OR
       CASES y
         OF ass(ass1_var): FALSE,
            skip(skip1_var): FALSE,
            comp(comp1_var, comp2_var, comp3_var):
              subterm(x, comp2_var) OR subterm(x, comp3_var),
            iif(iif1_var, iif2_var, iif3_var):
              subterm(x, iif2_var) OR subterm(x, iif3_var),
            while(while1_var, while2_var): subterm(x, while2_var),
            cons(cons1_var, cons2_var): subterm(x, cons2_var)
         ENDCASES;

  reduce_nat(ass?_fun: [Hoare -> nat], skip?_fun: [Hoare -> nat],
             comp?_fun: [[Hoare, nat, nat] -> nat],
             iif?_fun: [[Hoare, nat, nat] -> nat],
             while?_fun: [[Hoare, nat] -> nat],
             cons?_fun: [[Hoare, nat] -> nat]):
        [tree -> nat] =
      LAMBDA (tree_adtvar: tree):
        LET red: [tree -> nat] =
              reduce_nat(ass?_fun, skip?_fun, comp?_fun, iif?_fun,
                         while?_fun, cons?_fun)
          IN
          CASES tree_adtvar
            OF ass(ass1_var): ass?_fun(ass1_var),
               skip(skip1_var): skip?_fun(skip1_var),
               comp(comp1_var, comp2_var, comp3_var):
                 comp?_fun(comp1_var, red(comp2_var), red(comp3_var)),
               iif(iif1_var, iif2_var, iif3_var):
                 iif?_fun(iif1_var, red(iif2_var), red(iif3_var)),
               while(while1_var, while2_var):
                 while?_fun(while1_var, red(while2_var)),
               cons(cons1_var, cons2_var):
                 cons?_fun(cons1_var, red(cons2_var))
            ENDCASES;

  REDUCE_nat(ass?_fun: [[Hoare, tree] -> nat],
             skip?_fun: [[Hoare, tree] -> nat],
             comp?_fun: [[Hoare, nat, nat, tree] -> nat],
             iif?_fun: [[Hoare, nat, nat, tree] -> nat],
             while?_fun: [[Hoare, nat, tree] -> nat],
             cons?_fun: [[Hoare, nat, tree] -> nat]):
        [tree -> nat] =
      LAMBDA (tree_adtvar: tree):
        LET red: [tree -> nat] =
              REDUCE_nat(ass?_fun, skip?_fun, comp?_fun, iif?_fun,
                         while?_fun, cons?_fun)
          IN
          CASES tree_adtvar
            OF ass(ass1_var): ass?_fun(ass1_var, tree_adtvar),
               skip(skip1_var): skip?_fun(skip1_var, tree_adtvar),
               comp(comp1_var, comp2_var, comp3_var):
                 comp?_fun(comp1_var, red(comp2_var), red(comp3_var),
                           tree_adtvar),
               iif(iif1_var, iif2_var, iif3_var):
                 iif?_fun(iif1_var, red(iif2_var), red(iif3_var),
                          tree_adtvar),
               while(while1_var, while2_var):
                 while?_fun(while1_var, red(while2_var), tree_adtvar),
               cons(cons1_var, cons2_var):
                 cons?_fun(cons1_var, red(cons2_var), tree_adtvar)
            ENDCASES;

  reduce_ordinal(ass?_fun: [Hoare -> ordinal], skip?_fun: [Hoare -> ordinal],
                 comp?_fun: [[Hoare, ordinal, ordinal] -> ordinal],
                 iif?_fun: [[Hoare, ordinal, ordinal] -> ordinal],
                 while?_fun: [[Hoare, ordinal] -> ordinal],
                 cons?_fun: [[Hoare, ordinal] -> ordinal]):
        [tree -> ordinal] =
      LAMBDA (tree_adtvar: tree):
        LET red: [tree -> ordinal] =
              reduce_ordinal(ass?_fun, skip?_fun, comp?_fun, iif?_fun,
                             while?_fun, cons?_fun)
          IN
          CASES tree_adtvar
            OF ass(ass1_var): ass?_fun(ass1_var),
               skip(skip1_var): skip?_fun(skip1_var),
               comp(comp1_var, comp2_var, comp3_var):
                 comp?_fun(comp1_var, red(comp2_var), red(comp3_var)),
               iif(iif1_var, iif2_var, iif3_var):
                 iif?_fun(iif1_var, red(iif2_var), red(iif3_var)),
               while(while1_var, while2_var):
                 while?_fun(while1_var, red(while2_var)),
               cons(cons1_var, cons2_var):
                 cons?_fun(cons1_var, red(cons2_var))
            ENDCASES;

  REDUCE_ordinal(ass?_fun: [[Hoare, tree] -> ordinal],
                 skip?_fun: [[Hoare, tree] -> ordinal],
                 comp?_fun: [[Hoare, ordinal, ordinal, tree] -> ordinal],
                 iif?_fun: [[Hoare, ordinal, ordinal, tree] -> ordinal],
                 while?_fun: [[Hoare, ordinal, tree] -> ordinal],
                 cons?_fun: [[Hoare, ordinal, tree] -> ordinal]):
        [tree -> ordinal] =
      LAMBDA (tree_adtvar: tree):
        LET red: [tree -> ordinal] =
              REDUCE_ordinal(ass?_fun, skip?_fun, comp?_fun, iif?_fun,
                             while?_fun, cons?_fun)
          IN
          CASES tree_adtvar
            OF ass(ass1_var): ass?_fun(ass1_var, tree_adtvar),
               skip(skip1_var): skip?_fun(skip1_var, tree_adtvar),
               comp(comp1_var, comp2_var, comp3_var):
                 comp?_fun(comp1_var, red(comp2_var), red(comp3_var),
                           tree_adtvar),
               iif(iif1_var, iif2_var, iif3_var):
                 iif?_fun(iif1_var, red(iif2_var), red(iif3_var),
                          tree_adtvar),
               while(while1_var, while2_var):
                 while?_fun(while1_var, red(while2_var), tree_adtvar),
               cons(cons1_var, cons2_var):
                 cons?_fun(cons1_var, red(cons2_var), tree_adtvar)
            ENDCASES;

  <<:  (strict_well_founded?[tree]) =
      LAMBDA (x, y: tree):
        CASES y
          OF ass(ass1_var): FALSE,
             skip(skip1_var): FALSE,
             comp(comp1_var, comp2_var, comp3_var):
               (x = comp2_var OR x << comp2_var) OR
                x = comp3_var OR x << comp3_var,
             iif(iif1_var, iif2_var, iif3_var):
               (x = iif2_var OR x << iif2_var) OR
                x = iif3_var OR x << iif3_var,
             while(while1_var, while2_var):
               x = while2_var OR x << while2_var,
             cons(cons1_var, cons2_var): x = cons2_var OR x << cons2_var
          ENDCASES;

  % Subtype TCC generated (at line 63, column 25) for  S(h)
      % expected type  {x: Stm[V] |
                     %          Sequence?(x) OR Conditional?(x) OR While?(x)}
  inference_tree?_TCC1: OBLIGATION
    FORALL (t: tree, h: Hoare, t1: tree, t2: tree):
      Sequence?(S(h)) AND t = comp(h, t1, t2) IMPLIES
       Sequence?[V](S(h)) OR Conditional?[V](S(h)) OR While?[V](S(h));

  % Subtype TCC generated (at line 63, column 49) for  S(h)
      % expected type  {x: Stm[V] | Sequence?(x) OR Conditional?(x)}
  inference_tree?_TCC2: OBLIGATION
    FORALL (t: tree, h: Hoare, t1: tree, t2: tree):
      S1(S(h)) = S(H(t1)) AND Sequence?(S(h)) AND t = comp(h, t1, t2) IMPLIES
       Sequence?[V](S(h)) OR Conditional?[V](S(h));

  % Termination TCC generated (at line 64, column 22) for  inference_tree?(t1)
  inference_tree?_TCC3: OBLIGATION
    FORALL (t: tree, h: Hoare, t1: tree, t2: tree):
      S2(S(h)) = S(H(t2)) AND
       S1(S(h)) = S(H(t1)) AND Sequence?(S(h)) AND t = comp(h, t1, t2)
       IMPLIES t1 << t;

  % Termination TCC generated (at line 64, column 46) for  inference_tree?(t2)
  inference_tree?_TCC4: OBLIGATION
    FORALL (t: tree, v: [{z: tree | z << t} -> bool], h: Hoare, t1: tree,
            t2: tree):
           v(t1) AND S2(S(h)) = S(H(t2)) AND S1(S(h)) = S(H(t1))
       AND Sequence?(S(h)) AND t = comp(h, t1, t2)
       IMPLIES t2 << t;

  % Subtype TCC generated (at line 69, column 25) for  S(h)
      % expected type  {x: Stm[V] |
                     %          Sequence?(x) OR Conditional?(x) OR While?(x)}
  inference_tree?_TCC5: OBLIGATION
    FORALL (t: tree, h: Hoare, t1: tree, t2: tree):
      Conditional?(S(h)) AND t = iif(h, t1, t2) IMPLIES
       Sequence?[V](S(h)) OR Conditional?[V](S(h)) OR While?[V](S(h));

  % Subtype TCC generated (at line 69, column 49) for  S(h)
      % expected type  {x: Stm[V] | Sequence?(x) OR Conditional?(x)}
  inference_tree?_TCC6: OBLIGATION
    FORALL (t: tree, h: Hoare, t1: tree, t2: tree):
      S1(S(h)) = S(H(t1)) AND Conditional?(S(h)) AND t = iif(h, t1, t2)
       IMPLIES Sequence?[V](S(h)) OR Conditional?[V](S(h));

  % Termination TCC generated (at line 70, column 22) for  inference_tree?(t1)
  inference_tree?_TCC7: OBLIGATION
    FORALL (t: tree, h: Hoare, t1: tree, t2: tree):
      S2(S(h)) = S(H(t2)) AND
       S1(S(h)) = S(H(t1)) AND Conditional?(S(h)) AND t = iif(h, t1, t2)
       IMPLIES t1 << t;

  % Termination TCC generated (at line 70, column 46) for  inference_tree?(t2)
  inference_tree?_TCC8: OBLIGATION
    FORALL (t: tree, v: [{z: tree | z << t} -> bool], h: Hoare, t1: tree,
            t2: tree):
           v(t1) AND S2(S(h)) = S(H(t2)) AND S1(S(h)) = S(H(t1))
       AND Conditional?(S(h)) AND t = iif(h, t1, t2)
       IMPLIES t2 << t;

  % Subtype TCC generated (at line 71, column 38) for  S(h)
      % expected type  {x: Stm[V] | Conditional?(x) OR While?(x)}
  inference_tree?_TCC9: OBLIGATION
    FORALL (t: tree, v: [{z: tree | z << t} -> bool], h: Hoare, t1: tree,
            t2: tree):
           v(t2) AND v(t1) AND S2(S(h)) = S(H(t2)) AND S1(S(h)) = S(H(t1))
       AND Conditional?(S(h)) AND t = iif(h, t1, t2)
       IMPLIES Conditional?[V](S(h)) OR While?[V](S(h));

  % Termination TCC generated (at line 75, column 39) for  inference_tree?(t)
  inference_tree?_TCC10: OBLIGATION
    FORALL (t: tree, h: Hoare, t1: tree):
      While?(S(h)) AND t = while(h, t1) IMPLIES t1 << t;

  % Subtype TCC generated (at line 76, column 37) for  S(h)
      % expected type  {x: Stm[V] | Conditional?(x) OR While?(x)}
  inference_tree?_TCC11: OBLIGATION
    FORALL (t: tree, v: [{z: tree | z << t} -> bool], h: Hoare, t1: tree):
      v(t1) AND While?(S(h)) AND t = while(h, t1) IMPLIES
       Conditional?[V](S(h)) OR While?[V](S(h));

  % Termination TCC generated (at line 80, column 22) for  inference_tree?(t)
  inference_tree?_TCC12: OBLIGATION
    FORALL (t: tree, h: Hoare, t1: tree): t = cons(h, t1) IMPLIES t1 << t;

  % Subtype TCC generated (at line 85, column 36) for
      % skip(LAMBDA s: TRUE, Skip, LAMBDA s: TRUE)
      % expected type  inference_tree
  inference_tree_TCC1: OBLIGATION
    inference_tree?(skip(LAMBDA s: TRUE, Skip[V], LAMBDA s: TRUE));


body:
  % Extras for list_props (prelude)
  %
  % Author: David Lester Manchester University 25/12/2007.

  list_props_aux[T:TYPE]: THEORY

  BEGIN

    l, l1, l2, l3: VAR list[T]
    x: VAR T

    length_is_0: LEMMA length(l) = 0 IFF l = null


    append_is_null: LEMMA null?(append(l1,l2)) IFF (null?(l1) AND null?(l2))

    append_eq1: LEMMA append(l1,l2) = append(l1,l3) IFF l2 = l3
    append_eq2: LEMMA append(l2,l1) = append(l3,l1) IFF l2 = l3

  END list_props_aux


body:
  %------------------------------------------------------------------------------
  % An Instruction Set for an Abstract Machine for while
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  Instruction[V:TYPE+]: THEORY

  BEGIN

    Instruction: DATATYPE
    BEGIN
      PUSH(n:int)                     : PUSH?
      FETCH(x1:V)                     : FETCH?
      UNARY(f1:[int->int])            : UNARY?
      BINARY(f2:[[int,int]->int])     : BINARY?
      STORE(x2:V)                     : STORE?
      NOOP                            : NOOP?
      BRANCH(c1,c2:list[Instruction]) : BRANCH?
      LOOP(c3,c4:list[Instruction])   : LOOP?
    END Instruction

    Code: TYPE+ = list[Instruction] CONTAINING null

    i,j: VAR int

    PUSH_TRUE:  MACRO Instruction = PUSH(b2n(TRUE))
    PUSH_FALSE: MACRO Instruction = PUSH(b2n(FALSE))
    ADD:   MACRO Instruction = BINARY(lambda i,j: i+j)
    SUB:   MACRO Instruction = BINARY(lambda i,j: i-j)
    MUL:   MACRO Instruction = BINARY(lambda i,j: i*j)
    EQ:    MACRO Instruction = BINARY(lambda i,j: b2n(i=j))
    LE:    MACRO Instruction = BINARY(lambda i,j: b2n(i<=j))
    NEG:   MACRO Instruction = UNARY(lambda i: 1-i)
    B_AND: MACRO Instruction = MUL

  END Instruction

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

  Instruction_ord_defaxiom: AXIOM
         (FORALL (n: int): Instruction_ord(PUSH(n)) = 0)
     AND (FORALL (x1: V): Instruction_ord(FETCH(x1)) = 1)
     AND (FORALL (f1: [int -> int]): Instruction_ord(UNARY(f1)) = 2)
     AND (FORALL (f2: [[int, int] -> int]): Instruction_ord(BINARY(f2)) = 3)
     AND (FORALL (x2: V): Instruction_ord(STORE(x2)) = 4)
     AND Instruction_ord(NOOP) = 5
     AND (FORALL (c1: list[Instruction], c2: list[Instruction]):
            Instruction_ord(BRANCH(c1, c2)) = 6)
     AND (FORALL (c3: list[Instruction], c4: list[Instruction]):
            Instruction_ord(LOOP(c3, c4)) = 7);

  Instruction_PUSH_extensionality: AXIOM
    FORALL (PUSH?_var: (PUSH?), PUSH?_var2: (PUSH?)):
      n(PUSH?_var) = n(PUSH?_var2) IMPLIES PUSH?_var = PUSH?_var2;

  Instruction_PUSH_eta: AXIOM
    FORALL (PUSH?_var: (PUSH?)): PUSH(n(PUSH?_var)) = PUSH?_var;

  Instruction_FETCH_extensionality: AXIOM
    FORALL (FETCH?_var: (FETCH?), FETCH?_var2: (FETCH?)):
      x1(FETCH?_var) = x1(FETCH?_var2) IMPLIES FETCH?_var = FETCH?_var2;

  Instruction_FETCH_eta: AXIOM
    FORALL (FETCH?_var: (FETCH?)): FETCH(x1(FETCH?_var)) = FETCH?_var;

  Instruction_UNARY_extensionality: AXIOM
    FORALL (UNARY?_var: (UNARY?), UNARY?_var2: (UNARY?)):
      f1(UNARY?_var) = f1(UNARY?_var2) IMPLIES UNARY?_var = UNARY?_var2;

  Instruction_UNARY_eta: AXIOM
    FORALL (UNARY?_var: (UNARY?)): UNARY(f1(UNARY?_var)) = UNARY?_var;

  Instruction_BINARY_extensionality: AXIOM
    FORALL (BINARY?_var: (BINARY?), BINARY?_var2: (BINARY?)):
      f2(BINARY?_var) = f2(BINARY?_var2) IMPLIES BINARY?_var = BINARY?_var2;

  Instruction_BINARY_eta: AXIOM
    FORALL (BINARY?_var: (BINARY?)): BINARY(f2(BINARY?_var)) = BINARY?_var;

  Instruction_STORE_extensionality: AXIOM
    FORALL (STORE?_var: (STORE?), STORE?_var2: (STORE?)):
      x2(STORE?_var) = x2(STORE?_var2) IMPLIES STORE?_var = STORE?_var2;

  Instruction_STORE_eta: AXIOM
    FORALL (STORE?_var: (STORE?)): STORE(x2(STORE?_var)) = STORE?_var;

  Instruction_NOOP_extensionality: AXIOM
    FORALL (NOOP?_var: (NOOP?), NOOP?_var2: (NOOP?)): NOOP?_var = NOOP?_var2;

  Instruction_BRANCH_extensionality: AXIOM
    FORALL (BRANCH?_var: (BRANCH?), BRANCH?_var2: (BRANCH?)):
      c1(BRANCH?_var) = c1(BRANCH?_var2) AND
       c2(BRANCH?_var) = c2(BRANCH?_var2)
       IMPLIES BRANCH?_var = BRANCH?_var2;

  Instruction_BRANCH_eta: AXIOM
    FORALL (BRANCH?_var: (BRANCH?)):
      BRANCH(c1(BRANCH?_var), c2(BRANCH?_var)) = BRANCH?_var;

  Instruction_LOOP_extensionality: AXIOM
    FORALL (LOOP?_var: (LOOP?), LOOP?_var2: (LOOP?)):
      c3(LOOP?_var) = c3(LOOP?_var2) AND c4(LOOP?_var) = c4(LOOP?_var2)
       IMPLIES LOOP?_var = LOOP?_var2;

  Instruction_LOOP_eta: AXIOM
    FORALL (LOOP?_var: (LOOP?)):
      LOOP(c3(LOOP?_var), c4(LOOP?_var)) = LOOP?_var;

  Instruction_n_PUSH: AXIOM
    FORALL (PUSH1_var: int): n(PUSH(PUSH1_var)) = PUSH1_var;

  Instruction_x1_FETCH: AXIOM
    FORALL (FETCH1_var: V): x1(FETCH(FETCH1_var)) = FETCH1_var;

  Instruction_f1_UNARY: AXIOM
    FORALL (UNARY1_var: [int -> int]): f1(UNARY(UNARY1_var)) = UNARY1_var;

  Instruction_f2_BINARY: AXIOM
    FORALL (BINARY1_var: [[int, int] -> int]):
      f2(BINARY(BINARY1_var)) = BINARY1_var;

  Instruction_x2_STORE: AXIOM
    FORALL (STORE1_var: V): x2(STORE(STORE1_var)) = STORE1_var;

  Instruction_c1_BRANCH: AXIOM
    FORALL (BRANCH1_var: list[Instruction], BRANCH2_var: list[Instruction]):
      c1(BRANCH(BRANCH1_var, BRANCH2_var)) = BRANCH1_var;

  Instruction_c2_BRANCH: AXIOM
    FORALL (BRANCH1_var: list[Instruction], BRANCH2_var: list[Instruction]):
      c2(BRANCH(BRANCH1_var, BRANCH2_var)) = BRANCH2_var;

  Instruction_c3_LOOP: AXIOM
    FORALL (LOOP1_var: list[Instruction], LOOP2_var: list[Instruction]):
      c3(LOOP(LOOP1_var, LOOP2_var)) = LOOP1_var;

  Instruction_c4_LOOP: AXIOM
    FORALL (LOOP1_var: list[Instruction], LOOP2_var: list[Instruction]):
      c4(LOOP(LOOP1_var, LOOP2_var)) = LOOP2_var;

  Instruction_inclusive: AXIOM
    FORALL (Instruction_var: Instruction):
          PUSH?(Instruction_var) OR FETCH?(Instruction_var)
       OR UNARY?(Instruction_var) OR BINARY?(Instruction_var)
       OR STORE?(Instruction_var) OR NOOP?(Instruction_var)
       OR BRANCH?(Instruction_var) OR LOOP?(Instruction_var);

  Instruction_induction: AXIOM
    FORALL (p: [Instruction -> boolean]):
      (     FORALL (PUSH1_var: int): p(PUSH(PUSH1_var))
        AND FORALL (FETCH1_var: V): p(FETCH(FETCH1_var))
        AND FORALL (UNARY1_var: [int -> int]): p(UNARY(UNARY1_var))
        AND FORALL (BINARY1_var: [[int, int] -> int]): p(BINARY(BINARY1_var))
        AND FORALL (STORE1_var: V): p(STORE(STORE1_var)) AND p(NOOP)
        AND FORALL (BRANCH1_var: list[Instruction],
                    BRANCH2_var: list[Instruction]):
              every(p)(BRANCH1_var) AND every(p)(BRANCH2_var) IMPLIES
               p(BRANCH(BRANCH1_var, BRANCH2_var))
        AND FORALL (LOOP1_var: list[Instruction],
                    LOOP2_var: list[Instruction]):
              every(p)(LOOP1_var) AND every(p)(LOOP2_var) IMPLIES
               p(LOOP(LOOP1_var, LOOP2_var)))
       IMPLIES (FORALL (Instruction_var: Instruction): p(Instruction_var));

  Instruction_well_founded: AXIOM strict_well_founded?[Instruction](<<);

  Instruction: TYPE

  PUSH?: [Instruction -> boolean]

  FETCH?: [Instruction -> boolean]

  UNARY?: [Instruction -> boolean]

  BINARY?: [Instruction -> boolean]

  STORE?: [Instruction -> boolean]

  NOOP?: [Instruction -> boolean]

  BRANCH?: [Instruction -> boolean]

  LOOP?: [Instruction -> boolean]

  n: [(PUSH?) -> int]

  x1: [(FETCH?) -> V]

  f1: [(UNARY?) -> [int -> int]]

  f2: [(BINARY?) -> [[int, int] -> int]]

  x2: [(STORE?) -> V]

  c1: [(BRANCH?) -> list[Instruction]]

  c2: [(BRANCH?) -> list[Instruction]]

  c3: [(LOOP?) -> list[Instruction]]

  c4: [(LOOP?) -> list[Instruction]]

  PUSH: [int -> (PUSH?)]

  FETCH: [V -> (FETCH?)]

  UNARY: [[int -> int] -> (UNARY?)]

  BINARY: [[[int, int] -> int] -> (BINARY?)]

  STORE: [V -> (STORE?)]

  BRANCH: [[list[Instruction], list[Instruction]] -> (BRANCH?)]

  LOOP: [[list[Instruction], list[Instruction]] -> (LOOP?)]

  Instruction_ord: [Instruction -> upto(7)]

  ord(x: Instruction): [Instruction -> upto(7)] =
      CASES x
        OF PUSH(PUSH1_var): 0,
           FETCH(FETCH1_var): 1,
           UNARY(UNARY1_var): 2,
           BINARY(BINARY1_var): 3,
           STORE(STORE1_var): 4,
           NOOP: 5,
           BRANCH(BRANCH1_var, BRANCH2_var): 6,
           LOOP(LOOP1_var, LOOP2_var): 7
        ENDCASES

  subterm(x: Instruction, y: Instruction):  boolean =
      x = y OR
       CASES y
         OF PUSH(PUSH1_var): FALSE,
            FETCH(FETCH1_var): FALSE,
            UNARY(UNARY1_var): FALSE,
            BINARY(BINARY1_var): FALSE,
            STORE(STORE1_var): FALSE,
            NOOP: FALSE,
            BRANCH(BRANCH1_var, BRANCH2_var):
              some[Instruction]
                  ((LAMBDA (z: Instruction): subterm(x, z)))(BRANCH1_var)
               OR
               some[Instruction]
                   ((LAMBDA (z: Instruction): subterm(x, z)))(BRANCH2_var),
            LOOP(LOOP1_var, LOOP2_var):
              some[Instruction]
                  ((LAMBDA (z: Instruction): subterm(x, z)))(LOOP1_var)
               OR
               some[Instruction]
                   ((LAMBDA (z: Instruction): subterm(x, z)))(LOOP2_var)
         ENDCASES;

  reduce_nat(PUSH?_fun: [int -> nat], FETCH?_fun: [V -> nat],
             UNARY?_fun: [[int -> int] -> nat],
             BINARY?_fun: [[[int, int] -> int] -> nat],
             STORE?_fun: [V -> nat], NOOP?_fun: nat,
             BRANCH?_fun: [[list[nat], list[nat]] -> nat],
             LOOP?_fun: [[list[nat], list[nat]] -> nat]):
        [Instruction -> nat] =
      LAMBDA (Instruction_adtvar: Instruction):
        LET red: [Instruction -> nat] =
              reduce_nat(PUSH?_fun, FETCH?_fun, UNARY?_fun, BINARY?_fun,
                         STORE?_fun, NOOP?_fun, BRANCH?_fun, LOOP?_fun)
          IN
          CASES Instruction_adtvar
            OF PUSH(PUSH1_var): PUSH?_fun(PUSH1_var),
               FETCH(FETCH1_var): FETCH?_fun(FETCH1_var),
               UNARY(UNARY1_var): UNARY?_fun(UNARY1_var),
               BINARY(BINARY1_var): BINARY?_fun(BINARY1_var),
               STORE(STORE1_var): STORE?_fun(STORE1_var),
               NOOP: NOOP?_fun,
               BRANCH(BRANCH1_var, BRANCH2_var):
                 BRANCH?_fun(map[Instruction, nat](red)(BRANCH1_var),
                             map[Instruction, nat](red)(BRANCH2_var)),
               LOOP(LOOP1_var, LOOP2_var):
                 LOOP?_fun(map[Instruction, nat](red)(LOOP1_var),
                           map[Instruction, nat](red)(LOOP2_var))
            ENDCASES;

  REDUCE_nat(PUSH?_fun: [[int, Instruction] -> nat],
             FETCH?_fun: [[V, Instruction] -> nat],
             UNARY?_fun: [[[int -> int], Instruction] -> nat],
             BINARY?_fun: [[[[int, int] -> int], Instruction] -> nat],
             STORE?_fun: [[V, Instruction] -> nat],
             NOOP?_fun: [Instruction -> nat],
             BRANCH?_fun: [[list[nat], list[nat], Instruction] -> nat],
             LOOP?_fun: [[list[nat], list[nat], Instruction] -> nat]):
        [Instruction -> nat] =
      LAMBDA (Instruction_adtvar: Instruction):
        LET red: [Instruction -> nat] =
              REDUCE_nat(PUSH?_fun, FETCH?_fun, UNARY?_fun, BINARY?_fun,
                         STORE?_fun, NOOP?_fun, BRANCH?_fun, LOOP?_fun)
          IN
          CASES Instruction_adtvar
            OF PUSH(PUSH1_var): PUSH?_fun(PUSH1_var, Instruction_adtvar),
               FETCH(FETCH1_var): FETCH?_fun(FETCH1_var, Instruction_adtvar),
               UNARY(UNARY1_var): UNARY?_fun(UNARY1_var, Instruction_adtvar),
               BINARY(BINARY1_var):
                 BINARY?_fun(BINARY1_var, Instruction_adtvar),
               STORE(STORE1_var): STORE?_fun(STORE1_var, Instruction_adtvar),
               NOOP: NOOP?_fun(Instruction_adtvar),
               BRANCH(BRANCH1_var, BRANCH2_var):
                 BRANCH?_fun(map[Instruction, nat](red)(BRANCH1_var),
                             map[Instruction, nat](red)(BRANCH2_var),
                             Instruction_adtvar),
               LOOP(LOOP1_var, LOOP2_var):
                 LOOP?_fun(map[Instruction, nat](red)(LOOP1_var),
                           map[Instruction, nat](red)(LOOP2_var),
                           Instruction_adtvar)
            ENDCASES;

  reduce_ordinal(PUSH?_fun: [int -> ordinal], FETCH?_fun: [V -> ordinal],
                 UNARY?_fun: [[int -> int] -> ordinal],
                 BINARY?_fun: [[[int, int] -> int] -> ordinal],
                 STORE?_fun: [V -> ordinal], NOOP?_fun: ordinal,
                 BRANCH?_fun: [[list[ordinal], list[ordinal]] -> ordinal],
                 LOOP?_fun: [[list[ordinal], list[ordinal]] -> ordinal]):
        [Instruction -> ordinal] =
      LAMBDA (Instruction_adtvar: Instruction):
        LET red: [Instruction -> ordinal] =
              reduce_ordinal(PUSH?_fun, FETCH?_fun, UNARY?_fun, BINARY?_fun,
                             STORE?_fun, NOOP?_fun, BRANCH?_fun, LOOP?_fun)
          IN
          CASES Instruction_adtvar
            OF PUSH(PUSH1_var): PUSH?_fun(PUSH1_var),
               FETCH(FETCH1_var): FETCH?_fun(FETCH1_var),
               UNARY(UNARY1_var): UNARY?_fun(UNARY1_var),
               BINARY(BINARY1_var): BINARY?_fun(BINARY1_var),
               STORE(STORE1_var): STORE?_fun(STORE1_var),
               NOOP: NOOP?_fun,
               BRANCH(BRANCH1_var, BRANCH2_var):
                 BRANCH?_fun(map[Instruction, ordinal](red)(BRANCH1_var),
                             map[Instruction, ordinal](red)(BRANCH2_var)),
               LOOP(LOOP1_var, LOOP2_var):
                 LOOP?_fun(map[Instruction, ordinal](red)(LOOP1_var),
                           map[Instruction, ordinal](red)(LOOP2_var))
            ENDCASES;

  REDUCE_ordinal(PUSH?_fun: [[int, Instruction] -> ordinal],
                 FETCH?_fun: [[V, Instruction] -> ordinal],
                 UNARY?_fun: [[[int -> int], Instruction] -> ordinal],
                 BINARY?_fun:
                   [[[[int, int] -> int], Instruction] -> ordinal],
                 STORE?_fun: [[V, Instruction] -> ordinal],
                 NOOP?_fun: [Instruction -> ordinal],
                 BRANCH?_fun:
                   [[list[ordinal], list[ordinal], Instruction] -> ordinal],
                 LOOP?_fun:
                   [[list[ordinal], list[ordinal], Instruction] ->
                      ordinal]):
        [Instruction -> ordinal] =
      LAMBDA (Instruction_adtvar: Instruction):
        LET red: [Instruction -> ordinal] =
              REDUCE_ordinal(PUSH?_fun, FETCH?_fun, UNARY?_fun, BINARY?_fun,
                             STORE?_fun, NOOP?_fun, BRANCH?_fun, LOOP?_fun)
          IN
          CASES Instruction_adtvar
            OF PUSH(PUSH1_var): PUSH?_fun(PUSH1_var, Instruction_adtvar),
               FETCH(FETCH1_var): FETCH?_fun(FETCH1_var, Instruction_adtvar),
               UNARY(UNARY1_var): UNARY?_fun(UNARY1_var, Instruction_adtvar),
               BINARY(BINARY1_var):
                 BINARY?_fun(BINARY1_var, Instruction_adtvar),
               STORE(STORE1_var): STORE?_fun(STORE1_var, Instruction_adtvar),
               NOOP: NOOP?_fun(Instruction_adtvar),
               BRANCH(BRANCH1_var, BRANCH2_var):
                 BRANCH?_fun(map[Instruction, ordinal](red)(BRANCH1_var),
                             map[Instruction, ordinal](red)(BRANCH2_var),
                             Instruction_adtvar),
               LOOP(LOOP1_var, LOOP2_var):
                 LOOP?_fun(map[Instruction, ordinal](red)(LOOP1_var),
                           map[Instruction, ordinal](red)(LOOP2_var),
                           Instruction_adtvar)
            ENDCASES;

  NOOP: (NOOP?)

  <<:  (strict_well_founded?[Instruction]) =
      LAMBDA (x, y: Instruction):
        CASES y
          OF PUSH(PUSH1_var): FALSE,
             FETCH(FETCH1_var): FALSE,
             UNARY(UNARY1_var): FALSE,
             BINARY(BINARY1_var): FALSE,
             STORE(STORE1_var): FALSE,
             NOOP: FALSE,
             BRANCH(BRANCH1_var, BRANCH2_var):
               some[Instruction]
                   (LAMBDA (z: Instruction): x = z OR x << z)(BRANCH1_var)
                OR
                some[Instruction]
                    (LAMBDA (z: Instruction): x = z OR x << z)(BRANCH2_var),
             LOOP(LOOP1_var, LOOP2_var):
               some[Instruction]
                   (LAMBDA (z: Instruction): x = z OR x << z)(LOOP1_var)
                OR
                some[Instruction]
                    (LAMBDA (z: Instruction): x = z OR x << z)(LOOP2_var)
          ENDCASES;


body:
  %------------------------------------------------------------------------------
  % An Abstract Machine for while
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  am[V:TYPE+]: THEORY

  BEGIN

    IMPORTING Cont[V], Instruction[V], State[V], list_props_aux

    Stack:  TYPE+ = list[int]
    Config: TYPE+ = [Code,Stack,State]

    c,c0,c1,c2: VAR Code
    e,e0,e1,e2: VAR Stack
    s,s0,s1,s2: VAR State
    n,n0,n1,n2,k,k1,k2: VAR nat
    pn: VAR posnat
    cf,cf0,cf1,cf2: VAR Config
    i: VAR int
    x: VAR V
    f1: VAR [int->int]
    f2: VAR [[int,int]->int]

    check1(c,e,s):bool = NOT null?(e)
    check2(c,e,s):bool = (NOT null?(e)) AND (NOT null?(cdr(e)))

    push(i,e):          Stack = cons(i,e)
    pop(e:(cons?[int])):Stack = cdr(e)
    top(e:(cons?[int])):int   = car(e)

    step(c,e,s): Config
      = IF null?(c) THEN (c,e,s) ELSE
        CASES car(c) OF
          PUSH(i)      : (cdr(c),push(i,e),s),
          FETCH(x)     : (cdr(c),push(s(x),e),s),
          UNARY(f1)    : IF check1(c,e,s)
                         THEN (cdr(c),push(f1(top(e)),pop(e)),s)
                         ELSE (c,e,s) ENDIF,
          BINARY(f2)   : IF check2(c,e,s)
                         THEN (cdr(c),push(f2(top(e),top(pop(e))),pop(pop(e))),s)
                         ELSE (c,e,s) ENDIF,
          STORE(x)     : IF check1(c,e,s)
                         THEN (cdr(c),pop(e),assign(x,top(e))(s))
                         ELSE (c,e,s) ENDIF,
          NOOP         : (cdr(c),e,s),
          BRANCH(c1,c2): IF check1(c,e,s)
                         THEN IF top(e) = 1
                              THEN (append(c1,cdr(c)),pop(e),s)
                              ELSE (append(c2,cdr(c)),pop(e),s) ENDIF
                         ELSE (c,e,s) ENDIF,
          LOOP(c1,c2)  : (append(c1,
                           cons(BRANCH(append(c2,cons(LOOP(c1,c2),null)),
                                       cons(NOOP,null)),cdr(c))),e,s)
        ENDCASES ENDIF

    tr(n)(cf0,cf): RECURSIVE bool
      = IF n=0 THEN cf0=cf
               ELSE (NOT null?(cf0`1)) AND
                    cf0 /= step(cf0)   AND
                    tr(n-1)(step(cf0),cf) ENDIF
        MEASURE n

    step_append: LEMMA NOT null?(c1) AND
                       (append(c1,c2),e,s) /= step((append(c1,c2),e,s)) =>
                       (c1,e,s) /= step((c1,e,s))

    tr_add: LEMMA tr(k1+k2)(cf0,cf2) IFF
                  EXISTS cf1: tr(k1)(cf0,cf1) AND tr(k2)(cf1,cf2)
    tr_eq:  LEMMA tr(k)(cf0,cf1) AND tr(k)(cf0,cf2) => cf1 = cf2

    code_partial: LEMMA                                                 % N&N 3.4
      tr(k)((c0,e0,s0),(c1,e1,s1)) =>
      tr(k)((append(c0,c2),append(e0,e2),s0), (append(c1,c2),append(e1,e2),s1))

    code_split: LEMMA                                                   % N&N 3.5
      tr(k)((append(c1,c2),e,s),(null,e2,s2)) =>
      EXISTS e1,s1,k1,k2: tr(k1)((c1,e,s),(null,e1,s1)) AND
                          tr(k2)((c2,e1,s1),(null,e2,s2)) AND
                          k1+k2=k

    IMPORTING Cont

    M(c):Cont
      = lambda s:
          IF EXISTS n,s1: tr(n)((c,null,s),(null,null,s1))
          THEN up(choose({s1 | EXISTS n: tr(n)((c,null,s),(null,null,s1))}))
          ELSE bottom ENDIF

    M_deterministic: LEMMA M(c)(s) = up(s1) IFF                         % N&N 3.6
                           EXISTS n: tr(n)((c,null,s),(null,null,s1))

  END am

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

  % Subtype TCC generated (at line 34, column 57) for  e
      % expected type  (cons?[int])
  check2_TCC1: OBLIGATION
    FORALL (e: Stack): (NOT null?(e)) IMPLIES cons?[int](e);

  % Subtype TCC generated (at line 42, column 16) for  c
      % expected type  (cons?[Instruction[V]])
  step_TCC1: OBLIGATION
    FORALL (c: Code[V]): NOT null?(c) IMPLIES cons?[Instruction[V]](c);

  % Subtype TCC generated (at line 46, column 48) for  e
      % expected type  (cons?[int])
  step_TCC2: OBLIGATION
    FORALL (c: Code[V], e: Stack, s: State[V]):
      NOT null?(c) IMPLIES
       (FORALL (f1: [int -> int]):
          check1(c, e, s) AND car(c) = UNARY(f1) IMPLIES cons?[int](e));

  % Subtype TCC generated (at line 49, column 48) for  e
      % expected type  (cons?[int])
  step_TCC3: OBLIGATION
    FORALL (c: Code[V], e: Stack, s: State[V]):
      NOT null?(c) IMPLIES
       (FORALL (f2: [[int, int] -> int]):
          check2(c, e, s) AND car(c) = BINARY(f2) IMPLIES cons?[int](e));

  % Subtype TCC generated (at line 49, column 55) for  pop(e)
      % expected type  (cons?[int])
  step_TCC4: OBLIGATION
    FORALL (c: Code[V], e: Stack, s: State[V]):
      NOT null?(c) IMPLIES
       (FORALL (f2: [[int, int] -> int]):
          check2(c, e, s) AND car(c) = BINARY(f2) IMPLIES cons?[int](pop(e)));

  % Subtype TCC generated (at line 52, column 40) for  e
      % expected type  (cons?[int])
  step_TCC5: OBLIGATION
    FORALL (c: Code[V], e: Stack, s: State[V]):
      NOT null?(c) IMPLIES
       (FORALL (x: V):
          check1(c, e, s) AND car(c) = STORE(x) IMPLIES cons?[int](e));

  % Subtype TCC generated (at line 56, column 35) for  e
      % expected type  (cons?[int])
  step_TCC6: OBLIGATION
    FORALL (c: Code[V], e: Stack, s: State[V]):
      NOT null?(c) IMPLIES
       (FORALL (c1: list[Instruction[V]], c2: list[Instruction[V]]):
          check1(c, e, s) AND car(c) = BRANCH(c1, c2) IMPLIES cons?[int](e));

  % Subtype TCC generated (at line 69, column 21) for  n - 1
      % expected type  nat
  tr_TCC1: OBLIGATION
    FORALL (n: nat, cf0: Config):
      cf0 /= step(cf0) AND (NOT null?(cf0`1)) AND NOT n = 0 IMPLIES
       n - 1 >= 0;

  % Termination TCC generated (at line 69, column 18) for  tr(n - 1)
  tr_TCC2: OBLIGATION
    FORALL (n: nat, cf0: Config):
      cf0 /= step(cf0) AND (NOT null?(cf0`1)) AND NOT n = 0 IMPLIES n - 1 < n;

  % Subtype TCC generated (at line 95, column 23) for
      % {s1 | EXISTS n: tr(n)((c, null, s), (null, null, s1))}
      % expected type  p: (nonempty?[State[V]])
  M_TCC1: OBLIGATION
    FORALL (c: Code[V], s):
      (EXISTS n, s1: tr(n)((c, null, s), (null, null, s1))) IMPLIES
       nonempty?[State[V]]
           ({s1 |
               EXISTS n:
                 tr(n)
                   ((c, null[int], s),
                    (null[Instruction[V]], null[int], s1))});


body:
  %------------------------------------------------------------------------------
  % A Compiler for while
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  compiler[V:TYPE+]: THEORY

  BEGIN

    IMPORTING AExp[V], BExp[V], Stm[V], Instruction[V], list_props_aux

    a: VAR AExp
    b: VAR BExp
    S: VAR Stm

    CA(a): RECURSIVE Code =
       cases a of
         N(n)       : cons(PUSH(n),null),
         V(x)       : cons(FETCH(x),null),
         Add(a1,a2) : append(CA(a2),append(CA(a1),cons(ADD,null))),
         Sub(a1,a2) : append(CA(a2),append(CA(a1),cons(SUB,null))),
         Mul(a1,a2) : append(CA(a2),append(CA(a1),cons(MUL,null)))
       endcases
       MEASURE a by <<

    CB(b) : RECURSIVE Code =
       cases b of
         TT         : cons(PUSH_TRUE,null),
         FF         : cons(PUSH_FALSE,null),
         Eq(a1,a2)  : append(CA(a2),append(CA(a1),cons(EQ,null))),
         Le(a1,a2)  : append(CA(a2),append(CA(a1),cons(LE,null))),
         Neg(b)     : append(CB(b),cons(NEG,null)),
         Band(b1,b2): append(CB(b2),append(CB(b1),cons(B_AND,null)))
       endcases
       MEASURE b by <<

    CS(S) : RECURSIVE Code =
       cases S of
         Assign(x,a)          : append(CA(a),cons(STORE(x),null)),
         Skip                 : cons(NOOP,null),
         Sequence(S1,S2)      : append(CS(S1),CS(S2)),
         Conditional(b,S1,S2) : append(CB(b),cons(BRANCH(CS(S1),CS(S2)),null)),
         While(b,S1)          : cons(LOOP(CB(b),CS(S1)),null)
       endcases
       MEASURE S by <<

    nonnull_CA: LEMMA NOT null?(CA(a))
    nonnull_CB: LEMMA NOT null?(CB(b))
    nonnull_CS: LEMMA NOT null?(CS(S))

  END compiler

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

  % Termination TCC generated (at line 27, column 27) for  CA(a2)
  CA_TCC1: OBLIGATION
    FORALL (a: AExp[V], a1: AExp[V], a2: AExp[V]):
      a = Add(a1, a2) IMPLIES <<[V](a2, a);

  % Termination TCC generated (at line 27, column 41) for  CA(a1)
  CA_TCC2: OBLIGATION
    FORALL (a: AExp[V], a1: AExp[V], a2: AExp[V]):
      a = Add(a1, a2) IMPLIES <<[V](a1, a);

  % Termination TCC generated (at line 28, column 27) for  CA(a2)
  CA_TCC3: OBLIGATION
    FORALL (a: AExp[V], a1: AExp[V], a2: AExp[V]):
      a = Sub(a1, a2) IMPLIES <<[V](a2, a);

  % Termination TCC generated (at line 28, column 41) for  CA(a1)
  CA_TCC4: OBLIGATION
    FORALL (a: AExp[V], a1: AExp[V], a2: AExp[V]):
      a = Sub(a1, a2) IMPLIES <<[V](a1, a);

  % Termination TCC generated (at line 29, column 27) for  CA(a2)
  CA_TCC5: OBLIGATION
    FORALL (a: AExp[V], a1: AExp[V], a2: AExp[V]):
      a = Mul(a1, a2) IMPLIES <<[V](a2, a);

  % Termination TCC generated (at line 29, column 41) for  CA(a1)
  CA_TCC6: OBLIGATION
    FORALL (a: AExp[V], a1: AExp[V], a2: AExp[V]):
      a = Mul(a1, a2) IMPLIES <<[V](a1, a);

  % Termination TCC generated (at line 39, column 27) for  CB(b)
  CB_TCC1: OBLIGATION
    FORALL (b: BExp[V], b1: BExp[V]): b = Neg(b1) IMPLIES <<[V](b1, b);

  % Termination TCC generated (at line 40, column 27) for  CB(b2)
  CB_TCC2: OBLIGATION
    FORALL (b: BExp[V], b1: BExp[V], b2: BExp[V]):
      b = Band(b1, b2) IMPLIES <<[V](b2, b);

  % Termination TCC generated (at line 40, column 41) for  CB(b1)
  CB_TCC3: OBLIGATION
    FORALL (b: BExp[V], b1: BExp[V], b2: BExp[V]):
      b = Band(b1, b2) IMPLIES <<[V](b1, b);

  % Termination TCC generated (at line 48, column 37) for  CS(S1)
  CS_TCC1: OBLIGATION
    FORALL (S: Stm[V], S1: Stm[V], S2: Stm[V]):
      S = Sequence(S1, S2) IMPLIES <<[V](S1, S);

  % Termination TCC generated (at line 48, column 44) for  CS(S2)
  CS_TCC2: OBLIGATION
    FORALL (S: Stm[V], S1: Stm[V], S2: Stm[V]):
      S = Sequence(S1, S2) IMPLIES <<[V](S2, S);

  % Termination TCC generated (at line 49, column 55) for  CS(S1)
  CS_TCC3: OBLIGATION
    FORALL (S: Stm[V], b: BExp[V], S1: Stm[V], S2: Stm[V]):
      S = Conditional(b, S1, S2) IMPLIES <<[V](S1, S);

  % Termination TCC generated (at line 49, column 62) for  CS(S2)
  CS_TCC4: OBLIGATION
    FORALL (S: Stm[V], b: BExp[V], S1: Stm[V], S2: Stm[V]):
      S = Conditional(b, S1, S2) IMPLIES <<[V](S2, S);

  % Termination TCC generated (at line 50, column 46) for  CS(S1)
  CS_TCC5: OBLIGATION
    FORALL (S: Stm[V], b: BExp[V], S1: Stm[V]):
      S = While(b, S1) IMPLIES <<[V](S1, S);


body:
  %------------------------------------------------------------------------------
  % The Equivalence of a Compiler/Abstract Machine
  %         and Structural Operational Semantics
  %
  % All references are to HR and F Nielson "Semantics with Applications:
  % A Formal Introduction", John Wiley & Sons, 1992. (revised edition
  % available: http://www.daimi.au.dk/~hrn )
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            25/12/07  Initial Version
  %------------------------------------------------------------------------------

  bisimulation[V:TYPE+]: THEORY

  BEGIN

    IMPORTING compiler[V], am[V], sos[V]

    x: VAR V
    a: VAR AExp
    b: VAR BExp
    n,m: VAR nat
    pn: VAR posnat
    e: VAR list[int]
    s,s0,s1: VAR State
    S: VAR Stm
    sc,sc0,sc1: VAR sos.Config
    ac,ac0,ac1,ac2: VAR am.Config

    correct_AExp: LEMMA EXISTS n: am.tr(n)((CA(a),e,s),(null,cons(A(a)(s),e),s))
                                                                       % N&N 3.18
    correct_BExp: LEMMA EXISTS n: am.tr(n)((CB(b),e,s),(null,cons(B(b)(s),e),s))
                                                                       % N&N 3.19

    eq_AExp: LEMMA am.tr(n)((CA(a),e,s),(null,cons(A(a)(s),e),s)) AND
                   am.tr(m)((CA(a),e,s),ac) AND
                   null?(ac`1) =>
                   n = m AND ac`2 = cons(A(a)(s),e) AND ac`3 = s

    AExp_steps: LEMMA am.tr(n)((CA(a),e,s),(null,cons(A(a)(s),e),s)) => n >= 1

    AExp_e: LEMMA am.tr(n)((CA(a),e,s),(null,cons(A(a)(s),e),s)) AND
                        pn <= n AND am.tr(pn)((CA(a),e,s),ac) =>
                        length(ac`2) >= 1+length(e)

    eq_BExp: LEMMA am.tr(n)((CB(b),e,s),(null,cons(B(b)(s),e),s)) AND
                   am.tr(m)((CB(b),e,s),ac) AND
                   null?(ac`1) =>
                   n = m AND ac`2 = cons(B(b)(s),e) AND ac`3 = s

    BExp_steps: LEMMA am.tr(n)((CB(b),e,s),(null,cons(B(b)(s),e),s)) => n >= 1

    BExp_e: LEMMA am.tr(n)((CB(b),e,s),(null,cons(B(b)(s),e),s)) AND
                        pn <= n AND am.tr(pn)((CB(b),e,s),ac) =>
                        length(ac`2) >= 1+length(e)

  ;
    ~(sc,ac): bool
      = IF terminal?(sc)
        THEN ac`1 = null[Instruction] AND ac`2 = null[int] AND s1(sc) = ac`3
        ELSE ac`1 = CS(S(sc))         AND ac`2 = null[int] AND s(sc)  = ac`3
        ENDIF

    sos_step: LEMMA
       sos.I(S,s) ~ ac0 =>
       EXISTS pn,ac1: sos.step(S,s) ~ ac1 AND am.tr(pn)(ac0,ac1)

    sos_steps: LEMMA sos.tr(n)(sos.I(S,s0),T(s1)) =>
                     EXISTS m: am.tr(m)((CS(S),null[int],s0),
                                        (null[Instruction],null[int],s1))

    am_step1: LEMMA sos.I(S,s) ~ ac AND
                    sos.step(S,s) ~ ac1 =>
                    EXISTS pn: am.tr(pn)(ac,ac1) AND
                    FORALL n,ac2: n <= pn AND am.tr(n)(ac,ac2) =>
                                  (null?(ac2`2) IFF (n=0 OR n=pn))

    am_steps: LEMMA                                                    % N&N 3.27
      am.tr(m)((CS(S),null[int],s0),(null[Instruction],null[int],s1)) =>
      EXISTS n: sos.tr(n)(sos.I(S,s0),T(s1))

    bisimulation: LEMMA M(CS(S)) = SS(S)                               % N&N 3.28

  END bisimulation

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

  % Subtype TCC generated (at line 61, column 64) for  sc
      % expected type  (T?)
  tilde_TCC1: OBLIGATION
    FORALL (sc: sos[V].Config, ac: am[V].Config):
      ac`2 = null[int] AND ac`1 = null[Instruction] AND terminal?(sc) IMPLIES
       T?[V](sc);

  % Subtype TCC generated (at line 62, column 23) for  sc
      % expected type  (I?[V])
  tilde_TCC2: OBLIGATION
    FORALL (sc: sos[V].Config): NOT terminal?(sc) IMPLIES I?[V](sc);


