# TheoryBodies

body:
  bv_arith_caret: THEORY

  BEGIN

    IMPORTING bv_arith_nat, bv_caret, div,
              bv_sum, bv_arith_concat % For proofs only

    N: VAR posnat
    i: VAR int
    


    bv_shift    : THEOREM (FORALL (bv:bvec[N], ss: below(N)):
                         bv2nat(bv^(N-1,ss)) = div(bv2nat(bv), exp2(ss)))
  	      
    bv_bottom   : THEOREM (FORALL (bv:bvec[N], ss: below(N)):
                            bv2nat(bv^(ss,0)) = mod(bv2nat(bv),exp2(ss+1)) )
  	      
    bv_top      : THEOREM (FORALL (bv:bvec[N], ss: below(N)):
                           bv^(N-1,ss) = nat2bv[N-ss](div(bv2nat(bv), exp2(ss))))

    bv_bot      : THEOREM (FORALL (bv:bvec[N], nn: below(N)):
                            bv^(nn,0) = nat2bv[nn+1](mod(bv2nat(bv),exp2(nn+1))))

    bv_add_subrange : THEOREM (FORALL (bv1,bv2:bvec[N], nn: below(N)):
                                 (bv1 + bv2)^(nn,0) = bv1^(nn,0) + bv2^(nn,0))

    bv_plus_caret: LEMMA (FORALL (bv1: bvec[N], nn: below(N)):
                                 (bv1 + i)^(nn,0) = bv1^(nn,0) + i)

    bv_middle      : THEOREM (FORALL (n: posnat, i,j: below(n), bv: bvec[n]): 
                        i >= j IMPLIES
                      bv2nat(bv^(i,j)) = mod(div(bv2nat(bv), exp2(j)),exp2(i-j+1)))


    bv2nat_caret_00: THEOREM FORALL (n: posnat, bv: bvec[n]):
                                bv2nat(bv^(0,0)) = b2n(bv^0)

    bv2nat_lem     : THEOREM FORALL (n: above(1), bv: bvec[n]):
                                bv2nat(bv)  = 2 * bv2nat(bv ^ (n - 1, 1)) + bv ^ 0

  END bv_arith_caret

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

  % Subtype TCC generated (at line 14, column 34) for  N - 1
      % expected type  below(N)
  bv_shift_TCC1: OBLIGATION
    FORALL (N: posnat, ss: below(N)): N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 14, column 38) for  ss
      % expected type  upto(N - 1)
  bv_shift_TCC2: OBLIGATION FORALL (N: posnat, ss: below(N)): ss <= N - 1;

  % Subtype TCC generated (at line 14, column 34) for  N - ss
      % expected type  nat
  bv_shift_TCC3: OBLIGATION FORALL (N: posnat, ss: below(N)): N - ss >= 0;

  % Subtype TCC generated (at line 17, column 40) for  0
      % expected type  upto(ss)
  bv_bottom_TCC1: OBLIGATION FORALL (N: posnat, ss: below(N)): 0 <= ss;

  % Subtype TCC generated (at line 20, column 52) for
      % div(bv2nat(bv), exp2(ss))
      % expected type  val: below(exp2(N - ss))
  bv_top_TCC1: OBLIGATION
    FORALL (N: posnat, bv: bvec[N], ss: below(N)):
      div(bv2nat[N](bv), exp2(ss)) < exp2(N - ss);

  % Subtype TCC generated (at line 33, column 33) for  j
      % expected type  upto(i)
  bv_middle_TCC1: OBLIGATION
    FORALL (n: posnat, i, j: below(n)): i >= j IMPLIES j <= i;

  % Subtype TCC generated (at line 89, column 18) for  1 + i - j
      % expected type  nat
  bv_middle_TCC2: OBLIGATION
    FORALL (n: posnat, i, j: below(n)): i >= j IMPLIES 1 + i - j >= 0;

  % Subtype TCC generated (at line 33, column 73) for  i - j + 1
      % expected type  nat
  bv_middle_TCC3: OBLIGATION
    FORALL (n: posnat, i, j: below(n)): i >= j IMPLIES i - j + 1 >= 0;

  % Subtype TCC generated (at line 37, column 41) for  0
      % expected type  below(n)
  bv2nat_caret_00_TCC1: OBLIGATION FORALL (n: posnat): 0 < n;

  % Subtype TCC generated (at line 40, column 61) for  n - 1
      % expected type  below(n)
  bv2nat_lem_TCC1: OBLIGATION FORALL (n: above(1)): n - 1 >= 0 AND n - 1 < n;

  % Subtype TCC generated (at line 40, column 68) for  1
      % expected type  upto(n - 1)
  bv2nat_lem_TCC2: OBLIGATION FORALL (n: above(1)): 1 <= n - 1;

  % Subtype TCC generated (at line 40, column 61) for  n - 1
      % expected type  nat
  bv2nat_lem_TCC3: OBLIGATION FORALL (n: above(1)): n - 1 >= 0;

  % Subtype TCC generated (at line 40, column 79) for  0
      % expected type  below[n]
  bv2nat_lem_TCC4: OBLIGATION FORALL (n: above(1)): 0 < n;


body:
  bv_arith_caret_concat_rules: THEORY
  BEGIN

    IMPORTING bv_arith_caret


    N,m: VAR posnat
    i1,i: VAR int
    n1: VAR nat

  %  bv_caret_concat_over_addition_1: THEOREM FORALL (bvn:bvec[N], bvm:bvec[m]):
  %                                  n1 >= m AND  n1 < m+N =>
  %        ((bvn o bvm + i1)^(n1,m) o (bvm + i1)) = (bvn^(n1-m,0) o bvm + i1)
  %
  %  superrange_addition: THEOREM FORALL (bv: bvec[N], n2,n3,n4 : nat):
  %      (N > n4 & n4 >= n3 & n3 = n2 + 1 & n2 >= 0) => 
  %        ((bv + i)^(n4,n3) o (bv^(n2,0) + i)) = (bv^(n4,0) + i)

  END bv_arith_caret_concat_rules 


body:
  bv_arith_nat_caret_rules: THEORY
  BEGIN

    IMPORTING bv_arith_caret

    N: VAR posnat

    bv_shift_rule  : THEOREM FORALL (bv:bvec[N], ss: below(N)):
                         bv2nat(bv^(N-1,ss)) = div(bv2nat(bv), exp2(ss))
  	      
    bv_bottom_rule : THEOREM FORALL (bv:bvec[N], ss: below(N)):
                         bv2nat(bv^(ss,0)) = mod(bv2nat(bv),exp2(ss+1))
  	      

    bv_middle_rule : THEOREM (FORALL (i,j: below(N), bv: bvec[N]): i >= j IMPLIES
                         bv2nat(bv^(i,j)) = 
                             mod(div(bv2nat(bv), exp2(j)),exp2(i-j+1)))


    bv_caret_00_rule : THEOREM FORALL (n: posnat, bv: bvec[n]):
                                bv2nat(bv^(0,0)) = b2n(bv^0)

    bv2nat_lem_rule  : THEOREM FORALL (n: above(1), bv: bvec[n]):
                                2 * bv2nat(bv ^ (n - 1, 1)) + b2n(bv ^ 0) 
                                   = bv2nat(bv)

  END bv_arith_nat_caret_rules

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

  % Subtype TCC generated (at line 9, column 34) for  N - 1
      % expected type  below(N)
  bv_shift_rule_TCC1: OBLIGATION
    FORALL (N: posnat, ss: below(N)): N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 9, column 38) for  ss
      % expected type  upto(N - 1)
  bv_shift_rule_TCC2: OBLIGATION
    FORALL (N: posnat, ss: below(N)): ss <= N - 1;

  % Subtype TCC generated (at line 9, column 34) for  N - ss
      % expected type  nat
  bv_shift_rule_TCC3: OBLIGATION
    FORALL (N: posnat, ss: below(N)): N - ss >= 0;

  % Subtype TCC generated (at line 12, column 37) for  0
      % expected type  upto(ss)
  bv_bottom_rule_TCC1: OBLIGATION FORALL (N: posnat, ss: below(N)): 0 <= ss;

  % Subtype TCC generated (at line 16, column 36) for  j
      % expected type  upto(i)
  bv_middle_rule_TCC1: OBLIGATION
    FORALL (N: posnat, i, j: below(N)): i >= j IMPLIES j <= i;

  % Subtype TCC generated (at line 89, column 18) for  1 + i - j
      % expected type  nat
  bv_middle_rule_TCC2: OBLIGATION
    FORALL (N: posnat, i, j: below(N)): i >= j IMPLIES 1 + i - j >= 0;

  % Subtype TCC generated (at line 17, column 61) for  i - j + 1
      % expected type  nat
  bv_middle_rule_TCC3: OBLIGATION
    FORALL (N: posnat, i, j: below(N)): i >= j IMPLIES i - j + 1 >= 0;

  % Subtype TCC generated (at line 21, column 41) for  0
      % expected type  below(n)
  bv_caret_00_rule_TCC1: OBLIGATION FORALL (n: posnat): 0 < n;

  % Subtype TCC generated (at line 24, column 47) for  n - 1
      % expected type  below(n)
  bv2nat_lem_rule_TCC1: OBLIGATION
    FORALL (n: above(1)): n - 1 >= 0 AND n - 1 < n;

  % Subtype TCC generated (at line 24, column 54) for  1
      % expected type  upto(n - 1)
  bv2nat_lem_rule_TCC2: OBLIGATION FORALL (n: above(1)): 1 <= n - 1;

  % Subtype TCC generated (at line 24, column 47) for  n - 1
      % expected type  nat
  bv2nat_lem_rule_TCC3: OBLIGATION FORALL (n: above(1)): n - 1 >= 0;

  % Subtype TCC generated (at line 24, column 69) for  0
      % expected type  below[n]
  bv2nat_lem_rule_TCC4: OBLIGATION FORALL (n: above(1)): 0 < n;


body:
  bv_arith_caret_rules: THEORY
  BEGIN

    IMPORTING bv_arith_caret

    n,N: VAR posnat
    i: VAR int
    m,nn: VAR nat

    bv_add_caret       : THEOREM FORALL (bv1, bv2:bvec[N]): nn < N => 
                                      (bv1 + bv2)^(nn,0) = bv1^(nn,0) + bv2^(nn,0)


    bv_caret_over_plus : THEOREM FORALL (bvn:bvec[N]): nn < N => 
                                      (bvn + i)^(nn,0) = bvn^(nn,0) + i

    bv_odd_even_pc     : THEOREM FORALL (bv: bvec[N]):
                                      (bv + nn)^0 = NOT (bv + (nn-1))^0

    bv_even_odd_pc     : THEOREM FORALL (bv: bvec[N]):
                                      (bv + (-n))^0 = NOT ((bv + (-n+1))^0)


  %  PCp1              : LEMMA FORALL (bv: bvec[N]): N > 1 IMPLIES
  %                                   (NOT bv^0) => (bv + 1)^(N-1, 1) = bv^(N-1, 1)


    bv_plus_caret_rule : LEMMA FORALL (bv1, bv2 : bvec[N]):
                               m <= nn AND nn + 1 < N => 
                           (bv1 + bv2) ^ (nn, m) = (bv1^(nn,0) + bv2^(nn,0))^(nn,m)


  END bv_arith_caret_rules

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

  % Subtype TCC generated (at line 11, column 52) for  0
      % expected type  upto(nn)
  bv_add_caret_TCC1: OBLIGATION
    FORALL (N: posnat, nn: nat): nn < N IMPLIES 0 <= nn;

  % Subtype TCC generated (at line 18, column 46) for  0
      % expected type  below[N]
  bv_odd_even_pc_TCC1: OBLIGATION FORALL (N: posnat): 0 < N;

  % Subtype TCC generated (at line 30, column 40) for  nn
      % expected type  below(N)
  bv_plus_caret_rule_TCC1: OBLIGATION
    FORALL (N: posnat, m, nn: nat): m <= nn AND nn + 1 < N IMPLIES nn < N;

  % Subtype TCC generated (at line 30, column 58) for  0
      % expected type  upto(nn)
  bv_plus_caret_rule_TCC2: OBLIGATION
    FORALL (N: posnat, m, nn: nat): m <= nn AND nn + 1 < N IMPLIES 0 <= nn;

  % Subtype TCC generated (at line 30, column 76) for  nn
      % expected type  below(1 + nn)
  bv_plus_caret_rule_TCC3: OBLIGATION
    FORALL (N: posnat, m, nn: nat):
      m <= nn AND nn + 1 < N IMPLIES nn < 1 + nn;


body:
  bv_caret_concat: THEORY

  BEGIN

    IMPORTING bv_arith_concat, bv_caret

    n,m: VAR posnat
    b  : VAR bit

    caret_fill	   : THEOREM FORALL (i: below(n), j: upto(i)): 
  			        fill[n](b)^(i,j) = fill[i-j+1](b)
   
    caret_concat_bot : THEOREM FORALL (i: below(n+m), j: upto(i),
                                       bvn: bvec[n], bvm: bvec[m]):
  			         i < m IMPLIES (bvn o bvm)^(i,j) = bvm^(i,j)
   
    caret_concat_top : THEOREM FORALL (i: below(n+m), j: upto(i),
                                       bvn: bvec[n], bvm: bvec[m]):
  			        j >= m 
  				  IMPLIES (bvn o bvm)^(i,j) = bvn^(i-m, j-m)
   
    caret_concat_all : THEOREM FORALL (i: below(n+m), j: upto(i), 
                                       bvn: bvec[n], bvm: bvec[m]):
  			        i >= m AND j < m 
  				   IMPLIES (bvn o bvm)^(i,j) = 
                                        bvn^(i-m,0) o bvm^(m-1,j) 

    bv_decomposition : THEOREM FORALL (N: above(1), k: below(N-1), bvn: bvec[N]):
                                  bvn^(N-1,k+1) o bvn^(k,0) = bvn
   
    caret_concat_join: THEOREM FORALL (bvn: bvec[n], i1,i2: below[n],
                                           j1: upto[i1], j2: upto[i2]):
                                 (j1=i2+1) =>
                                     (bvn^(i1,j1) o bvn^(i2,j2) =  bvn^(i1,j2));

    concat_bottom	   : THEOREM FORALL (bvn: bvec[n], bvm: bvec[m]):
                                  (bvn o bvm)^(m-1,0) = bvm
   
    concat_top	   : THEOREM FORALL (bvn: bvec[n], bvm: bvec[m]):
                                   (bvn o bvm)^((n+m-1),m) = bvn

  END bv_caret_concat

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

  % Subtype TCC generated (at line 11, column 39) for  1 + i - j
      % expected type  nat
  caret_fill_TCC1: OBLIGATION
    FORALL (n: posnat, i: below(n), j: upto(i)): 1 + i - j >= 0;

  % Subtype TCC generated (at line 20, column 39) for  i - m
      % expected type  below(n)
  caret_concat_top_TCC1: OBLIGATION
    FORALL (m, n: posnat, i: below(m + n), j: upto(i)):
      j >= m IMPLIES i - m >= 0 AND i - m < n;

  % Subtype TCC generated (at line 20, column 44) for  j - m
      % expected type  upto(i - m)
  caret_concat_top_TCC2: OBLIGATION
    FORALL (m, n: posnat, i: below(m + n), j: upto(i)):
      j >= m IMPLIES j - m >= 0 AND j - m <= i - m;

  % Subtype TCC generated (at line 26, column 43) for  i - m
      % expected type  below(n)
  caret_concat_all_TCC1: OBLIGATION
    FORALL (m, n: posnat, i: below(m + n), j: upto(i)):
      i >= m AND j < m IMPLIES i - m >= 0 AND i - m < n;

  % Subtype TCC generated (at line 26, column 47) for  0
      % expected type  upto(i - m)
  caret_concat_all_TCC2: OBLIGATION
    FORALL (m, n: posnat, i: below(m + n), j: upto(i)):
      i >= m AND j < m IMPLIES 0 <= i - m;

  % Subtype TCC generated (at line 26, column 57) for  m - 1
      % expected type  below(m)
  caret_concat_all_TCC3: OBLIGATION
    FORALL (m, n: posnat, i: below(m + n), j: upto(i)):
      i >= m AND j < m IMPLIES m - 1 >= 0 AND m - 1 < m;

  % Subtype TCC generated (at line 26, column 61) for  j
      % expected type  upto(m - 1)
  caret_concat_all_TCC4: OBLIGATION
    FORALL (m, n: posnat, i: below(m + n), j: upto(i)):
      i >= m AND j < m IMPLIES j <= m - 1;

  % Subtype TCC generated (at line 89, column 18) for  1 + i - m
      % expected type  nat
  caret_concat_all_TCC5: OBLIGATION
    FORALL (m, n: posnat, i: below(m + n), j: upto(i)):
      i >= m AND j < m IMPLIES 1 + i - m >= 0;

  % Subtype TCC generated (at line 26, column 57) for  m - j
      % expected type  nat
  caret_concat_all_TCC6: OBLIGATION
    FORALL (m, n: posnat, i: below(m + n), j: upto(i)):
      i >= m AND j < m IMPLIES m - j >= 0;

  % Subtype TCC generated (at line 29, column 37) for  N - 1
      % expected type  below(N)
  bv_decomposition_TCC1: OBLIGATION
    FORALL (N: above(1), k: below(N - 1)): N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 29, column 41) for  k + 1
      % expected type  upto(N - 1)
  bv_decomposition_TCC2: OBLIGATION
    FORALL (N: above(1), k: below(N - 1)): k + 1 <= N - 1;

  % Subtype TCC generated (at line 29, column 53) for  k
      % expected type  below(N)
  bv_decomposition_TCC3: OBLIGATION
    FORALL (N: above(1), k: below(N - 1)): k < N;

  % Subtype TCC generated (at line 29, column 55) for  0
      % expected type  upto(k)
  bv_decomposition_TCC4: OBLIGATION
    FORALL (N: above(1), k: below(N - 1)): 0 <= k;

  % Subtype TCC generated (at line 29, column 37) for  N - 1 - k
      % expected type  nat
  bv_decomposition_TCC5: OBLIGATION
    FORALL (N: above(1), k: below(N - 1)): N - 1 - k >= 0;

  % Subtype TCC generated (at line 89, column 18) for  1 + i2 - j2
      % expected type  nat
  caret_concat_join_TCC1: OBLIGATION
    FORALL (n: posnat, i1, i2: below[n], j1: upto[i1], j2: upto[i2]):
      (j1 = i2 + 1) IMPLIES 1 + i2 - j2 >= 0;

  % Subtype TCC generated (at line 34, column 73) for  j2
      % expected type  upto(i1)
  caret_concat_join_TCC2: OBLIGATION
    FORALL (n: posnat, i1, i2: below[n], j1: upto[i1], j2: upto[i2]):
      (j1 = i2 + 1) IMPLIES j2 <= i1;

  % Subtype TCC generated (at line 34, column 65) for  bvn ^ (i1, j2)
      % expected type  bvec[2 + i1 + i2 - j1 - j2]
  caret_concat_join_TCC3: OBLIGATION
    FORALL (n: posnat, bvn: bvec[n], i1, i2: below[n], j1: upto[i1],
            j2: upto[i2]):
      (j1 = i2 + 1) IMPLIES
       (FORALL (x: nat):
          (^[n](bvn, (i1, j2)))(x) IMPLIES
           (x < 1 + i1 - j2 IFF x < 2 + i1 + i2 - j1 - j2));

  % Subtype TCC generated (at line 37, column 45) for  m - 1
      % expected type  below(m + n)
  concat_bottom_TCC1: OBLIGATION
    FORALL (m, n: posnat): m - 1 >= 0 AND m - 1 < m + n;

  % Subtype TCC generated (at line 37, column 49) for  0
      % expected type  upto(m - 1)
  concat_bottom_TCC2: OBLIGATION FORALL (m: posnat): 0 <= m - 1;

  % Subtype TCC generated (at line 40, column 47) for  (n + m - 1)
      % expected type  below(m + n)
  concat_top_TCC1: OBLIGATION
    FORALL (m, n: posnat): (n + m - 1) >= 0 AND (n + m - 1) < m + n;

  % Subtype TCC generated (at line 40, column 54) for  m
      % expected type  upto((m + n - 1))
  concat_top_TCC2: OBLIGATION FORALL (m, n: posnat): m <= (m + n - 1);


body:
  bv_caret_concat_rules: THEORY

  BEGIN

    IMPORTING bv_caret_concat
    n,m: VAR posnat
    i,j: VAR nat
    b: VAR bit

    bv_concat_bottom     : LEMMA FORALL (bvn: bvec[n], bvm: bvec[m]):
                                  (bvn o bvm)^((m-1), 0) = bvm
   
    bv_concat_top	       : LEMMA FORALL (bvn: bvec[n], bvm: bvec[m]):
                                   (bvn o bvm)^((n+m-1), m) = bvn

    bv_caret_concat_low  : LEMMA FORALL (bvn: bvec[n], bvm: bvec[m]):
                                   (i < m) AND (j <= i) =>  
                                     (bvn o bvm)^(i, j) = bvm^(i, j) 

    bv_caret_concat_high : LEMMA FORALL (bvn: bvec[n], bvm: bvec[m]):
  			          i < n+m AND m <= j AND j <= i 
  				    IMPLIES (bvn o bvm)^(i,j) = bvn^(i-m, j-m)


    bv_caret_concat_split: LEMMA FORALL (bvn: bvec[n], bvm: bvec[m]):
                                   (i < n+m) AND (i >= m) AND
                                    (j < m) AND (j <= i) =>
                               (bvn o bvm)^(i,j) = bvn^(i-m, 0) o bvm^(m-1,j)


    bv_caret_recomp      : LEMMA FORALL (n: posnat, bvn: bvec[n], 
                                        i1,j1,i2,j2: below[n]):
                               (i1 >= j1) AND (i2 >= j2) AND (j1=i2+1) =>
                                  (bvn^(i1,j1) o bvn^(i2,j2) =  bvn^(i1,j2));

    bv_ucaret_concat_1   : LEMMA FORALL (bvn: bvec[n], bvm: bvec[m]):
                                    i < m => (bvn o bvm)^i = bvm^i

    bv_ucaret_concat_2   : LEMMA FORALL (bvn: bvec[n], bvm: bvec[m]): 
                                   (i < n+m) AND (i >= m) => 
                                      (bvn o bvm)^i = bvn^(i-m)  

    bv_caret_fill        : LEMMA FORALL (i: below(n), j: upto(i)): 
  			      fill[n](b)^(i,j) = fill[i-j+1](b)
   

  END bv_caret_concat_rules

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

  % Subtype TCC generated (at line 11, column 46) for  (m - 1)
      % expected type  below(m + n)
  bv_concat_bottom_TCC1: OBLIGATION
    FORALL (m, n: posnat): (m - 1) >= 0 AND (m - 1) < m + n;

  % Subtype TCC generated (at line 11, column 52) for  0
      % expected type  upto((m - 1))
  bv_concat_bottom_TCC2: OBLIGATION FORALL (m: posnat): 0 <= (m - 1);

  % Subtype TCC generated (at line 14, column 47) for  (n + m - 1)
      % expected type  below(m + n)
  bv_concat_top_TCC1: OBLIGATION
    FORALL (m, n: posnat): (n + m - 1) >= 0 AND (n + m - 1) < m + n;

  % Subtype TCC generated (at line 14, column 55) for  m
      % expected type  upto((m + n - 1))
  bv_concat_top_TCC2: OBLIGATION FORALL (m, n: posnat): m <= (m + n - 1);

  % Subtype TCC generated (at line 18, column 48) for  i
      % expected type  below(m + n)
  bv_caret_concat_low_TCC1: OBLIGATION
    FORALL (i, j: nat, m, n: posnat): (i < m) AND (j <= i) IMPLIES i < m + n;

  % Subtype TCC generated (at line 22, column 29) for  i
      % expected type  below(m + n)
  bv_caret_concat_high_TCC1: OBLIGATION
    FORALL (i, j: nat, m, n: posnat):
      i < n + m AND m <= j AND j <= i IMPLIES i < m + n;

  % Subtype TCC generated (at line 22, column 41) for  i - m
      % expected type  below(n)
  bv_caret_concat_high_TCC2: OBLIGATION
    FORALL (i, j: nat, m, n: posnat):
      i < n + m AND m <= j AND j <= i IMPLIES i - m >= 0 AND i - m < n;

  % Subtype TCC generated (at line 22, column 46) for  j - m
      % expected type  upto(i - m)
  bv_caret_concat_high_TCC3: OBLIGATION
    FORALL (i, j: nat, m, n: posnat):
      i < n + m AND m <= j AND j <= i IMPLIES j - m >= 0 AND j - m <= i - m;

  % Subtype TCC generated (at line 28, column 42) for  i
      % expected type  below(m + n)
  bv_caret_concat_split_TCC1: OBLIGATION
    FORALL (i, j: nat, m, n: posnat):
      (i < n + m) AND (i >= m) AND (j < m) AND (j <= i) IMPLIES i < m + n;

  % Subtype TCC generated (at line 28, column 54) for  i - m
      % expected type  below(n)
  bv_caret_concat_split_TCC2: OBLIGATION
    FORALL (i, j: nat, m, n: posnat):
      (i < n + m) AND (i >= m) AND (j < m) AND (j <= i) IMPLIES
       i - m >= 0 AND i - m < n;

  % Subtype TCC generated (at line 28, column 59) for  0
      % expected type  upto(i - m)
  bv_caret_concat_split_TCC3: OBLIGATION
    FORALL (i, j: nat, m, n: posnat):
      (i < n + m) AND (i >= m) AND (j < m) AND (j <= i) IMPLIES 0 <= i - m;

  % Subtype TCC generated (at line 28, column 69) for  m - 1
      % expected type  below(m)
  bv_caret_concat_split_TCC4: OBLIGATION
    FORALL (i, j: nat, m, n: posnat):
      (i < n + m) AND (i >= m) AND (j < m) AND (j <= i) IMPLIES
       m - 1 >= 0 AND m - 1 < m;

  % Subtype TCC generated (at line 28, column 73) for  j
      % expected type  upto(m - 1)
  bv_caret_concat_split_TCC5: OBLIGATION
    FORALL (i, j: nat, m, n: posnat):
      (i < n + m) AND (i >= m) AND (j < m) AND (j <= i) IMPLIES j <= m - 1;

  % Subtype TCC generated (at line 89, column 18) for  1 + i - m
      % expected type  nat
  bv_caret_concat_split_TCC6: OBLIGATION
    FORALL (i, j: nat, m, n: posnat):
      (i < n + m) AND (i >= m) AND (j < m) AND (j <= i) IMPLIES
       1 + i - m >= 0;

  % Subtype TCC generated (at line 28, column 69) for  m - j
      % expected type  nat
  bv_caret_concat_split_TCC7: OBLIGATION
    FORALL (i, j: nat, m, n: posnat):
      (i < n + m) AND (i >= m) AND (j < m) AND (j <= i) IMPLIES m - j >= 0;

  % Subtype TCC generated (at line 34, column 41) for  j1
      % expected type  upto(i1)
  bv_caret_recomp_TCC1: OBLIGATION
    FORALL (n: posnat, i1, j1, i2, j2: below[n]):
      (i1 >= j1) AND (i2 >= j2) AND (j1 = i2 + 1) IMPLIES j1 <= i1;

  % Subtype TCC generated (at line 34, column 55) for  j2
      % expected type  upto(i2)
  bv_caret_recomp_TCC2: OBLIGATION
    FORALL (n: posnat, i1, j1, i2, j2: below[n]):
      (i1 >= j1) AND (i2 >= j2) AND (j1 = i2 + 1) IMPLIES j2 <= i2;

  % Subtype TCC generated (at line 89, column 18) for  1 + i1 - j1
      % expected type  nat
  bv_caret_recomp_TCC3: OBLIGATION
    FORALL (n: posnat, i1, j1, i2, j2: below[n]):
      (i1 >= j1) AND (i2 >= j2) AND (j1 = i2 + 1) IMPLIES 1 + i1 - j1 >= 0;

  % Subtype TCC generated (at line 89, column 18) for  1 + i2 - j2
      % expected type  nat
  bv_caret_recomp_TCC4: OBLIGATION
    FORALL (n: posnat, i1, j1, i2, j2: below[n]):
      (i1 >= j1) AND (i2 >= j2) AND (j1 = i2 + 1) IMPLIES 1 + i2 - j2 >= 0;

  % Subtype TCC generated (at line 34, column 70) for  j2
      % expected type  upto(i1)
  bv_caret_recomp_TCC5: OBLIGATION
    FORALL (n: posnat, i1, j1, i2, j2: below[n]):
      (i1 >= j1) AND (i2 >= j2) AND (j1 = i2 + 1) IMPLIES j2 <= i1;

  % Subtype TCC generated (at line 34, column 62) for  bvn ^ (i1, j2)
      % expected type  bvec[2 + i1 + i2 - j1 - j2]
  bv_caret_recomp_TCC6: OBLIGATION
    FORALL (n: posnat, bvn: bvec[n], i1, j1, i2, j2: below[n]):
      (i1 >= j1) AND (i2 >= j2) AND (j1 = i2 + 1) IMPLIES
       (FORALL (x: nat):
          (^[n](bvn, (i1, j2)))(x) IMPLIES
           (x < 1 + i1 - j2 IFF x < 2 + i1 + i2 - j1 - j2));

  % Subtype TCC generated (at line 37, column 55) for  i
      % expected type  below[m + n]
  bv_ucaret_concat_1_TCC1: OBLIGATION
    FORALL (i: nat, m, n: posnat): i < m IMPLIES i < m + n;

  % Subtype TCC generated (at line 41, column 48) for  i
      % expected type  below[m + n]
  bv_ucaret_concat_2_TCC1: OBLIGATION
    FORALL (i: nat, m, n: posnat): (i < n + m) AND (i >= m) IMPLIES i < m + n;

  % Subtype TCC generated (at line 41, column 57) for  (i - m)
      % expected type  below[n]
  bv_ucaret_concat_2_TCC2: OBLIGATION
    FORALL (i: nat, m, n: posnat):
      (i < n + m) AND (i >= m) IMPLIES (i - m) >= 0 AND (i - m) < n;

  % Subtype TCC generated (at line 44, column 37) for  1 + i - j
      % expected type  nat
  bv_caret_fill_TCC1: OBLIGATION
    FORALL (n: posnat, i: below(n), j: upto(i)): 1 + i - j >= 0;


body:
  %------------------------------------------------------------------------
  %
  % Integer interpretation of a bitvector (twos-complement interpretation)
  % ----------------------------------------------------------------------
  %
  %   Defines:
  %
  %      minint: int = -exp2(N-1)
  %      maxint: int =  exp2(N-1) - 1
  %      rng_2s_comp: TYPE = {i: int | minint <= i AND i <= maxint}
  %      bv2int : [bvec[N] -> rng_2s_comp] 
  %      int2bv : [rng_2s_comp  -> bvec[N]]
  %  
  %   Establishes:
  %  
  %      bv2int_bij : THEOREM bijective?(bv2int)
  %      bv2int_inv : THEOREM bv2int(int2bv(iv))=iv
  %
  %   Note.  The int2bv should be avoided in practice.  It is necessary
  %          for the development of the library.
  %
  %------------------------------------------------------------------------
  bv_int[N: posnat]: THEORY
  BEGIN

    IMPORTING bv_nat[N], bv_int_defs[N]

  % Definitions have been moved to the prelude theory bv_int_defs
  % to support Yices

  %   minint: int = -exp2(N-1)
  %   maxint: int =  exp2(N-1) - 1

  %   bv_maxint_to_minint:    LEMMA maxint = -minint - 1
  %   bv_minint_to_maxint:    LEMMA minint = -maxint - 1

  %   in_rng_2s_comp(i: int): bool = (minint <= i AND i <= maxint)
  %   rng_2s_comp: TYPE = {i: int | minint <= i AND i <= maxint}

  %   bv2int(bv: bvec[N]): rng_2s_comp = IF bv2nat(bv) < exp2(N-1) THEN bv2nat(bv)
  %                                      ELSE bv2nat(bv) - exp2(N) ENDIF

    i           : VAR below(N)
    iv,ii       : VAR rng_2s_comp
    bv, bv1, bv2: VAR bvec[N]

      
    bv2int_inj    : THEOREM % injective?(bv2int)
                                 bv2int(bv1) = bv2int(bv2) IMPLIES (bv1 = bv2)

    bv2int_surj   : THEOREM % surjective?(bv2int)
                                (EXISTS (bv: bvec[N]): bv2int(bv) = iv)

    bv2int_bij    : THEOREM bijective?(bv2int)

    bv2int_lem    : THEOREM bv2int(bv) = bv2nat(bv) - exp2(N) * bv^(N - 1)

    bv2int_fill_F : THEOREM bv2int(fill[N](FALSE)) = 0

    bv2int_fill_T : THEOREM bv2int(fill[N](TRUE)) = -1

    bv2int_top_bit: THEOREM IF bv2int(bv) >= 0 THEN bv^(N-1) = FALSE 
                            ELSE bv^(N-1) = TRUE ENDIF

    bv2int_topbit : THEOREM bv^(N-1) IFF (bv2int(bv) < 0)

  % ---------- Properties of int2bv ----------------------------


  %  int2bv(iv: rng_2s_comp): {bv | bv2int(bv) = iv}

    int2bv_def : THEOREM int2bv = inverse(bv2int) 

    int2bv_bij : THEOREM bijective?[rng_2s_comp,bvec[N]](int2bv)

    bv2int_inv : THEOREM bv2int(int2bv(iv))=iv

    int2bv_inv : THEOREM int2bv(bv2int(bv)) = bv

    int2bv_2nat: THEOREM  int2bv(ii) = IF ii >= 0 THEN nat2bv[N](ii)
                                     ELSE nat2bv[N](ii+exp2(N)) ENDIF


  END bv_int

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

  % Subtype TCC generated (at line 56, column 66) for  (N - 1)
      % expected type  below[N]
  bv2int_lem_TCC1: OBLIGATION (N - 1) >= 0 AND (N - 1) < N;

  % Subtype TCC generated (at line 80, column 63) for  ii
      % expected type  val: below(exp2(N))
  int2bv_2nat_TCC1: OBLIGATION
    FORALL (ii: rng_2s_comp[N]): ii >= 0 IMPLIES ii < exp2(N);

  % Subtype TCC generated (at line 81, column 50) for  ii + exp2(N)
      % expected type  val: below(exp2(N))
  int2bv_2nat_TCC2: OBLIGATION
    FORALL (ii: rng_2s_comp[N]):
      NOT ii >= 0 IMPLIES ii + exp2(N) >= 0 AND ii + exp2(N) < exp2(N);


body:
  bv_arith_int_concat: THEORY

  BEGIN

    IMPORTING bv_arith_nat, bv_int,
              bv_arith_concat % For proofs only



    bv2int_concat      : LEMMA FORALL (n, m: posnat, bvn: bvec[n], bvm: bvec[m]):
                                  bv2int(bvn o bvm) = bv2int(bvn) * exp2(m) 
                                                      + bv2int(bvm) 
                                                      + b2n(bvm^(m-1)) * exp2(m)

  END bv_arith_int_concat

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

  % Subtype TCC generated (at line 10, column 75) for  m + n
      % expected type  posnat
  bv2int_concat_TCC1: OBLIGATION FORALL (n, m: posnat): m + n > 0;

  % Subtype TCC generated (at line 13, column 63) for  (m - 1)
      % expected type  below[m]
  bv2int_concat_TCC2: OBLIGATION
    FORALL (n, m: posnat): (m - 1) >= 0 AND (m - 1) < m;


body:
  %------------------------------------------------------------------------
  %
  % Defines functions over bit vectors interpreted as natural numbers.
  %
  %    Introduces:
  %
  %         - :  bv1 - bv2
  %         - : [bvec -> bvec] 
  %         - : [bvec, bvec -> bvec]
  %         overflow    : [bvec, bvec -> bool]  
  %         underflow   : [bvec, bvec -> bool]  
  %   
  %------------------------------------------------------------------------
  bv_arithmetic[N: posnat]: THEORY
  BEGIN

    IMPORTING bv_int[N], bv_arith_caret, bv_arithmetic_defs[N]

    bv, bv1, bv2 : VAR bvec[N]

  % The following three definitions are now in the prelude theory
  %   bv_arithmetic_defs - they were moved there to support Yices

  % ---------- 2's complement negation of a bit vector ----------
      
  %   -(bv: bvec[N]): { bvn: bvec[N] | bv2int(bvn) = 
  %                               IF bv2int(bv) = minint THEN bv2int(bv)
  %                               ELSE -(bv2int(bv)) ENDIF}

  % ---------- 2's complement subtraction of two bit vectors ----------
      
  %   -(bv1, bv2): bvec[N] = (bv1 + (-bv2))

  % ---------- Define conditions for 2's complement overflow  ----------

      
  %   overflow(bv1,bv2): bool = (bv2int(bv1) + bv2int(bv2)) > maxint
  %                              OR (bv2int(bv1) + bv2int(bv2)) < minint 

  % === Properties of these additional functions ================================

    % ----------------------------------------------------------------------
    % If the result is in the range of 2s complement integers, addition of
    % two bit vectors is the same as for a natural number interpretation
    % ----------------------------------------------------------------------
     
    bv_top_bit_0: LEMMA  bv^(N-1) = FALSE IFF bv2nat(bv) < exp2(N-1)

    bv2int_add  : THEOREM in_rng_2s_comp(bv2int(bv1) + bv2int(bv2))
                           IMPLIES bv2int(bv1 + bv2) = bv2int(bv1) + bv2int(bv2)  
      
    bv2int_neg : LEMMA bv2int(-bv) = IF bv2int(bv) = minint THEN bv2int(bv)
                                     ELSE -(bv2int(bv)) ENDIF 

    bv2int_minus_1  : LEMMA bv2int(bv1) > minint AND bv2int(bv) = 1 
                         IMPLIES bv2int(bv1 - bv) = bv2int(bv1) - 1

    bv2int_plus_1: LEMMA bv2int(bv + 1) = IF bv2int(bv) = maxint[N] THEN minint[N]
                                         ELSE bv2int(bv) + 1 ENDIF 

    bv2int_elim    : LEMMA bv1 + bv2int(bv2) = bv1 + bv2

    i: VAR int
    bv2int_plus_i: LEMMA bv2int(bv+i) =
                         mod(bv2int(bv) + exp2(N) * b2n(bv^(N - 1)) + i, exp2(N))
                           - exp2(N) * b2n((bv + i)^(N - 1))

    bv2int_maxint : LEMMA bv2int(bv) = maxint IFF bv = b0 o fill[N-1](TRUE)
      
    bv2int_minint : LEMMA bv2int(bv) = minint IFF bv = b1 o fill[N-1](FALSE)

    IMPORTING bv_bitwise[N]
   
    n          : VAR upto(N)
     
    bv2nat_compl_max  : THEOREM bv2nat_rec(n, bv) + bv2nat_rec(n, NOT bv) 
                            = exp2(n) - 1

    % ----------------------------------------------------------------------
    % The 2s complement of a number is its 1s complement + 1
    % ----------------------------------------------------------------------

    bv_twos_compl     : THEOREM -bv2int(bv) = bv2int(NOT bv) + 1;

    bv_unary_minus    : THEOREM (-bv) = (NOT bv) + 1

    bv2nat_NOT     : COROLLARY bv2nat(NOT bv) = exp2(N) - bv2nat(bv) - 1  
   

    bv2int_NOT     : COROLLARY bv2int(NOT bv) = -bv2int(bv) - 1

    bv2nat_minus_bv: COROLLARY bv2nat(-bv) = IF bv2nat(bv) = 0 THEN 0
                                             ELSE exp2(N) - bv2nat(bv) ENDIF

    bv_is_minint   : COROLLARY bv2int(-bv) = bv2int(bv) 
                                 IMPLIES bv2int(bv) = minint OR bv2int(bv) = 0
   
    bv_neg_distrib : THEOREM -(bv1 + bv2) = -bv1 + -bv2

    bv_double_neg  : THEOREM -(-(bv1)) = bv1


  END bv_arithmetic

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

  % Subtype TCC generated (at line 47, column 27) for  (N - 1)
      % expected type  below[N]
  bv_top_bit_0_TCC1: OBLIGATION (N - 1) >= 0 AND (N - 1) < N;

  % Subtype TCC generated (at line 47, column 62) for  N - 1
      % expected type  nat
  bv_top_bit_0_TCC2: OBLIGATION N - 1 >= 0;


body:
  bv_extend [N: posnat] : THEORY
  % -----------------------------------------------------------------------  
  %    Introduces:
  %	zero_extend: [k: above(N) -> [bvec[N] -> bvec[l]]] =
  %	sign_extend: [k: above(N) -> [bvec[N] -> bvec[l]]] =
  %	zero_extend_lsend: [k: above(N) -> [bvec[N] -> bvec[l]]]
  %	lsb_extend: [k: above(N) -> [bvec[N] -> bvec[l]]] =
  %   
  % -----------------------------------------------------------------------  

  BEGIN

    IMPORTING bv_caret, bv_concat, bv_extend_defs[N]
      
    bv: VAR bvec[N]
    k: VAR above(N)

  % Definitions have been moved to the prelude theory bv_extend_defs
  % to support Yices
    %------------------------------------------------------------------------
    % zero_extend returns a function that extends a bit vector to length k 
    % such that its interpretation as a natural number remains unchanged.
    % That is, it fills 0's at the most significant positions.
    %------------------------------------------------------------------------

  %   zero_extend(k: above(N)): [bvec[N] -> bvec[k]] =
  %        (LAMBDA bv: fill[k-N](FALSE) o bv )

    %------------------------------------------------------------------------
    % sign_extend returns a function that extends a bit vector to length k
    % by repeating the most significant bit of the given bit vector.
    % The set above(N) contains nat numbers greater than n.
    %------------------------------------------------------------------------

  %   sign_extend(k: above(N)): [bvec[N] -> bvec[k]] =
  %        (LAMBDA bv:  fill[k-N](bv^(N-1)) o bv )
    %------------------------------------------------------------------------
    % zero_extend_lsend returns a function that extends a bit vector to
    % length k by padding 0's at the least significant end of bvec.
    % That is, the bv2nat interpretation of the argument increases by 2**(k-N)
    %------------------------------------------------------------------------
      
  %   zero_extend_lsend(k: above(N)): [bvec[N] -> bvec[k]] =
  %         (LAMBDA bv:  bv o fill[k-N](FALSE))
    
    %------------------------------------------------------------------------
    % lsb_extend returns a function that extends a bit vector to
    % length k by repeating the lsb of the bit vector at its
    % least significant end.
    %------------------------------------------------------------------------
      
  %   lsb_extend(k: above(N)): [bvec[N] -> bvec[k]] =
  %        (LAMBDA bv: bv o fill[k-N](bv^0)) 

    zero_extend_def       : LEMMA zero_extend(k)(bv)  = fill[k-N](FALSE) o bv
    
    sign_extend_def       : LEMMA sign_extend(k)(bv)  = fill[k-N](bv^(N-1)) o bv 
    
    zero_extend_lsend_def : LEMMA zero_extend_lsend(k)(bv) = bv o fill[k-N](FALSE)
    
    lsb_extend__def       : LEMMA lsb_extend(k)(bv)        = bv o fill[k-N](bv^0)

  END bv_extend

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

  % Subtype TCC generated (at line 55, column 59) for  k - N
      % expected type  nat
  zero_extend_def_TCC1: OBLIGATION FORALL (k: above(N)): k - N >= 0;

  % Subtype TCC generated (at line 57, column 68) for  (N - 1)
      % expected type  below[N]
  sign_extend_def_TCC1: OBLIGATION (N - 1) >= 0 AND (N - 1) < N;

  % Subtype TCC generated (at line 61, column 77) for  0
      % expected type  below[N]
  lsb_extend__def_TCC1: OBLIGATION 0 < N;


body:
  bv_arith_extend: THEORY

  BEGIN

    IMPORTING bv_extend, bv_arithmetic, bv_arith_int_concat, bv_bitwise

    n: VAR posnat    

    zero_extend_lem  : THEOREM (FORALL (bv: bvec[n], k: above(n)):
                          bv2nat[k](zero_extend[n](k)(bv)) = bv2nat(bv))

    sign_to_zero     : THEOREM (FORALL (bv: bvec[n], k: above(n)):
                                sign_extend[n](k)(bv) =
  			         IF bv(n-1) THEN 
                                      NOT(zero_extend[n](k)(NOT(bv)))
  			         ELSE zero_extend[n](k)(bv)
  			         ENDIF)

    sign_extend_lem  : THEOREM (FORALL (bv: bvec[n], k: above(n)):
                                 bv2int[k](sign_extend[n](k)(bv)) = bv2int(bv))

    zero_extend_lsend: THEOREM (FORALL (bv: bvec[n], k: above(n)):
                                  bv2nat(zero_extend_lsend[n](k)(bv)) 
                                     = bv2nat(bv) * exp2(k-n))

    pos_nat_below(n) : TYPE = {nn: nat | nn > 0 AND nn < n} 
    bv2int_elim_gen  : LEMMA (FORALL (m: pos_nat_below(n),
                                      bv1: bvec[n],bv2: bvec[m]):
                          bv1 + sign_extend[m](n)(bv2) = bv1 + bv2int[m](bv2))



  END bv_arith_extend

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

  % Subtype TCC generated (at line 14, column 18) for  n - 1
      % expected type  below(n)
  sign_to_zero_TCC1: OBLIGATION FORALL (n: posnat): n - 1 >= 0 AND n - 1 < n;

  % Subtype TCC generated (at line 24, column 55) for  k - n
      % expected type  nat
  zero_extend_lsend_TCC1: OBLIGATION
    FORALL (n: posnat, k: above(n)): k - n >= 0;

  % Subtype TCC generated (at line 29, column 45) for  n
      % expected type  k: above(m)
  bv2int_elim_gen_TCC1: OBLIGATION
    FORALL (n: posnat, m: pos_nat_below(n)): n > m;


body:
  bv_overflow[N:posnat]: THEORY

  BEGIN

    IMPORTING bv_arithmetic[N]

    bv,bv1,bv2: var bvec[N]

    overflow(bv1,bv2): bool = NOT in_rng_2s_comp(bv2int(bv1) + bv2int(bv2))

    overflow_then_eq: LEMMA overflow(bv1,bv2) IMPLIES 
                                bv1 ^ (N - 1) = bv2 ^ (N - 1)
    
    i: VAR int  

    bv2int_overflow_nat : LEMMA NOT in_rng_2s_comp(bv2int(bv1) + bv2int(bv2))
                                      IMPLIES bv2int(bv1 + bv2) = 
                                        bv2nat(bv1) + bv2nat(bv2) - exp2(N)

    bv_not_in_rng_int   : LEMMA NOT in_rng_2s_comp(bv2int(bv1) + bv2int(bv2))
                                      IMPLIES bv2int(bv1 + bv2) =
                                          bv2int(bv1) + bv2int(bv2) 
                                                + exp2(N) * b2n(bv1(N - 1))
                                                + exp2(N) * b2n(bv2(N - 1))
                                                - exp2(N)

    bv2int_add_overflow : THEOREM NOT in_rng_2s_comp(bv2int(bv1) + bv2int(bv2))
                             IMPLIES bv2int(bv1 + bv2) =
              		       IF bv2int(bv1) >= 0 AND bv2int(bv2) >= 0
              			  THEN bv2int(bv1) + bv2int(bv2) - exp2(N)
              		       ELSE bv2int(bv1) + bv2int(bv2) + exp2(N) 
                                 ENDIF


    bv_sum_limits       : LEMMA bv2int(bv1) + bv2int(bv2) <= 2 * maxint AND
                                bv2int(bv1) + bv2int(bv2) >= 2 * minint  

    bv_bits_for_overflow: LEMMA (bv1 ^ (N - 1) = bv2 ^ (N - 1)
                                AND bv1 ^ (N - 1) /= (bv1 + bv2) ^ (N - 1))
                                    IMPLIES overflow(bv1, bv2)

    bv_overflow_bits_ne : LEMMA overflow(bv1,bv2) IMPLIES 
                                        (bv1 ^ (N - 1) /= (bv1 + bv2) ^ (N - 1))

    bv_overflow_def     : THEOREM overflow(bv1, bv2) =
                                     ((bv1 ^ (N - 1) = bv2 ^ (N - 1))
                                     AND (bv1 ^ (N - 1) /= (bv1 + bv2) ^ (N - 1)))

  END bv_overflow

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

  % Subtype TCC generated (at line 12, column 37) for  (N - 1)
      % expected type  below[N]
  overflow_then_eq_TCC1: OBLIGATION
    FORALL (bv1, bv2: bvec[N]):
      overflow(bv1, bv2) IMPLIES (N - 1) >= 0 AND (N - 1) < N;

  % Subtype TCC generated (at line 23, column 66) for  N - 1
      % expected type  below(N)
  bv_not_in_rng_int_TCC1: OBLIGATION
    FORALL (bv1, bv2: bvec[N]):
      NOT in_rng_2s_comp(bv2int(bv1) + bv2int(bv2)) IMPLIES
       N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 38, column 38) for  (N - 1)
      % expected type  below[N]
  bv_bits_for_overflow_TCC1: OBLIGATION (N - 1) >= 0 AND (N - 1) < N;


body:
  bv_arith_int_rules: THEORY
  BEGIN

    IMPORTING bv_arithmetic, bv_overflow, bv_arith_extend, bv_arith_caret

    n,N: VAR posnat

    singleton_int: LEMMA FORALL (bv: bvec[n], i: below[n]):
                              bv2int[1](bv^(i,i)) = - b2n(bv^i)

    bv2int_add_combined_rule: LEMMA FORALL (bv1, bv2: bvec[n]):
         bv2int(bv1 + bv2) =
           IF in_rng_2s_comp[n](bv2int(bv1) + bv2int(bv2)) THEN 
                bv2int(bv1) + bv2int(bv2)
           ELSIF bv2int(bv1) >= 0 AND bv2int(bv2) >= 0 THEN 
                bv2int(bv1) + bv2int(bv2) - exp2(n)
           ELSE 
               bv2int(bv1) + bv2int(bv2) + exp2(n) 
           ENDIF

     bv2int_add_no_overflow: LEMMA FORALL (bv1, bv2: bvec[n]):
                        in_rng_2s_comp[n](bv2int(bv1) + bv2int(bv2)) =>
                           bv2int(bv1 + bv2) = bv2int(bv1) + bv2int(bv2)

     bv2int_add_overflow: LEMMA FORALL (bv1, bv2: bvec[n]):
                       (NOT in_rng_2s_comp[n](bv2int(bv1) + bv2int(bv2))) =>
            		   bv2int(bv1 + bv2) =
            		     IF bv2int(bv1) >= 0 & bv2int(bv2) >= 0
            			THEN bv2int(bv1) + bv2int(bv2) - exp2(n)
            		     ELSE bv2int(bv1) + bv2int(bv2) + exp2(n) ENDIF


     sign_bit_of_unary_minus: LEMMA FORALL (bv: bvec[n]):
               (-bv)^(n-1) = IF bv2int(bv) = minint[n] THEN TRUE
                             ELSIF NOT bv^(n-1) THEN 
                                 IF bv2int(bv) = 0 THEN FALSE 
                                 ELSE TRUE ENDIF
                             ELSE FALSE ENDIF

  END bv_arith_int_rules

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

  % Subtype TCC generated (at line 9, column 44) for  i
      % expected type  upto(i)
  singleton_int_TCC1: OBLIGATION FORALL (n: posnat, i: below[n]): i <= i;

  % Subtype TCC generated (at line 34, column 20) for  (n - 1)
      % expected type  below[n]
  sign_bit_of_unary_minus_TCC1: OBLIGATION
    FORALL (n: posnat): (n - 1) >= 0 AND (n - 1) < n;


body:
  %------------------------------------------------------------------------
  %
  % Rules derived from bv_arith_nat
  % -------------------------------
  %
  %
  %   o The association rules move bitvectors to the left and integers to the
  %     right.
  %
  %   o Rules collapse bv2nat(expressions) into expressions involving
  %     bv2nat of individual bitvectors 
  %
  %------------------------------------------------------------------------
  bv_arith_nat_rules: THEORY
  BEGIN

    IMPORTING bv_arith_nat

    N: VAR posnat
    n: VAR nat
    i,i1,i2: VAR int
    b: VAR bit

  % ---------- rules involving addition of two bitvectors ----------

    bv_add_rule              : LEMMA FORALL (bv1,bv2: bvec[N]):
                                 bv2nat(bv1) + bv2nat(bv2) < exp2(N) IMPLIES
                                    bv2nat(bv1 + bv2) = bv2nat(bv1) + bv2nat(bv2)

    bv_add_overflow     : LEMMA FORALL (bv1,bv2: bvec[N]):
                                 bv2nat(bv1) + bv2nat(bv2) >= exp2(N) IMPLIES
                          bv2nat(bv1 + bv2) = bv2nat(bv1) + bv2nat(bv2) - exp2(N)


  % ------- rules involving bitvector plus a constant

    bv_fill_F_plus_i : LEMMA bv2nat(fill[N](FALSE) + i) = mod(i,exp2(N))

    bv_plus_fill_T   : LEMMA FORALL (bv: bvec[N]): bv2nat(bv) /= 0 IMPLIES
                                       bv2nat(bv + fill[N](TRUE)) = bv2nat(bv) - 1

    bv2nat_elim_rule : LEMMA FORALL (bv1,bv2: bvec[N]): 
                                         bv1 + bv2nat(bv2) = bv1 + bv2

    bv2nat_plus: LEMMA FORALL (bv: bvec[N]): n < (exp2(N) - bv2nat(bv)) =>
                                               bv2nat(bv + n) = bv2nat(bv) + n

    bv2nat_plus2: LEMMA FORALL (bv: bvec[N]): n < exp2(N) AND 
                                              bv2nat(bv) + n >= exp2(N) =>
                           bv2nat(bv +  n) = bv2nat(bv) - (exp2(N) - n)


    bv2nat_minus : LEMMA FORALL (bv: bvec[N]):  n <= bv2nat(bv) =>
                                                 bv2nat(bv - n) = bv2nat(bv) - n

    bv2nat_minus2 : LEMMA FORALL (bv: bvec[N]):  n > bv2nat(bv) AND n < exp2(N) =>
                                   bv2nat(bv - n) = bv2nat(bv) - n + exp2(N)


    bv2nat_neg : LEMMA FORALL (bv: bvec[N]):  i < 0 AND (-i) <= bv2nat(bv) =>
                                                 bv2nat(bv + i) = bv2nat(bv) + i

    bv2nat_neg2: LEMMA FORALL (bv: bvec[N]): i < 0 AND (-i) > bv2nat(bv) AND
                                               (-i) < exp2(N) =>
                                  bv2nat(bv + i) = bv2nat(bv) + i + exp2(N)

  % if the above rewrites fail, reduce magnitude via mod:

    bv2nat_neg_modulo: LEMMA FORALL (bv: bvec[N]): i <= -exp2(N) =>
                              bv2nat(bv + i) = bv2nat(bv + (-mod(-i, exp2(N))))


  % ----------- miscellaneous rules ----------

    singleton_nat_alt   : LEMMA FORALL (bv: bvec[N]):
                                  N = 1 => bv2nat[N](bv) = b2n(bv^0)

  END bv_arith_nat_rules

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

  % Subtype TCC generated (at line 76, column 64) for  0
      % expected type  below[N]
  singleton_nat_alt_TCC1: OBLIGATION FORALL (N: posnat): N = 1 IMPLIES 0 < N;


body:
  bv_arith_minus_rules: THEORY
  BEGIN

    IMPORTING bv_arithmetic

    N: VAR posnat

    bv_assoc_obliviation : LEMMA FORALL (bv1,bv2: bvec[N]):
                                  bv1 + (-(bv1) + bv2) = bv2

    bv_neg_identity      : LEMMA FORALL (bv1: bvec[N]): -(-(bv1)) = bv1
    
    bv_sub_normalization : LEMMA FORALL (bv1,bv2: bvec[N]):
                                   (bv1 - bv2) = bv1 + (-bv2)
    
    bv_neg_distribution  : LEMMA FORALL (bv1,bv2: bvec[N]):
                                   -(bv1 + bv2) = -bv1 + -bv2
    
    
    bv_plus_neg_distrib  : LEMMA FORALL (i: int, bv: bvec[N]):
                                      -(bv + i) = -bv + (-i)

    bv_sub_identity_R    : LEMMA FORALL (bv1: bvec[N]):
                                  bv1 + -(fill[N](FALSE)) = bv1
    
    bv_sub_identity_L    : LEMMA FORALL (bv1: bvec[N]):
                                  -(fill[N](FALSE)) + bv1 = bv1
    
    bv_fill_increment_R  : LEMMA FORALL (bv1: bvec[N]):
                                  (bv1 + -(fill[N](TRUE))) = bv1 + 1
    
    bv_fill_increment_L  : LEMMA FORALL (bv1: bvec[N]):
                                  (-(fill[N](TRUE)) + bv1) = bv1 + 1
    
    bv_not_normalization : LEMMA FORALL (bv1,bv2: bvec[N]):
                                  (NOT (bv1)) = -(bv1) + (-1)


  END bv_arith_minus_rules


body:
  bv_arith_rules: THEORY
  BEGIN

    IMPORTING bv_arith_nat

    N: VAR posnat
    n: VAR nat
    i,i1,i2: VAR int
    b: VAR bit

  % ---------- rules involving addition of two bitvectors ----------

    bv_add_normalization     : LEMMA FORALL (bv1,bv2,bv3: bvec[N]): 
                                           bv1 + (bv2 + bv3) = (bv1 + bv2) + bv3

    bv_add_both_sides        : LEMMA FORALL (bv1,bv2,bv3: bvec[N]):
                                       (bv1 + bv3 = bv2 + bv3) IFF bv1 = bv2

    bv_add_associative       : LEMMA FORALL (bv1,bv2,bv3: bvec[N]):
                                        bv1 + (bv2 + bv3) = (bv1 + bv2) + bv3 

    bv_add_identity_R        : LEMMA FORALL (bv1: bvec[N]): 
                                           bv1 + fill[N](FALSE) = bv1

    bv_add_identity_L        : LEMMA FORALL (bv1: bvec[N]): 
                                           fill[N](FALSE) + bv1 = bv1

  % ------- rules involving bitvector plus a constant

    bv_plus_wrap_rule : LEMMA FORALL (bv: bvec[N]): bv + i*exp2(N) = bv

    bv_fill_T_plus1   : LEMMA fill[N](TRUE) + 1 = fill[N](FALSE)


    bv_plus_0         : LEMMA FORALL (bv: bvec[N]): i = 0 IMPLIES bv + i = bv

    bv_plus_inj_rule  : LEMMA FORALL (bv: bvec[N]),(n1,n2: below(exp2(N))):
                                        (bv + n1 = bv + n2) = (n1 = n2)

  % ----- rules involving addition of two bitvectors and integers -----

  %  bv_bit_add_normalization : LEMMA FORALL (bv1,bv2: bvec[N]):
  %                                         bv1 + (bv2 + b) = (bv1 + b) + bv2 

    bv_plus_assoc1           : LEMMA FORALL (bv1,bv2: bvec[N]):
                                   bv1 + (bv2 + i) = (bv1 + bv2) + i

    bv_plus_assoc2           : LEMMA FORALL (bv1,bv2: bvec[N]):
                                  (bv1 + i) + bv2  = (bv1 + bv2) + i

    bv_plus_2int_assoc       : LEMMA FORALL (bv1: bvec[N]):
                                  (bv1 + i1) + i2  = bv1 + (i1 + i2) 


    bv_add_2_consts_1   : LEMMA FORALL (bv: bvec[N]),(k1,k2: int):
                                        (bv + k1) + k2 = bv + (k1+k2)

    bv_add_2_consts_2   : LEMMA FORALL (bv1,bv2: bvec[N]),(k1,k2: int):
                                 (bv1 + k1) + (bv2 + k2) = (bv1 + bv2) + (k1 + k2) 

  % ---- The following converts +(bv1,bv2) INTO bv plus constant

    fill_T_plus_bv   : LEMMA (FORALL (bv: bvec[N]): fill[N](TRUE) + bv = (bv - 1))
    bv_plus_fill_T   : LEMMA (FORALL (bv: bvec[N]): bv + fill[N](TRUE) = (bv - 1))


  END bv_arith_rules


body:
  bv_concat_rules: THEORY

  BEGIN

    IMPORTING bv_arith_concat, bv_bitwise

    m,n,p: VAR nat
    b: VAR bit


  %  -------- concatenation normalization -------- 


     bv_concat_null_r      : LEMMA FORALL (bvn:bvec[n], bv0: bvec[0]):
                                     (bvn o bv0 = bvn)
   
     bv_concat_null_l      : LEMMA FORALL (bvn:bvec[n], bv0: bvec[0]):
                                     (bv0 o bvn = bvn)

     bv_concat_associative : LEMMA FORALL (bvm:bvec[m], bvn:bvec[n], bvp:bvec[p]):
                                     (bvm o (bvn o bvp)) = ((bvm o bvn) o bvp) 

  %  -------- fill concatenation -------- 

     n1, n2, n3: VAR nat
    
     bv_concat_fill_fill : LEMMA fill[n1](b) o fill[n2](b) = fill[n1+n2](b)

     bv_concat_2fill     : LEMMA FORALL (bv: bvec[n]): 
                                       (fill[n1](b) o (fill[n2](b)) o bv) 
                                           = (fill[n1+n2](b) o bv);

  % ---------- miscellaneous --------

    bv_concat_top_rule  : LEMMA FORALL (N: posnat, bvn: bvec[N], bvm: bvec[m]):
                                           (bvn o bvm)^(N+m-1) = bvn^(N-1)

    bv_not_over_concat  : LEMMA FORALL (bvm: bvec[m], bvn: bvec[n]):
                                        (NOT (bvm o bvn)) = (NOT bvm) o (NOT bvn)

  END bv_concat_rules

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

  % Subtype TCC generated (at line 36, column 54) for  (N + m - 1)
      % expected type  below[N + m]
  bv_concat_top_rule_TCC1: OBLIGATION
    FORALL (m: nat, N: posnat): (N + m - 1) >= 0 AND (N + m - 1) < N + m;

  % Subtype TCC generated (at line 36, column 68) for  (N - 1)
      % expected type  below[N]
  bv_concat_top_rule_TCC2: OBLIGATION
    FORALL (N: posnat): (N - 1) >= 0 AND (N - 1) < N;


body:
  bv_caret_bitwise: THEORY
  BEGIN

    IMPORTING bv_caret, bv_bitwise

    n: VAR nat

    bv_OR_caret : LEMMA (FORALL (bv1,bv2: bvec[n], i: below(n), j: upto(i)):
                         (bv1 OR bv2)^(i,j) = (bv1^(i,j) OR bv2^(i,j)))

    bv_AND_caret: LEMMA (FORALL (bv1,bv2: bvec[n], i: below(n), j: upto(i)):
                         (bv1 AND bv2)^(i,j) = (bv1^(i,j) AND bv2^(i,j)))

    bv_IFF_caret: LEMMA (FORALL (bv1,bv2: bvec[n], i: below(n), j: upto(i)):
                         (bv1 IFF bv2)^(i,j) = (bv1^(i,j) IFF bv2^(i,j)))

    bv_XOR_caret: LEMMA (FORALL (bv1,bv2: bvec[n], i: below(n), j: upto(i)):
                         XOR(bv1,bv2)^(i,j) = (bv1^(i,j) XOR bv2^(i,j)) )

    bv_NOT_caret: LEMMA (FORALL (bv: bvec[n], i: below(n), j: upto(i)):
                         (NOT bv)^(i,j) = NOT bv^(i,j) )

  END bv_caret_bitwise

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

  % Subtype TCC generated (at line 89, column 18) for  1 + i - j
      % expected type  nat
  bv_OR_caret_TCC1: OBLIGATION
    FORALL (n: nat, i: below(n), j: upto(i)): 1 + i - j >= 0;


body:
  bv_caret_bitwise_rules: THEORY
  % -----------------------------------------------------------------------
  % Rules derived from bv_bitwise and bv_caret
  %
  % -----------------------------------------------------------------------  
  BEGIN

    IMPORTING bv_caret_bitwise


    N : VAR nat

    bv_caret_OR       : LEMMA (FORALL (bv1,bv2: bvec[N], i: below[N], j: upto(i)):
                          (bv1 OR bv2)^(i,j) = (bv1^(i,j) OR bv2^(i,j)))

    bv_caret_AND      : LEMMA (FORALL (bv1,bv2: bvec[N], i: below[N], j: upto(i)):
                          (bv1 AND bv2)^(i,j) = (bv1^(i,j) AND bv2^(i,j)))

    bv_caret_XOR      : LEMMA (FORALL (bv1,bv2: bvec[N], i: below[N], j: upto(i)):
                          XOR(bv1,bv2)^(i,j) = (bv1^(i,j) XOR bv2^(i,j)) )

    bv_caret_IFF      : LEMMA (FORALL (bv1,bv2: bvec[N], i: below(N), j: upto(i)):
                          (bv1 IFF bv2)^(i,j) = (bv1^(i,j) IFF bv2^(i,j)))
    
    bv_caret_NOT      : LEMMA (FORALL (bv: bvec[N], i: below(N), j: upto(i)):
                          (NOT bv)^(i,j) = NOT bv^(i,j) )



    bv_caret_OR_unary : LEMMA (FORALL (bv1, bv2: bvec[N], i: below[N]):
                          (bv1 OR bv2)^i = (bv1^i OR bv2^i))

    bv_caret_AND_unary: LEMMA (FORALL (bv1,bv2: bvec[N], i: below[N]):
                          (bv1 AND bv2)^i = (bv1^i AND bv2^i))

    bv_caret_XOR_unary: LEMMA (FORALL (bv1,bv2: bvec[N], i: below[N]):
                          XOR(bv1,bv2)^i = (bv1^i XOR bv2^i) )

    bv_caret_IFF_unary: LEMMA (FORALL (bv1,bv2: bvec[N], i: below[N]):
                            IFF(bv1,bv2)^i = (bv1^i IFF bv2^i) )

    bv_caret_NOT_unary: LEMMA (FORALL (bv: bvec[N], i: below[N]):
                          (NOT bv)^i = NOT bv^i )


  END bv_caret_bitwise_rules

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

  % Subtype TCC generated (at line 89, column 18) for  1 + i - j
      % expected type  nat
  bv_caret_OR_TCC1: OBLIGATION
    FORALL (N: nat, i: below[N], j: upto(i)): 1 + i - j >= 0;


body:
  bv_caret_rules: THEORY
  %-----------------------------------------------------------------------
  %  
  %-----------------------------------------------------------------------  
  BEGIN

    IMPORTING bv_caret

    N, n, m : VAR nat
    i, j, i1, j1, i2, j2, k : VAR nat
    b: VAR bit

    bv_caret_remove     : LEMMA FORALL (bv: bvec[N]): 
                                  i=N-1 AND j=0 => bv^(i,j) = bv

    bv_caret_ii_0_rule  : LEMMA FORALL (bv: bvec[N]): 
                                  i < N => bv^(i,i)^0 = bv^i

    bv_caret_elim_rule  : LEMMA FORALL (bv: bvec[N]): 
                                  i < N AND j <= i AND k < i-j+1 => 
                                      bv ^ (i, j) ^ k = bv^(j+k)

    bv_caret_denormalize: LEMMA FORALL (n: posnat, bvn: bvec[n]):
                                  i1 < n         AND   j1 <= i1 AND 
                                  i2 < i1-j1+1   AND   j2 <= i2 AND 
                                  i2-j2+1 <= i1-j1+1 =>
                                     (bvn^(i1, j1))^(i2, j2) = bvn^(i2+j1, j2+j1)


    bv_fill_caret       : LEMMA n < m AND k < m AND k <= n =>
                                     (fill[m](b))^(n, k) = fill[n-k+1](b)

    bv_fill_caret_unary : LEMMA n < m => (fill[m](b))^n = b

  END bv_caret_rules 

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

  % Subtype TCC generated (at line 14, column 53) for  i
      % expected type  below(N)
  bv_caret_remove_TCC1: OBLIGATION
    FORALL (N, i, j: nat): i = N - 1 AND j = 0 IMPLIES i < N;

  % Subtype TCC generated (at line 14, column 55) for  j
      % expected type  upto(i)
  bv_caret_remove_TCC2: OBLIGATION
    FORALL (N, i, j: nat): i = N - 1 AND j = 0 IMPLIES j <= i;

  % Subtype TCC generated (at line 14, column 60) for  bv
      % expected type  bvec[1 + i - j]
  bv_caret_remove_TCC3: OBLIGATION
    FORALL (N, i, j: nat, bv: bvec[N]):
      i = N - 1 AND j = 0 IMPLIES
       (FORALL (x: nat): bv(x) IMPLIES (x < N IFF x < 1 + i - j));

  % Subtype TCC generated (at line 17, column 47) for  i
      % expected type  upto(i)
  bv_caret_ii_0_rule_TCC1: OBLIGATION
    FORALL (N, i: nat): i < N IMPLIES i <= i;

  % Subtype TCC generated (at line 21, column 50) for  k
      % expected type  below[1 + i - j]
  bv_caret_elim_rule_TCC1: OBLIGATION
    FORALL (N, i, j, k: nat):
      i < N AND j <= i AND k < i - j + 1 IMPLIES k < 1 + i - j;

  % Subtype TCC generated (at line 89, column 18) for  1 + i - j
      % expected type  nat
  bv_caret_elim_rule_TCC2: OBLIGATION
    FORALL (N, i, j, k: nat):
      i < N AND j <= i AND k < i - j + 1 IMPLIES 1 + i - j >= 0;

  % Subtype TCC generated (at line 21, column 58) for  (j + k)
      % expected type  below[N]
  bv_caret_elim_rule_TCC3: OBLIGATION
    FORALL (N, i, j, k: nat):
      i < N AND j <= i AND k < i - j + 1 IMPLIES (j + k) < N;

  % Subtype TCC generated (at line 27, column 51) for  i2
      % expected type  below(1 + i1 - j1)
  bv_caret_denormalize_TCC1: OBLIGATION
    FORALL (i1, i2, j1, j2: nat, n: posnat):
           i1 < n AND j1 <= i1 AND i2 < i1 - j1 + 1 AND j2 <= i2
       AND i2 - j2 + 1 <= i1 - j1 + 1
       IMPLIES i2 < 1 + i1 - j1;

  % Subtype TCC generated (at line 89, column 18) for  1 + i1 - j1
      % expected type  nat
  bv_caret_denormalize_TCC2: OBLIGATION
    FORALL (i1, i2, j1, j2: nat, n: posnat):
           i1 < n AND j1 <= i1 AND i2 < i1 - j1 + 1 AND j2 <= i2
       AND i2 - j2 + 1 <= i1 - j1 + 1
       IMPLIES 1 + i1 - j1 >= 0;

  % Subtype TCC generated (at line 27, column 66) for  i2 + j1
      % expected type  below(n)
  bv_caret_denormalize_TCC3: OBLIGATION
    FORALL (i1, i2, j1, j2: nat, n: posnat):
           i1 < n AND j1 <= i1 AND i2 < i1 - j1 + 1 AND j2 <= i2
       AND i2 - j2 + 1 <= i1 - j1 + 1
       IMPLIES i2 + j1 < n;

  % Subtype TCC generated (at line 27, column 73) for  j2 + j1
      % expected type  upto(i2 + j1)
  bv_caret_denormalize_TCC4: OBLIGATION
    FORALL (i1, i2, j1, j2: nat, n: posnat):
           i1 < n AND j1 <= i1 AND i2 < i1 - j1 + 1 AND j2 <= i2
       AND i2 - j2 + 1 <= i1 - j1 + 1
       IMPLIES j2 + j1 <= i2 + j1;

  % Subtype TCC generated (at line 31, column 66) for  1 + n - k
      % expected type  nat
  bv_fill_caret_TCC1: OBLIGATION
    FORALL (k, m, n: nat): k <= n AND k < m AND n < m IMPLIES 1 + n - k >= 0;


body:
  bv_bitwise_rules: THEORY
  % -----------------------------------------------------------------------
  % Rules derived from bv_bitwise
  %
  %   o move fill[N]() to the right
  %
  %   o association to the left
  %
  % -----------------------------------------------------------------------  
  BEGIN

    IMPORTING bv_bitwise

    N : VAR nat
    b : VAR bit
    nb: VAR nbit

    bv_NOT_NOT           : LEMMA FORALL (bv:bvec[N]): (NOT (NOT bv)) = bv

    bv_NOT_caret         : LEMMA FORALL (bv:bvec[N]) (i: below(N)): 
                                        (NOT(bv))^i = NOT (bv^i)

    bv_fill_NOT          : LEMMA (NOT (fill[N](b))) = fill[N](NOT b)   

    bv_AND_fill_normalize: LEMMA FORALL (bv1 : bvec[N]):
                                   (fill[N](b) AND bv1) = (bv1 AND fill[N](b))

    bv_AND_fill_F        : LEMMA FORALL (bv1: bvec[N]): 
                                  (bv1 AND fill[N](FALSE)) = fill[N](FALSE)

    bv_AND_fill_T        : LEMMA FORALL 
                                  (bv1: bvec[N]): (bv1 AND fill[N](TRUE)) = bv1

    bv_AND_same          : LEMMA FORALL (bv1, bv2: bvec[N]):
                                    (bv1 = bv2) => (bv1 AND bv2) = bv1

    bv_AND_associative   : LEMMA FORALL (bv1, bv2, bv3: bvec[N]):
                                 (bv1 AND (bv2 AND bv3)) = ((bv1 AND bv2) AND bv3)

    bv_AND_bv_2eq        : LEMMA FORALL (bv1, bv2, bv3: bvec[N]):
                              bv1 = bv2 => (bv1 AND (bv2 AND bv3)) = (bv2 AND bv3)

    bv_OR_fill_normalize : LEMMA FORALL (bv1: bvec[N]): 
                                    (fill[N](b) OR bv1) = (bv1 OR fill[N](b))

    bv_OR_fill_F          : LEMMA FORALL (bv1: bvec[N]): 
                                   (bv1 OR fill[N](FALSE)) = bv1

    bv_OR_fill_T          : LEMMA FORALL (bv1: bvec[N]): 
                                    (bv1 OR fill[N](TRUE)) = fill[N](TRUE)
   
    bv_OR_bv_eq          : LEMMA FORALL (bv1, bv2: bvec[N]):
                                    (bv1 = bv2) => (bv1 OR bv2) = bv1

    bv_OR_associative    : LEMMA FORALL (bv1, bv2, bv3: bvec[N]):
                                    (bv1 OR (bv2 OR bv3)) = ((bv1 OR bv2) OR bv3)

    bv_OR_bv_bv_2eq      : LEMMA FORALL (bv1, bv2, bv3: bvec[N]):
                             (bv1 = bv2) => (bv1 OR (bv2 OR bv3)) = (bv2 OR bv3)

    bv_XOR_fill_normalize: LEMMA FORALL (bv1 : bvec[N]):
                             (fill[N](b) XOR bv1) = (bv1 XOR fill[N](b))

    bv_XOR_fill_F        : LEMMA FORALL (bv1: bvec[N]): 
                             (bv1 XOR fill[N](FALSE)) = bv1

    bv_XOR_fill_T        : LEMMA FORALL (bv1: bvec[N]): 
                             (bv1 XOR fill[N](TRUE)) = (NOT bv1)

    bv_XOR_bv_2eq        : LEMMA FORALL (bv1, bv2: bvec[N]):
                             (bv1 = bv2) => (bv1 XOR bv2) = fill[N](FALSE)

    bv_XOR_associative   : LEMMA FORALL (bv1, bv2, bv3: bvec[N]):
                             (bv1 XOR (bv2 XOR bv3)) = ((bv1 XOR bv2) XOR bv3)

    bv_XOR_bv_bv_2eq     : LEMMA FORALL (bv1, bv2, bv3: bvec[N]):
                              bv1 = bv2 => (bv1 XOR (bv2 XOR bv3)) = bv3



  END bv_bitwise_rules


body:
  bv_nat_rules: THEORY

  BEGIN

    IMPORTING bv_nat

    n: VAR nat

    bv2nat_fill_F   : LEMMA bv2nat(fill[n](FALSE)) = 0
    bv2nat_fill_T   : LEMMA bv2nat(fill[n](TRUE)) = exp2(n)-1

    bv2nat_top_bit_F: LEMMA FORALL (bvn: bvec[n]):
                               n > 0 AND bv2nat(bvn) < exp2(n-1) 
                                    IMPLIES bvn^(n-1) = FALSE

    bv2nat_top_bit_T: LEMMA FORALL (bvn: bvec[n]): 
                               n > 0 AND bv2nat(bvn) >= exp2(n-1) 
                                    IMPLIES bvn^(n-1) = TRUE 

    bv2nat_inj_rule : LEMMA FORALL (bv1, bv2: bvec[n]): bv2nat(bv1) = bv2nat(bv2) 
                                                          IMPLIES bv1 = bv2

    b: VAR bit
    bv_fill_unit_nat: LEMMA n = 1 => bv2nat[n](fill[n](b)) = b2n(b)

  END bv_nat_rules

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

  % Subtype TCC generated (at line 13, column 58) for  n - 1
      % expected type  nat
  bv2nat_top_bit_F_TCC1: OBLIGATION FORALL (n: nat): n > 0 IMPLIES n - 1 >= 0;

  % Subtype TCC generated (at line 14, column 47) for  (n - 1)
      % expected type  below[n]
  bv2nat_top_bit_F_TCC2: OBLIGATION
    FORALL (n: nat, bvn: bvec[n]):
      n > 0 AND bv2nat(bvn) < exp2(n - 1) IMPLIES
       (n - 1) >= 0 AND (n - 1) < n;

  % Subtype TCC generated (at line 18, column 47) for  (n - 1)
      % expected type  below[n]
  bv2nat_top_bit_T_TCC1: OBLIGATION
    FORALL (n: nat, bvn: bvec[n]):
      n > 0 AND bv2nat(bvn) >= exp2(n - 1) IMPLIES
       (n - 1) >= 0 AND (n - 1) < n;


body:
  mod_rules: THEORY
  BEGIN

     IMPORTING mod

    i, i1, i2: VAR int
    n, k: VAR nat
    m, m1, m2: VAR posnat

    
  % ---------- Some basic rules about mod ---------- 
    
    mod_rule1     : LEMMA n >= m => mod(n, m) = mod(n-m, m)
    mod_rule2     : LEMMA n < m => mod(n, m) = n
    mod_rule3     : LEMMA i < 0 => mod(i, m) = mod(i+m, m)


    mod_mod_rule  : LEMMA mod(mod(i, m), m) = mod(i, m)
    mod_eq_rule1  : LEMMA m1 = m2 => mod(n + m1, m2) = mod(n, m2)
    mod_eq_rule2  : LEMMA m1 = m2 => mod(m1, m2) = 0

    mod_wrap_rule1: LEMMA n < m AND k <= m AND k >= m-n
                            IMPLIES mod(n+k, m) = n - (m-k)

    mod_wrap_rule2: LEMMA k < n AND n = m IMPLIES mod(n+k, m) = n - (m-k)


    mod_flatten1  : LEMMA mod(mod(i1, m) + i2, m) = mod(i1 + i2, m)
    mod_flatten2  : LEMMA mod(i1 + mod(i2, m), m) = mod(i1 + i2, m)


    mod_gt_rule   : LEMMA (i<2*m) AND (i >= m) IMPLIES mod(i,m) = i-m

    mod_lt        : LEMMA (i > -2*m) AND (i < 0) IMPLIES mod(i,m) = mod(i+m,m)

    mod_identity  : LEMMA (i >= 0) AND (i < m) IMPLIES mod(i,m) = i
    
    mod_gt_log2   : LEMMA i >= 2*m IMPLIES mod(i,m) = mod(mod(i,2*m),m);
    
    mod_gt_log16  : LEMMA i >= 16*m IMPLIES mod(i,m) = mod(mod(i,16*m),m)
    
    mod_gt_log256 : LEMMA i >= 256*m IMPLIES (mod(i,m) = mod(mod(i,256*m),m));
    
    mod_lt_log256 : LEMMA i <= -256*m IMPLIES mod(i,m) = mod(mod(i,256*m),m)
    
    mod_lt_log16  : LEMMA i <= -16*m IMPLIES mod(i,m) = mod(mod(i,16*m),m)
    
    mod_lt_log2   : LEMMA i <= -2*m IMPLIES mod(i,m) = mod(mod(i,2*m),m)
    

  END mod_rules


body:
  %------------------------------------------------------------------------
  %  bit-vectors rules
  %  --------------------------------
  %       
  %      Index:
  %      ------
  %
  %                                    syntactic objects/mneumonic
  %
  %        theory             |   +   | bv2nat | bv2int |       |   o    | AND
  %                           | arith |  nat   |   int  | caret | concat | bitwise
  %  -------------------------|-------|--------|--------|-------------------------
  %  mod_rules                |       |        |        |       |	       |
  %  bv_nat_rules             |       |   x    |        |       |	       |
  %  bv_bitwise_rules         |       |        |        |       |	       |  x    
  %  bv_caret_rules           |       |        |        |  x    |	       |    
  %  bv_caret_bitwise_rules   |       |        |        |  x    |	       |  x    
  %  bv_concat_rules          |       |        |        |       |	  x    |     
  %  bv_arith_nat_rules       |   x   |   x    |        |       |	       |      
  %  bv_arith_caret_rules     |       |   x    |        |  x    |	       |      
  %  bv_caret_concat_rules    |       |        |        |  x    |	  x    |      
  %  bv_arith_rules           |   x   |        |        |       |	       |      
  %  bv_arith_minus_rules     |   x   |        |        |       |	       |      
  %  bv_arith_nat_rules       |   x   |   x    |        |       |	       |      
  %  bv_arith_int_rules       |   x   |        |   x    |       |        |      
  %  bv_arith_caret_rules     |   x   |        |        |  x    |	       |       
  %  bv_arith_nat_caret_rules |   x   |        |        |  x    |	       | 
  %  bv_arith_int_caret_rules |   x   |        |   x    |  x    |        |      
  %
  %
  % NOTE: the presence of bv1 - bv2 or -bv indicates the need for bv2int
  %
  %------------------------------------------------------------------------
  bv_rules: THEORY
  BEGIN

    IMPORTING
       mod_rules,               % -- rules about mod function
       bv_nat_rules,            % -- rules involving only bv2nat
       bv_bitwise_rules,        % -- rules involving bitwise ops
       bv_caret_rules,          % -- rules involving ^
       bv_caret_bitwise_rules,  % -- rules involving ^ and bitwise ops
       bv_concat_rules,         % -- rules involving o
       bv_arith_rules,          % -- rules involving + 
       bv_arith_minus_rules,     % -- rules involving + and -
       bv_arith_nat_rules,      % -- rules involving bv2nat and +
       bv_arith_int_rules,      % -- rules involving bv2int and +
       bv_caret_concat_rules,   % -- rules involving ^ and o
       bv_arith_caret_rules,    % -- rules involving ^ and +          
       bv_arith_nat_caret_rules, % -- rules involving ^ and + and bv2nat         
       bv_arith_caret_concat_rules

  END bv_rules


body:
  bv_arith_int_caret: THEORY
  BEGIN


    IMPORTING bv_arithmetic, bv_arith_caret

  %  IMPORTING bv_int, bv_arith_caret, bv_caret_concat

    N: VAR posnat

    bv_sign_of_frag_neg: LEMMA FORALL (bvn: bvec[N], i: below[N]):
                                  bv2int(bvn) < 0 => bv2int(bvn^(N-1, i)) < 0
    
    bv_sign_of_frag_pos: LEMMA FORALL (bvn: bvec[N], i: below[N]):
                                  bv2int(bvn) >= 0 => bv2int(bvn^(N-1, i)) >= 0


    bv2int_top   : THEOREM FORALL (bv: bvec[N], i: below[N]):
                                 bv2int(bv^(N-1,i)) = floor(bv2int(bv)/ exp2(i))


    bv2int_concat : LEMMA FORALL (n, m: posnat, bvn: bvec[n], bvm: bvec[m]):
                           bv2int(bvn o bvm) = 
                               bv2int(bvn) * exp2(m) + bv2int(bvm) 
                                  + (b2n(bvm^(m-1)) * exp2(m))

    bv2int_bottom : THEOREM FORALL (bv: bvec[N], i: below[N]):
                              bv2int(bv^(i,0)) 
                               = mod(bv2int(bv),exp2(i+1)) - exp2(i+1)*b2n(bv^(i)) 

    in_small_rng   : LEMMA (FORALL (bv: bvec[N], i: below[N]):
                             i > 0 AND in_rng_2s_comp[i](bv2int(bv)) IMPLIES
  	                             (bv = fill[N-i](bv^(N-1)) o bv^(i-1,0)))


    in_rng_i_bv2int: LEMMA FORALL (bv: bvec[N], i: below[N]): i > 0 
                               AND in_rng_2s_comp[i](bv2int(bv)) IMPLIES
                                   bv2int[N](bv) = bv2int[i](bv^(i-1,0))

    bv_caret_negate: LEMMA FORALL (bv1: bvec[N], m: below[N]): 
                                      (-bv1)^(m,0) = -(bv1^(m,0))


    bv2int_in_rng_i    : LEMMA FORALL (bv: bvec[N], n: {np: posnat | np < N}):
                             in_rng_2s_comp[n](bv2int(bv)) => 
                                (bv = fill[N-n](bv^(n-1)) o bv^(n-1, 0))
    
    bv2int_in_rng_i_top: LEMMA FORALL (bv: bvec[N], n: {np: posnat | np < N}):
                              in_rng_2s_comp[n](bv2int(bv)) => 
                                 (bv^(N-1, n) = fill[N-n](bv^(n-1)))


    IMPORTING bv_arith_extend
    
    bv2int_of_sign_extension: LEMMA FORALL (bv: bvec[N], n: {np: posnat | np < N}):
                          in_rng_2s_comp[n](bv2int(bv)) =>
                             bv2int(bv^(n-1, 0)) = bv2int(bv)


  END bv_arith_int_caret

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

  % Subtype TCC generated (at line 12, column 63) for  N - 1
      % expected type  below(N)
  bv_sign_of_frag_neg_TCC1: OBLIGATION
    FORALL (N: posnat, bvn: bvec[N], i: below[N]):
      bv2int(bvn) < 0 IMPLIES N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 12, column 68) for  i
      % expected type  upto(N - 1)
  bv_sign_of_frag_neg_TCC2: OBLIGATION
    FORALL (N: posnat, bvn: bvec[N], i: below[N]):
      bv2int(bvn) < 0 IMPLIES i <= N - 1;

  % Subtype TCC generated (at line 12, column 63) for  N - i
      % expected type  posnat
  bv_sign_of_frag_neg_TCC3: OBLIGATION
    FORALL (N: posnat, bvn: bvec[N], i: below[N]):
      bv2int(bvn) < 0 IMPLIES N - i >= 0 AND N - i > 0;

  % Subtype TCC generated (at line 15, column 64) for  N - 1
      % expected type  below(N)
  bv_sign_of_frag_pos_TCC1: OBLIGATION
    FORALL (N: posnat, bvn: bvec[N], i: below[N]):
      bv2int(bvn) >= 0 IMPLIES N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 15, column 69) for  i
      % expected type  upto(N - 1)
  bv_sign_of_frag_pos_TCC2: OBLIGATION
    FORALL (N: posnat, bvn: bvec[N], i: below[N]):
      bv2int(bvn) >= 0 IMPLIES i <= N - 1;

  % Subtype TCC generated (at line 15, column 64) for  N - i
      % expected type  posnat
  bv_sign_of_frag_pos_TCC3: OBLIGATION
    FORALL (N: posnat, bvn: bvec[N], i: below[N]):
      bv2int(bvn) >= 0 IMPLIES N - i >= 0 AND N - i > 0;

  % Subtype TCC generated (at line 19, column 42) for  N - 1
      % expected type  below(N)
  bv2int_top_TCC1: OBLIGATION
    FORALL (N: posnat, i: below[N]): N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 19, column 46) for  i
      % expected type  upto(N - 1)
  bv2int_top_TCC2: OBLIGATION FORALL (N: posnat, i: below[N]): i <= N - 1;

  % Subtype TCC generated (at line 19, column 42) for  N - i
      % expected type  posnat
  bv2int_top_TCC3: OBLIGATION
    FORALL (N: posnat, i: below[N]): N - i >= 0 AND N - i > 0;

  % Subtype TCC generated (at line 22, column 70) for  m + n
      % expected type  posnat
  bv2int_concat_TCC1: OBLIGATION FORALL (n, m: posnat): m + n > 0;

  % Subtype TCC generated (at line 25, column 44) for  (m - 1)
      % expected type  below[m]
  bv2int_concat_TCC2: OBLIGATION
    FORALL (n, m: posnat): (m - 1) >= 0 AND (m - 1) < m;

  % Subtype TCC generated (at line 28, column 41) for  0
      % expected type  upto(i)
  bv2int_bottom_TCC1: OBLIGATION FORALL (N: posnat, i: below[N]): 0 <= i;

  % Subtype TCC generated (at line 33, column 41) for  N - i
      % expected type  nat
  in_small_rng_TCC1: OBLIGATION
    FORALL (N: posnat, bv: bvec[N], i: below[N]):
      i > 0 AND in_rng_2s_comp[i](bv2int(bv)) IMPLIES N - i >= 0;

  % Subtype TCC generated (at line 33, column 62) for  i - 1
      % expected type  below(N)
  in_small_rng_TCC2: OBLIGATION
    FORALL (N: posnat, bv: bvec[N], i: below[N]):
      i > 0 AND in_rng_2s_comp[i](bv2int(bv)) IMPLIES
       i - 1 >= 0 AND i - 1 < N;

  % Subtype TCC generated (at line 33, column 66) for  0
      % expected type  upto(i - 1)
  in_small_rng_TCC3: OBLIGATION
    FORALL (N: posnat, bv: bvec[N], i: below[N]):
      i > 0 AND in_rng_2s_comp[i](bv2int(bv)) IMPLIES 0 <= i - 1;

  % Subtype TCC generated (at line 46, column 50) for  (n - 1)
      % expected type  below[N]
  bv2int_in_rng_i_TCC1: OBLIGATION
    FORALL (N: posnat, bv: bvec[N], n: {np: posnat | np < N}):
      in_rng_2s_comp[n](bv2int(bv)) IMPLIES (n - 1) >= 0 AND (n - 1) < N;

  % Subtype TCC generated (at line 46, column 41) for  N - n
      % expected type  nat
  bv2int_in_rng_i_TCC2: OBLIGATION
    FORALL (N: posnat, bv: bvec[N], n: {np: posnat | np < N}):
      in_rng_2s_comp[n](bv2int(bv)) IMPLIES N - n >= 0;

  % Subtype TCC generated (at line 46, column 67) for  0
      % expected type  upto(n - 1)
  bv2int_in_rng_i_TCC3: OBLIGATION
    FORALL (N: posnat, bv: bvec[N], n: {np: posnat | np < N}):
      in_rng_2s_comp[n](bv2int(bv)) IMPLIES 0 <= n - 1;

  % Subtype TCC generated (at line 50, column 41) for  n
      % expected type  upto(N - 1)
  bv2int_in_rng_i_top_TCC1: OBLIGATION
    FORALL (N: posnat, bv: bvec[N], n: {np: posnat | np < N}):
      in_rng_2s_comp[n](bv2int(bv)) IMPLIES n <= N - 1;


body:
  bv_constants: THEORY
  %------------------------------------------------------------------------
  %
  %  Bitvector constants
  %  -------------------
  %
  %    This theory enables one to build bitvector constants using
  %    the hexadecimal constants h0 through HF and the o concatentation
  %    operator.  The user is urged to avoid using nat2bv or int2bv to
  %    construct bitvector constants.  If this is impossible and bitvector
  %    constants such as nat2bv[16](1) are present in a specification, it is
  %    often prudent to quickly rewrite them to the corresponding LAMBDA
  %    expressions easily defined using the hexadecimal constants and 
  %    concatentation.
  %
  %------------------------------------------------------------------------   

  BEGIN

     IMPORTING bv[4], bv_concat

     h0: bvec[4] = (LAMBDA (i: below[4]): FALSE)
     h1: bvec[4] = (LAMBDA (i: below[4]): i = 0 )
     h2: bvec[4] = (LAMBDA (i: below[4]): i = 1 )
     h3: bvec[4] = (LAMBDA (i: below[4]): i = 0 OR i = 1)
     h4: bvec[4] = (LAMBDA (i: below[4]): i = 2)
     h5: bvec[4] = (LAMBDA (i: below[4]): i = 0 OR i = 2)
     h6: bvec[4] = (LAMBDA (i: below[4]): i = 1 OR i = 2)
     h7: bvec[4] = (LAMBDA (i: below[4]): NOT i = 3 )
     h8: bvec[4] = (LAMBDA (i: below[4]): i = 3 )
     h9: bvec[4] = (LAMBDA (i: below[4]): i = 0 OR i = 3 )
     hA: bvec[4] = (LAMBDA (i: below[4]): i = 1 OR i = 3 )
     hB: bvec[4] = (LAMBDA (i: below[4]): NOT i = 2)
     hC: bvec[4] = (LAMBDA (i: below[4]): i = 2 OR i = 3 )
     hD: bvec[4] = (LAMBDA (i: below[4]): NOT (i = 1))
     hE: bvec[4] = (LAMBDA (i: below[4]): NOT (i = 0))
     hF: bvec[4] = (LAMBDA (i: below[4]): TRUE)


     h0_lem: LEMMA h0  = b0 o b0 o b0 o b0
     h1_lem: LEMMA h1 = b0 o b0 o b0 o b1
     h2_lem: LEMMA h2 = b0 o b0 o b1 o b0
     h3_lem: LEMMA h3 = b0 o b0 o b1 o b1
     h4_lem: LEMMA h4 = b0 o b1 o b0 o b0
     h5_lem: LEMMA h5 = b0 o b1 o b0 o b1
     h6_lem: LEMMA h6 = b0 o b1 o b1 o b0
     h7_lem: LEMMA h7 = b0 o b1 o b1 o b1
     h8_lem: LEMMA h8 = b1 o b0 o b0 o b0
     h9_lem: LEMMA h9 = b1 o b0 o b0 o b1
     hA_lem: LEMMA hA = b1 o b0 o b1 o b0
     hB_lem: LEMMA hB = b1 o b0 o b1 o b1
     hC_lem: LEMMA hC = b1 o b1 o b0 o b0
     hD_lem: LEMMA hD = b1 o b1 o b0 o b1
     hE_lem: LEMMA hE = b1 o b1 o b1 o b0
     hF_lem: LEMMA hF = b1 o b1 o b1 o b1

  END bv_constants


body:
  %------------------------------------------------------------------------
  %
  % Operational definition of bitvector addition
  % -------------------------------------------------
  %
  %   Author
  %
  %         Victor Carreno
  %
  %   Defines:
  %
  %       oba_sum - "sum" output of one bit adder
  %       oba_cout - overflow bit of one bit adder
  %       bv_adder - n-bit adder
  %
  %   Establishes:
  %
  %       adder_is_add: THEOREM bv_adder(bv1,bv2,FALSE) = bv1 + bv2   
  %
  %------------------------------------------------------------------------

  bv_adder[N:posnat]: THEORY

  BEGIN


     IMPORTING bv_bitwise[N], bv_nat[N]
     
     a,b,cin : VAR bit
     
     % =======   oba is a One Bit Adder   ======================================
     %
     %                 |---------------|
     %         a   --->|               |
     %                 |               | ----> sum
     %         b   --->|     oba       |
     %                 |               | ----> cout
     %         cin --->|               |
     %                 |---------------|
     %
     % =========================================================================
     
     oba_sum (a,b,cin): bit = (a XOR b XOR cin)
     oba_cout (a,b,cin): bit = ((a AND b) OR (a AND cin) OR (b AND cin))
     
     oba_correct: LEMMA a + b + cin = 2 * oba_cout (a,b,cin) + oba_sum (a,b,cin)
     
     a_cin: VAR bit
     x,y: VAR bvec[N]
     n: VAR below[N]
     
     % =======  
     %
     %     x   y   cin      x   y   cin        x   y   cin       x    y   
     %      n   n   __n_     n-1 n-1 __n-1      1   1   __1_      0    0  __ a_cin
     %     |   |   |    |   |   |   |           |   |   |    |   |   |   |
     %    -----------   |  -----------         -----------   |  -----------
     %    |         |   |  |         |         |         |   |  |         |
     %    |_________|   |  |_________|         |_________|   |  |_________|
     %      |    |      |____|    |            __|    |      |____|    | 
     %      c    s           c    s              c    s           c    s
     %       n    n           n-1  n-1            1    1           0    0
     %
     % =========================================================================
     
     n_cout_rec (n,x,y,a_cin): RECURSIVE bit =
       IF n =0 THEN oba_cout(x^(0),y^(0),a_cin)
       ELSE oba_cout(x^(n),y^(n),n_cout_rec(n-1,x,y,a_cin))
       ENDIF
       MEASURE n
     
     bv_adder(x,y,a_cin): bvec[N] =
       (LAMBDA (i:below(N)): 
        IF i=0 THEN oba_sum(x^(0),y^(0),a_cin)
        ELSE oba_sum(x^(i),y^(i),n_cout_rec(i-1,x,y,a_cin))
        ENDIF)
     
     adder_correct_rec: LEMMA 
         exp2(n+1)*n_cout_rec(n,x,y,a_cin)+bv2nat_rec(n+1,bv_adder(x,y,a_cin)) =
         bv2nat_rec(n+1,x) + bv2nat_rec(n+1,y) + a_cin
     
     adder_correct: THEOREM 
         exp2(N)*n_cout_rec(N-1,x,y,a_cin) + bv2nat(bv_adder(x,y,a_cin)) =  
         bv2nat(x) + bv2nat(y) + a_cin

     IMPORTING bv_arith_nat

     bv1,bv2: VAR bvec[N]
     adder_is_add: THEOREM bv_adder(bv1,bv2,FALSE) = bv1 + bv2 
                               
  END bv_adder

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

  % Subtype TCC generated (at line 67, column 30) for  (0)
      % expected type  below[N]
  n_cout_rec_TCC1: OBLIGATION FORALL (n: below[N]): n = 0 IMPLIES (0) < N;

  % Subtype TCC generated (at line 68, column 42) for  n - 1
      % expected type  below[N]
  n_cout_rec_TCC2: OBLIGATION
    FORALL (n: below[N]): NOT n = 0 IMPLIES n - 1 >= 0 AND n - 1 < N;

  % Termination TCC generated (at line 68, column 31) for
      % n_cout_rec(n - 1, x, y, a_cin)
  n_cout_rec_TCC3: OBLIGATION
    FORALL (n: below[N]): NOT n = 0 IMPLIES n - 1 < n;

  % Subtype TCC generated (at line 79, column 52) for  n + 1
      % expected type  upto(N)
  adder_correct_rec_TCC1: OBLIGATION FORALL (n: below[N]): n + 1 <= N;

  % Subtype TCC generated (at line 83, column 26) for  N - 1
      % expected type  below[N]
  adder_correct_TCC1: OBLIGATION N - 1 >= 0 AND N - 1 < N;


body:
  bv_rotate [N: posnat ] : THEORY
  %-----------------------------------------------------------------------  
  %  Defines rotate operations.
  %  Introduces:
  %      rotate_right(k: upto(N), bv: bvec[N]): bvec[N] 
  %      rotate_left(k: upto(N), bv: bvec[N]): bvec[N] 
  %      rot_r1(bv: bvec[N]): bvec[N] 
  %      rot_l1(bv: bvec[N]): bvec[N] 
  %-----------------------------------------------------------------------  

  BEGIN

    IMPORTING bv_concat, bv_caret

    rotate_right(k: upto(N), bv: bvec[N]): bvec[N] = 
       IF (k = 0) OR (k = N) THEN bv 
       ELSE bv^(k-1,0) o bv^(N-1, k) ENDIF

    rotate_left(k: upto(N), bv: bvec[N]): bvec[N] =
       IF (k=0) OR (k = N) THEN bv 
       ELSE bv^(N-k-1, 0) o bv^(N-1,N-k) ENDIF

    rot_r1(bv: bvec[N]): bvec[N] = rotate_right(1,bv)

    rot_l1(bv: bvec[N]): bvec[N] = rotate_left(1,bv)

    i:  VAR below(N)
    k:  VAR upto(N)
    bv: VAR bvec[N]

    rotate_right_0   : LEMMA rotate_right(0,bv)= bv

    rotate_right_lem : LEMMA rotate_right(k,bv)^i =
                               IF i+k < N THEN bv^(i+k) ELSE bv^(i+k-N) ENDIF

    rotate_left_0    : LEMMA rotate_left(0,bv)= bv

    rotate_left_lem  : LEMMA rotate_left(k,bv)^i = 
                               IF i-k >= 0 THEN bv^(i-k) ELSE bv^(N+i-k) ENDIF

    iterate_rot_r1   : LEMMA iterate(rot_r1,k)(bv) = rotate_right(k,bv)

    iterate_rot_l1   : LEMMA iterate(rot_l1,k)(bv) = rotate_left(k,bv)

  END bv_rotate

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

  % Subtype TCC generated (at line 17, column 14) for  k - 1
      % expected type  below(N)
  rotate_right_TCC1: OBLIGATION
    FORALL (k: upto(N)):
      NOT (k = 0) AND NOT (k = N) IMPLIES k - 1 >= 0 AND k - 1 < N;

  % Subtype TCC generated (at line 17, column 18) for  0
      % expected type  upto(k - 1)
  rotate_right_TCC2: OBLIGATION
    FORALL (k: upto(N)): NOT (k = 0) AND NOT (k = N) IMPLIES 0 <= k - 1;

  % Subtype TCC generated (at line 17, column 27) for  N - 1
      % expected type  below(N)
  rotate_right_TCC3: OBLIGATION
    FORALL (k: upto(N)):
      NOT (k = 0) AND NOT (k = N) IMPLIES N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 17, column 32) for  k
      % expected type  upto(N - 1)
  rotate_right_TCC4: OBLIGATION
    FORALL (k: upto(N)): NOT (k = 0) AND NOT (k = N) IMPLIES k <= N - 1;

  % Subtype TCC generated (at line 17, column 27) for  N - k
      % expected type  nat
  rotate_right_TCC5: OBLIGATION
    FORALL (k: upto(N)): NOT (k = 0) AND NOT (k = N) IMPLIES N - k >= 0;

  % Subtype TCC generated (at line 21, column 14) for  N - k - 1
      % expected type  below(N)
  rotate_left_TCC1: OBLIGATION
    FORALL (k: upto(N)):
      NOT (k = 0) AND NOT (k = N) IMPLIES N - k - 1 >= 0 AND N - k - 1 < N;

  % Subtype TCC generated (at line 21, column 21) for  0
      % expected type  upto(N - 1 - k)
  rotate_left_TCC2: OBLIGATION
    FORALL (k: upto(N)): NOT (k = 0) AND NOT (k = N) IMPLIES 0 <= N - 1 - k;

  % Subtype TCC generated (at line 21, column 34) for  N - k
      % expected type  upto(N - 1)
  rotate_left_TCC3: OBLIGATION
    FORALL (k: upto(N)):
      NOT (k = 0) AND NOT (k = N) IMPLIES N - k >= 0 AND N - k <= N - 1;

  % Subtype TCC generated (at line 23, column 46) for  1
      % expected type  upto(N)
  rot_r1_TCC1: OBLIGATION 1 <= N;

  % Subtype TCC generated (at line 31, column 40) for  0
      % expected type  upto(N)
  rotate_right_0_TCC1: OBLIGATION 0 <= N;

  % Subtype TCC generated (at line 34, column 63) for  (i + k - N)
      % expected type  below[N]
  rotate_right_lem_TCC1: OBLIGATION
    FORALL (i: below(N), k: upto(N)):
      NOT i + k < N IMPLIES (i + k - N) >= 0 AND (i + k - N) < N;

  % Subtype TCC generated (at line 39, column 50) for  (i - k)
      % expected type  below[N]
  rotate_left_lem_TCC1: OBLIGATION
    FORALL (i: below(N), k: upto(N)): i - k >= 0 IMPLIES (i - k) < N;

  % Subtype TCC generated (at line 39, column 64) for  (N + i - k)
      % expected type  below[N]
  rotate_left_lem_TCC2: OBLIGATION
    FORALL (i: below(N), k: upto(N)):
      NOT i - k >= 0 IMPLIES (N + i - k) >= 0 AND (N + i - k) < N;


body:
  bv_shift [N: nat ] : THEORY
  %-----------------------------------------------------------------------  
  %  Defines shift operations.
  %  Introduces:
  %     left_shift(i: nat, bv: bvec[N]): bvec[N]
  %     right_shift(i: nat, bv: bvec[N]): bvec[N] 
  %     left_shift_with(k: upto(N), bvk: bvec[k], bv: bvec[N]): bvec[N]
  %     right_shift_with(k: upto(N), bvk: bvec[k], bv: bvec[N]): bvec[N]
  %-----------------------------------------------------------------------  

  BEGIN

    IMPORTING bv_concat, bv_caret

    %------------------------------------------------------------------------
    % right_shift (left_shift) shifts a bit vector by a given number of
    % positions to the right (left) filling 0's to the shifted bits
    %------------------------------------------------------------------------

    right_shift(i: nat, bv: bvec[N]): bvec[N] =
      IF i = 0 THEN bv
      ELSIF i < N THEN fill[i](FALSE) o bv^(N-1, i) 
      ELSE fill[N](FALSE) ENDIF
   
      
    left_shift(i: nat, bv: bvec[N]): bvec[N] =
      IF i = 0 THEN bv
      ELSIF i < N THEN bv^(N-i-1, 0) o fill[i](FALSE) 
      ELSE fill[N](FALSE) ENDIF

    %------------------------------------------------------------------------    
    % left_shift_with (right_shift_with) shifts a bit vector by a given
    % number of positions to the left (right) replacing the shifted bits
    % by the bit vector given as the second argument.
    %------------------------------------------------------------------------

    left_shift_with(k: upto(N), bvk: bvec[k], bv: bvec[N]): bvec[N] =
       IF k = N THEN bvk
       ELSE bv^(N-k-1, 0) o bvk ENDIF

    right_shift_with(k: upto(N), bvk: bvec[k], bv: bvec[N]): bvec[N] =
       IF k = N THEN bvk
       ELSE bvk o bv^(N-1, k) ENDIF

  END bv_shift

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

  % Subtype TCC generated (at line 22, column 42) for  N - 1
      % expected type  below(N)
  right_shift_TCC1: OBLIGATION
    FORALL (i: nat): i < N AND NOT i = 0 IMPLIES N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 22, column 47) for  i
      % expected type  upto(N - 1)
  right_shift_TCC2: OBLIGATION
    FORALL (i: nat): i < N AND NOT i = 0 IMPLIES i <= N - 1;

  % Subtype TCC generated (at line 22, column 42) for  N - i
      % expected type  nat
  right_shift_TCC3: OBLIGATION
    FORALL (i: nat): i < N AND NOT i = 0 IMPLIES N - i >= 0;

  % Subtype TCC generated (at line 28, column 25) for  N - i - 1
      % expected type  below(N)
  left_shift_TCC1: OBLIGATION
    FORALL (i: nat):
      i < N AND NOT i = 0 IMPLIES N - i - 1 >= 0 AND N - i - 1 < N;

  % Subtype TCC generated (at line 28, column 32) for  0
      % expected type  upto(N - 1 - i)
  left_shift_TCC2: OBLIGATION
    FORALL (i: nat): i < N AND NOT i = 0 IMPLIES 0 <= N - 1 - i;

  % Subtype TCC generated (at line 38, column 19) for  bvk
      % expected type  bvec[N]
  left_shift_with_TCC1: OBLIGATION
    FORALL (k: upto(N), bvk: bvec[k]):
      k = N IMPLIES (FORALL (x: nat): bvk(x) IMPLIES (x < k IFF x < N));

  % Subtype TCC generated (at line 39, column 14) for  N - k - 1
      % expected type  below(N)
  left_shift_with_TCC2: OBLIGATION
    FORALL (k: upto(N)): NOT k = N IMPLIES N - k - 1 >= 0 AND N - k - 1 < N;

  % Subtype TCC generated (at line 39, column 21) for  0
      % expected type  upto(N - 1 - k)
  left_shift_with_TCC3: OBLIGATION
    FORALL (k: upto(N)): NOT k = N IMPLIES 0 <= N - 1 - k;

  % Subtype TCC generated (at line 39, column 14) for  N - k
      % expected type  nat
  left_shift_with_TCC4: OBLIGATION
    FORALL (k: upto(N)): NOT k = N IMPLIES N - k >= 0;

  % Subtype TCC generated (at line 43, column 20) for  N - 1
      % expected type  below(N)
  right_shift_with_TCC1: OBLIGATION
    FORALL (k: upto(N)): NOT k = N IMPLIES N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 43, column 25) for  k
      % expected type  upto(N - 1)
  right_shift_with_TCC2: OBLIGATION
    FORALL (k: upto(N)): NOT k = N IMPLIES k <= N - 1;


body:
  bv_fract [N: above(1)]: THEORY
  %------------------------------------------------------------------------------
  % Defines an interpretation of bit vectors as 2's complement fractions.
  %
  %   Introduces:
  %        bv2fract: function [bvec[N] -> bv2fract_range]
  %------------------------------------------------------------------------------
  BEGIN

    IMPORTING bv, exp2
    
    %----------------------------------------------------------------------------
    % Using a 2's complement representation, a bit vector of size N can 
    % represent any fraction of the form i/exp2(N-1) as a rational number, 
    % where i ranges over all integers representable by a bit vector of size N.
    % The predicate bv2fract_range characterizes this set of rationals.
    %--------------------------------------------------------------------------- 

    fract_numerator_range: TYPE = {i: int| i >= -exp2(N-1) & i < exp2(N-1)}

    bv2fract_range(r: rational): bool =
       (EXISTS (i: fract_numerator_range): (r = i/exp2(N-1)) )

    bv2fract_range: TYPE = (bv2fract_range) CONTAINING 0

    bv2fract: [bvec[N] -> bv2fract_range]

    %---------------------------------------------------------------------------
    % The following min and max definitions ignore 0 and -1, instead
    % naming their nearest fractional representations.
    %---------------------------------------------------------------------------

    min_pos_fract: bv2fract_range = 1/exp2(N-1)
    max_pos_fract: bv2fract_range = 1 - 1/exp2(N-1)

    min_neg_fract: bv2fract_range = -1/exp2(N-1)
    max_neg_fract: bv2fract_range = -1 + 1/exp2(N-1)

  END bv_fract

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

  % Subtype TCC generated (at line 19, column 52) for  N - 1
      % expected type  nat
  fract_numerator_range_TCC1: OBLIGATION N - 1 >= 0;

  % Subtype TCC generated (at line 24, column 53) for  0
      % expected type  bv2fract_range
  bv2fract_range_TCC1: OBLIGATION bv2fract_range(0);

  % Subtype TCC generated (at line 33, column 34) for  1 / exp2(N - 1)
      % expected type  bv2fract_range
  min_pos_fract_TCC1: OBLIGATION bv2fract_range(1 / exp2(N - 1));

  % Subtype TCC generated (at line 34, column 34) for  1 - 1 / exp2(N - 1)
      % expected type  bv2fract_range
  max_pos_fract_TCC1: OBLIGATION bv2fract_range(1 - 1 / exp2(N - 1));

  % Subtype TCC generated (at line 36, column 34) for  -1 / exp2(N - 1)
      % expected type  bv2fract_range
  min_neg_fract_TCC1: OBLIGATION bv2fract_range(-1 / exp2(N - 1));

  % Subtype TCC generated (at line 37, column 34) for  -1 + 1 / exp2(N - 1)
      % expected type  bv2fract_range
  max_neg_fract_TCC1: OBLIGATION bv2fract_range(-1 + 1 / exp2(N - 1));


body:
  %------------------------------------------------------------------------
  %  Foundation of bit-vectors theory.
  %  --------------------------------
  %    Authors:  Paul Miner
  %              Ricky W. Butler
  %              Mandayam Srivas
  %              Steve Miller
  %              Dave Greve
  %     
  %    Index:
  %    ------
  %      bv                  -- basic definition of bitvector type "bvec"
  %      bv_nat              -- interpretes bvec as a natural number
  %      bv_int              -- interpretes bvec as an integer
  %      bv_arithmetic       -- defines basic operators (i.e. + - >) over
  %                             bitvectors
  %      bv_arith_nat        -- defines bv + i, bv - i, etc
  %      bv_adder            -- operational defn of bitvector addition
  %      bv_arith_caret      -- arithmetic over caret 
  %      bv_caret            -- defines extractor operator ^ that
  %      bv_concat           -- defines concatenation operator o
  %      bv_arith_concat     -- calculates bv2nat(bv1 o bv2)
  %      bv_constants        -- defines some useful bitvector constants
  %      bv_caret_concat     -- lemmas concerning ^ and o
  %      bv_bitwise          -- defines bit-wise logical operations on bitvectors
  %      bv_caret_bitwise    -- lemmas about bit-wise logical operations and ^
  %      bv_shift            -- defines shift operations
  %      bv_extend           -- zero and sign extend operations
  %      bv_arith_extend     -- lemmas about extend operations
  %      bv_fract            -- defines fractional interpretation of a bitvector
  %      bv_overflow         -- relates overflow to top bits
  %      bv_arith_int_caret  -- lemmas with bv2int and ^
  %      bv_arith_int_concat -- lemmas with bv2int and o
  %
  %
  %                               bv
  %                               |
  %       ------------------------------------------------------------
  %       |        |                 |               |               |
  %  bv_bitwise  bv_nat          bv_concat       bv_fract        bv_caret
  %  |   |         |                 |                               |
  %  |   |    --------        ---------------------|                 |        
  %  |   |    |      |        |                    |                 |
  %  |   |  bv_int   |    bv_arith_concat          |                 |      
  %  |   |    |      |        |                    |                 |          
  %  |   |    |      |        | _______==========================================
  %  |   |    | bv_arith_nat  | |      ||        ||           ||               ||
  %  |   |    |      |        | | bv_shift  bv_extend bv_caret_concat    bv_rotate
  %  |   |    |      |        | |     |         |
  %  |   |    |      |        | |     |         |
  %  |   |    |      |        | |     |         |
  %  |   |    |      |        | |     |         |
  %  |   |    |    bv_arith_caret     |         |
  %  |   |    |      |        |       |         |
  %  |   bv_arithmetic       bv_arith_shift     |    
  %  |            |                             |
  %  |            ------------------------      |
  %  |                    |         |    |      |
  % bv_caret_bitwise  bv_overflow   |    bv_arith_extend
  %                                 |
  %                          bv_arith_int_caret
  %----------------------------------------------------------------------------
  bv_core: THEORY
    
   BEGIN

    IMPORTING bv, bv_bitwise, bv_nat, bv_concat, bv_fract, bv_caret, 
              bv_int,  bv_arith_concat, bv_shift, bv_rotate,
              bv_caret_concat,  bv_extend,  bv_arith_extend, 
              bv_arith_nat, bv_adder, bv_arith_caret,
              bv_arithmetic, bv_overflow, bv_caret_bitwise, bv_constants,
              bv_arith_concat,
              bv_arith_int_caret, bv_arith_int_concat

  END bv_core


body:
  %
  %  BitvectorUtil
  %  =============
  %
  %  for Translating Java Classes into the Higher Order Logic of PVS.
  %
  %  All integral types are interpreted as PVS integers, without 
  %  taking bounds into account
  %
  %  Author: Bart Jacobs
  %  Integrated with the bitvector library by Sam Owre <owre@csl.sri.com>

  BitvectorUtil[N : nat] : THEORY
  BEGIN

    ASSUMING
       N_size: ASSUMPTION N >= 2
    ENDASSUMING

    IMPORTING bv_core, bv_rules, bv_notes

    bv, bv1, bv2 : VAR bvec[N]
    BV, BV1, BV2 : VAR bvec[2*N]
    k : VAR int

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % auxiliary results
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    bvec_induction : LEMMA % :-)
      FORALL(p:PRED[bvec[N]]) :
        p(fill[N](FALSE))
          AND
        (FORALL(bv:bvec[N]) : p(bv) IMPLIES p(bv+1))
          IMPLIES
        FORALL(bv:bvec[N]) : p(bv)

    plus_min_zero : LEMMA % :-)
      bv + (-bv) = fill[N](FALSE)

    min_fill_F : LEMMA % :-)
      -fill[N](FALSE) = fill[N](FALSE)

    inc_zero : LEMMA % :-)
      (bv+1)(0) IFF NOT bv(0)

    sum_upper_n : LEMMA % :-)
      FORALL(F : [nat -> nat], high,low,n : nat) :
        low <= n AND n <= high
          IMPLIES
        sigma(low, high, F) >= F(n)

    bv2nat_upper_n : LEMMA % :-)
      FORALL(n:below(N)) :
        bv(n) IMPLIES bv2nat(bv) >= exp2(n)

    bv2nat_upperbound : LEMMA % :-)
      FORALL(n:below(N)) :
        bv2nat(bv) < exp2(n) 
          IFF
        FORALL(k:below(N)) : k >= n IMPLIES NOT bv(k)

    bv2nat_upperbound_caret : LEMMA % :-)
      FORALL(n:below(N)) :
        bv2nat[N](bv) < exp2(n) 
          IMPLIES
        bv2nat[N](bv) = IF n = 0
                        THEN 0
                        ELSE bv2nat[n](bv^(n-1,0))
                        ENDIF

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % Widen & Narrow
  %
  % These are typical Java Integral operations to move back and forth
  % between integral types. Widen doubles the length of the 
  % representation (e.g. from byte to short (8 to 16 bits), or
  % from short to int (16 to 32 bits). It does so by keeping the sign.
  % 
  % In the reverse direction, narrowing drops half of the bits (the
  % most significant ones) in going e.g. from int to short. This
  % may affect the sign.
  %
  % See, JLS (Java Language Specification, 2nd ed.), 5.1.2 and 5.1.3.
  %
  % Operations on integral types typically first ``promote'' the
  % arguments to int type.
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    widen(bv) : bvec[2*N] = 
      LAMBDA(k:below(2*N)) : IF k < N-1
                             THEN bv(k) 
                             ELSE bv(N-1) % negative byte
                             ENDIF

    bv2int_widen : LEMMA % :-)
      bv2int[2*N](widen(bv)) = bv2int[N](bv)

    widen_inj : LEMMA % :-)
      (widen(bv1) = widen(bv2)) = (bv1 = bv2)

    bv2int_plus_widens : LEMMA % :-)
      bv2int[2*N](widen(bv1) + widen(bv2)) = bv2int[N](bv1) + bv2int[N](bv2)

    bv2int_min_widen : LEMMA % :-)
      bv2int[2*N](-widen(bv)) = -bv2int[N](bv)

    bv2nat_widen : LEMMA % :-)
      bv2nat(widen(bv)) = IF bv2nat(bv) < exp2(N-1)
                          THEN bv2nat(bv)
                          ELSE bv2nat(bv) + exp2(2*N)-exp2(N)
                          ENDIF

    bv2nat_widen_null : LEMMA % :-)
      (bv2nat(widen(bv)) = 0) = (bv2nat(bv) = 0)

    narrow(BV) : bvec[N] = BV^(N-1,0)

    bv2int_narrow : LEMMA % :-)
      -exp2(N-1) <= bv2int(BV) AND bv2int(BV) < exp2(N-1)
        IMPLIES
      bv2int[N](narrow(BV)) = bv2int[2*N](BV)

    narrow_int2bv : LEMMA % :-)
      -exp2(N-1) <= k AND k < exp2(N-1)
        IMPLIES
      narrow(int2bv[2*N](k)) = int2bv[N](k)

    narrow_widen : LEMMA % :-)
      narrow(widen(bv)) = bv;

    narrow_plus : LEMMA % :-)
      narrow(BV1 + BV2) = narrow(BV1) + narrow(BV2)

    narrow_min : LEMMA % :-)
      narrow(-BV) = -narrow(BV)
      
    narrow_minus : LEMMA % :-)
      narrow(BV1 - BV2) = narrow(BV1) - narrow(BV2)

    % The next lemma will probably not often work because of the representation
    % of bitvectors, namely as:  (x o (x o (x o (x...))))

    narrow_concat : LEMMA %-)
      FORALL (bv1,bv2 : bvec[N]):
        narrow[2*N](bv1 o bv2) = bv2

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % More auxiliary results
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    leftshift_zero : LEMMA % :-)
      left_shift(0, bv) = bv

    leftshift_inc : LEMMA % :-)
      FORALL(n:below(N-1)) : 
        n > 0  % Condition needed to prevent circular rewriting
          IMPLIES
        left_shift(n+1, bv) = left_shift(1, left_shift(n, bv))

    bv2nat_leftshift : LEMMA % :-)
      FORALL(n:below(N)) :
        bv2nat(bv) < exp2(N-n) 
          IMPLIES 
        bv2nat(left_shift(n, bv)) = exp2(n) * bv2nat(bv)

    bv2nat_rightshift_upperbound : LEMMA % :-)
      FORALL(n:below(N)) :
        exp2(n) * bv2nat(right_shift(n, bv)) <= bv2nat(bv)

    bv2int_rightshift_upperbound : LEMMA % :-)
      FORALL(n:below(N)) : 
        bv2int(bv) >= 0
          IMPLIES
        exp2(n) * bv2int(right_shift(n, bv)) <= bv2int(bv)

    rightshift_zero : LEMMA % :-)
      right_shift(0, bv) = bv

    rightshift_inc : LEMMA % :-)
      FORALL(n:below(N-1)) :
        n > 0  % Condition needed to prevent circular rewriting
          IMPLIES
        right_shift(n+1, bv) = right_shift(1, right_shift(n, bv))

    bv2int_rightshift_pos : LEMMA % :-)
      FORALL(n:posnat) : 
        bv2int(right_shift(n, bv)) >= 0

    leftshift1_add_aux : LEMMA % :-)
      FORALL(n:below(N-1)) : 
        n_cout_rec[N](n+1, left_shift(1, bv1), left_shift(1, bv2), FALSE)
        =
        n_cout_rec[N](n, bv1, bv2, FALSE)

    leftshift1_add : LEMMA % :-)
     left_shift(1, bv1 + bv2) = 
       left_shift(1, bv1) + left_shift(1, bv2)

    narrow_rightshift : LEMMA % :-)
      FORALL(n:nat) :
      0 <= bv2int(BV) AND bv2int(BV) < exp2(N)
          IMPLIES
        narrow(right_shift(n, BV)) = right_shift(n, narrow(BV))

  END BitvectorUtil

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

  % Subtype TCC generated (at line 22, column 26) for  N
      % expected type  posnat
  plus_min_zero_TCC1: OBLIGATION N > 0;

  % Subtype TCC generated (at line 47, column 11) for  0
      % expected type  below(N)
  inc_zero_TCC1: OBLIGATION 0 < N;

  % Subtype TCC generated (at line 71, column 41) for  n - 1
      % expected type  below(N)
  bv2nat_upperbound_caret_TCC1: OBLIGATION
    FORALL (bv: bvec[N], n: below(N)):
      NOT n = 0 AND bv2nat[N](bv) < exp2(n) IMPLIES n - 1 >= 0 AND n - 1 < N;

  % Subtype TCC generated (at line 71, column 45) for  0
      % expected type  upto(n - 1)
  bv2nat_upperbound_caret_TCC2: OBLIGATION
    FORALL (bv: bvec[N], n: below(N)):
      NOT n = 0 AND bv2nat[N](bv) < exp2(n) IMPLIES 0 <= n - 1;

  % Subtype TCC generated (at line 96, column 35) for  k
      % expected type  below(N)
  widen_TCC1: OBLIGATION FORALL (k: below(2 * N)): k < N - 1 IMPLIES k < N;

  % Subtype TCC generated (at line 97, column 35) for  N - 1
      % expected type  below(N)
  widen_TCC2: OBLIGATION
    FORALL (k: below(2 * N)): NOT k < N - 1 IMPLIES N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 101, column 11) for  2 * N
      % expected type  posnat
  bv2int_widen_TCC1: OBLIGATION 2 * N > 0;

  % Subtype TCC generated (at line 113, column 45) for  N - 1
      % expected type  nat
  bv2nat_widen_TCC1: OBLIGATION N - 1 >= 0;

  % Subtype TCC generated (at line 121, column 29) for  N - 1
      % expected type  below(2 * N)
  narrow_TCC1: OBLIGATION N - 1 >= 0 AND N - 1 < 2 * N;

  % Subtype TCC generated (at line 121, column 33) for  0
      % expected type  upto(N - 1)
  narrow_TCC2: OBLIGATION 0 <= N - 1;

  % Subtype TCC generated (at line 131, column 23) for  k
      % expected type  iv: rng_2s_comp[2 * N]
  narrow_int2bv_TCC1: OBLIGATION
    FORALL (k: int):
      k < exp2(N - 1) AND -exp2(N - 1) <= k IMPLIES
       minint[2 * N] <= k AND k <= maxint[2 * N];

  % Subtype TCC generated (at line 131, column 39) for  k
      % expected type  iv: rng_2s_comp[N]
  narrow_int2bv_TCC2: OBLIGATION
    FORALL (k: int):
      k < exp2(N - 1) AND -exp2(N - 1) <= k IMPLIES
       minint[N] <= k AND k <= maxint[N];

  % Subtype TCC generated (at line 169, column 24) for  N - n
      % expected type  nat
  bv2nat_leftshift_TCC1: OBLIGATION FORALL (n: below(N)): N - n >= 0;

  % Subtype TCC generated (at line 198, column 20) for  n + 1
      % expected type  below[N]
  leftshift1_add_aux_TCC1: OBLIGATION FORALL (n: below(N - 1)): n + 1 < N;

  % Subtype TCC generated (at line 200, column 20) for  n
      % expected type  below[N]
  leftshift1_add_aux_TCC2: OBLIGATION FORALL (n: below(N - 1)): n < N;


body:
  %
  %  BitvectorMultiplication
  %  =======================
  %
  %  for Translating Java Classes into the Higher Order Logic of PVS.
  %
  %  All integral types are interpreted as PVS integers, without 
  %  taking bounds into account
  %
  %  Author: Bart Jacobs
  %  Integrated with the bitvector library by Sam Owre <owre@csl.sri.com>

  BitvectorMultiplication[N : posnat] : THEORY
  BEGIN

    ASSUMING
       N_size: ASSUMPTION N >= 2
    ENDASSUMING

    IMPORTING BitvectorUtil[N]

    bv, bv1, bv2, bv3 : VAR bvec[N]

    times_rec(bv1:bvec[N], bv2:bvec[N], n:nat) : RECURSIVE bvec[N] =
      IF n = 0
      THEN fill[N](FALSE)
      ELSIF bv1(0)
      THEN bv2 + left_shift(1, times_rec(right_shift(1, bv1), bv2, n-1))
      ELSE left_shift(1, times_rec(right_shift(1, bv1), bv2, n-1))
      ENDIF
      MEASURE n;

    *(bv1, bv2) : bvec[N] = times_rec(bv1, bv2, N)

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % auxiliary results
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    times_rec_zero_right : LEMMA % :-)
      FORALL(n:nat) : 
        times_rec(bv, fill[N](FALSE), n) = fill[N](FALSE)

    times_rec_zero_left : LEMMA % :-)
      FORALL(n:nat) : 
        times_rec(fill[N](FALSE), bv, n) = fill[N](FALSE)

    times_rec_repeat : LEMMA % :-)
      FORALL(n,m:nat) : 
        bv2nat(bv1) < exp2(n)
          IMPLIES
        times_rec(bv1, bv2, n+m) = times_rec(bv1, bv2, n)

  % Distributivity of zero

    times_zero_first : LEMMA % :-)
      fill[N](FALSE) * bv = fill[N](FALSE)

    times_zero_second : LEMMA % :-)
      bv * fill[N](FALSE) = fill[N](FALSE)

  % inc-right

    times_rec_inc_right : LEMMA % :-)
      FORALL(n:below(N+1)) : 
        times_rec(bv1, bv2+1, n) = 
          times_rec(bv1, bv2, n) + (IF n = 0
                                    THEN fill[N](FALSE)
                                    ELSE (fill[N-n](FALSE) o bv1 ^ (n-1, 0))
                                    ENDIF)

    times_rec_max_inc_right : LEMMA % :-)
      times_rec(bv1, bv2+1, N) = 
        times_rec(bv1, bv2, N) + bv1

    times_rec_max_inc_n_right : LEMMA % :-)
      FORALL(n:nat) : 
        times_rec(bv1, bv2+n, N) =
          iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + bv1, n)
                          (times_rec(bv1, bv2, N))

    times_rec_iterate : LEMMA % :-)
      times_rec(bv1, bv2, N) =
        iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + bv1, bv2nat(bv2))
                        (fill[N](FALSE))

  % two crucial auxiliary results, on which much of the subsequent reasoning
  % depends:

    bv2nat_iterate : LEMMA % :-)
      FORALL(n:nat) :
        n * bv2nat(bv1) < exp2(N) 
          IMPLIES
        bv2nat(iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + bv1, n)(fill[N](FALSE)))
          = n * bv2nat(bv1)

    bv2int_iterate : LEMMA % :-)
      FORALL(n:nat) :
        -exp2(N-1) <= n * bv2int(bv1) AND n * bv2int(bv1) < exp2(N-1) 
          IMPLIES
        bv2int(iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + bv1, n)(fill[N](FALSE)))
          = n * bv2int(bv1)

  % towards commutativity, proved by bitvector induction

    iterate_inc : LEMMA % :-)
      FORALL(n:nat) :
        iterate[bvec[N]](LAMBDA (b:bvec[N]): b + (bv1 + 1), n)
                        (fill[N](FALSE))
        =
        iterate[bvec[N]](LAMBDA (b:bvec[N]): b + bv1, n)
                      (fill[N](FALSE)) + n

    iterate_inc_m : LEMMA % :-)
      FORALL(n,m:nat) :
        iterate[bvec[N]](LAMBDA (b:bvec[N]): b + (bv1 + m), n)
                        (fill[N](FALSE))
        =
        iterate[bvec[N]](LAMBDA (b:bvec[N]): b + bv1, n)
                      (fill[N](FALSE)) + (n * m)

    iterate_modulo : LEMMA % :-)
      FORALL(i:nat) : 
        iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + bv2, i * exp2(N))
                        (fill[N](FALSE))    
        = 
        fill[N](FALSE)

    iterate_comm : LEMMA % :-)
      iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + bv1, bv2nat(bv2))
                      (fill[N](FALSE))    
      =
      iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + bv2, bv2nat(bv1))
                      (fill[N](FALSE))    

    times_rec_comm : LEMMA % :-)
      times_rec(bv1, bv2, N) = times_rec(bv2, bv1, N)

    times_comm : LEMMA % :-)
      bv1 * bv2 = bv2 * bv1

  % commutation with min

    iterate_min_second : LEMMA % :-)
      FORALL(n:nat) : 
        iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + (-bv), n)
                        (fill[N](FALSE))    
        =
        -iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + bv, n)
                        (fill[N](FALSE))    

    times_rec_min_first : LEMMA % :-)
      times_rec(-bv1, bv2, N) = -times_rec(bv1, bv2, N)
        
    times_rec_min_second : LEMMA % :-)
      times_rec(bv1, -bv2, N) = -times_rec(bv1, bv2, N)

    times_min_first : LEMMA % :-)
      (-bv1) * bv2 = -(bv1 * bv2)

    times_min_second : LEMMA % :-)
      bv1 * (-bv2) = -(bv1 * bv2)

  % multiplicative unit

    one : bvec[N] = (LAMBDA(k:below(N)) : k=0)

    bv2nat_one : LEMMA % :-)
      bv2nat[N](one) = 1

    bv2int_one : LEMMA % :-)
      bv2int[N](one) = 1

    times_one_first : LEMMA % :-)
      one * bv = bv

    times_one_second : LEMMA % :-)
      bv * one = bv

  % distributivity over +

    iterate_zero_add : LEMMA % :-)
      FORALL(n:nat) : 
        iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + bv1, n)
                        (bv2)    
        =
        iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + bv1, n)
                        (fill[N](FALSE)) + bv2

    times_rec_distr : LEMMA % :-)
      times_rec(bv1, bv2 + bv3, N)
      =
      times_rec(bv1, bv2, N) + times_rec(bv1, bv3, N)

    times_distr_right : LEMMA % :-)
      bv1 * (bv2 + bv3) = (bv1 * bv2) + (bv1 * bv3)
      
    times_distr_left : LEMMA % :-)
      (bv1 + bv2) * bv3 = (bv1 * bv3) + (bv2 * bv3)
      
    times_distr_iterate : LEMMA % :-)
      FORALL(n:nat) :
        bv2 * iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + bv1, n)(fill[N](FALSE))
        =
        iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + (bv2 * bv1), n)(fill[N](FALSE))

  % associativity

    times_assoc : LEMMA % :-)
      (bv1 * bv2) * bv3 = bv1 * (bv2 * bv3)

  % Now we can say that bvec[N] carries a commutative group structure
  % (0, +, -) and a commutative monoid structure (*, one), and that
  % the latter preserves the group structure. More formally, (*, one)
  % is a commutative monoid in the category of commutative groups,
  % see MacLane, Categories for the Working Mathematician (1972), 
  % Chapter VII, section 3.

  END BitvectorMultiplication

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

  % Assuming TCC generated (at line 20, column 12) for  BitvectorUtil[N]
      % generated from assumption BitvectorUtil.N_size
  IMP_BitvectorUtil_TCC1: OBLIGATION N >= 2;

  % Subtype TCC generated (at line 27, column 14) for  0
      % expected type  below(N)
  times_rec_TCC1: OBLIGATION FORALL (n: nat): NOT n = 0 IMPLIES 0 < N;

  % Subtype TCC generated (at line 28, column 65) for  n - 1
      % expected type  nat
  times_rec_TCC2: OBLIGATION
    FORALL (bv1: bvec[N], n: nat): bv1(0) AND NOT n = 0 IMPLIES n - 1 >= 0;

  % Termination TCC generated (at line 28, column 29) for
      % times_rec(right_shift(1, bv1), bv2, n - 1)
  times_rec_TCC3: OBLIGATION
    FORALL (bv1: bvec[N], n: nat): bv1(0) AND NOT n = 0 IMPLIES n - 1 < n;

  % Subtype TCC generated (at line 29, column 59) for  n - 1
      % expected type  nat
  times_rec_TCC4: OBLIGATION
    FORALL (bv1: bvec[N], n: nat):
      NOT bv1(0) AND NOT n = 0 IMPLIES n - 1 >= 0;

  % Termination TCC generated (at line 29, column 23) for
      % times_rec(right_shift(1, bv1), bv2, n - 1)
  times_rec_TCC5: OBLIGATION
    FORALL (bv1: bvec[N], n: nat): NOT bv1(0) AND NOT n = 0 IMPLIES n - 1 < n;

  % Subtype TCC generated (at line 70, column 45) for  N - n
      % expected type  nat
  times_rec_inc_right_TCC1: OBLIGATION
    FORALL (n: below(N + 1)): NOT n = 0 IMPLIES N - n >= 0;

  % Subtype TCC generated (at line 70, column 66) for  n - 1
      % expected type  below(N)
  times_rec_inc_right_TCC2: OBLIGATION
    FORALL (n: below(N + 1)): NOT n = 0 IMPLIES n - 1 >= 0 AND n - 1 < N;

  % Subtype TCC generated (at line 70, column 71) for  0
      % expected type  upto(n - 1)
  times_rec_inc_right_TCC3: OBLIGATION
    FORALL (n: below(N + 1)): NOT n = 0 IMPLIES 0 <= n - 1;

  % Subtype TCC generated (at line 100, column 12) for  N - 1
      % expected type  nat
  bv2int_iterate_TCC1: OBLIGATION N - 1 >= 0;


body:
  %
  %  BitvectorMultiplicationWidenNarrow
  %  ==================================
  %
  %  for Translating Java Classes into the Higher Order Logic of PVS.
  %
  %  All integral types are interpreted as PVS integers, without 
  %  taking bounds into account
  %
  %  Author: Bart Jacobs
  %  Integrated with the bitvector library by Sam Owre <owre@csl.sri.com>

  BitvectorMultiplicationWidenNarrow[N : posnat] : THEORY
  BEGIN
    ASSUMING
       N_size: ASSUMPTION N >= 2
    ENDASSUMING

    IMPORTING BitvectorMultiplication[N],
              BitvectorMultiplication[2*N]

    bv, bv1, bv2 : VAR bvec[N]
    BV, BV1, BV2 : VAR bvec[2*N]

    bv2nat_narrow : LEMMA % :-)
      bv2nat(BV) < exp2(N) IMPLIES bv2nat(narrow(BV)) = bv2nat(BV)

    bv2nat_times_rec : LEMMA % :-)
      bv2nat(BV1) < exp2(N) AND bv2nat(BV2) < exp2(N)
        IMPLIES
      bv2nat(times_rec[2*N](BV1, BV2, 2*N)) = bv2nat(BV1) * bv2nat(BV2)

    bv2nat_times : LEMMA % :-)
      bv2nat(BV1) * bv2nat(BV2) < exp2(2*N)
        IMPLIES
      bv2nat(BV1 * BV2) = bv2nat(BV1) * bv2nat(BV2)

    bv2int_times : LEMMA % :-)
     -exp2(2*N-1) < bv2int(BV1) * bv2int(BV2) 
       AND 
     bv2int(BV1) * bv2int(BV2) < exp2(2*N-1)
        IMPLIES
      bv2int(BV1 * BV2) = bv2int(BV1) * bv2int(BV2)

  % main results for computing outcomes of multiplications:

    bv2int_times_widens : LEMMA % :-)
      bv2int(widen(bv1) * widen(bv2)) = bv2int(bv1) * bv2int(bv2)

    bv2int_times_int2bv_first : LEMMA % :-)
      FORALL(k:int) :
       -exp2(2*N-1) < k * bv2int(BV) AND k * bv2int(BV) < exp2(2*N-1)      
         AND
       -exp2(2*N-1) <= k AND k < exp2(2*N-1)      
         IMPLIES
       bv2int[2*N](int2bv[2*N](k) * BV) = k * bv2int(BV)

    bv2int_times_int2bv_second : LEMMA % :-)
      FORALL(k:int) :
       -exp2(2*N-1) < k * bv2int(BV) AND k * bv2int(BV) < exp2(2*N-1)      
         AND
       -exp2(2*N-1) <= k AND k < exp2(2*N-1)      
         IMPLIES
       bv2int[2*N](BV * int2bv[2*N](k)) = k * bv2int(BV)

  % narrow and multiplication

    narrow_iterate : LEMMA % :-)
      FORALL(n:nat) :
        narrow(iterate[bvec[2*N]](LAMBDA(b:bvec[2*N]) : b + BV1, n)
                                 (fill[2*N](FALSE)))
        =
        iterate[bvec[N]](LAMBDA(b:bvec[N]) : b + narrow(BV1), n)(fill[N](FALSE))

    bv2nat_split : LEMMA % :-)
      bv2nat(BV) = exp2(N) * bv2nat(BV^(2*N-1,N)) + bv2nat(BV^(N-1,0))

    narrow_times : LEMMA % :-)
      narrow(BV1 * BV2) = narrow(BV1) * narrow(BV2)


  % JLS, 15.17.1:
  %
  % The binary * operator performs multiplication, producing the product
  % of its operands. Multiplication is a commutative operation if the
  % operand expressions have no side effects. While integer multiplication
  % is associative when the operands are all of the same type,
  % floating-point multiplication is not associative. If an integer
  % multiplication overflows, then the result is the low-order bits of the
  % mathematical product as represented in some sufficiently large
  % two's-complement format. As a result, if overflow occurs, then the sign
  % of the result may not be the same as the sign of the mathematical
  % product of the two operand values.
  %
  % This is formalised in the following way:

    times_is_java_times : LEMMA % :-)
      bv1 * bv2 = narrow(widen(bv1) * widen(bv2))

  END BitvectorMultiplicationWidenNarrow

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

  % Assuming TCC generated (at line 19, column 12) for
      % BitvectorMultiplication[N]
      % generated from assumption BitvectorMultiplication.N_size
  IMP_BitvectorMultiplication_TCC1: OBLIGATION N >= 2;

  % Assuming TCC generated (at line 20, column 12) for
      % BitvectorMultiplication[2 * N]
      % generated from assumption BitvectorMultiplication.N_size
  IMP_BitvectorMultiplication_TCC2: OBLIGATION 2 * N >= 2;

  % Subtype TCC generated (at line 39, column 9) for  2 * N - 1
      % expected type  nat
  bv2int_times_TCC1: OBLIGATION 2 * N - 1 >= 0;

  % Subtype TCC generated (at line 56, column 29) for  k
      % expected type  iv: rng_2s_comp[2 * N]
  bv2int_times_int2bv_first_TCC1: OBLIGATION
    FORALL (BV: bvec[2 * N], k: int):
      -exp2(2 * N - 1) < k * bv2int(BV) AND
       k * bv2int(BV) < exp2(2 * N - 1) AND
        -exp2(2 * N - 1) <= k AND k < exp2(2 * N - 1)
       IMPLIES minint[2 * N] <= k AND k <= maxint[2 * N];

  % Subtype TCC generated (at line 76, column 38) for  2 * N - 1
      % expected type  below(2 * N)
  bv2nat_split_TCC1: OBLIGATION 2 * N - 1 >= 0 AND 2 * N - 1 < 2 * N;

  % Subtype TCC generated (at line 76, column 44) for  N
      % expected type  upto(2 * N - 1)
  bv2nat_split_TCC2: OBLIGATION N <= 2 * N - 1;

  % Subtype TCC generated (at line 76, column 61) for  N - 1
      % expected type  below(2 * N)
  bv2nat_split_TCC3: OBLIGATION N - 1 >= 0 AND N - 1 < 2 * N;

  % Subtype TCC generated (at line 76, column 65) for  0
      % expected type  upto(N - 1)
  bv2nat_split_TCC4: OBLIGATION 0 <= N - 1;


body:
  %
  %  DivisionUtil
  %  ============
  %
  %  for Translating Java Classes into the Higher Order Logic of PVS.
  %
  %  All integral types are interpreted as PVS integers, without 
  %  taking bounds into account
  %
  %  Author: Bart Jacobs
  %  Integrated with the bitvector library by Sam Owre <owre@csl.sri.com>

  DivisionUtil : THEORY
  BEGIN

    IMPORTING BitvectorUtil

    leftshift_with : LEMMA % :-)
      FORALL(n:nat, bv:bvec[n], b:bool) : 
        n > 1 AND bv2nat[n](bv) < exp2(n-1)
          IMPLIES
        bv2nat[n](left_shift(1, bv) WITH [(0) := b]) = 2 * bv2nat[n](bv) + b2n(b)

    bv2nat_minus3 : LEMMA % :-)
      FORALL(n:posnat, bv1, bv2:bvec[n]) :
        bv2nat[n](bv1) <= bv2nat[n](bv2)
          IMPLIES
        bv2nat[n](bv2 - bv1) = bv2nat[n](bv2) - bv2nat[n](bv1);

  END DivisionUtil

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

  % Subtype TCC generated (at line 20, column 37) for  n - 1
      % expected type  nat
  leftshift_with_TCC1: OBLIGATION FORALL (n: nat): n > 1 IMPLIES n - 1 >= 0;

  % Subtype TCC generated (at line 22, column 41) for  0
      % expected type  below(n)
  leftshift_with_TCC2: OBLIGATION
    FORALL (n: nat, bv: bvec[n]):
      n > 1 AND bv2nat[n](bv) < exp2(n - 1) IMPLIES 0 < n;


body:
  %
  %  BitvectorOneComplementDivision
  %  ==============================
  %
  %  for Translating Java Classes into the Higher Order Logic of PVS.
  %
  %  All integral types are interpreted as PVS integers, without 
  %  taking bounds into account
  %
  %  Author: Bart Jacobs
  %  Integrated with the bitvector library by Sam Owre <owre@csl.sri.com>

  BitvectorOneComplementDivision[N : posnat] : THEORY
  BEGIN

    ASSUMING
       N_size: ASSUMPTION N >= 2
    ENDASSUMING

    IMPORTING DivisionUtil,
              BitvectorMultiplication[N]

    bv, bv1, bv2, bv3 : VAR bvec[N]
    dvs, dvd, rem, quot, aux : VAR bvec[N]

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % The next function implements 1-complement division-remainder
  % computation, following for instance: Stallings, Computer Organization
  % and Architecture (4th ed., 1996), Section 8.3: Integer arithmetic.
  %
  % Basically, it follows the standard paper-and-pencil approach.
  %
  % The function should be called with rem = fill[N](FALSE), n = N,
  % see the subsequent definitions of div and rem.
  %
  % Names: dvs = divisor, 
  %        dvd = dividend (as in dividend/divisor), 
  %        rem = remainder, 
  %        n   = counter
  % 
  % An output tuple should be interpreted as (dvd/dvs, dvd%dvs), see
  % the subsequent definitions of div and rem.
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    divrem(dvd, dvs, rem : bvec[N], n : nat) : RECURSIVE [bvec[N], bvec[N]] =
      IF n = 0
      THEN (dvd, rem)
      ELSE LET 
               rem1 = left_shift(1, rem) WITH [(0) := dvd(N-1)],
               dvd1 = left_shift(1, dvd)
           IN
               IF bv2nat[N](dvs) <= bv2nat[N](rem1)
               THEN divrem(dvd1 WITH [(0) := TRUE], dvs, rem1-dvs, n-1)
               ELSE divrem(dvd1, dvs, rem1, n-1)
               ENDIF
      ENDIF
      MEASURE n;

  % div

    div(dvd, dvs) : bvec[N] = divrem(dvd, dvs, fill[N](FALSE), N)`1;

  % rem

    rem(dvd, dvs) : bvec[N] = divrem(dvd, dvs, fill[N](FALSE), N)`2

  % Some easy results about div and rem

    divrem_dvd : LEMMA % :-)
      FORALL(n:below(N+1), k:below(N-n)) :
        divrem(dvd, dvs, rem, n)`1(k+n) = dvd(k)

    divrem_dvs0 : LEMMA % :-)
      FORALL(n:below(N+1)) :
        divrem(dvd, fill[N](FALSE), rem, n) = 
          ((LAMBDA(i:below(N)) : IF i < n
                                 THEN TRUE
                                 ELSE dvd(i-n)
                                 ENDIF),

           (LAMBDA(i:below(N)) : IF i < n
                                 THEN dvd(N-n+i)
                                 ELSE rem(i-n)
                                 ENDIF))

  % A couple of auxiliary results needed for the key invariant
  % property of divrem below.

    bv2nat_left_false_inc : LEMMA % :-)
      FORALL(n:below(N)) :
        bv2nat[N](LAMBDA(i:below(N)) :
                    IF i < n+1
                    THEN bv(i)
                    ELSE FALSE
                    ENDIF)
        =
        bv2nat[N](LAMBDA(i:below(N)) :
                    IF i < n
                    THEN bv(i)
                    ELSE FALSE
                    ENDIF) + exp2(n) * b2n(bv(n))

    bv2nat_right_false_inc : LEMMA % :-)
      FORALL(n:below(N)) :
        bv2nat[N](LAMBDA(i:below(N)) :
                    IF i < n
                    THEN FALSE
                    ELSE bv(i)
                    ENDIF) 
        =
        bv2nat[N](LAMBDA(i:below(N)) :
                    IF i < n+1
                    THEN FALSE
                    ELSE bv(i)
                    ENDIF) + exp2(n) * b2n(bv(n))

    bv2nat_left_false_dec : LEMMA % :-)
      FORALL(n:below(N)) :
        bv2nat[N](LAMBDA(i:below(N)) :
                    IF i < N-n
                    THEN bv(i+n)
                    ELSE FALSE
                    ENDIF)
        =
        bv2nat[N](LAMBDA(i:below(N)) :
                    IF i < N-n-1
                    THEN bv(i+n)
                    ELSE FALSE
                    ENDIF) + exp2(N-n-1) * b2n(bv(N-1))

    bv2nat_split : LEMMA % :-)
      FORALL(m:below(N+1)) :
        bv2nat[N](LAMBDA(i:below(N)) :
                    IF i < m
                    THEN bv1(i+N-m)
                    ELSE bv2(i-m)
                    ENDIF)
        =
        bv2nat[N](LAMBDA(i:below(N)) :
                    IF i < m
                    THEN bv1(i+N-m)
                    ELSE FALSE
                    ENDIF)
        + exp2(m) * bv2nat[N](LAMBDA(i:below(N)) :
                                IF i < N-m
                                THEN bv2(i)
                                ELSE FALSE
                                ENDIF)

    bv2nat_left_false_minus : LEMMA % :-)
      FORALL(n:below(N)) :
        bv2nat[N](LAMBDA (i: below(N)):
                    IF i < N - n
                    THEN bv(i + n)
                    ELSE FALSE
                    ENDIF)
        =
        2 * bv2nat[N](LAMBDA (i: below(N)):
                    IF i < N - n - 1
                    THEN bv(1 + i + n)
                    ELSE FALSE
                    ENDIF)
        + b2n(bv(n))

    bv2nat_leftshift_exp : LEMMA % :-)
      bv2nat(bv) = bv2nat(left_shift(1, bv))/2 + exp2(N-1) * b2n(bv(N-1))

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % The above divrem function is too compact. For instance, it overwrites
  % the argument dvd from the left, which becomes the intended quotient.
  % In this way we cannot formulate the intended invariant property.
  % Therefore we introduce a more explicit auxiliary variation `divrem_mem' 
  % with ``memory'', which keeps the dvd argument.
  % Also, in its cycles it considers only the appropriate part of the
  % remainder argument.
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    divrem_mem(aux, dvs, quot, rem : bvec[N], n : below(N+1)) : 
      RECURSIVE [bvec[N], bvec[N], bvec[N]] =
        IF n = 0
        THEN (aux, quot, rem)
        ELSE LET 
                 aux1  = left_shift(1, aux) WITH [(0) := quot(N-1)],
                 rem1  = left_shift(1, rem) WITH [(0) := quot(N-1)],
                 quot1 = left_shift(1, quot)
             IN
                 IF bv2nat[N](dvs) <= bv2nat[N](LAMBDA(i:below(N)) : IF i < N-n+1
                                                                     THEN rem1(i)
                                                                     ELSE FALSE
                                                                     ENDIF)
                 THEN divrem_mem(aux1, dvs, quot1 WITH [(0) := TRUE], 
                                 (LAMBDA(i:below(N)) : IF i < N-n+1
                                                       THEN rem1(i)
                                                       ELSE FALSE
                                                       ENDIF) - dvs, n-1)
                 ELSE divrem_mem(aux1, dvs, quot1, rem1, n-1)
                 ENDIF
        ENDIF
        MEASURE n;

  % The next three results relate divrem_mem with divrem, and with div and rem.

    divrem_mem_first_second_third : LEMMA % :-)
      FORALL(n:below(N+1)) :
        LET
            drm = divrem_mem(aux, dvs, quot, rem, n),
            dr  = divrem(quot, dvs, (LAMBDA(i:below(N)) : IF i < N-n
                                                          THEN rem(i)
                                                          ELSE FALSE
                                                          ENDIF), n)
        IN 
            drm`1 = (LAMBDA(i:below(N)) : IF i < n
                                          THEN quot(N-n+i)
                                          ELSE aux(i-n)
                                          ENDIF)
              AND
            drm`2 = dr`1
              AND
            drm`3 = dr`2

    divrem_mem_rem : LEMMA % :-)
      FORALL(n:below(N+1)) :
        (LAMBDA(i:below(N)) : IF i < N-n
                              THEN rem(i)
                              ELSE FALSE
                              ENDIF) < dvs 
          IMPLIES 
        divrem_mem(aux, dvs, dvd, rem, n)`3 < dvs

    div_divrem_mem : LEMMA % :-)
      div(dvd, dvs) = divrem_mem(fill[N](FALSE), dvs, dvd, fill[N](FALSE), N)`2

    rem_divrem_mem : LEMMA % :-)
      rem(dvd, dvs) = divrem_mem(fill[N](FALSE), dvs, dvd, fill[N](FALSE), N)`3

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % The key invariant property of divrem_mem. The parameter n should be
  % interpreted as the number of cycles that still need to be performed
  % to complete the computation.
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    divrem_mem_invariant : LEMMA % :-)
      FORALL(n:below(N+1)) : 
        LET 
            start_n = (LAMBDA(i:below(N)) : IF i < n
                                            THEN quot(N-n+i)
                                            ELSE aux(i-n)
                                            ENDIF),
            quot_n =  (LAMBDA(i:below(N)) : IF i < N-n
                                            THEN quot(i)
                                            ELSE FALSE
                                            ENDIF),
            rem_n =   (LAMBDA(i:below(N)) : IF i < n
                                            THEN quot(N-n+i)
                                            ELSE rem(i-n)
                                            ENDIF),
            drm = divrem_mem(aux, dvs, quot, rem, n)
        IN
            bv2nat[N](start_n) = 
              exp2(n) * bv2nat[N](dvs) * bv2nat[N](quot_n) + bv2nat[N](rem_n)
              IMPLIES
            bv2nat[N](drm`1) = 
              bv2nat[N](dvs) * bv2nat[N](drm`2) + bv2nat[N](drm`3)

  % Key properties of div and rem, including: 
  %     (a/b)*b+(a%b) = a and a%b < b
  % The `1' in the names of the lemmas refers to the 1-complement interpretation.

    divrem1_eq : LEMMA % :-)
      bv2nat(div(dvd, dvs)) * bv2nat(dvs) + bv2nat(rem(dvd, dvs)) = bv2nat(dvd)

    rem1_below_dvs : LEMMA % :-)
      bv2nat(dvs) /= 0 IMPLIES bv2nat(rem(dvd, dvs)) < bv2nat(dvs)

    rem1_dvs0 : LEMMA % :-)
      rem(dvd, fill[N](FALSE)) = dvd

    div1_dvs0 : LEMMA % :-)
      div(dvd, fill[N](FALSE)) = fill[N](TRUE)

    div1_below_dvd : LEMMA % :-)
      bv2nat(dvs) /= 0 IMPLIES bv2nat(div(dvd, dvs)) <= bv2nat(dvd)

    divrem1_uniqueness : LEMMA % :-)
      FORALL(q,r:nat) : 
        r < bv2nat(dvs) AND q * bv2nat(dvs) + r = bv2nat(dvd)
          IMPLIES
        q = bv2nat(div(dvd, dvs)) AND r = bv2nat(rem(dvd, dvs));

    divrem1_dvs1 : LEMMA % :-)
      div(dvd, one) = dvd AND rem(dvd, one) = fill[N](FALSE)

    div1_eq0 : LEMMA % :-)
      (bv2nat(div(dvd, dvs)) = 0) = (bv2nat(dvd) < bv2nat(dvs))

  END BitvectorOneComplementDivision

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

  % Assuming TCC generated (at line 21, column 12) for
      % BitvectorMultiplication[N]
      % generated from assumption BitvectorMultiplication.N_size
  IMP_BitvectorMultiplication_TCC1: OBLIGATION N >= 2;

  % Subtype TCC generated (at line 55, column 37) for  0
      % expected type  below(N)
  divrem_TCC1: OBLIGATION
    FORALL (dvd, dvs, rem: bvec[N], n: nat):
      NOT n = 0 IMPLIES
       (FORALL (rem1: bvec[N]):
          rem1 = left_shift(1, rem) WITH [(0) := dvd(N - 1)] IMPLIES
           (FORALL (dvd1: bvec[N]):
              bv2nat[N](dvs) <= bv2nat[N](rem1) AND dvd1 = left_shift(1, dvd)
               IMPLIES 0 < N));

  % Subtype TCC generated (at line 55, column 65) for  n - 1
      % expected type  nat
  divrem_TCC2: OBLIGATION
    FORALL (dvd, dvs, rem: bvec[N], n: nat):
      NOT n = 0 IMPLIES
       (FORALL (rem1: bvec[N]):
          rem1 = left_shift(1, rem) WITH [(0) := dvd(N - 1)] IMPLIES
           (FORALL (dvd1: bvec[N]):
              bv2nat[N](dvs) <= bv2nat[N](rem1) AND dvd1 = left_shift(1, dvd)
               IMPLIES n - 1 >= 0));

  % Termination TCC generated (at line 55, column 18) for
      % divrem(dvd1 WITH [(0) := TRUE], dvs, rem1 - dvs, n - 1)
  divrem_TCC3: OBLIGATION
    FORALL (dvd, dvs, rem: bvec[N], n: nat):
      NOT n = 0 IMPLIES
       (FORALL (rem1: bvec[N]):
          rem1 = left_shift(1, rem) WITH [(0) := dvd(N - 1)] IMPLIES
           (FORALL (dvd1: bvec[N]):
              bv2nat[N](dvs) <= bv2nat[N](rem1) AND dvd1 = left_shift(1, dvd)
               IMPLIES n - 1 < n));

  % Subtype TCC generated (at line 56, column 42) for  n - 1
      % expected type  nat
  divrem_TCC4: OBLIGATION
    FORALL (dvd, dvs, rem: bvec[N], n: nat):
      NOT n = 0 IMPLIES
       (FORALL (rem1: bvec[N]):
          rem1 = left_shift(1, rem) WITH [(0) := dvd(N - 1)] IMPLIES
           (FORALL (dvd1: bvec[N]):
              NOT bv2nat[N](dvs) <= bv2nat[N](rem1) AND
               dvd1 = left_shift(1, dvd)
               IMPLIES n - 1 >= 0));

  % Termination TCC generated (at line 56, column 18) for
      % divrem(dvd1, dvs, rem1, n - 1)
  divrem_TCC5: OBLIGATION
    FORALL (dvd, dvs, rem: bvec[N], n: nat):
      NOT n = 0 IMPLIES
       (FORALL (rem1: bvec[N]):
          rem1 = left_shift(1, rem) WITH [(0) := dvd(N - 1)] IMPLIES
           (FORALL (dvd1: bvec[N]):
              NOT bv2nat[N](dvs) <= bv2nat[N](rem1) AND
               dvd1 = left_shift(1, dvd)
               IMPLIES n - 1 < n));

  % Subtype TCC generated (at line 51, column 46) for  0
      % expected type  below(N)
  divrem_TCC6: OBLIGATION FORALL (n: nat): NOT n = 0 IMPLIES 0 < N;

  % Subtype TCC generated (at line 51, column 56) for  N - 1
      % expected type  below(N)
  divrem_TCC7: OBLIGATION
    FORALL (n: nat): NOT n = 0 IMPLIES N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 73, column 33) for  k + n
      % expected type  below(N)
  divrem_dvd_TCC1: OBLIGATION
    FORALL (n: below(N + 1), k: below(N - n)): k + n < N;

  % Subtype TCC generated (at line 73, column 44) for  k
      % expected type  below(N)
  divrem_dvd_TCC2: OBLIGATION
    FORALL (n: below(N + 1), k: below(N - n)): k < N;

  % Subtype TCC generated (at line 80, column 40) for  i - n
      % expected type  below(N)
  divrem_dvs0_TCC1: OBLIGATION
    FORALL (n: below(N + 1), i: below(N)):
      NOT i < n IMPLIES i - n >= 0 AND i - n < N;

  % Subtype TCC generated (at line 84, column 40) for  N - n + i
      % expected type  below(N)
  divrem_dvs0_TCC2: OBLIGATION
    FORALL (n: below(N + 1), i: below(N)):
      i < n IMPLIES N - n + i >= 0 AND N - n + i < N;

  % Subtype TCC generated (at line 123, column 26) for  i + n
      % expected type  below(N)
  bv2nat_left_false_dec_TCC1: OBLIGATION
    FORALL (n: below(N), i: below(N)): i < N - n IMPLIES i + n < N;

  % Subtype TCC generated (at line 129, column 26) for  i + n
      % expected type  below(N)
  bv2nat_left_false_dec_TCC2: OBLIGATION
    FORALL (n: below(N), i: below(N)): i < N - n - 1 IMPLIES i + n < N;

  % Subtype TCC generated (at line 131, column 32) for  N - n - 1
      % expected type  nat
  bv2nat_left_false_dec_TCC3: OBLIGATION FORALL (n: below(N)): N - n - 1 >= 0;

  % Subtype TCC generated (at line 131, column 48) for  N - 1
      % expected type  below(N)
  bv2nat_left_false_dec_TCC4: OBLIGATION
    FORALL (n: below(N)): N - 1 >= 0 AND N - 1 < N;

  % Subtype TCC generated (at line 137, column 27) for  i + N - m
      % expected type  below(N)
  bv2nat_split_TCC1: OBLIGATION
    FORALL (m: below(N + 1), i: below(N)):
      i < m IMPLIES i + N - m >= 0 AND i + N - m < N;

  % Subtype TCC generated (at line 162, column 26) for  1 + i + n
      % expected type  below(N)
  bv2nat_left_false_minus_TCC1: OBLIGATION
    FORALL (n: below(N), i: below(N)): i < N - n - 1 IMPLIES 1 + i + n < N;

  % Subtype TCC generated (at line 168, column 52) for  N - 1
      % expected type  nat
  bv2nat_leftshift_exp_TCC1: OBLIGATION N - 1 >= 0;

  % Subtype TCC generated (at line 199, column 67) for  n - 1
      % expected type  below(1 + N)
  divrem_mem_TCC1: OBLIGATION
    FORALL (aux, dvs, quot, rem: bvec[N], n: below(N + 1)):
      NOT n = 0 IMPLIES
       (FORALL (aux1: bvec[N]):
          aux1 = left_shift(1, aux) WITH [(0) := quot(N - 1)] IMPLIES
           (FORALL (rem1: bvec[N]):
              rem1 = left_shift(1, rem) WITH [(0) := quot(N - 1)] IMPLIES
               (FORALL (quot1: bvec[N]):
                  bv2nat[N](dvs) <=
                   bv2nat[N]
                       (LAMBDA (i: below(N)):
                          IF i < N - n + 1 THEN rem1(i) ELSE FALSE ENDIF)
                   AND quot1 = left_shift(1, quot)
                   IMPLIES n - 1 >= 0 AND n - 1 < 1 + N)));

  % Termination TCC generated (at line 195, column 20) for
      % divrem_mem(aux1, dvs, quot1 WITH [(0) := TRUE],
      %            (LAMBDA (i: below(N)):
      %               IF i < N - n + 1 THEN rem1(i) ELSE FALSE ENDIF)
      %             - dvs,
      %            n - 1)
  divrem_mem_TCC2: OBLIGATION
    FORALL (aux, dvs, quot, rem: bvec[N], n: below(N + 1)):
      NOT n = 0 IMPLIES
       (FORALL (aux1: bvec[N]):
          aux1 = left_shift(1, aux) WITH [(0) := quot(N - 1)] IMPLIES
           (FORALL (rem1: bvec[N]):
              rem1 = left_shift(1, rem) WITH [(0) := quot(N - 1)] IMPLIES
               (FORALL (quot1: bvec[N]):
                  bv2nat[N](dvs) <=
                   bv2nat[N]
                       (LAMBDA (i: below(N)):
                          IF i < N - n + 1 THEN rem1(i) ELSE FALSE ENDIF)
                   AND quot1 = left_shift(1, quot)
                   IMPLIES n - 1 < n)));

  % Subtype TCC generated (at line 200, column 55) for  n - 1
      % expected type  below(1 + N)
  divrem_mem_TCC3: OBLIGATION
    FORALL (aux, dvs, quot, rem: bvec[N], n: below(N + 1)):
      NOT n = 0 IMPLIES
       (FORALL (aux1: bvec[N]):
          aux1 = left_shift(1, aux) WITH [(0) := quot(N - 1)] IMPLIES
           (FORALL (rem1: bvec[N]):
              rem1 = left_shift(1, rem) WITH [(0) := quot(N - 1)] IMPLIES
               (FORALL (quot1: bvec[N]):
                  NOT bv2nat[N](dvs) <=
                       bv2nat[N]
                           (LAMBDA (i: below(N)):
                              IF i < N - n + 1 THEN rem1(i) ELSE FALSE ENDIF)
                   AND quot1 = left_shift(1, quot)
                   IMPLIES n - 1 >= 0 AND n - 1 < 1 + N)));

  % Termination TCC generated (at line 200, column 20) for
      % divrem_mem(aux1, dvs, quot1, rem1, n - 1)
  divrem_mem_TCC4: OBLIGATION
    FORALL (aux, dvs, quot, rem: bvec[N], n: below(N + 1)):
      NOT n = 0 IMPLIES
       (FORALL (aux1: bvec[N]):
          aux1 = left_shift(1, aux) WITH [(0) := quot(N - 1)] IMPLIES
           (FORALL (rem1: bvec[N]):
              rem1 = left_shift(1, rem) WITH [(0) := quot(N - 1)] IMPLIES
               (FORALL (quot1: bvec[N]):
                  NOT bv2nat[N](dvs) <=
                       bv2nat[N]
                           (LAMBDA (i: below(N)):
                              IF i < N - n + 1 THEN rem1(i) ELSE FALSE ENDIF)
                   AND quot1 = left_shift(1, quot)
                   IMPLIES n - 1 < n)));

  % Subtype TCC generated (at line 235, column 73) for  N
      % expected type  below(1 + N)
  div_divrem_mem_TCC1: OBLIGATION N < 1 + N;


body:
  %
  %  BitvectorTwoComplementDivision
  %  ==============================
  %
  %  for Translating Java Classes into the Higher Order Logic of PVS.
  %
  %  All integral types are interpreted as PVS integers, without 
  %  taking bounds into account
  %
  %  Author: Bart Jacobs
  %  Integrated with the bitvector library by Sam Owre <owre@csl.sri.com>

  BitvectorTwoComplementDivision[N:posnat] : THEORY
  BEGIN

    ASSUMING
       N_size: ASSUMPTION N >= 2
    ENDASSUMING

    IMPORTING BitvectorOneComplementDivision[N],
              BitvectorOneComplementDivision[2*N],
              BitvectorMultiplicationWidenNarrow[N]

    dvd, dvs, bv : VAR bvec[N]
    DVD, DVS, BV : VAR bvec[2*N]

  % First some additional results about one-complement division,
  % requiring parameter 2*N.

    DIVREM1_eq : LEMMA % :-)
      div(DVD, DVS) * DVS + rem(DVD, DVS) = DVD

    div1_cancel : LEMMA % :-)
      bv2nat(BV) * bv2nat(DVD) < exp2(2*N)
        AND
      bv2nat(BV) * bv2nat(DVS) < exp2(2*N)
        AND
      bv2nat(BV) /= 0
        IMPLIES
      div(BV * DVD, BV * DVS) = div(DVD, DVS)
        AND
      (bv2nat(DVS) /= 0 IMPLIES 
         rem(BV * DVD, BV * DVS) = BV * rem(DVD, DVS));

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % Definitions for 2-complement interpretation
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    /(dvd, dvs) : bvec[N] =
      IF bv2int[N](dvd) >= 0
      THEN IF bv2int[N](dvs) >= 0
           THEN div[N](dvd, dvs)
           ELSE -div[N](dvd, -dvs)
           ENDIF
      ELSE IF bv2int[N](dvs) >= 0
           THEN -div[N](-dvd, dvs)
           ELSE div[N](-dvd, -dvs)
           ENDIF
      ENDIF;

    //(dvd, dvs) : bvec[N] =
      IF bv2int[N](dvd) >= 0
      THEN IF bv2int[N](dvs) >= 0
           THEN rem[N](dvd, dvs)
           ELSE rem[N](dvd, -dvs)
           ENDIF
      ELSE IF bv2int[N](dvs) >= 0
           THEN -rem[N](-dvd, dvs)
           ELSE -rem[N](-dvd, -dvs)
           ENDIF
      ENDIF

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % Below the relevant texts from the Java Language Specification (2nd ed.)
  % are included. All the stated properties about divisition and remainder
  % are proven below (plus of few more, like divrem_widens).
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % JLS 15.17.2 Division Operator
  %
  % The binary / operator performs division, producing the quotient of its
  % operands. The left-hand operand is the dividend and the right-hand
  % operand is the divisor. Integer division rounds toward 0. That is, the
  % quotient produced for operands n and d that are integers after binary
  % numeric promotion (§5.6.2) is an integer value q whose magnitude is as
  % large as possible while satisfying |d * q| <= |n|; moreover, q is
  % positive when and n and d have the same sign, but q is negative when
  % and n and d have opposite signs. There is one special case that does
  % not satisfy this rule: if the dividend is the negative integer of
  % largest possible magnitude for its type, and the divisor is -1, then
  % integer overflow occurs and the result is equal to the
  % dividend. Despite the overflow, no exception is thrown in this
  % case. On the other hand, if the value of the divisor in an integer
  % division is 0, then an ArithmeticException is thrown. 
  %
  %
  % JLS 15.17.3 Remainder Operator 
  %
  % The binary % operator is said to yield the remainder of its operands
  % from an implied division; the left-hand operand is the dividend and
  % the right-hand operand is the divisor. In C and C++, the remainder
  % operator accepts only integral operands, but in the Java programming
  % language, it also accepts floating-point operands. The remainder
  % operation for operands that are integers after binary numeric
  % promotion (§5.6.2) produces a result value such that (a/b)*b+(a%b) is
  % equal to a. This identity holds even in the special case that the
  % dividend is the negative integer of largest possible magnitude for its
  % type and the divisor is -1 (the remainder is 0). It follows from this
  % rule that the result of the remainder operation can be negative only
  % if the dividend is negative, and can be positive only if the dividend
  % is positive; moreover, the magnitude of the result is always less than
  % the magnitude of the divisor. If the value of the divisor for an
  % integer remainder operator is 0, then an ArithmeticException is
  % thrown. 
  %
  % Examples: 
  %	5%3 produces 2 (note that 5/3 produces 1) 
  %	5%(-3) produces 2 (note that 5/(-3) produces -1) 
  %	(-5)%3 produces -2 (note that (-5)/3 produces -1) 
  %	(-5)%(-3) produces -2 (note that (-5)/(-3) produces 1) 
  %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


  %  div_minus_dvd : LEMMA
  %    (-dvd) / dvs = -(dvd / dvs)

    rem_dvs0 : LEMMA % :-)
      dvd // fill[N](FALSE) = dvd

    div_dvs0 : LEMMA % :-)
      dvd / fill[N](FALSE) = IF bv2int[N](dvd) >= 0
                             THEN fill[N](TRUE)  % -1
                             ELSE one[N]         % 1
                             ENDIF

    divrem_dvs1 : LEMMA % :-)
      dvd / one = dvd AND dvd // one = fill[N](FALSE)

    rem_below_dvs : LEMMA % :-)
      bv2int(dvs) /= 0
        IMPLIES
      abs(bv2int(dvd // dvs)) < abs(bv2int(dvs))

    divrem_eq : LEMMA % :-)
      NOT (bv2int(dvd) = -exp2(N-1) AND bv2int(dvs) = -1)
        IMPLIES
      bv2int[N](dvd / dvs) * bv2int[N](dvs) + bv2int[N](dvd // dvs) 
        = bv2int[N](dvd)

    divrem_overflow : LEMMA % :-)
      bv2int(dvd) = -exp2(N-1) AND bv2int(dvs) = -1
        IMPLIES
      bv2int[N](dvd / dvs) = -exp2(N-1) AND bv2int[N](dvd // dvs) = 0

    div_sgn : LEMMA % :-)
      NOT (bv2int(dvd) = -exp2(N-1) AND bv2int(dvs) = -1)
        AND
      bv2int(dvs) /= 0
        IMPLIES
      ((bv2int(dvd / dvs) > 0) = 
          ((bv2int(dvd) >= bv2int(dvs) AND bv2int(dvs) > 0)
           OR
           (bv2int(dvd) <= bv2int(dvs) AND bv2int(dvs) < 0)))
        AND
      ((bv2int(dvd / dvs) = 0) = 
          (abs(bv2int(dvd)) < abs(bv2int(dvs))))
        AND
      ((bv2int(dvd / dvs) < 0) = 
          ((bv2int(dvd) >= -bv2int(dvs) AND bv2int(dvs) < 0)
           OR
           (bv2int(dvd) <= -bv2int(dvs) AND bv2int(dvs) > 0)))

    rem_sgn : LEMMA % :-)
      ((bv2int(dvd) > 0) IMPLIES (bv2int(dvd // dvs) >= 0))
         AND
      ((bv2int(dvd) < 0) IMPLIES (bv2int(dvd // dvs) <= 0))

    divrem_uniqueness : LEMMA % :-)
      FORALL(q,r:int) : 
        (NOT (bv2int(dvd) = -exp2(N-1) AND bv2int(dvs) = -1))
          AND
        bv2int(dvs) /= 0
          AND
        ((q > 0) = 
          ((bv2int(dvd) >= bv2int(dvs) AND bv2int(dvs) > 0)
           OR
           (bv2int(dvd) <= bv2int(dvs) AND bv2int(dvs) < 0)))
          AND
        ((q = 0) = 
           (abs(bv2int(dvd)) < abs(bv2int(dvs))))
          AND
        ((q < 0) = 
           ((bv2int(dvd) >= -bv2int(dvs) AND bv2int(dvs) < 0)
            OR
            (bv2int(dvd) <= -bv2int(dvs) AND bv2int(dvs) > 0)))
          AND
        ((bv2int(dvd) > 0) IMPLIES (r >= 0))
          AND
        ((bv2int(dvd) < 0) IMPLIES (r <= 0))
          AND
        abs(r) < abs(bv2int(dvs)) 
          AND 
        q * bv2int(dvs) + r = bv2int(dvd)
          IMPLIES
        q = bv2int(dvd / dvs) AND r = bv2int(dvd // dvs)


  % from JLS: division ... is an integer value q whose magnitude is as
  % large as possible while satisfying |d * q| <= |n|

    div_largest : LEMMA % :-)
      FORALL(q:int) : 
        bv2int(dvs) /= 0
          AND
        abs(bv2int(dvs) * q) <= abs(bv2int(dvd)) 
          IMPLIES 
        abs(q) <= abs(bv2int(dvd/dvs))

  END BitvectorTwoComplementDivision

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

  % Assuming TCC generated (at line 20, column 12) for
      % BitvectorOneComplementDivision[N]
      % generated from assumption BitvectorOneComplementDivision.N_size
  IMP_BitvectorOneComplementDivision_TCC1: OBLIGATION N >= 2;

  % Assuming TCC generated (at line 21, column 12) for
      % BitvectorOneComplementDivision[2 * N]
      % generated from assumption BitvectorOneComplementDivision.N_size
  IMP_BitvectorOneComplementDivision_TCC2: OBLIGATION 2 * N >= 2;

  % Subtype TCC generated (at line 155, column 29) for  N - 1
      % expected type  nat
  divrem_eq_TCC1: OBLIGATION N - 1 >= 0;


body:
  %
  %  BitvectorTwoComplementDivisionWidenNarrow
  %  =========================================
  %
  %  for Translating Java Classes into the Higher Order Logic of PVS.
  %
  %  All integral types are interpreted as PVS integers, without 
  %  taking bounds into account
  %
  %  Author: Bart Jacobs
  %  Integrated with the bitvector library by Sam Owre <owre@csl.sri.com>

  BitvectorTwoComplementDivisionWidenNarrow[N:posnat] : THEORY
  BEGIN

    ASSUMING
       N_size: ASSUMPTION N >= 2
    ENDASSUMING

    IMPORTING BitvectorTwoComplementDivision[N],
              BitvectorTwoComplementDivision[2*N]

    dvd, dvs, bv : VAR bvec[N]
    DVD, DVS, BV : VAR bvec[2*N]

    DIVREM_eq : LEMMA % :-)
      (DVD / DVS) * DVS + (DVD // DVS) = DVD

    divrem_widens : LEMMA % :-)
      NOT (bv2int(dvd) = -exp2(N-1) AND bv2int(dvs) = -1)
        IMPLIES
      widen(dvd) / widen(dvs) = widen(dvd / dvs)
        AND
      widen(dvd) // widen(dvs) = widen(dvd // dvs)

    div_cancel : LEMMA % :-)
     -exp2(2*N-1) < bv2int(BV) * bv2int(DVD) 
       AND 
      bv2int(BV) * bv2int(DVD) < exp2(2*N-1)
        AND
     -exp2(2*N-1) < bv2int(BV) * bv2int(DVS) 
       AND 
      bv2int(BV) * bv2int(DVS) < exp2(2*N-1)
        AND
      bv2int(BV) /= 0
        AND
      bv2int(DVS) /= 0
        AND
      NOT (bv2int(DVD) = -exp2(2 * N - 1) AND bv2int(DVS) = -1)
        IMPLIES
      (BV * DVD) / (BV * DVS) = DVD / DVS
        AND
      (BV * DVD) // (BV * DVS) = BV * (DVD // DVS)

  END BitvectorTwoComplementDivisionWidenNarrow

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

  % Assuming TCC generated (at line 20, column 12) for
      % BitvectorTwoComplementDivision[N]
      % generated from assumption BitvectorTwoComplementDivision.N_size
  IMP_BitvectorTwoComplementDivision_TCC1: OBLIGATION N >= 2;

  % Assuming TCC generated (at line 21, column 12) for
      % BitvectorTwoComplementDivision[2 * N]
      % generated from assumption BitvectorTwoComplementDivision.N_size
  IMP_BitvectorTwoComplementDivision_TCC2: OBLIGATION 2 * N >= 2;

  % Subtype TCC generated (at line 30, column 29) for  N - 1
      % expected type  nat
  divrem_widens_TCC1: OBLIGATION N - 1 >= 0;

  % Subtype TCC generated (at line 37, column 9) for  2 * N - 1
      % expected type  nat
  div_cancel_TCC1: OBLIGATION 2 * N - 1 >= 0;


body:
  %
  %  JAVA BITVECTOR INTEGRALS
  %  ========================
  %
  %  for Translating Java Classes into the Higher Order Logic of PVS.
  %
  %  All integral types are interpreted as PVS integers, without 
  %  taking bounds into account
  %
  %  Author: Bart Jacobs
  %  Started: Wednesday 24 May 00 10:59:26 bart@frustratie
  %  Last-modified: $Date$
  %  Last-modified by: $Author$


  bv_mult_div_rem: THEORY
  BEGIN
    IMPORTING BitvectorUtil, BitvectorMultiplication,
              BitvectorMultiplicationWidenNarrow, DivisionUtil,
              BitvectorOneComplementDivision, BitvectorTwoComplementDivision,
              BitvectorTwoComplementDivisionWidenNarrow
   END bv_mult_div_rem


body:
  %------------------------------------------------------------------------
  %
  %  Top of finite sets theory   Version 2.2    5/22/97
  %  --------------------------------------------------------------
  %      Authors: Ricky W. Butler   NASA Langley Research Center
  %               Bruno Dutertre    Royal Holloway & Bedford New College
  %               Damir Jamsek      Odyssey Research Associates
  %               Sam Owre          SRI International
  %               David Griffioen   CWI and KUN (Catholic University 
  %                                 Nijmegen), the Netherlands.
  %   
  %      Index:
  %      ------
  %        finite_sets            -- main theory that is imported
  %                                  (provides basic type and cardinality)
  %        finite_sets_sum        -- summation over a set
  %        finite_sets_minmax     -- min and max over a set
  %        finite_sets_inductions -- induction schemes
  %        finite_sets_sum_real   -- additional properties for summations
  %                                  over real-valued functions
  %        finite_sets_int        -- special properties of integer sets
  %        finite_sets_nat        -- special properties of natural sets
  %        finite_sets_pred       -- lemmas involving predicate subtypes
  %        finite_sets_below      -- lemmas involving sets of below and upto
  %        finite_sets_eq         -- lemmas to show set is finite via mappings
  %        finite_sets_card_eq    -- equal cardinality of two dissimilar sets
  %        finite_sets_rules      -- experimental AUTO-REWRITE-THEORY rules
  %        finite_sets_minmax_props -- properties of min and max of finite sets
  %        finite_cross           -- cartesian product of finite sets is finite
  %        fs_constructors,       -- constructors for one, two, three element sets
  %        finite_sets_product,   -- product over finite sets
  %        finite_sets_product_real, -- product over finite sets of reals
  %        card_tricks,              -- more lemmas about card
  %        finite_sets_subtype_props

  %
  %  This theory was designed for making libraries and is not intended
  %  for importing.  One should directly import one of the above listed
  %  theories.
  %
  %------------------------------------------------------------------------
  top: THEORY
  BEGIN

    IMPORTING finite_sets, 
              finite_sets_sum, 
              finite_sets_minmax, 
              finite_sets_inductions,
              finite_sets_sum_real, 
              finite_sets_int, 
              finite_sets_nat, 
              finite_sets_pred,
              finite_sets_below, 
              finite_sets_card_eq, 
              finite_sets_eq,
              finite_sets_minmax_props, 
              finite_cross, 
              fs_constructors,
              finite_sets_product,
              finite_sets_product_real,
              card_tricks,
              finite_sets_subtype_props


  END top


body:
  card_tricks  [ T: TYPE, S: TYPE FROM T ] : THEORY
  %-------------------------------------------------------------------------------
  %
  %   AUTHOR: Ben Di Vito     NASA Langley
  %-------------------------------------------------------------------------------
  BEGIN

    U:   VAR set[S]
    V:   VAR set[T]
    A:   VAR finite_set[S]
    B:   VAR finite_set[T]
    m,n: VAR nat
    x,y: VAR T

    subtype_full?: LEMMA full?[(U)](U)

    subtype_fullset: LEMMA fullset[(U)] = U

    non_subtype_elements(V): set[T] =
        difference(V, extend[T, S, boolean, FALSE](fullset[S]))

    extend_restrict: LEMMA
        empty?(non_subtype_elements(V))
        IMPLIES extend[T, S, boolean, FALSE](restrict[T, S, boolean](V)) = V

    union_extend_restrict: LEMMA
        union(non_subtype_elements(V),
              extend[T, S, boolean, FALSE](restrict[T, S, boolean](V)))
        = V

    disjoint_extend_restrict: LEMMA
        disjoint?(non_subtype_elements(V),
                  extend[T, S, boolean, FALSE](restrict[T, S, boolean](V)))

    card_restrict_subtype: LEMMA
        empty?(non_subtype_elements(B))
        IMPLIES card(restrict[T, S, boolean](B)) = card(B)

    same_card_subset_extend: LEMMA
        subset?(extend[T, S, boolean, FALSE](A), B) AND card(A) = card(B) 
        IMPLIES extend[T, S, boolean, FALSE](A) = B

    card_restrict_plus: LEMMA
        card(non_subtype_elements(B)) + card(restrict[T, S, boolean](B))
        = card(B)

    card_restrict_less: LEMMA
        nonempty?(non_subtype_elements(B))
        IMPLIES card(restrict[T, S, boolean](B)) < card(B)


  END card_tricks

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

  % Subtype TCC generated (at line 44, column 11) for  non_subtype_elements(B)
      % expected type  S: finite_set[T]
  card_restrict_plus_TCC1: OBLIGATION
    FORALL (B: finite_set[T]): is_finite[T](non_subtype_elements(B));


body:
  finite_sets_subtype_props  [ T1, T2: TYPE ] : THEORY
  %-------------------------------------------------------------------------------
  %
  %   AUTHOR: Ben Di Vito     NASA Langley
  %-------------------------------------------------------------------------------
  BEGIN

    IMPORTING card_tricks

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

    only_subtype_elements: LEMMA empty?(non_subtype_elements[T1, (A)](A)) AND
                                 empty?(non_subtype_elements[T2, (B)](B))

    same_card_inj_bij: LEMMA
        FORALL (f: [ (A) -> (B) ]):
     	  card(A) = card(B) AND injective?(f) IMPLIES bijective?(f)

  END finite_sets_subtype_props 


body:
  finite_sets_inductions[T: TYPE]: THEORY

  BEGIN

    IMPORTING finite_sets[T]

    S, S1, S2 : VAR finite_set
    SS,U : VAR non_empty_finite_set
    e : VAR T
    P : VAR pred[finite_set]
    Q : VAR pred[non_empty_finite_set]
    n : VAR nat

    cardinal_induction       : LEMMA (FORALL S : P(S)) IFF 
                                        (FORALL n, S : card(S) = n IMPLIES P(S)) 

    finite_set_induction     : THEOREM P(emptyset[T])
                                        AND (FORALL e,S: P(S) IMPLIES P(add(e,S)))
                                           IMPLIES (FORALL S: P(S))

    finite_set_ind_modified  : THEOREM  P(emptyset[T]) AND 
                               (FORALL e,S: NOT S(e) AND P(S) IMPLIES P(add(e,S)))
                                         IMPLIES (FORALL S: P(S))

    finite_set_induction_rest: THEOREM P(emptyset[T])
                                       AND (FORALL SS : P(rest(SS)) IMPLIES P(SS))
                                               IMPLIES (FORALL S : P(S))

    finite_set_induction_union: THEOREM P(emptyset[T])
                                        AND (FORALL e: P(singleton(e)))
                    AND (FORALL S1,S2: P(S1) AND P(S2) IMPLIES P(union(S1,S2)))
                                       IMPLIES (FORALL S: P(S))


    finite_set_induction_gen: THEOREM (FORALL S:
                                   (FORALL S2: card(S2) < card(S) IMPLIES P(S2))
                                                  IMPLIES P(S))
                                    IMPLIES (FORALL S: P(S))


  % -------- Induction rules for non empty sets ----------------


    nonempty_card_induction : LEMMA (FORALL U : Q(U)) IFF 
  	                      (FORALL S, n : n > 0 AND card(S) = n IMPLIES Q(S))

    nonempty_finite_set_induct : THEOREM (FORALL e : Q(singleton(e)))
         AND (FORALL e, U : Q(U) AND NOT U(e) IMPLIES Q(add(e, U)))
                                          IMPLIES (FORALL U : Q(U))

  END finite_sets_inductions

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

  % Subtype TCC generated (at line 45, column 70) for  S
      % expected type  non_empty_finite_set[T]
  nonempty_card_induction_TCC1: OBLIGATION
    FORALL (S, n): n > 0 AND card(S) = n IMPLIES NOT empty?[T](S);


body:
  finite_sets_product[T, R: TYPE, one:R, *:[R,R -> R] ]: THEORY
  %----------------------------------------------------------------------
  %  
  %                                      ----
  %                                      |  |    
  %  sum(S: finite_set[T], f:[T->R]) =   |  |  f(i) 
  %                                      |  |
  %                                      member(i,S)
  %  
  %----------------------------------------------------------------------
  BEGIN

    ASSUMING
       r,r1,r2,r3 : VAR R
       one_identity: ASSUMPTION identity?(*)(one)
       mult_ac:       ASSUMPTION associative?(*) AND commutative?(*)
    ENDASSUMING

    mult_one_right: LEMMA r * one = r 
    mult_one_left : LEMMA one* r = r
    mult_assoc     : LEMMA (r1 * r2) * r3 = r1 * (r2 * r3) 
    mult_comm      : LEMMA r1 * r2 = r2 * r1

    IMPORTING finite_sets_inductions[T], sets_lemmas[T]

    f,g: VAR [T -> R]
    S, A, B: VAR finite_set
    x: VAR T

    product(S,f) : RECURSIVE R = 
      IF (empty?(S)) THEN one
      ELSE f(choose(S)) * product(rest(S),f)
      ENDIF MEASURE (LAMBDA S,f: card(S))

    product_emptyset  : THEOREM product(emptyset[T],f) = one

    product_singleton : THEOREM product(singleton(x),f) = f(x);

    product_x         : THEOREM (FORALL (x: (S)): 
                                product(S, f) = f(x) * product(remove(x, S), f))

    product_x1_x2     : LEMMA (FORALL (x1,x2: (S)): f(x1) * product(remove(x1,S),f) 
                                = f(x2) * product(remove(x2,S),f))

    product_add       : THEOREM product(add(x,S),f) 
                            = product(S,f) * IF member(x,S) THEN one ELSE f(x) ENDIF

    product_remove    : THEOREM product(remove(x,S),f) 
                            * IF member(x,S) THEN f(x) ELSE one ENDIF = product(S,f)

    product_rest      : THEOREM NOT empty?(S) IMPLIES
                              f(choose(S)) * product(rest(S),f) = product(S,f)
   
    product_disj_union: THEOREM disjoint?(A,B) IMPLIES 
                              product(union(A,B),f) = product(A,f) * product(B,f) 

    product_diff_subset: THEOREM subset?(A, B) IMPLIES 
  		            product(difference(B, A), f) * product(A, f) = product(B, f) 

    product_union      : THEOREM product(union(A,B),f) * product(intersection(A,B),f) 
                                   = product(A,f) * product(B,f) 

    product_diff_intersection: THEOREM product(A,f) = 
                              product(difference(A,B),f) * product(intersection(A,B),f) 

    product_f_g         : LEMMA (FORALL (x: (S)): f(x) = g(x)) 
                                 IMPLIES product(S, f) = product(S, g)

    product_particular  : THEOREM product(S,f) = product(S, f WITH [x := one])
  			       * IF S(x) THEN f(x) ELSE one ENDIF 

    product_distributive: THEOREM product(A,f) * product(A,g) = 
                                  product(A,(LAMBDA x: f(x) * g(x))) 

  END finite_sets_product

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

  % Subtype TCC generated (at line 32, column 18) for  S
      % expected type  p: (nonempty?[T])
  product_TCC1: OBLIGATION
    FORALL (S: finite_set[T], f: [T -> R]):
      NOT (empty?(S)) IMPLIES nonempty?[T](S);

  % Termination TCC generated (at line 32, column 24) for  product(rest(S), f)
  product_TCC2: OBLIGATION
    FORALL (S: finite_set[T], f: [T -> R]):
      NOT (empty?(S)) IMPLIES card[T](rest[T](S)) < card[T](S);

  % Subtype TCC generated (at line 52, column 37) for  S
      % expected type  p: (nonempty?[T])
  product_rest_TCC1: OBLIGATION
    FORALL (S: finite_set[T]): NOT empty?(S) IMPLIES nonempty?[T](S);


body:
  finite_sets_product_real[T: TYPE]: THEORY
  %------------------------------------------------------------------------
  %
  % finite product over real-valued functions   
  %
  %   Authors: Ricky W. Butler
  %            David Griffioen
  %
  %   NOTES:
  %      -- there are several theorems which are virtually idential to
  %         theorems in finite_sets_product.  They are repeated here to prevent
  %         the need for commands such as (LEMMA product_emptyset[T,real,1,*])
  %      -- the theorems with names ending in "_rew" are especially useful
  %         for rewriting.  Some of these take advantage of the fact that
  %         since we have real-valued functions we have a "-" available.
  %------------------------------------------------------------------------
  BEGIN


    IMPORTING finite_sets_product[T,real,1,*]    %% prelude_aux

    S, A, B: VAR finite_set[T]
    t: VAR T
    c,N: VAR real
    cnz: VAR nzreal
    f,g: VAR function[T -> real]

    SS: VAR non_empty_finite_set[T]

    product_const        : THEOREM product(S, (LAMBDA t: c)) = c^card(S) 

    product_1_is_card    : COROLLARY product(S,(LAMBDA t: 1)) = 1

    product_mult         : THEOREM product(S,(LAMBDA t: c*f(t))) = c^card(S)*product(S,f) 


    product_eq_0        : THEOREM product(S,f) = 0 IMPLIES  
                                            (EXISTS (t:(S)): f(t) = 0)



  % ----------- Some rewrite rules using "-" ------------------

    product_empty?       : THEOREM empty?(S) IMPLIES product(S,f) = 1

    product_emptyset_rew : THEOREM S = emptyset[T] IMPLIES product(S,f) = 1

    product_singleton_rew: THEOREM card(S) = 1 AND S(t) IMPLIES product(S,f) = f(t)

    product_remove_rew   : THEOREM f(t) /= 0 IMPLIES 
                            product(remove(t,S),f) = product(S,f) /
                                  IF S(t) THEN f(t) ELSE 1 ENDIF 

    product_rest_rew     : THEOREM NOT empty?(S) AND f(choose(S)) /= 0 IMPLIES
                                  product(rest(S),f) = product(S,f) / f(choose(S))

    product_union_rew    : THEOREM product(union(A,B),f)*product(intersection(A,B),f) 
                                    = product(A,f) * product(B,f)

  % -------- products of slightly modified functions ----------

    product_eq_funs       : THEOREM (FORALL (t: (S)): f(t) = g(t)) 
                                 IMPLIES product(S, f) = product(S, g)

    product_particular_gen: THEOREM product(S,f) = product(S, f WITH [t := cnz])
  			       * IF S(t) THEN f(t)/cnz ELSE 1 ENDIF 


  % ----- some order relationships involving product -----

    product_nonneg   : LEMMA (FORALL (t: (S)): f(t) >= 0) IMPLIES product(S,f) >= 0

    product_pos      : LEMMA (FORALL (t: (S)): f(t) > 0) IMPLIES product(S,f) > 0 OR
                                                      S = emptyset[T]

    product_nz       : LEMMA (FORALL (t: (SS)): f(t) /= 0) IMPLIES product(SS,f) /= 0 

    product_posreal: JUDGEMENT product(A: non_empty_finite_set[T], f: [T -> posreal])
              HAS_TYPE posreal

    product_int: JUDGEMENT product(A: finite_set[T], f: [T -> int]) HAS_TYPE int

    product_nat: JUDGEMENT product(A: finite_set[T], f: [T -> nat]) HAS_TYPE nat

  % ----- Special properties non-negative valued functions -----

    fnr,gnr: VAR [T -> nonneg_real]

    Fnat:  VAR function[T -> nat]

    product_eq_1        : THEOREM product(S,Fnat) = 1 IMPLIES  
                                            (FORALL (t:(S)): Fnat(t) = 1)


  % ----- Special properties positive valued functions -----

  %  Fposnat: VAR [T -> posnat]
  %  product_subset   : THEOREM subset?(A,B) IMPLIES product(A,Fposnat) <= product(B,Fposnat)


    JUDGEMENT product(A: finite_set[T], f: [T -> nonneg_real])
              HAS_TYPE nonneg_real
    JUDGEMENT product(A: finite_set[T], f: [T -> nonneg_int]) HAS_TYPE nonneg_int
    JUDGEMENT product(A: non_empty_finite_set[T], f: [T->posnat]) HAS_TYPE posnat

  %  JUDGEMENT product(A: non_empty_finite_set[T], f: [T->negreal]) HAS_TYPE negreal
  %  JUDGEMENT product(A: finite_set[T], f: [T -> nonpos_real]) HAS_TYPE nonpos_real
  %  JUDGEMENT product(A: finite_set[T], f: [T -> negint]) HAS_TYPE negint

  END finite_sets_product_real

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

  % Assuming TCC generated (at line 20, column 12) for
      % finite_sets_product
      %     [T, real, 1,
      %      restrict[[numfield, numfield], [real, real], numfield](*)]
      % generated from assumption finite_sets_product.one_identity
  IMP_finite_sets_product_TCC1: OBLIGATION
    identity?[real]
        (restrict[[numfield, numfield], [real, real], numfield](*))(1);

  % Assuming TCC generated (at line 20, column 12) for
      % finite_sets_product
      %     [T, real, 1,
      %      restrict[[numfield, numfield], [real, real], numfield](*)]
      % generated from assumption finite_sets_product.mult_ac
  IMP_finite_sets_product_TCC2: OBLIGATION
    associative?[real]
        (restrict[[numfield, numfield], [real, real], numfield](*))
     AND
     commutative?[real]
         (restrict[[numfield, numfield], [real, real], numfield](*));

  % Subtype TCC generated (at line 30, column 63) for  card(S)
      % expected type  {i: int | c /= 0 OR i >= 0}
  product_const_TCC1: OBLIGATION
    FORALL (S: finite_set[T], c: real): c /= 0 OR card[T](S) >= 0;

  % Subtype TCC generated (at line 54, column 60) for  S
      % expected type  p: (nonempty?[T])
  product_rest_rew_TCC1: OBLIGATION
    FORALL (S: finite_set[T]): NOT empty?(S) IMPLIES nonempty?[T](S);

  % Judgement subtype TCC generated (at line 78, column 29) for  product(A, f)
      % expected type  posreal
  product_posreal: OBLIGATION
    FORALL (A: non_empty_finite_set[T], f: [T -> posreal]):
      product
          [T, real, 1,
           restrict[[numfield, numfield], [real, real], numfield](*)]
          (A, f)
       >= 0
       AND
       product
           [T, real, 1,
            restrict[[numfield, numfield], [real, real], numfield](*)]
           (A, f)
        > 0;

  % Judgement subtype TCC generated (at line 81, column 25) for  product(A, f)
      % expected type  int
  product_int: OBLIGATION
    FORALL (A: finite_set[T], f: [T -> int]):
      rational_pred(product
                        [T, real, 1,
                         restrict
                             [[numfield, numfield], [real, real], numfield]
                             (*)]
                        (A, f))
       AND
       integer_pred(product
                        [T, real, 1,
                         restrict
                             [[numfield, numfield], [real, real], numfield]
                             (*)]
                        (A, f));

  % Judgement subtype TCC generated (at line 83, column 25) for  product(A, f)
      % expected type  nat
  product_nat: OBLIGATION
    FORALL (A: finite_set[T], f: [T -> nat]):
      product
          [T, real, 1,
           restrict[[numfield, numfield], [real, real], numfield](*)]
          (A, f)
       >= 0;

  % Judgement subtype TCC generated (at line 101, column 12) for  product(A, f)
      % expected type  nonneg_real
  product_TCC1: OBLIGATION
    FORALL (A: finite_set[T], f: [T -> nonneg_real]):
      product
          [T, real, 1,
           restrict[[numfield, numfield], [real, real], numfield](*)]
          (A, f)
       >= 0;

  % Judgement subtype TCC generated (at line 104, column 12) for  product(A, f)
      % expected type  posnat
  product_TCC2: OBLIGATION
    FORALL (A: non_empty_finite_set[T], f: [T -> posnat]):
      product
          [T, real, 1,
           restrict[[numfield, numfield], [real, real], numfield](*)]
          (A, f)
       > 0;


body:
  fs_constructors[T: TYPE]: THEORY
  BEGIN

    a1,a2,a3,a4,a5: VAR T

    fs(a1): non_empty_finite_set[T] = {t:T | t = a1}

    fs(a1,a2): non_empty_finite_set[T] = {t:T | t = a1 OR t = a2}

    fs(a1,a2,a3): non_empty_finite_set[T] = {t:T | t = a1 OR t = a2 OR t = a3}

    fs(a1,a2,a3,a4): non_empty_finite_set[T] = {t:T | t = a1 OR t = a2 OR t = a3 OR t = a4}

    fs(a1,a2,a3,a4,a5): non_empty_finite_set[T] 
       = {t:T | t = a1 OR t = a2 OR t = a3 OR t = a4 OR t = a5}


  END fs_constructors

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

  % Subtype TCC generated (at line 6, column 36) for  {t: T | t = a1}
      % expected type  non_empty_finite_set[T]
  fs_TCC1: OBLIGATION
    FORALL (a1: T):
      is_finite[T]({t: T | t = a1}) AND NOT empty?[T]({t: T | t = a1});

  % Subtype TCC generated (at line 8, column 39) for
      % {t: T | t = a1 OR t = a2}
      % expected type  non_empty_finite_set[T]
  fs_TCC2: OBLIGATION
    FORALL (a1: T, a2: T):
      is_finite[T]({t: T | t = a1 OR t = a2}) AND
       NOT empty?[T]({t: T | t = a1 OR t = a2});

  % Subtype TCC generated (at line 10, column 42) for
      % {t: T | t = a1 OR t = a2 OR t = a3}
      % expected type  non_empty_finite_set[T]
  fs_TCC3: OBLIGATION
    FORALL (a1: T, a2: T, a3: T):
      is_finite[T]({t: T | t = a1 OR t = a2 OR t = a3}) AND
       NOT empty?[T]({t: T | t = a1 OR t = a2 OR t = a3});

  % Subtype TCC generated (at line 12, column 45) for
      % {t: T | t = a1 OR t = a2 OR t = a3 OR t = a4}
      % expected type  non_empty_finite_set[T]
  fs_TCC4: OBLIGATION
    FORALL (a1: T, a2: T, a3: T, a4: T):
      is_finite[T]({t: T | t = a1 OR t = a2 OR t = a3 OR t = a4}) AND
       NOT empty?[T]({t: T | t = a1 OR t = a2 OR t = a3 OR t = a4});

  % Subtype TCC generated (at line 15, column 7) for
      % {t: T |     t = a1 OR t = a2 OR t = a3 OR t = a4 OR t = a5}
      % expected type  non_empty_finite_set[T]
  fs_TCC5: OBLIGATION
    FORALL (a1: T, a2: T, a3: T, a4: T, a5: T):
      is_finite[T]
          ({t: T |     t = a1 OR t = a2 OR t = a3 OR t = a4 OR t = a5})
       AND
       NOT empty?[T]
               ({t: T |     t = a1 OR t = a2 OR t = a3 OR t = a4 OR t = a5});


body:
  % proof that the cartesian product of two finite sets is finite
  %
  % Author: Alfons Geser, National Institute of Aerospace

  finite_cross[T1, T2: TYPE]: THEORY

  BEGIN

    X: VAR set[T1]
    Y: VAR set[T2]

    is_finite_cross: LEMMA is_finite_type[T1] AND is_finite_type[T2] 
                              IMPLIES is_finite_type[[T1,T2]]

  END finite_cross


body:
  finite_sets_minmax[T: TYPE, <= : (total_order?[T])]: THEORY
  BEGIN

    IMPORTING  finite_sets_inductions[T]

    fsmin(x,y:T): T = IF x <= y THEN x ELSE y ENDIF
    fsmax(x,y:T): T = IF x <= y THEN y ELSE x ENDIF

    a,x,y: VAR T
    SS: VAR non_empty_finite_set

    minrec(SS): RECURSIVE T = 
                  IF empty?(rest(SS)) THEN choose(SS)
                  ELSE fsmin(choose(SS),minrec(rest(SS)))
                  ENDIF
                MEASURE (LAMBDA SS: card(SS))

    maxrec(SS): RECURSIVE T = 
                  IF empty?(rest(SS)) THEN choose(SS)
                  ELSE fsmax(choose(SS),maxrec(rest(SS)))
                  ENDIF
                MEASURE (LAMBDA SS: card(SS))

    lt_reflexive:     LEMMA FORALL (x: T): <=(x, x)
    lt_transitive:    LEMMA FORALL (x,y,z:T): <=(x, y) & <=(y, z) => <=(x, z)
    lt_total:         LEMMA FORALL (x,y:T) : x <= y OR y <= x
    lt_antisymmetric: LEMMA FORALL (x,y: T): <=(x, y) & <=(y, x) => x = y

    min(SS): {a: T | SS(a) AND (FORALL (x: T): SS(x) IMPLIES a <= x)}
    max(SS): {a: T | SS(a) AND (FORALL (x: T): SS(x) IMPLIES x <= a)}
   

    min_lem: LEMMA (min(SS) = a IFF
                    SS(a) AND (FORALL (x: (SS)): a <= x))

    max_lem: LEMMA (max(SS) = a IFF
                    SS(a) AND (FORALL (x: (SS)): x <= a))

    A,B:   VAR non_empty_finite_set

    min_union: LEMMA min(A) = x AND min(B) = y IMPLIES
                        min(union(A,B)) = fsmin(x,y)

    max_union: LEMMA max(A) = x AND max(B) = y IMPLIES
                        max(union(A,B)) = fsmax(x,y)


  END finite_sets_minmax

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

  % Termination TCC generated (at line 14, column 38) for  minrec(rest(SS))
  minrec_TCC1: OBLIGATION
    FORALL (SS: non_empty_finite_set[T]):
      NOT empty?(rest(SS)) IMPLIES card[T](rest[T](SS)) < card[T](SS);

  % Existence TCC generated (at line 29, column 2) for
      % min(SS): {a: T | SS(a) AND (FORALL (x: T): SS(x) IMPLIES a <= x)}
  min_TCC1: OBLIGATION
    EXISTS (x1:
              [SS: non_empty_finite_set[T] ->
                 {a: T | SS(a) AND (FORALL (x: T): SS(x) IMPLIES a <= x)}]):
      TRUE;

  % Existence TCC generated (at line 30, column 2) for
      % max(SS): {a: T | SS(a) AND (FORALL (x: T): SS(x) IMPLIES x <= a)}
  max_TCC1: OBLIGATION
    EXISTS (x1:
              [SS: non_empty_finite_set[T] ->
                 {a: T | SS(a) AND (FORALL (x: T): SS(x) IMPLIES x <= a)}]):
      TRUE;


body:
  finite_sets_minmax_props[T: TYPE, <= : (total_order?[T])]: THEORY
  %----------------------------------------------------------------------------
  % Some useful properties about min and max of finite sets
  %
  % Author : Alfons Geser, National Institute of Aerospace
  % Date   : Aug 26, 2003
  %----------------------------------------------------------------------------
  BEGIN

    IMPORTING finite_sets_minmax[T,<=]

    a,x,y: VAR T
    SS: VAR non_empty_finite_set

    max_le: LEMMA max(SS) <= a IFF (FORALL (x: T): SS(x) => x <= a)

    le_max: LEMMA a <= max(SS) IFF (EXISTS (x: T): SS(x) & a <= x)

  END finite_sets_minmax_props


body:
  func_composition  [ T1, T2, T3 : TYPE ] : THEORY
  %------------------------------------------------------------------------
  %      Author:  Bruno Dutertre 
  %
  %      Composition of injective, surjective, bijective functions
  %------------------------------------------------------------------------

    BEGIN

    f1 : VAR [T1 -> T2]
    f2 : VAR [T2 -> T3]

    composition_injective : LEMMA injective?(f1) AND injective?(f2) 
                                     IMPLIES injective?(f2 o f1)

    composition_surjective: LEMMA surjective?(f1) AND surjective?(f2) 
                                     IMPLIES surjective?(f2 o f1)

    composition_bijective : LEMMA bijective?(f1) AND bijective?(f2) 
                                     IMPLIES bijective?(f2 o f1)

    %  ---------------- Cancellation laws ----------------

    f, g : VAR [T1 -> T2]
    h, k : VAR [T2 -> T3]

    composition_def          : LEMMA (FORALL (x : T1) : h(f(x)) = (h o f)(x))
    
    composition_left_cancel1 : LEMMA injective?(h)  
                                        IMPLIES  (h o f = h o g IFF f = g)
    
    composition_left_cancel2 : LEMMA bijective?(h)  
                                        IMPLIES  (h o f = h o g IFF f = g)

   
    composition_right_cancel1: LEMMA surjective?(f)  
                                        IMPLIES  (h o f = k o f IFF h = k)
    
    composition_right_cancel2: LEMMA bijective?(f) 
                                        IMPLIES  (h o f = k o f IFF h = k)

  END func_composition


body:
  finite_sets_eq[T1, T2 : TYPE] : THEORY
  %-------------------------------------------------------------------------
  %
  %      by Bruno Dutertre    Royal Holloway & Bedford New College
  % 
  %      Equipotence of finite sets  
  %
  %-------------------------------------------------------------------------

  BEGIN


    N: VAR nat

    IMPORTING finite_sets, func_composition

    E: VAR finite_set[T1]
    F: VAR finite_set[T2]

    S: VAR set[T1]
    U: VAR set[T2]

    injection_to_finite_set    : LEMMA
          (EXISTS (f: [(S)->(F)]): injective?(f)) IMPLIES is_finite(S)

    surjection_from_finite_set : LEMMA
          (EXISTS (f: [(E)->(U)]): surjective?(f)) IMPLIES is_finite(U)

    injection_to_finite_set2   : LEMMA
          (FORALL S, F, (f: [(S)->(F)]): injective?(f) IMPLIES is_finite(S))

    surjection_from_finite_set2: LEMMA
          (FORALL E, U, (f: [(E)->(U)]): surjective?(f) IMPLIES is_finite(U))

    bijection_finite_set1      : LEMMA
          (EXISTS (f: [(S)->(F)]): bijective?(f)) IMPLIES is_finite(S)

    bijection_finite_set2      : LEMMA
          (EXISTS (f: [(E)->(U)]): bijective?(f)) IMPLIES is_finite(U)

  END finite_sets_eq


body:
  finite_sets_card_eq[T1, T2 : TYPE] : THEORY
  %-------------------------------------------------------------------------
  %
  %      by Bruno Dutertre    Royal Holloway & Bedford New College
  % 
  % Establishes:
  %
  %       card_eq_bij : LEMMA card(E) = card(F) IFF 
  %                                  EXISTS (f: [(E)->(F)]): bijective?(f)
  %
  %-------------------------------------------------------------------------

  BEGIN

    IMPORTING finite_sets, func_composition

    E: VAR finite_set[T1]
    F: VAR finite_set[T2]

    N: VAR nat
    card_injection         : LEMMA (EXISTS (f : [(E)->below[N]]) : injective?(f)) 
                                       IMPLIES card(E) <= N
    
    card_surjection        : LEMMA (EXISTS (f : [(E)->below[N]]) : surjective?(f)) 
                                       IMPLIES N <= card(E) 
    

    injection_and_cardinal : LEMMA (EXISTS (f : [(E)->(F)]): injective?(f))
                                              IMPLIES card(E) <= card(F)

    surjection_and_cardinal: LEMMA (EXISTS (f: [(E)->(F)]): surjective?(f))
                                              IMPLIES card(F) <= card(E)

    card_eq_bij            : LEMMA card(E) = card(F) IFF 
                                            EXISTS (f: [(E)->(F)]): bijective?(f)

  END finite_sets_card_eq


body:
  finite_sets_below[N: nat]: THEORY
  BEGIN

    IMPORTING finite_sets

    A,B,BS: VAR set[below(N)]
    US: VAR set[upto(N)]

    finite_below      : LEMMA is_finite[below(N)](BS)

    card_below_fullset: LEMMA card[below(N)](fullset[below(N)]) = N

    card_below        : LEMMA card[below(N)](BS) <= N

    finite_upto       : LEMMA is_finite[upto(N)](US)

    card_upto_fullset : LEMMA card[upto(N)](fullset[upto(N)]) = N + 1

    card_upto         : LEMMA card[upto(N)](US) <= N + 1

    k: VAR nat
    pidgeon_hole      : LEMMA card(A) + card(B) >= N + k IMPLIES 
                                  card(intersection(A,B)) >= k


  END finite_sets_below

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

  % Subtype TCC generated (at line 11, column 43) for  fullset[below(N)]
      % expected type  S: finite_set[below(N)]
  card_below_fullset_TCC1: OBLIGATION is_finite[below(N)](fullset[below(N)]);

  % Subtype TCC generated (at line 13, column 43) for  BS
      % expected type  S: finite_set[below(N)]
  card_below_TCC1: OBLIGATION
    FORALL (BS: set[below(N)]): is_finite[below(N)](BS);

  % Subtype TCC generated (at line 17, column 42) for  fullset[upto(N)]
      % expected type  S: finite_set[upto(N)]
  card_upto_fullset_TCC1: OBLIGATION is_finite[upto(N)](fullset[upto(N)]);

  % Subtype TCC generated (at line 19, column 42) for  US
      % expected type  S: finite_set[upto(N)]
  card_upto_TCC1: OBLIGATION
    FORALL (US: set[upto(N)]): is_finite[upto(N)](US);

  % Subtype TCC generated (at line 23, column 37) for  intersection(A, B)
      % expected type  S: finite_set[below(N)]
  pidgeon_hole_TCC1: OBLIGATION
    FORALL (A, B: set[below(N)], k: nat):
      card(A) + card(B) >= N + k IMPLIES
       is_finite[below(N)](intersection[below(N)](A, B));


body:
  finite_sets_pred[T: TYPE]: THEORY
  BEGIN

    IMPORTING finite_sets

    P, P1, P2: VAR pred[T]

    finite_pred: LEMMA is_finite(fullset[T]) IMPLIES
                          is_finite[T]({x: T | P(x)})


    card_implies: LEMMA is_finite(fullset[T]) AND
                        (FORALL (x: T): P1(x) IMPLIES P2(x)) 
               IMPLIES card({x: T | P1(x)}) <= card({x: T | P2(x)})

  END finite_sets_pred

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

  % Subtype TCC generated (at line 14, column 26) for  {x: T | P1(x)}
      % expected type  S: finite_set[T]
  card_implies_TCC1: OBLIGATION
    FORALL (P1, P2: pred[T]):
      (FORALL (x: T): P1(x) IMPLIES P2(x)) AND is_finite(fullset[T]) IMPLIES
       is_finite[T]({x: T | P1(x)});

  % Subtype TCC generated (at line 14, column 50) for  {x: T | P2(x)}
      % expected type  S: finite_set[T]
  card_implies_TCC2: OBLIGATION
    FORALL (P1, P2: pred[T]):
      (FORALL (x: T): P1(x) IMPLIES P2(x)) AND is_finite(fullset[T]) IMPLIES
       is_finite[T]({x: T | P2(x)});


body:
  finite_sets_nat: THEORY
   BEGIN
    IMPORTING finite_sets[nat]

    n, N: VAR nat
    i, j: VAR nat
    p: VAR pred[nat]

    finite_bounded       : LEMMA is_finite({j: nat | j < N })

    card_bounded         : LEMMA card({j: nat | j < N}) = N    

    finite_bounded_subset: LEMMA is_finite({j: nat | j < N AND p(j)})

    card_bounded_subset  : LEMMA card({j: nat | j < N AND p(j)}) <= N

  % ------------------------------------------------------------------------
  % The following lemmas apply is_finite[nat] and card[nat] to subtype
  % sets.  This should be avoided if possible.  See finite_subint for
  % preferred lemmas.
  % ------------------------------------------------------------------------

    finite_nat_below   : LEMMA is_finite[nat]({x: below(n) | TRUE})

    card_nat_below     : LEMMA card[nat]({x: below(n) | TRUE}) = n

    finite_nat_upto    : LEMMA is_finite[nat]({x: upto(n) | TRUE})

    card_nat_upto      : LEMMA card[nat]({x: upto(n) | TRUE}) = n + 1

    finite_nat_subrange: LEMMA
        is_finite[nat](restrict[int, nat, bool]({x: subrange(i, j) | TRUE}))

    card_nat_subrange  : LEMMA
        card[nat](restrict[int, nat, bool]({x: subrange(i, j) | TRUE})) =
                                 IF i <= j THEN j - i + 1 ELSE 0 ENDIF


  END finite_sets_nat

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

  % Subtype TCC generated (at line 11, column 36) for  {j: nat | j < N}
      % expected type  S: finite_set[nat]
  card_bounded_TCC1: OBLIGATION
    FORALL (N: nat): is_finite[nat]({j: nat | j < N});

  % Subtype TCC generated (at line 15, column 36) for
      % {j: nat | j < N AND p(j)}
      % expected type  S: finite_set[nat]
  card_bounded_subset_TCC1: OBLIGATION
    FORALL (N: nat, p: pred[nat]): is_finite[nat]({j: nat | j < N AND p(j)});

  % Subtype TCC generated (at line 25, column 39) for
      % extend[nat, below(n), bool, FALSE]({x: below(n) | TRUE})
      % expected type  S: finite_set[nat]
  card_nat_below_TCC1: OBLIGATION
    FORALL (n: nat):
      is_finite[nat]
          (extend[nat, below(n), bool, FALSE]({x: below(n) | TRUE}));

  % Subtype TCC generated (at line 29, column 39) for
      % extend[nat, upto(n), bool, FALSE]({x: upto(n) | TRUE})
      % expected type  S: finite_set[nat]
  card_nat_upto_TCC1: OBLIGATION
    FORALL (n: nat):
      is_finite[nat](extend[nat, upto(n), bool, FALSE]({x: upto(n) | TRUE}));

  % Subtype TCC generated (at line 35, column 16) for
      % restrict[int, nat, bool]
      %     (extend[int, subrange(i, j), bool, FALSE]
      %          ({x: subrange(i, j) | TRUE}))
      % expected type  S: finite_set[nat]
  card_nat_subrange_TCC1: OBLIGATION
    FORALL (i, j: nat):
      is_finite[nat]
          (restrict[int, nat, bool]
               (extend[int, subrange(i, j), bool, FALSE]
                    ({x: subrange(i, j) | TRUE})));


body:
  finite_sets_int: THEORY
   BEGIN
    IMPORTING finite_sets[int]

    i, j, x: VAR int

    p: VAR pred[int]

    in_subrng(x,i,j): bool = (i <= x) AND (x <= j)

    finite_subrng       : LEMMA is_finite({x | in_subrng(x,i,j)})

    finite_subrng_subset: LEMMA is_finite({x | in_subrng(x,i,j) AND p(x)})

    card_subrng         : LEMMA card({x | in_subrng(x,i,j)}) =
                                    IF i <= j THEN abs(j-i+1) ELSE 0 ENDIF


  % ------------------------------------------------------------------------
  % The following lemmas apply is_finite[nat] and card[nat] to subtype
  % sets.  This should be avoided if possible.  See finite_subint for
  % preferred lemmas.
  % ------------------------------------------------------------------------

    finite_int_subrange     : LEMMA is_finite[int]({x: subrange(i, j) | TRUE})

    finite_int_subrange_pred: LEMMA is_finite[int]({x: subrange(i, j) | p(x)})

    card_int_subrange       : LEMMA card[int]({x: subrange(i, j) | TRUE}) =
                                      IF i <= j THEN abs(j-i+1) ELSE 0 ENDIF

  END finite_sets_int

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

  % Subtype TCC generated (at line 15, column 35) for
      % {x | in_subrng(x, i, j)}
      % expected type  S: finite_set[int]
  card_subrng_TCC1: OBLIGATION
    FORALL (i, j: int): is_finite[int]({x | in_subrng(x, i, j)});

  % Subtype TCC generated (at line 29, column 44) for
      % extend[int, subrange(i, j), bool, FALSE]({x: subrange(i, j) | TRUE})
      % expected type  S: finite_set[int]
  card_int_subrange_TCC1: OBLIGATION
    FORALL (i, j: int):
      is_finite[int]
          (extend[int, subrange(i, j), bool, FALSE]
               ({x: subrange(i, j) | TRUE}));


body:
  prelude_aux[T: TYPE]: THEORY

  BEGIN

    % these lemmas should go in prelude

    rest_emptyset: LEMMA (FORALL (S: set[T], t:T): rest(S) = emptyset[T]
                             AND S(t) IMPLIES choose(S) = t)


  END prelude_aux

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

  % Subtype TCC generated (at line 8, column 51) for  S
      % expected type  p: (nonempty?[T])
  rest_emptyset_TCC1: OBLIGATION
    FORALL (S: set[T], t: T):
      rest(S) = emptyset[T] AND S(t) IMPLIES nonempty?[T](S);


body:
  finite_sets_sum[T, R: TYPE, zero:R, +:[R,R -> R] ]: THEORY
  %----------------------------------------------------------------------
  %  
  %                                              ----
  %                                              \     
  %  sum(S: finite_set[T], f:[T->R]) = zero +       f(i) 
  %                                              /
  %                                              ----
  %                                              member(i,S)
  %  
  %----------------------------------------------------------------------
  BEGIN

    ASSUMING
       r,r1,r2,r3 : VAR R
       zero_identity: ASSUMPTION identity?(+)(zero)
       plus_ac:       ASSUMPTION associative?(+) AND commutative?(+)
    ENDASSUMING

    plus_zero_right: LEMMA r + zero = r 
    plus_zero_left : LEMMA zero + r = r
    plus_assoc     : LEMMA (r1 + r2) + r3 = r1 + (r2 + r3) 
    plus_comm      : LEMMA r1 + r2 = r2 + r1

    IMPORTING finite_sets[T], finite_sets_inductions[T], sets_lemmas[T]

    f,g: VAR [T -> R]
    S, A, B: VAR finite_set
    x: VAR T

    sum(S,f) : RECURSIVE R = 
      IF (empty?(S)) THEN zero
      ELSE f(choose(S)) + sum(rest(S),f)
      ENDIF MEASURE (LAMBDA S,f: card(S))

    sum_emptyset  : THEOREM sum(emptyset[T],f) = zero

    sum_singleton : THEOREM sum(singleton(x),f) = f(x) + zero ;

    sum_x         : THEOREM (FORALL (x: (S)): 
                                sum(S, f) = f(x) + sum(remove(x, S), f))

    sum_x1_x2     : LEMMA (FORALL (x1,x2: (S)): f(x1) + sum(remove(x1,S),f) 
                                = f(x2) + sum(remove(x2,S),f))

    sum_add       : THEOREM sum(add(x,S),f) 
                            = sum(S,f) + IF member(x,S) THEN zero ELSE f(x) ENDIF

    sum_remove    : THEOREM sum(remove(x,S),f) 
                            + IF member(x,S) THEN f(x) ELSE zero ENDIF = sum(S,f)

    sum_rest      : THEOREM NOT empty?(S) IMPLIES
                              f(choose(S)) + sum(rest(S),f) = sum(S,f)
   
    sum_disj_union: THEOREM disjoint?(A,B) IMPLIES 
                              sum(union(A,B),f) = sum(A,f) + sum(B,f) 

    sum_diff_subset: THEOREM subset?(A, B) IMPLIES 
  		            sum(difference(B, A), f) + sum(A, f) = sum(B, f) 

    sum_union      : THEOREM sum(union(A,B),f) + sum(intersection(A,B),f) =
                                           sum(A,f) + sum(B,f) 

    sum_diff_intersection: THEOREM sum(A,f) = 
                              sum(difference(A,B),f) + sum(intersection(A,B),f) 

    sum_f_g         : LEMMA (FORALL (x: (S)): f(x) = g(x)) 
                                 IMPLIES sum(S, f) = sum(S, g)

    sum_particular  : THEOREM sum(S,f) = sum(S, f WITH [x := zero])
  			       + IF S(x) THEN f(x) ELSE zero ENDIF 

    sum_distributive: THEOREM sum(A,f) + sum(A,g) = 
                                  sum(A,(LAMBDA x: f(x) + g(x))) 

  END finite_sets_sum

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

  % Subtype TCC generated (at line 33, column 18) for  S
      % expected type  p: (nonempty?[T])
  sum_TCC1: OBLIGATION
    FORALL (S: finite_set[T], f: [T -> R]):
      NOT (empty?(S)) IMPLIES nonempty?[T](S);

  % Termination TCC generated (at line 33, column 24) for  sum(rest(S), f)
  sum_TCC2: OBLIGATION
    FORALL (S: finite_set[T], f: [T -> R]):
      NOT (empty?(S)) IMPLIES card[T](rest[T](S)) < card[T](S);

  % Subtype TCC generated (at line 53, column 37) for  S
      % expected type  p: (nonempty?[T])
  sum_rest_TCC1: OBLIGATION
    FORALL (S: finite_set[T]): NOT empty?(S) IMPLIES nonempty?[T](S);


body:
  finite_sets_sum_real[T: TYPE]: THEORY
  %------------------------------------------------------------------------
  %
  % finite sum over real-valued functions   
  %
  %   Authors: Ricky W. Butler
  %            David Griffioen
  %
  %   NOTES:
  %      -- there are several theorems which are virtually idential to
  %         theorems in finite_sets_sum.  They are repeated here to prevent
  %         the need for commands such as (LEMMA sum_emptyset[T,real,0,+])
  %      -- the theorems with names ending in "_rew" are especially useful
  %         for rewriting.  Some of these take advantage of the fact that
  %         since we have real-valued functions we have a "-" available.
  %------------------------------------------------------------------------
  BEGIN


    IMPORTING finite_sets_sum[T,real,0,+], prelude_aux

    S, A, B: VAR finite_set[T]
    t: VAR T
    c,N: VAR real
    f,g: VAR function[T -> real]

    sum_const        : THEOREM sum(S, (LAMBDA t: c)) = c*card(S) 

    sum_1_is_card    : COROLLARY sum(S,(LAMBDA t: 1)) = card(S)

    sum_mult         : THEOREM sum(S,(LAMBDA t: c*f(t))) = c*sum(S,f) 

  % ----------- Some rewrite rules using "-" ------------------

    sum_empty?       : THEOREM empty?(S) IMPLIES sum(S,f) = 0

    sum_emptyset_rew : THEOREM S = emptyset[T] IMPLIES sum(S,f) = 0

    sum_singleton_rew: THEOREM card(S) = 1 AND S(t) IMPLIES sum(S,f) = f(t)

    sum_remove_rew   : THEOREM sum(remove(t,S),f) = sum(S,f) -
                                  IF member(t,S) THEN f(t) ELSE 0 ENDIF 


    sum_rest_rew     : THEOREM NOT empty?(S) IMPLIES
                                  sum(rest(S),f) = sum(S,f) - f(choose(S))

    sum_union_rew    : THEOREM sum(union(A,B),f) = sum(A,f) + sum(B,f)
                                   - sum(intersection(A,B),f) 


  % -------- sums of slightly modified functions ----------

    sum_eq_funs       : THEOREM (FORALL (t: (S)): f(t) = g(t)) 
                                 IMPLIES sum(S, f) = sum(S, g)

    sum_particular_gen: THEOREM sum(S,f) = sum(S, f WITH [t := c])
  			       + IF S(t) THEN f(t) - c ELSE 0 ENDIF 


  % ----- some order relationships involving sum -----

    sum_bound    : THEOREM (FORALL (t: (S)): f(t) <= N) 
                               IMPLIES sum(S,f) <= N*card(S)

    sum_order    : THEOREM (FORALL (t:T): f(t) <= g(t)) IMPLIES
                             sum(S,f) <= sum(S,g)

    sum_nonneg   : LEMMA (FORALL (t: (S)): f(t) >= 0) IMPLIES sum(S,f) >= 0

    sum_pos      : LEMMA (FORALL (t: (S)): f(t) > 0) IMPLIES sum(S,f) > 0 OR
                                                      S = emptyset[T]

    JUDGEMENT sum(A: non_empty_finite_set[T], f: [T -> posreal])
              HAS_TYPE posreal

    JUDGEMENT sum(A: finite_set[T], f: [T -> int]) HAS_TYPE int

    JUDGEMENT sum(A: finite_set[T], f: [T -> nat]) HAS_TYPE nat

  % ----- Special properties non-negative valued functions -----

    fnr,gnr: VAR [T -> nonneg_real]

    sum_subset   : THEOREM subset?(A,B) IMPLIES sum(A,fnr) <= sum(B,fnr)

    sum_order_sub: THEOREM subset?(A,B) AND (FORALL (t:T): fnr(t) <= gnr(t))
                             IMPLIES sum(A,fnr) <= sum(B,gnr)

    gn:  VAR function[T -> nat]
    gi:  VAR function[T -> nonneg_int]

    sum_0_nat       : THEOREM sum(S,gn) = 0 IMPLIES  S = emptyset[T] OR
                                            (FORALL (t:(S)): gn(t) = 0)

    sum_is_null     : COROLLARY sum(S,gn) = 0 => (S(t) => gn(t) = 0)

    sum_0_int       : THEOREM sum(S,gi) = 0 IMPLIES S = emptyset[T]
                                                 OR (FORALL (t:(S)): gi(t) = 0)

    sum_0_non_neg   : THEOREM sum(S,f) = 0 AND (FORALL (t: (S)): f(t) >= 0) 
                               IMPLIES S = emptyset[T] 
                                        OR (FORALL (t:(S)): f(t) = 0)

    JUDGEMENT sum(A: finite_set[T], f: [T -> nonneg_real])
              HAS_TYPE nonneg_real
    JUDGEMENT sum(A: finite_set[T], f: [T -> nonneg_int]) HAS_TYPE nonneg_int
    JUDGEMENT sum(A: non_empty_finite_set[T], f: [T->posnat]) HAS_TYPE posnat

  %  JUDGEMENT sum(A: non_empty_finite_set[T], f: [T->negreal]) HAS_TYPE negreal
  %  JUDGEMENT sum(A: finite_set[T], f: [T -> nonpos_real]) HAS_TYPE nonpos_real
  %  JUDGEMENT sum(A: finite_set[T], f: [T -> negint]) HAS_TYPE negint

  END finite_sets_sum_real

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

  % Assuming TCC generated (at line 20, column 12) for
      % finite_sets_sum
      %     [T, real, 0,
      %      restrict[[numfield, numfield], [real, real], numfield](+)]
      % generated from assumption finite_sets_sum.zero_identity
  IMP_finite_sets_sum_TCC1: OBLIGATION
    identity?[real]
        (restrict[[numfield, numfield], [real, real], numfield](+))(0);

  % Assuming TCC generated (at line 20, column 12) for
      % finite_sets_sum
      %     [T, real, 0,
      %      restrict[[numfield, numfield], [real, real], numfield](+)]
      % generated from assumption finite_sets_sum.plus_ac
  IMP_finite_sets_sum_TCC2: OBLIGATION
    associative?[real]
        (restrict[[numfield, numfield], [real, real], numfield](+))
     AND
     commutative?[real]
         (restrict[[numfield, numfield], [real, real], numfield](+));

  % Subtype TCC generated (at line 46, column 69) for  S
      % expected type  p: (nonempty?[T])
  sum_rest_rew_TCC1: OBLIGATION
    FORALL (S: finite_set[T]): NOT empty?(S) IMPLIES nonempty?[T](S);

  % Judgement subtype TCC generated (at line 74, column 12) for  sum(A, f)
      % expected type  posreal
  sum_TCC1: OBLIGATION
    FORALL (A: non_empty_finite_set[T], f: [T -> posreal]):
      sum
          [T, real, 0,
           restrict[[numfield, numfield], [real, real], numfield](+)]
          (A, f)
       >= 0
       AND
       sum
           [T, real, 0,
            restrict[[numfield, numfield], [real, real], numfield](+)]
           (A, f)
        > 0;

  % Judgement subtype TCC generated (at line 77, column 12) for  sum(A, f)
      % expected type  int
  sum_TCC2: OBLIGATION
    FORALL (A: finite_set[T], f: [T -> int]):
      rational_pred(sum
                        [T, real, 0,
                         restrict
                             [[numfield, numfield], [real, real], numfield]
                             (+)]
                        (A, f))
       AND
       integer_pred(sum
                        [T, real, 0,
                         restrict
                             [[numfield, numfield], [real, real], numfield]
                             (+)]
                        (A, f));

  % Judgement subtype TCC generated (at line 79, column 12) for  sum(A, f)
      % expected type  nat
  sum_TCC3: OBLIGATION
    FORALL (A: finite_set[T], f: [T -> nat]):
      sum
          [T, real, 0,
           restrict[[numfield, numfield], [real, real], numfield](+)]
          (A, f)
       >= 0;

  % Judgement subtype TCC generated (at line 105, column 12) for  sum(A, f)
      % expected type  nonneg_real
  sum_TCC4: OBLIGATION
    FORALL (A: finite_set[T], f: [T -> nonneg_real]):
      sum
          [T, real, 0,
           restrict[[numfield, numfield], [real, real], numfield](+)]
          (A, f)
       >= 0;

  % Judgement subtype TCC generated (at line 108, column 12) for  sum(A, f)
      % expected type  posnat
  sum_TCC5: OBLIGATION
    FORALL (A: non_empty_finite_set[T], f: [T -> posnat]):
      sum
          [T, real, 0,
           restrict[[numfield, numfield], [real, real], numfield](+)]
          (A, f)
       > 0;


body:
  top: THEORY
  %-------------------------------------------------------------------------
  % Integers library  
  %
  %       Authors:   Rick Butler       NASA Langley
  %                  Paul Miner        NASA Langley
  %                  Bruno Dutertre    Royal Holloway & Bedford New College
  %                  Alfons Geser      HTWK Leipzig, Germany
  %
  % Date: May, 2009
  %------------------------------------------------------------------------------

  %
  % Defines "div" according to the Ada Reference Manual
  %
  %  div                 -- Ada Reference Manual division theory
  %  rem                 -- Ada Reference Manual rem theory
  %
  % This div truncates toward zero on a negative argument.
  %
  % Version 1.2 Changed mod to mod_ in PVS4.0 because PVS no longer allows you to 
  %             redefine a theory defined in the prelude.
  % Version 1.3 Changed "divides" to "divides?" so as to not conflict with
  %             prelude definition
  % Version 1.4 Moved all of number_theory library to ints library
  %
  % NOTE: The old approach of having two different definitions of "div"
  %       and "mod" defined in different theories is no longer reasonable
  %       given that "mod" is now defined in the prelude.  The alternate
  %       definitions are now named "tdiv" and "tmod"
  % 
  % NOTE: mod_ has been removed since it is now in prelude.  The additional lemmas
  %       not in prelude are now in mod_lems
  % 
  %
  % Version 1.5  product operator theories added
  %
  %-------------------------------------------------------------------------
  BEGIN
     IMPORTING div,           % integer division
               rem,           % old version of "rem", prelude version supercedes
               mod_div_lems,  % modular arithmetic lemmas that involve div
               mod_lems,      % modular arithmetic lemmas
  	     gcd,           % greatest common divisor
               gcd_fractions, % division by gcd
  	     tdiv, tmod,    % versions that trunc away from zero for neg arg
               max_upto,      % max of a set of upto
               max_below,     % max of a set of below
               div_nat,       % integer division over nats
               mod_nat,       % mod over nats
               abstract_min,  % defines min over type T satisfying P
               abstract_max,  % defines max over type T satisfying P
  	     floor_div_lems,
  	     floor_more,
  	     max_below,
  	     max_bounded_posnat,
               max_finite_set_nat,
  	     min_nat,       % minimum value in a set of naturals
  	     min_posnat,    % minimum value in a set of positive naturals
  	     nat_fun_props, % injective/surgective functions over nats
  	     primes,        % definition of prime numbers
               factorial,     % factorial function (moved from reals library)
  	     pigeonhole,    % The pigeonhole principle


  %%           Since int is a subtype of reals these are really just special
  %%           cases of the theories in the reals library.  However, there is
  %%           a bug in the PVS judgments system that makes these still useful
  %%           As soon as that bug is fixed, these will be removed.

  	     product,              % generic theory
  	     product_below,
  	     product_int,
  	     product_nat,
  	     product_posnat,
  	     product_upto,


               well_nat       % contains an AXIOM that is proved in the orders library

  END top


body:
  %-------------------------------------------------------------------------
  %
  %  Well-orderings on sets of natural numbers.
  %
  %  For PVS version 3.2.  February 28, 2005
  %  ---------------------------------------------------------------------
  %      Author: Jerry James (jamesj@acm.org), University of Kansas
  %
  %  EXPORTS
  %  -------
  %  prelude: finite_sets[nat], orders[nat], sets[nat], relations[nat]
  %  finite_sets: finite_sets_inductions, finite_sets_minmax
  %  orders: bounded_orders[nat], minmax_orders[nat], relations_extra[nat],
  %    well_nat
  %
  %-------------------------------------------------------------------------
  well_nat: THEORY
   BEGIN

  %%  IMPORTING minmax_orders[nat]

    n, m: VAR nat
    S: VAR set[nat]
    F: VAR finite_set[nat]

    well_lt_nat: THEOREM FORALL S: well_ordered?[(S)](<)

    well_gt_nat: AXIOM FORALL F: well_ordered?[(F)](>)    %% Proved in orders library

   END well_nat


body:
  product[T: TYPE FROM int]: THEORY
  %------------------------------------------------------------------------------
  % The products theory introduces and defines properties of the product
  % function that multiples an arbitrary function F: [T -> int] over a range
  % from low to high
  %
  %  		           high
  %		           ----
  %  product(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

    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       : VAR int
    nzr       : VAR nzint

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

     product(low, high, F): RECURSIVE int
        = IF low > high THEN 1
          ELSE  F(high)*product(low, high-1, F)
          ENDIF                            
     MEASURE (LAMBDA low, high, F: abs(high+1-low))


    product_spl     : THEOREM T_pred(low + nn + rng) IMPLIES 
                             product(low, low+nn+rng, F) = 
                                product(low,low+nn,F) * product(low+nn+1,low+nn+rng,F)

    product_split   : THEOREM low - 1 <= z AND z <= high IMPLIES 
                              product(low, high, F) = 
                                       product(low, z, F) * product(z+1, high, F)


    product_div     : THEOREM low - 1 <= z AND z <= high AND product(low, z, F) /= 0 IMPLIES
                      product(low, high, F) / product(low, z, F) = product(z+1, high, F)

    product_div_neg : THEOREM low - 1 <= z AND z <= high AND 
                              product(low, high, F) /= 0 AND product(z+1, high, F) /= 0 
                         IMPLIES
                             product(low, z, F) / product(low, high, F) = 1/product(z+1, high, F)
   		 
    product_eq_arg  : THEOREM product(m, m, F) = F(m)


    product_first   : THEOREM high >= low IMPLIES 
                             product(low, high, F) = F(low) * product(low+1, high, F)

    product_last    : THEOREM high >= low IMPLIES 
                            product(low, high, F) = product(low, high-1, F) * F(high)

    product_middle : THEOREM high >= i AND i >= low IMPLIES
                            product(low, high, F) = product(low, i-1, F) * F(i) *
                                                  product(i+1, high, F) 

    product_const   : THEOREM product(low, high, (LAMBDA i: nzr)) = 
                             IF high >= low THEN nzr^(high-low+1) ELSE 1 ENDIF


    product_zero    : THEOREM low <= high IMPLIES product(low, high, (LAMBDA i: 0)) = 0

    product_scal    : THEOREM low <= high AND a /= 0 IMPLIES product(low, high, (LAMBDA i: a * F(i)))
                               = a^(high-low+1) * product(low, high, F)
                          
  %   B: VAR posint		 
  %   product_bound   : THEOREM low - 1 <= high AND
  %                          (FORALL i: i >= low AND i <= high IMPLIES 0 <= F(i) AND F(i) <= B)
  %                             IMPLIES product(low, high, F) <= B^(high-low+1) 


    product_ge_0    : THEOREM (FORALL (n: subrange(low,high)): F(n) >= 0)
                                  IMPLIES product(low,high,F) >= 0

    product_gt_0    : THEOREM (FORALL (n: subrange(low,high)): F(n) > 0)
                                  IMPLIES product(low,high,F) > 0


    product_shift_T : THEOREM (FORALL (i:T): T_pred(i+z)) IMPLIES 
  			         product(low+z,high+z,F) = 
                                      product(low,high, (LAMBDA (i:T): F(i+z)))

    product_shift_T2 : THEOREM T_pred(low+z) AND T_pred(high+z) IMPLIES 
   			         product(low+z,high+z,F) = 
                    product(low,high, (LAMBDA (i:T): IF T_pred(i+z) THEN F(i+z)
                                                   ELSE 1 ENDIF))

   
  % ------------------ Summation Involving Two Functions ------------------

    product_prod     : THEOREM product(low, high, F) * product(low, high, G)
                               = product(low, high, (LAMBDA i: F(i) * G(i)))

  %   product_minus   : THEOREM (FORALL (i: int): T_pred(i) IMPLIES G(i) /= 0) IMPLIES
  %                              product(low, high, F) / product(low, high, G)
  %                              = product(low, high, (LAMBDA i: F(i) / G(i)))

  %   product_abs_bnd  : THEOREM (FORALL (i: subrange(low,high)): abs(F(i)) <= G(i))
  %                        IMPLIES product(low, high, LAMBDA (n: T): abs(F(n))) <=
  %                                         product(low, high, G)

    restrict(F, low, high): function[T -> int] = 
       (LAMBDA i: IF i < low OR i > high THEN 0 ELSE F(i) ENDIF )

    product_restrict   : THEOREM l <= low AND h >= high IMPLIES	
                              product(low,high,F) = product(low,high,restrict(F,l,h))


    product_restrict_to: THEOREM product(low,high,F) = 
                                  product(low,high,restrict(F,low,high))

    product_restrict_eq: THEOREM restrict(F,low,high) = restrict(G,low,high) 
                                  IMPLIES product(low,high,F) = product(low,high,G) 


    product_eq         : THEOREM (FORALL (n: subrange(low,high)): F(n) = G(n))
                                  IMPLIES product(low,high,F) = product(low,high,G) 


  %   product_le         : THEOREM (FORALL (n: subrange(low,high)): 0 <= F(n) AND F(n) <= G(n))
  %                                 IMPLIES product(low,high,F) <= product(low,high,G) 

  %   product_lt         : THEOREM low <= high AND
  %                              (FORALL (n: subrange(low,high)): 0 <= F(n) AND F(n) < G(n))
  %                                 IMPLIES product(low,high,F) < product(low,high,G) 


    product_with         : THEOREM low <= i AND i <= high AND G(i) /= 0 AND
                               F = G WITH [i := a] IMPLIES
                            product(low, high,F) = a*product(low,high,G) / G(i)

  % ------------------------ Special Arguments --------------------------------

    product_nonneg     : THEOREM (FORALL i: F(i) >= 0) 
                                   IMPLIES product(low, high, F) >= 0
   
    Fnat: VAR function[T -> nat]
    Fposnat: VAR function[T -> posnat]

    prod_nat: JUDGEMENT product(low,high,Fnat) HAS_TYPE nat

    prod_posnat: JUDGEMENT product(low,high,Fposnat) HAS_TYPE posnat


    AUTO_REWRITE+ product_eq_arg

  %   product_nonneg_eq_0  : THEOREM product(low,high,Fnni) = 0 
  %                              IMPLIES  EXISTS (i: subrange(low,high)): Fnni(i) = 0


  END product

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

  % Subtype TCC generated (at line 50, 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 60, column 16) for  high
      % expected type  T
  product_TCC1: OBLIGATION
    FORALL (low: T_low, high: T_high): NOT low > high IMPLIES T_pred(high);

  % Subtype TCC generated (at line 60, column 35) for  high - 1
      % expected type  T_high
  product_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 60, column 22) for
      % product(low, high - 1, F)
  product_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 66, column 40) for  low + nn + rng
      % expected type  T_high
  product_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 67, column 42) for  low + nn
      % expected type  T_high
  product_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 67, column 62) for  low + nn + 1
      % expected type  T_low
  product_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 71, column 50) for  z
      % expected type  T_high
  product_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 71, column 66) for  z + 1
      % expected type  T_low
  product_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 86, column 53) for  low
      % expected type  T
  product_first_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low): high >= low IMPLIES T_pred(low);

  % Subtype TCC generated (at line 86, column 68) for  low + 1
      % expected type  T_low
  product_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 89, column 63) for  high - 1
      % expected type  T_high
  product_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 89, column 78) for  high
      % expected type  T
  product_last_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low): high >= low IMPLIES T_pred(high);

  % Subtype TCC generated (at line 92, column 63) for  i - 1
      % expected type  T_high
  product_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 93, column 56) for  i + 1
      % expected type  T_low
  product_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 96, column 52) for  (high - low + 1)
      % expected type  {i: int | nzr /= 0 OR i >= 0}
  product_const_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, nzr: nzint):
      high >= low IMPLIES nzr /= 0 OR (high - low + 1) >= 0;

  % Subtype TCC generated (at line 102, column 34) for  (high - low + 1)
      % expected type  {i: int | a /= 0 OR i >= 0}
  product_scal_TCC1: OBLIGATION
    FORALL (a: int, high: T_high, low: T_low):
      a /= 0 AND low <= high IMPLIES a /= 0 OR (high - low + 1) >= 0;

  % Subtype TCC generated (at line 110, column 63) for  n
      % expected type  T
  product_ge_0_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, n: subrange(low, high)): T_pred(n);

  % Subtype TCC generated (at line 118, column 20) for  low + z
      % expected type  T_low
  product_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 118, column 26) for  high + z
      % expected type  T_high
  product_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 119, column 71) for  i + z
      % expected type  T
  product_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 122, column 21) for  low + z
      % expected type  T_low
  product_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 122, column 27) for  high + z
      % expected type  T_high
  product_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);

  % Judgement subtype TCC generated (at line 178, column 22) for
      % product(low, high, Fnat)
      % expected type  nat
  prod_nat: OBLIGATION
    FORALL (Fnat, high, low): product(low, high, Fnat) >= 0;

  % Judgement subtype TCC generated (at line 180, column 25) for
      % product(low, high, Fposnat)
      % expected type  posnat
  prod_posnat: OBLIGATION
    FORALL (Fposnat, high, low): product(low, high, Fposnat) > 0;


body:
  product_upto[N: nat]: THEORY
  %------------------------------------------------------------------------------
  % The products theory introduces and defines properties of the product
  % function that multiples an arbitrary function F: [upto(N) -> int] over a range
  % from low to high
  %
  %  		           high
  %		           ----
  %  product(low, high, F) = |  |  F(j)
  %		           |  |
  %		         j = low
  %
  %  AUTHORS:
  %
  %    Rick Butler     NASA Langley Research Center           
  %    Paul Miner      NASA Langley Research Center           
  %
  %------------------------------------------------------------------------------
  BEGIN

    IMPORTING product[upto[N]]

    int_upto: TYPE = {i:int | i <= N}
    int_upto_T_high: JUDGEMENT int_upto SUBTYPE_OF T_high
    nat_is_T_low: JUDGEMENT nat SUBTYPE_OF T_low


    low, high, n, m: VAR upto[N]
    F: VAR function[upto[N] -> int]


  % --------- Following Theorems Not Provable In Generic Framework -------

    product_first_ge : THEOREM high >= low IMPLIES
                             product(low, high, F) = F(low) * product(low+1, high, F)

    product_last_ge  : THEOREM high >= low IMPLIES 
                            product(low, high, F) = product(low, high-1, F) * F(high)

    product_split_ge : THEOREM low-1 <= m AND m <= high IMPLIES 
                              product(low, high, F) = 
                                       product(low, m, F) * product(m+1, high, F)



  % ---- Auto-rewrites


    ing: VAR negint
    product_0_neg: LEMMA product(0,ing,F) = 1
    AUTO_REWRITE+ product_0_neg


  END product_upto

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

  % Assuming TCC generated (at line 21, column 12) for  product[upto[N]]
      % generated from assumption product.connected_domain
  IMP_product_TCC1: OBLIGATION
    (FORALL (x, y: upto[N]), (z: integer):
       x <= z AND z <= y IMPLIES z >= 0 AND z <= N);

  % Judgement subtype TCC generated (at line 24, column 29) for  x
      % expected type  T_high[upto[N]]
  int_upto_T_high: OBLIGATION
    FORALL (x: int_upto): x >= 0 AND x <= N OR (EXISTS (j: upto[N]): x <= j);

  % Judgement subtype TCC generated (at line 25, column 26) for  x
      % expected type  T_low[upto[N]]
  nat_is_T_low: OBLIGATION
    FORALL (x: nat): x >= 0 AND x <= N OR (EXISTS (j: upto[N]): j <= x);

  % Subtype TCC generated (at line 35, column 40) for  high
      % expected type  T_high[upto[N]]
  product_first_ge_TCC1: OBLIGATION
    FORALL (high, low: upto[N]):
      high >= low IMPLIES
       high >= 0 AND high <= N OR (EXISTS (j: upto[N]): high <= j);

  % Subtype TCC generated (at line 38, column 63) for  high - 1
      % expected type  T_high[upto[N]]
  product_last_ge_TCC1: OBLIGATION
    FORALL (high, low: upto[N]):
      high >= low IMPLIES
       high - 1 >= 0 AND high - 1 <= N OR
        (EXISTS (j: upto[N]): high - 1 <= j);

  % Subtype TCC generated (at line 41, column 41) for  high
      % expected type  T_high[upto[N]]
  product_split_ge_TCC1: OBLIGATION
    FORALL (high, low, m: upto[N]):
      m <= high AND low - 1 <= m IMPLIES
       high >= 0 AND high <= N OR (EXISTS (j: upto[N]): high <= j);

  % Subtype TCC generated (at line 42, column 50) for  m
      % expected type  T_high[upto[N]]
  product_split_ge_TCC2: OBLIGATION
    FORALL (high, low, m: upto[N]):
      m <= high AND low - 1 <= m IMPLIES
       m >= 0 AND m <= N OR (EXISTS (j: upto[N]): m <= j);

  % Subtype TCC generated (at line 50, column 33) for  ing
      % expected type  T_high[upto[N]]
  product_0_neg_TCC1: OBLIGATION
    FORALL (ing: negint):
      ing >= 0 AND ing <= N OR (EXISTS (j: upto[N]): ing <= j);


body:
  product_posnat: THEORY
  %------------------------------------------------------------------------------
  % The products theory introduces and defines properties of the product
  % function that multiples an arbitrary function F: [posnat -> int] over a range
  % from low to high
  %
  %  		           high
  %		           ----
  %  product(low, high, F) = |  |  F(j)
  %		           |  |
  %		         j = low
  %
  %  AUTHORS:
  %
  %    Rick Butler     NASA Langley Research Center           
  %    Paul Miner      NASA Langley Research Center           
  %
  %------------------------------------------------------------------------------
  BEGIN

    IMPORTING product[posnat]

    int_is_T_high: JUDGEMENT int SUBTYPE_OF T_high
    posnat_is_T_low : JUDGEMENT posnat SUBTYPE_OF T_low

    low, n, m: VAR posnat
    high: VAR int
    F: VAR function[posnat -> int]


  % --------- Following Theorems Not Provable In Generic Framework -------

    product_shift:  THEOREM product(low+m,high+m,F) = 
                                product(low,high, (LAMBDA (n: posnat): F(n+m)))

    product_shift_neg:  THEOREM low - m > 0 IMPLIES 
                           product(low-m,high-m,F) = 
                               product(low,high, (LAMBDA n: IF n-m <= 0 THEN 0 
                                                          ELSE F(n-m) 
                                                          ENDIF))

    product_split_ge : THEOREM low-1 <= m AND m <= high IMPLIES 
                              product(low, high, F) = 
                                       product(low, m, F) * product(m+1, high, F)


  END product_posnat

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

  % Assuming TCC generated (at line 21, column 12) for  product[posnat]
      % generated from assumption product.connected_domain
  IMP_product_TCC1: OBLIGATION
    (FORALL (x, y: posnat), (z: integer):
       x <= z AND z <= y IMPLIES z >= 0 AND z > 0);

  % Judgement subtype TCC generated (at line 23, column 27) for  x
      % expected type  T_high[posnat]
  int_is_T_high: OBLIGATION
    FORALL (x: int): x >= 0 AND x > 0 OR (EXISTS (j: posnat): x <= j);

  % Judgement subtype TCC generated (at line 24, column 30) for  x
      % expected type  T_low[posnat]
  posnat_is_T_low: OBLIGATION
    FORALL (x: posnat): x >= 0 AND x > 0 OR (EXISTS (j: posnat): j <= x);

  % Subtype TCC generated (at line 33, column 40) for  high + m
      % expected type  T_high[posnat]
  product_shift_TCC1: OBLIGATION
    FORALL (high: int, m: posnat):
      high + m >= 0 AND high + m > 0 OR (EXISTS (j: posnat): high + m <= j);

  % Subtype TCC generated (at line 37, column 33) for  low - m
      % expected type  T_low[posnat]
  product_shift_neg_TCC1: OBLIGATION
    FORALL (low, m: posnat):
      low - m > 0 IMPLIES
       low - m >= 0 AND low - m > 0 OR (EXISTS (j: posnat): j <= low - m);

  % Subtype TCC generated (at line 37, column 39) for  high - m
      % expected type  T_high[posnat]
  product_shift_neg_TCC2: OBLIGATION
    FORALL (high: int, low, m: posnat):
      low - m > 0 IMPLIES
       high - m >= 0 AND high - m > 0 OR (EXISTS (j: posnat): high - m <= j);

  % Subtype TCC generated (at line 39, column 63) for  n - m
      % expected type  posnat
  product_shift_neg_TCC3: OBLIGATION
    FORALL (low, m: posnat):
      low - m > 0 IMPLIES
       (FORALL (n): NOT n - m <= 0 IMPLIES n - m >= 0 AND n - m > 0);

  % Subtype TCC generated (at line 44, column 50) for  m
      % expected type  T_high[posnat]
  product_split_ge_TCC1: OBLIGATION
    FORALL (high: int, low, m: posnat):
      m <= high AND low - 1 <= m IMPLIES
       m >= 0 AND m > 0 OR (EXISTS (j: posnat): m <= j);


body:
  product_nat: THEORY
  %------------------------------------------------------------------------------
  % The products theory introduces and defines properties of the product
  % function that multiples an arbitrary function F: [nat -> int] over a range
  % from low to high
  %
  %  		           high
  %		           ----
  %  product(low, high, F) = |  |  F(j)
  %		           |  |
  %		         j = low
  %
  %  AUTHORS:
  %
  %    Rick Butler     NASA Langley Research Center           
  %    Paul Miner      NASA Langley Research Center           
  %
  %------------------------------------------------------------------------------
  BEGIN

    IMPORTING product[nat]

    int_is_T_high: JUDGEMENT int SUBTYPE_OF T_high
    nat_is_T_low : JUDGEMENT nat SUBTYPE_OF T_low

    high, i: VAR int
    low, n, m: VAR nat
    F: VAR function[nat -> int]


  % --------- Following Theorems Not Provable In Generic Framework -------


    product_shift:  THEOREM product(low+m,high+m,F) = 
                                product(low,high, (LAMBDA (n: nat): F(n+m)))

    product_shift_neg:  THEOREM low - m >= 0 IMPLIES 
                           product(low-m,high-m,F) = 
                               product(low,high, (LAMBDA n: IF n-m < 0 THEN 0 
                                                          ELSE F(n-m) 
                                                          ENDIF))

    product_shift_ng2:  THEOREM low - m >= 0 IMPLIES 
                           product(low-m,high-m,F) = 
                               product(low,high, (LAMBDA n: F(n~m)))

    product_shift_i:  THEOREM 0 <= low + i IMPLIES
                                product(low+i,high+i,F) = 
                                product(low,high, (LAMBDA (n: nat): IF n < low THEN 0
                                                                    ELSE F(n+i) ENDIF))

  % These next two are now trivial instatiations of the updated framework.

    product_first_ge : THEOREM high >= low IMPLIES  % slightly more general
                             product(low, high, F) = F(low) * product(low+1, high, F)


    product_split_ge : THEOREM low-1 <= i AND i <= high IMPLIES 
                              product(low, high, F) = 
                                       product(low, i, F) * product(i+1, high, F)


  % ---- Auto-rewrites


    ing: VAR negint
    product_0_neg: LEMMA product(0,ing,F) = 1
    AUTO_REWRITE+ product_0_neg

                                                        
  END product_nat

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

  % Assuming TCC generated (at line 21, column 12) for  product[nat]
      % generated from assumption product.connected_domain
  IMP_product_TCC1: OBLIGATION
    (FORALL (x, y: nat), (z: integer): x <= z AND z <= y IMPLIES z >= 0);

  % Judgement subtype TCC generated (at line 23, column 27) for  x
      % expected type  T_high[nat]
  int_is_T_high: OBLIGATION
    FORALL (x: int): x >= 0 OR (EXISTS (j: nat): x <= j);

  % Judgement subtype TCC generated (at line 24, column 27) for  x
      % expected type  T_low[nat]
  nat_is_T_low: OBLIGATION
    FORALL (x: nat): x >= 0 OR (EXISTS (j: nat): j <= x);

  % Subtype TCC generated (at line 34, column 40) for  high + m
      % expected type  T_high[nat]
  product_shift_TCC1: OBLIGATION
    FORALL (high: int, m: nat):
      high + m >= 0 OR (EXISTS (j: nat): high + m <= j);

  % Subtype TCC generated (at line 38, column 33) for  low - m
      % expected type  T_low[nat]
  product_shift_neg_TCC1: OBLIGATION
    FORALL (low, m: nat):
      low - m >= 0 IMPLIES low - m >= 0 OR (EXISTS (j: nat): j <= low - m);

  % Subtype TCC generated (at line 38, column 39) for  high - m
      % expected type  T_high[nat]
  product_shift_neg_TCC2: OBLIGATION
    FORALL (high: int, low, m: nat):
      low - m >= 0 IMPLIES high - m >= 0 OR (EXISTS (j: nat): high - m <= j);

  % Subtype TCC generated (at line 40, column 63) for  n - m
      % expected type  nat
  product_shift_neg_TCC3: OBLIGATION
    FORALL (low, m: nat):
      low - m >= 0 IMPLIES (FORALL (n): NOT n - m < 0 IMPLIES n - m >= 0);

  % Subtype TCC generated (at line 48, column 38) for  low + i
      % expected type  T_low[nat]
  product_shift_i_TCC1: OBLIGATION
    FORALL (i: int, low: nat):
      0 <= low + i IMPLIES low + i >= 0 OR (EXISTS (j: nat): j <= low + i);

  % Subtype TCC generated (at line 48, column 44) for  high + i
      % expected type  T_high[nat]
  product_shift_i_TCC2: OBLIGATION
    FORALL (high, i: int, low: nat):
      0 <= low + i IMPLIES high + i >= 0 OR (EXISTS (j: nat): high + i <= j);

  % Subtype TCC generated (at line 50, column 73) for  n + i
      % expected type  nat
  product_shift_i_TCC3: OBLIGATION
    FORALL (i: int, low: nat):
      0 <= low + i IMPLIES (FORALL (n: nat): NOT n < low IMPLIES n + i >= 0);

  % Subtype TCC generated (at line 60, column 50) for  i
      % expected type  T_high[nat]
  product_split_ge_TCC1: OBLIGATION
    FORALL (high, i: int, low: nat):
      i <= high AND low - 1 <= i IMPLIES i >= 0 OR (EXISTS (j: nat): i <= j);

  % Subtype TCC generated (at line 60, column 66) for  i + 1
      % expected type  T_low[nat]
  product_split_ge_TCC2: OBLIGATION
    FORALL (high, i: int, low: nat):
      i <= high AND low - 1 <= i IMPLIES
       i + 1 >= 0 OR (EXISTS (j: nat): j <= i + 1);

  % Subtype TCC generated (at line 67, column 33) for  ing
      % expected type  T_high[nat]
  product_0_neg_TCC1: OBLIGATION
    FORALL (ing: negint): ing >= 0 OR (EXISTS (j: nat): ing <= j);


body:
  product_int: THEORY
  %------------------------------------------------------------------------------
  % The products theory introduces and defines properties of the product
  % function that multiples an arbitrary function F: [int -> int] over a range
  % from low to high
  %
  %  		           high
  %		           ----
  %  product(low, high, F) = |  |  F(j)
  %		           |  |
  %		         j = low
  %
  %  AUTHORS:
  %
  %    Rick Butler     NASA Langley Research Center           
  %    Paul Miner      NASA Langley Research Center           
  %
  %------------------------------------------------------------------------------
  BEGIN

    IMPORTING product[int]

    int_is_T_high: JUDGEMENT int SUBTYPE_OF T_high
    int_is_T_low : JUDGEMENT int SUBTYPE_OF T_low

    low, high, i, j, m: VAR int
    F: VAR function[int -> int]


  % --------- Following Theorems Not Provable In Generic Framework -------

    product_shift    :  THEOREM product(low+j,high+j,F) = 
                                product(low,high, (LAMBDA (i: int): F(i+j)))


    product_split_ge : THEOREM low-1 <= m AND m <= high IMPLIES 
                              product(low, high, F) = 
                                       product(low, m, F) * product(m+1, high, F)


    product_first_ge : THEOREM high >= low IMPLIES
                             product(low, high, F) = F(low) * product(low+1, high, F)

    product_mid_ge  : THEOREM high >= i AND i >= low IMPLIES 
                            product(low, high, F) = product(low, i-1, F) * F(i) *
                                                  product(i+1, high, F) 

    product_last_ge  : THEOREM high >= low IMPLIES 
                            product(low, high, F) = product(low, high-1, F) * F(high)


  END product_int

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

  % Assuming TCC generated (at line 21, column 12) for  product[int]
      % generated from assumption product.connected_domain
  IMP_product_TCC1: OBLIGATION (FORALL (x, y: int), (z: integer): TRUE);


body:
  product_below[N: posnat]: THEORY %below(0) is an empty type
  %------------------------------------------------------------------------------
  % The products theory introduces and defines properties of the product
  % function that multiples an arbitrary function F: [below(N) -> int] over a range
  % from low to high
  %
  %  		           high
  %		           ----
  %  product(low, high, F) = |  |  F(j)
  %		           |  |
  %		         j = low
  %
  %  AUTHORS:
  %
  %    Rick Butler     NASA Langley Research Center           
  %    Paul Miner      NASA Langley Research Center           
  %
  %------------------------------------------------------------------------------
  BEGIN

    IMPORTING product[below(N)]

    int_below: TYPE = {i:int | i < N}
    int_below_T_high: JUDGEMENT int_below SUBTYPE_OF T_high
    nat_is_T_low: JUDGEMENT nat SUBTYPE_OF T_low

    low :VAR nat
    high : VAR int_below 
    n, m, i: VAR below[N]
    F: VAR function[below[N] -> int]


  % --------- Following Theorems Not Provable In Generic Framework -------

    product_first_ge : THEOREM high >= low IMPLIES
                             product(low, high, F) = F(low) * product(low+1, high, F)

    product_last_ge  : THEOREM high >= low IMPLIES 
                            product(low, high, F) = product(low, high-1, F) * F(high)

    product_split_ge : THEOREM low - 1 <= m AND m <= high IMPLIES 
                              product(low, high, F) = 
                                       product(low, m, F) * product(m+1, high, F)

  % ---- Auto-rewrites


    ing: VAR negint
    product_0_neg: LEMMA product(0,ing,F) = 1
    AUTO_REWRITE+ product_0_neg



  END product_below

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

  % Assuming TCC generated (at line 21, column 12) for  product[below(N)]
      % generated from assumption product.connected_domain
  IMP_product_TCC1: OBLIGATION
    (FORALL (x, y: below(N)), (z: integer):
       x <= z AND z <= y IMPLIES z >= 0 AND z < N);

  % Judgement subtype TCC generated (at line 24, column 30) for  x
      % expected type  T_high[below(N)]
  int_below_T_high: OBLIGATION
    FORALL (x: int_below): x >= 0 AND x < N OR (EXISTS (j: below(N)): x <= j);

  % Judgement subtype TCC generated (at line 25, column 26) for  x
      % expected type  T_low[below(N)]
  nat_is_T_low: OBLIGATION
    FORALL (x: nat): x >= 0 AND x < N OR (EXISTS (j: below(N)): j <= x);

  % Subtype TCC generated (at line 36, column 53) for  low
      % expected type  below[N]
  product_first_ge_TCC1: OBLIGATION
    FORALL (high: int_below, low: nat): high >= low IMPLIES low < N;

  % Subtype TCC generated (at line 39, column 63) for  high - 1
      % expected type  T_high[below(N)]
  product_last_ge_TCC1: OBLIGATION
    FORALL (high: int_below, low: nat):
      high >= low IMPLIES
       high - 1 >= 0 AND high - 1 < N OR
        (EXISTS (j: below(N)): high - 1 <= j);

  % Subtype TCC generated (at line 39, column 78) for  high
      % expected type  below[N]
  product_last_ge_TCC2: OBLIGATION
    FORALL (high: int_below, low: nat):
      high >= low IMPLIES high >= 0 AND high < N;

  % Subtype TCC generated (at line 43, column 50) for  m
      % expected type  T_high[below(N)]
  product_split_ge_TCC1: OBLIGATION
    FORALL (high: int_below, low: nat, m: below[N]):
      m <= high AND low - 1 <= m IMPLIES
       m >= 0 AND m < N OR (EXISTS (j: below(N)): m <= j);

  % Subtype TCC generated (at line 49, column 33) for  ing
      % expected type  T_high[below(N)]
  product_0_neg_TCC1: OBLIGATION
    FORALL (ing: negint):
      ing >= 0 AND ing < N OR (EXISTS (j: below(N)): ing <= j);


body:
  pigeonhole: THEORY

  BEGIN

    n : VAR nat

    pigeonhole_principle_nat: LEMMA
      FORALL (f:[below(n)->below(n)]):
      bijective?(f) IFF (injective?(f) OR surjective?(f))

  END pigeonhole


body:
  factorial: THEORY
  %----------------------------------------------------------------------------
  %
  %  Factorial function:  factorial(n) = n!
  %  
  %  Author: Rick Butler                   NASA Langley Research Center
  %
  %----------------------------------------------------------------------------
  BEGIN
   
     n,k: VAR nat

     factorial(n): recursive posnat =
            (if n = 0 then 1 else n*factorial(n-1) endif) MEASURE n

     factorial_0: LEMMA factorial(0) = 1
     factorial_1: LEMMA factorial(1) = 1
     factorial_2: LEMMA factorial(2) = 2
     factorial_3: LEMMA factorial(3) = 6

     factorial_def: LEMMA factorial(n) = IF n = 0 THEN 1 ELSE 
                                         n*factorial(n-1) ENDIF

     factorial_n:   LEMMA n > 0 IMPLIES
                            factorial(n) = n*factorial(n-1)

     factorial_plus1: LEMMA factorial(n+1) = (n+1)*factorial(n)

     factorial_gt: LEMMA n > k IMPLIES factorial(n) > k^(n-k)*factorial(k)

     factorial_ge: LEMMA n >= k IMPLIES factorial(n) >= k^(n-k)*factorial(k)

     factorial_incr: LEMMA k <= n IMPLIES factorial(k) <= factorial(n)

     factorial_strict_incr: LEMMA k /= 0 AND k < n 
                                  IMPLIES factorial(k) < factorial(n)


     factorial_lt_n2n: LEMMA factorial(n) <= n^n

     AUTO_REWRITE+ factorial_0
     AUTO_REWRITE+ factorial_1

  END factorial

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

  % Subtype TCC generated (at line 14, column 44) for  n - 1
      % expected type  nat
  factorial_TCC1: OBLIGATION FORALL (n: nat): NOT n = 0 IMPLIES n - 1 >= 0;

  % Termination TCC generated (at line 14, column 34) for  factorial(n - 1)
  factorial_TCC2: OBLIGATION FORALL (n: nat): NOT n = 0 IMPLIES n - 1 < n;

  % Subtype TCC generated (at line 14, column 32) for  n * factorial(n - 1)
      % expected type  posnat
  factorial_TCC3: OBLIGATION
    FORALL (n: nat, v: [{z: nat | z < n} -> posnat]):
      NOT n = 0 IMPLIES n * v(n - 1) > 0;

  % Subtype TCC generated (at line 25, column 53) for  n - 1
      % expected type  nat
  factorial_n_TCC1: OBLIGATION FORALL (n: nat): n > 0 IMPLIES n - 1 >= 0;

  % Subtype TCC generated (at line 29, column 55) for  (n - k)
      % expected type  {i: int | k /= 0 OR i >= 0}
  factorial_gt_TCC1: OBLIGATION
    FORALL (k, n: nat): n > k IMPLIES k /= 0 OR (n - k) >= 0;

  % Subtype TCC generated (at line 31, column 57) for  (n - k)
      % expected type  {i: int | k /= 0 OR i >= 0}
  factorial_ge_TCC1: OBLIGATION
    FORALL (k, n: nat): n >= k IMPLIES k /= 0 OR (n - k) >= 0;

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


body:
  max_bounded_posnat: THEORY
  BEGIN

    a,x,y,n,UB: VAR posnat

    S: VAR {A: (nonempty?[posnat]) | EXISTS UB: FORALL (y: (A)): y <= UB}

    bnd(S): { a |  FORALL (x: (S)): x <= a}

    max_rec(S,(i:{j: posnat | j >= choose(S)})): RECURSIVE posnat =
                                IF S(i) THEN i
                                ELSE max_rec(S,i-1)
                                ENDIF
                                MEASURE i - choose(S)


    m: VAR nat  
    max_rec_in: LEMMA n >= choose(S) AND m = n - choose(S) IMPLIES S(max_rec(S, n))

    max_rec_bnd: LEMMA n >= x AND n >= choose(S) AND S(x) AND m >= n - x 
                   IMPLIES x <= max_rec(S, n)

    max(S): {a: posnat | S(a) AND (FORALL x: S(x) IMPLIES x <= a)}

    maximum?(a, S) : bool = S(a) AND (FORALL x: S(x) IMPLIES x <= a)

    max_def        : LEMMA max(S) = a IFF maximum?(a, S)

    max_lem        : LEMMA maximum?(max(S),S)

    max_in         : LEMMA S(max(S))

  END max_bounded_posnat

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

  % Existence TCC generated (at line 8, column 2) for
      % bnd(S): {a | FORALL (x: (S)): x <= a}
  bnd_TCC1: OBLIGATION
    EXISTS (x1:
              [S:
                 {A: (nonempty?[posnat]) |
                          EXISTS UB: FORALL (y: (A)): y <= UB} ->
                 {a | FORALL (x: (S)): x <= a}]):
      TRUE;

  % Subtype TCC generated (at line 14, column 38) for  i - choose(S)
      % expected type  naturalnumber
  max_rec_TCC1: OBLIGATION
    FORALL (S:
              {A: (nonempty?[posnat]) | EXISTS UB: FORALL (y: (A)): y <= UB},
            (i: {j: posnat | j >= choose[posnat](S)})):
      i - choose[posnat](S) >= 0;

  % Subtype TCC generated (at line 12, column 45) for  i - 1
      % expected type  {j: posnat | j >= choose(S)}
  max_rec_TCC2: OBLIGATION
    FORALL (S:
              {A: (nonempty?[posnat]) | EXISTS UB: FORALL (y: (A)): y <= UB},
            (i: {j: posnat | j >= choose[posnat](S)})):
      NOT S(i) IMPLIES
       i - 1 >= 0 AND i - 1 > 0 AND i - 1 >= choose[posnat](S);

  % Termination TCC generated (at line 12, column 35) for  max_rec(S, i - 1)
  max_rec_TCC3: OBLIGATION
    FORALL (S:
              {A: (nonempty?[posnat]) | EXISTS UB: FORALL (y: (A)): y <= UB},
            (i: {j: posnat | j >= choose[posnat](S)})):
      NOT S(i) IMPLIES i - 1 - choose[posnat](S) < i - choose[posnat](S);

  % Existence TCC generated (at line 23, column 2) for
      % max(S): {a: posnat | S(a) AND (FORALL x: S(x) IMPLIES x <= a)}
  max_TCC1: OBLIGATION
    EXISTS (x1:
              [S:
                 {A: (nonempty?[posnat]) |
                          EXISTS UB: FORALL (y: (A)): y <= UB} ->
                 {a: posnat | S(a) AND (FORALL x: S(x) IMPLIES x <= a)}]):
      TRUE;


body:
  min_posnat: THEORY
  BEGIN

    S: VAR (nonempty?[posnat])
    n,a,x: VAR posnat

    min(S): {a: posnat | S(a) AND (FORALL x: S(x) IMPLIES a <= x)}

    minimum?(a, S) : bool = S(a) AND (FORALL x: S(x) IMPLIES a <= x)

    min_def        : LEMMA min(S) = a IFF minimum?(a, S)

    min_lem        : LEMMA minimum?(min(S),S)


  END min_posnat

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

  % Existence TCC generated (at line 7, column 2) for
      % min(S): {a: posnat | S(a) AND (FORALL x: S(x) IMPLIES a <= x)}
  min_TCC1: OBLIGATION
    EXISTS (x1:
              [S: (nonempty?[posnat]) ->
                 {a: posnat | S(a) AND (FORALL x: S(x) IMPLIES a <= x)}]):
      TRUE;


body:
  divides_lems: THEORY
  %----------------------------------------------------------------------------
  % 
  %  Divisibility
  %
  %  Author: Rick Butler
  %
  %  NOTE.  This theory joins the old divisibility theory with the prelude
  %         definitions.  If you hate the fact that the prelude definition of divides
  %         using x as an integer, you can use divides_rew instead.
  %
  %----------------------------------------------------------------------------
  BEGIN


     n,n1,n2: VAR nat
     m,m1,m2: VAR posnat
     i,j,k,ip,jp: VAR int
     nn,mm,ii,jj,kk: VAR nzint

     divides_rew: LEMMA divides(mm,i) = (EXISTS (k: int): i = mm*k)

     divides_lt: LEMMA i /= 0 IMPLIES divides(mm,i) IMPLIES mm <= abs(i)

     divides_lt_abs: LEMMA divides(mm,ii) IMPLIES abs(mm) <= abs(ii)

     divides_mod: LEMMA divides(m,i) = (mod(i,m) = 0)

     divides_sym: LEMMA divides(mm,ii) = divides(mm,-ii)

     divides_plus : LEMMA divides(mm,i) AND divides(mm,j) IMPLIES divides(mm,i+j)


     divides_plus_1: LEMMA mm > 1 IMPLIES 
                             divides(mm,ii) IMPLIES NOT divides(mm,ii+1)

     IMPORTING min_posnat

     lcm(m1,m2): int = min({k: posnat | divides(m1,k) AND divides(m2,k)})

     IMPORTING max_bounded_posnat

     gcd_noem: LEMMA nonempty?({k: posnat | divides(k, i) AND divides(k, j)})

     gcd_prep: LEMMA  
        FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
          EXISTS (UB: posnat):
          FORALL (y: ({k: posnat | divides(k, i) AND divides(k, j)})):
            y <= UB
   

  END divides_lems

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

  % Subtype TCC generated (at line 39, column 25) for
      % {k: posnat | divides(m1, k) AND divides(m2, k)}
      % expected type  S: (nonempty?[posnat])
  lcm_TCC1: OBLIGATION
    FORALL (m1: posnat, m2: posnat):
      nonempty?[posnat]({k: posnat | divides(m1, k) AND divides(m2, k)});


body:
  primes: THEORY
  %------------------------------------------------------------------------------
  %
  % A prime number is a natural number that has exactly two divisors 1 and itself.
  %
  % AUTHOR: Rick Butler
  %
  % NOTE: prime? returns false for negative integers
  %
  %-------------------------------------------------------------------------------
  BEGIN

     IMPORTING divides_lems,factorial

     m: VAR posnat
     N,n: VAR nat

     prime?(i: int): bool = (FORALL (j: posnat): j /= 1 AND j /= i IMPLIES
                                NOT divides(j,i)) 
                              AND i > 1               %% 1 is not a prime number by def

     prime_rew  : LEMMA prime?(n) = ((FORALL (j: posnat): j > 1 AND j < n IMPLIES
                                       NOT divides(j,n)) AND n > 1)

     prime_gt_1 : LEMMA prime?(n) IMPLIES n > 1


    % Also known as Euclid's lemma:

     prime_divides_prod: LEMMA prime?(n) IMPLIES FORALL (i,j:int):
       divides(n,i*j) IMPLIES (divides(n,i) OR divides(n,j))

     prime_divides_factorial: LEMMA prime?(n) IMPLIES 
       (divides(n,factorial(N))
        IFF
        N>=n)

     prod_primes_divides: LEMMA FORALL (m,n:nat,j:int):
       prime?(n) AND prime?(m) AND divides(m,j) AND divides(n,j)
       AND n/=m
       IMPLIES
       divides(m*n,j)


     prime_2    : LEMMA prime?(2)
     prime_3    : LEMMA prime?(3)
     prime_5    : LEMMA prime?(5)
     prime_7    : LEMMA prime?(7)

  %  AUTO_REWRITE+ prime_gt_1

  END primes


body:
  max_finite_set_nat: THEORY
  BEGIN

    IMPORTING  finite_sets@finite_sets_inductions[nat]

    a,x: VAR nat

    S: VAR non_empty_finite_set[nat]

    fsmax(x,y:nat): nat = IF x <= y THEN y ELSE x ENDIF

    maxrec(S): RECURSIVE nat = 
                  IF empty?(sets.rest(S)) THEN choose(S)
                  ELSE fsmax(choose(S),maxrec(sets.rest(S)))
                  ENDIF
                MEASURE (LAMBDA S: card(S))

    max(S): {a: nat | S(a) AND (FORALL x: S(x) IMPLIES x <= a)}

    maximum?(a, S) : bool = S(a) AND (FORALL x: S(x) IMPLIES x <= a)

    max_def        : LEMMA max(S) = a IFF maximum?(a, S)

    max_lem        : LEMMA maximum?(max(S),S)

    max_in         : LEMMA S(max(S))

  END max_finite_set_nat

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

  % Termination TCC generated (at line 14, column 37) for
      % maxrec(sets.rest(S))
  maxrec_TCC1: OBLIGATION
    FORALL (S: non_empty_finite_set[nat]):
      NOT empty?(sets.rest(S)) IMPLIES
       card[nat](sets[nat].rest(S)) < card[nat](S);

  % Existence TCC generated (at line 18, column 2) for
      % max(S): {a: nat | S(a) AND (FORALL x: S(x) IMPLIES x <= a)}
  max_TCC1: OBLIGATION
    EXISTS (x1:
              [S: non_empty_finite_set[nat] ->
                 {a: nat | S(a) AND (FORALL x: S(x) IMPLIES x <= a)}]):
      TRUE;


body:
  max_below[N: nat]: THEORY

    EXPORTING ALL

  BEGIN

    IMPORTING min_nat

    S: VAR (nonempty?[below[N]])
    n,a,x: VAR below[N]

    max(S): {a: below[N] | S(a) AND (FORALL x: S(x) IMPLIES a >= x)}

    maximum?(a, S) : bool = S(a) AND (FORALL x: S(x) IMPLIES a >= x)

    max_def         : LEMMA max(S) = a IFF maximum?(a, S)

    max_lem         : LEMMA maximum?(max(S), S)

  END max_below

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

  % Existence TCC generated (at line 12, column 2) for
      % max(S): {a: below[N] | S(a) AND (FORALL x: S(x) IMPLIES a >= x)}
  max_TCC1: OBLIGATION
    EXISTS (x1:
              [S: (nonempty?[below[N]]) ->
                 {a: below[N] | S(a) AND (FORALL x: S(x) IMPLIES a >= x)}]):
      TRUE;


body:
  floor_more: THEORY
  BEGIN

    n: VAR nat
    m: VAR posnat
    i,k: VAR int
    j: VAR nonzero_integer
    x: VAR real

  %-------------------- The following are now in the prelude --------------------
  %
  %  floor_val      : LEMMA i >= k*j AND i < (k+1)*j IMPLIES floor(i/j) = k 
  %
  %  floor_small    : LEMMA abs(i) < abs(j) IMPLIES
  %                            floor(i/j) = IF i/j >= 0 THEN 0 ELSE -1 ENDIF
  %
  %  floor_eq_0     : LEMMA floor(x) = 0 IFF x >= 0 AND x < 1

    floor_small_nat: LEMMA n < m IMPLIES floor(n/m) = 0

    floor_max      : LEMMA floor(n / m) <= n

  END floor_more


body:
  floor_div_lems: THEORY
  BEGIN

    i,k: VAR int
    j: VAR nonzero_integer
    x: VAR real

  %-------------------- following now in prelude --------------------
  %
  %  floor_val:   LEMMA i >= k*j AND i < (k+1)*j IMPLIES floor(i/j) = k 
  %
  %  floor_small: LEMMA  abs(i) < abs(j) IMPLIES
  %                         floor(i/j) = IF i/j >= 0 THEN 0 ELSE -1 ENDIF
  %
  %  floor_eq_0:  LEMMA floor(x) = 0 IMPLIES x >= 0 AND x < 1


    n: VAR nat
    m: VAR posnat

    floor_small_nat: LEMMA n < m IMPLIES floor(n/m) = 0

    is_multiple: LEMMA integer_pred(i/j) = (EXISTS k: i = k*j)
  	
  END floor_div_lems


body:
  max_upto[N: nat]: THEORY

    EXPORTING ALL

  BEGIN

    IMPORTING min_nat

    S: VAR (nonempty?[upto[N]])
    n,a,x: VAR upto[N]

    max(S): {a: upto[N] | S(a) AND (FORALL x: S(x) IMPLIES a >= x)}

    maximum?(a, S) : bool = S(a) AND (FORALL x: S(x) IMPLIES a >= x)

    max_def         : LEMMA max(S) = a IFF maximum?(a, S)

    max_lem         : LEMMA maximum?(max(S), S)

  END max_upto

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

  % Existence TCC generated (at line 12, column 2) for
      % max(S): {a: upto[N] | S(a) AND (FORALL x: S(x) IMPLIES a >= x)}
  max_TCC1: OBLIGATION
    EXISTS (x1:
              [S: (nonempty?[upto[N]]) ->
                 {a: upto[N] | S(a) AND (FORALL x: S(x) IMPLIES a >= x)}]):
      TRUE;


body:
  abstract_max[T: TYPE, N: nat, f: [T -> upto[N]], P: pred[T]]: THEORY
  BEGIN

     ASSUMING

     T_ne: ASSUMPTION EXISTS (t: T): P(t)

     ENDASSUMING

     IMPORTING max_upto

     TP: TYPE = {t: T | P(t)}


     n: VAR upto[N]

     S,SS: VAR T

     is_one(n): bool = (EXISTS (S: T): P(S) AND f(S) = n)

     prep0: LEMMA nonempty?({n: upto[N] | is_one(n)})

     max_f: upto[N] = max({n: upto[N] | is_one(n)})

     prep1: LEMMA nonempty?({S: T | f(S) = max_f AND P(S)})

     maximal?(S): bool = P(S) AND 
                         (FORALL (SS: T): P(SS) IMPLIES f(S) >= f(SS))

     max: {S: T | maximal?(S)} 


     max_def: LEMMA maximal?(max)

     max_in : LEMMA P(max) 

     max_is_max: LEMMA P(SS) IMPLIES f(max) >= f(SS) 


  END abstract_max

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

  % Subtype TCC generated (at line 23, column 24) for
      % {n: upto[N] | is_one(n)}
      % expected type  S: (nonempty?[upto[N]])
  max_f_TCC1: OBLIGATION nonempty?[upto[N]]({n: upto[N] | is_one(n)});

  % Existence TCC generated (at line 30, column 3) for
      % max: {S: T | maximal?(S)}
  max_TCC1: OBLIGATION EXISTS (x: {S: T | maximal?(S)}): TRUE;


body:
  abstract_min[T: TYPE, f: [T -> nat], P: pred[T]]: THEORY
  BEGIN

     ASSUMING

     T_ne: ASSUMPTION EXISTS (t: T): P(t)

     ENDASSUMING

     IMPORTING min_nat

     TP: TYPE = {t: T | P(t)}


     n: VAR nat

     S,SS: VAR T

     is_one(n): bool = (EXISTS (S: T): P(S) AND f(S) = n)

     prep0: LEMMA nonempty?({n: nat | is_one(n)})

     min_f: nat = min({n: nat | is_one(n)})

     prep1: LEMMA nonempty?({S: T | f(S) = min_f AND P(S)})

     minimal?(S): bool = P(S) AND 
                         (FORALL (SS: T): P(SS) IMPLIES f(S) <= f(SS))

     min: {S: T | minimal?(S)} 


     min_def: LEMMA minimal?(min)

     min_in : LEMMA P(min) 

     min_is_min: LEMMA P(SS) IMPLIES f(min) <= f(SS) 


  END abstract_min

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

  % Subtype TCC generated (at line 23, column 20) for  {n: nat | is_one(n)}
      % expected type  S: (nonempty?[nat])
  min_f_TCC1: OBLIGATION nonempty?[nat]({n: nat | is_one(n)});

  % Existence TCC generated (at line 30, column 3) for
      % min: {S: T | minimal?(S)}
  min_TCC1: OBLIGATION EXISTS (x: {S: T | minimal?(S)}): TRUE;


body:
  div_nat: THEORY
  %------------------------------------------------------------------------
  % Defines natural division:
  %
  %    Author:   Rick Butler                NASA Langley Research Center
  %
  % NOTE.  See div library for division defined over the integers
  % 
  %------------------------------------------------------------------------

  BEGIN

    IMPORTING floor_more

    n,k: VAR nat
    m: VAR posnat
    i: VAR int

    div(n,m): upto(n) = floor(n/m)

    div_nat      : LEMMA div(n,m) = IF n < m THEN 0 ELSE 1 + div(n-m,m) ENDIF

    div_value    : LEMMA n >= k*m AND n < (k+1)*m IMPLIES div(n,m) = k 

    div_sum_nat  : LEMMA n + i*m >= 0 IMPLIES div(n+i*m,m) = div(n,m) + i

    div_multiple : LEMMA div(k*m,m) = k   
    
    div_is_0     : LEMMA div(n,m) = 0 IFF n < m

  % ------------ some order relationships -------------
    
    div_smaller  : LEMMA m * div(n,m) <= n 

    div_rem_small: LEMMA n - m * div(n,m) < m

    div_mult_lt  : LEMMA n < k*m IFF div(n,m) < k

  % ------------ Special arguments ------------

    div_by_one   : LEMMA div(n,1) = n
                
    div_zero     : LEMMA div(0,m) = 0
                
    div_eq_arg   : LEMMA div(m,m) = 1

    div_one      : LEMMA m > 1 IMPLIES div(1,m) = 0
    
    div_even     : LEMMA integer_pred(n/m) IMPLIES n - m*div(n,m) = 0
    
  END div_nat

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

  % Subtype TCC generated (at line 19, column 22) for  floor(n / m)
      % expected type  upto(n)
  div_TCC1: OBLIGATION FORALL (n: nat, m: posnat): floor(n / m) <= n;

  % Subtype TCC generated (at line 21, column 63) for  n - m
      % expected type  nat
  div_nat_TCC1: OBLIGATION
    FORALL (m: posnat, n: nat): NOT n < m IMPLIES n - m >= 0;


body:
  mod_nat: THEORY
  %-----------------------------------------------------------------------
  %
  % NOTE: Given that "mod" is now defined in the prelude, this "mod" has
  %       been renamed "nmod" 
  %
  %-----------------------------------------------------------------------
  BEGIN
   
    n,k,n1,n2,c: VAR nat
    m,mk: VAR posnat
    i: VAR int

    IMPORTING div_nat

    nmod(n,m): below(m) = n - m*div(n,m)

    nmod_even    : LEMMA integer_pred(n/m) IMPLIES nmod(n,m) = 0

    nmod_lt_nat  : LEMMA n < m IMPLIES nmod(n,m) = n

    nmod_sum     : LEMMA n+i*m >= 0 IMPLIES nmod(n+i*m,m) = nmod(n,m)

    nmod_sum_nat : LEMMA n1 < m AND n2 < m IMPLIES
                            nmod(n1+n2,m) = IF n1 + n2 < m THEN n1+n2
                                           ELSE n1 + n2 - m
                                           ENDIF

    nmod_it_is   : LEMMA n = k + m*c AND k < m IMPLIES k = nmod(n,m)

    nmod_zero    : LEMMA nmod(0,m) = 0

    nmod_one     : LEMMA nmod(1,m) = IF m = 1 THEN 0
                                    ELSE 1
                                    ENDIF

    nmod_of_nmod  : LEMMA nmod(n + nmod(k,m), m) = nmod(n+k, m)

    nmod_mult    : LEMMA nmod(nmod(n,mk*m),m) = nmod(n,m)

  END mod_nat

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

  % Subtype TCC generated (at line 16, column 24) for  n - m * div(n, m)
      % expected type  below(m)
  nmod_TCC1: OBLIGATION
    FORALL (n: nat, m: posnat):
      n - m * div(n, m) >= 0 AND n - m * div(n, m) < m;


body:
  tdiv: THEORY

  %------------------------------------------------------------------------
  % Defines natural and integer division  (Number Theory Style)
  %
  % There is no universally agreed semantics for integer division for a
  % negative argument.  For a negative argument, division can be defined
  % with truncation towards or away from zero.  The definition in this
  % theory truncates away from zero (i.e. div(-7,3) = -3).  This is is the
  % approach used in most number theory books.  This approach has the
  % advantage that div(i,m) = the greatest integer less than i/m.  The
  % alternate approach (i.e. truncation towards zero: div(-7,3) = -2) is
  % simpler to compute because div(-i,m) = -div(i,m) under that
  % definition.  It is the method defined in tha Ada reference manual.
  %
  % To prevent confusion with other "div", this one has been renamed "tdiv"
  %
  %   
  %% AUTHOR
  % ------
  % 
  %   Ricky W. Butler   		   
  %   Mail Stop 130			     fax: (804) 864-4234
  %   NASA Langley Research Center	   phone: (804) 864-6198
  %   Hampton, Virginia 23681-0001
  %------------------------------------------------------------------------


    BEGIN

    i,k: VAR int
    n: VAR nat
    m: VAR posnat
    j: VAR nonzero_integer
    x: VAR real
    negi,ngi2: VAR negint

    tdiv(i,j): integer = floor(i/j)

    sgn(x): int = IF x >= 0 THEN 1 ELSE -1 ENDIF

    JUDGEMENT tdiv(n,m) HAS_TYPE nat
    JUDGEMENT tdiv(negi,m) HAS_TYPE  negint
    JUDGEMENT tdiv(negi,ngi2) HAS_TYPE  nonneg_int
    JUDGEMENT tdiv(m,negi) HAS_TYPE  negint

    tdiv_nat:        LEMMA tdiv(n,m) = IF n>=m THEN 1 + tdiv(n-m, m) ELSE 0 ENDIF

    tdiv_neg_d:	  LEMMA tdiv(i,-j) = IF integer_pred(i/j) THEN
  				      -tdiv(i,j)
  				    ELSE
  				      -tdiv(i,j)-1
  				    ENDIF 
  		       
    tdiv_neg:	  LEMMA tdiv(-i,j) = IF integer_pred(i/j) THEN
  			              -tdiv(i,j)
  				    ELSE
  				      -tdiv(i,j)-1
  				    ENDIF
   

    tdiv_def:      THEOREM tdiv(i,m) =
                             IF i >= m THEN 1 + tdiv(i-m, m) 
                             ELSIF i >= 0 THEN 0
                             ELSIF integer_pred(i/m) THEN -tdiv(-i,m) 
                             ELSE
                               -1 - tdiv(-i,m)           
                             ENDIF   

   
    tdiv_sgn:        LEMMA tdiv(i,-j) = tdiv(-i,j) 

    tdiv_value:      LEMMA i >= k*j AND i < (k+1)*j IMPLIES 
                            tdiv(i,j) = k

  % ================== tdiv for special values =============================

    tdiv_zero:	  LEMMA tdiv(0,j) = 0
    
    tdiv_one:	  LEMMA abs(j) > 1 IMPLIES tdiv(1,j) = 
                             IF j >= 0 THEN 0 ELSE -1 ENDIF
     
    tdiv_eq_arg:	  LEMMA tdiv(j,j) = 1
    
    tdiv_by_one:	  LEMMA tdiv(i,1) = i

    tdiv_eq_0:	  LEMMA tdiv(i,j) = 0 IMPLIES i = 0 OR
                      (sgn(i) = sgn(j) AND abs(i) < abs(j))
    
    tdiv_lt:	  LEMMA abs(i) < abs(j) IMPLIES 
                            tdiv(i,j) = IF i = 0 OR sgn(i) = sgn(j) THEN 0 
                                       ELSE -1
                                       ENDIF

    tdiv_parity:	  LEMMA sgn(i) = sgn(j) IMPLIES tdiv(i,j) >= 0
  		    
    tdiv_parity_neg: LEMMA sgn(i) /= sgn(j) IMPLIES tdiv(i,j) <= 0

    tdiv_smaller:    LEMMA m * tdiv(n,m) <= n 

    tdiv_abs:        LEMMA abs(tdiv(i,j)) =
                            IF integer_pred(i/j) OR sgn(i) = sgn(j) THEN
                               tdiv(abs(i),abs(j))
                            ELSE tdiv(abs(i),abs(j)) + 1
                            ENDIF
   
    tdiv_max:        LEMMA abs(j) * abs(tdiv(i,j)) <= abs(i) + abs(j)

  % ================== tdiv over addition =================================

    tdiv_multiple:      LEMMA tdiv(k*j,j) = k   

    tdiv_sum:           LEMMA tdiv(i+k*j,j) = tdiv(i,j) + k

  END tdiv

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

  % Judgement subtype TCC generated (at line 42, column 12) for  tdiv(n, m)
      % expected type  nat
  tdiv_TCC1: OBLIGATION FORALL (m, n): tdiv(n, m) >= 0;

  % Judgement subtype TCC generated (at line 43, column 12) for  tdiv(negi, m)
      % expected type  negint
  tdiv_TCC2: OBLIGATION
    FORALL (m, negi): tdiv(negi, m) <= 0 AND tdiv(negi, m) < 0;

  % Judgement subtype TCC generated (at line 44, column 12) for
      % tdiv(negi, ngi2)
      % expected type  nonneg_int
  tdiv_TCC3: OBLIGATION FORALL (negi, ngi2): tdiv(negi, ngi2) >= 0;

  % Judgement subtype TCC generated (at line 45, column 12) for  tdiv(m, negi)
      % expected type  negint
  tdiv_TCC4: OBLIGATION
    FORALL (m, negi): tdiv(m, negi) <= 0 AND tdiv(m, negi) < 0;


body:
  tmod: THEORY
  %------------------------------------------------------------------------
  %
  % mod function for number theory
  %
  % This has been defined using "tdiv"
  %
  % AUTHOR
  % ------
  % 
  %   Ricky W. Butler                email: r.w.butler@larc.nasa.gov
  %   Mail Stop 130                            fax: (804) 864-4234
  %   NASA Langley Research Center           phone: (804) 864-6198
  %   Hampton, Virginia 23681-0001
  %
  %
  %------------------------------------------------------------------------

  BEGIN


    IMPORTING tdiv

    i,k,cc: VAR int
    m: VAR posnat
    n,a,b,c: VAR nat   

    j: VAR nonzero_integer

    ml3: LEMMA abs(i -  m * floor(i/m)) < m
    ml4: LEMMA abs(i +  m * floor(-i/m)) < m

    mod(i,j): {k| abs(k) < abs(j)} = i-j*tdiv(i,j)

    mod_even:       LEMMA integer?(i/j) IMPLIES mod(i,j) = 0

    mod_neg:        LEMMA mod(-i,j) = IF integer?(i/j) THEN 0
                                      ELSE j - mod(i,j)
                                      ENDIF

    mod_neg_d:      LEMMA mod(i,-j) = IF integer?(i/j) THEN 0
                                      ELSE mod(i,j) - j 
                                      ENDIF

    mod_eq_arg:     LEMMA mod(j,j) = 0
    
    mod_lt:         LEMMA abs(i) < abs(j) IMPLIES mod(i,j) = 
                                    IF sgn(i) = sgn(j) OR i = 0 THEN i
                                    ELSE i + j
                                    ENDIF

    mod_lt_nat:     LEMMA n < m IMPLIES mod(n,m) = n

    mod_sum_pos:    LEMMA mod(i+k*m,m) = mod(i,m)

    mod_sum:        LEMMA mod(i+k*j,j) = mod(i,j)

    mod_it_is:      LEMMA a = b + m*c AND b < m IMPLIES b = mod(a,m)

    mod_zero:       LEMMA mod(0,j) = 0

    mod_0   :       LEMMA mod(0,j) = 0

    mod_one:        LEMMA mod(1,j) = IF abs(j) = 1 THEN 0
                                      ELSIF j > 0 THEN 1
                                      ELSE j + 1
                                      ENDIF

    mod_of_mod:     LEMMA mod(i + mod(k,m), m) = mod(i+k, m)

    mod_pos:        LEMMA mod(i,m) >= 0 AND mod(i,m) < m

    JUDGEMENT mod(i,m) HAS_TYPE below(m)

  % ------- connection with prelude rem --------------

    mod_to_rem: LEMMA mod(i,m) = rem(m)(i)

    mod_0_divides: LEMMA mod(i,j) = 0 IFF divides(j,i)

    AUTO_REWRITE+ mod_pos
    AUTO_REWRITE+ mod_0
    AUTO_REWRITE+ mod_eq_arg
    AUTO_REWRITE+ mod_sum_pos
    AUTO_REWRITE+ mod_of_mod
    AUTO_REWRITE+ mod_sum


  END tmod

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

  % Subtype TCC generated (at line 33, column 35) for  i - j * tdiv(i, j)
      % expected type  {k | abs(k) < abs(j)}
  mod_TCC1: OBLIGATION
    FORALL (i: int, j: nonzero_integer): abs(i - j * tdiv(i, j)) < abs(j);

  % Judgement subtype TCC generated (at line 73, column 12) for  mod(i, m)
      % expected type  below(m)
  mod_TCC2: OBLIGATION FORALL (i, m): mod(i, m) >= 0 AND mod(i, m) < m;


body:
  abs_rews : THEORY
  %------------------------------------------------------------------------
  %
  % Author: Rick Butler                  NASA Langley Research Center
  %
  % This introduces some lemmas and rewrites especially useful for integer
  % arguments.  See also reals@abs_lems
  %
  % To prevent name duplication with reals@abs_lems these rewrites are given
  % non-standard names.
  %------------------------------------------------------------------------
  BEGIN

    n: VAR nat
    x: VAR real

    abs_nat_rew      : LEMMA abs(n) = n

    abs_0_rew        : LEMMA abs(0) = 0

    abs_neg_rew      : LEMMA abs(-x) = abs(x)

    sgn_nat_rew      : LEMMA sgn(n) = 1

    AUTO_REWRITE+  abs_0_rew
    AUTO_REWRITE+  abs_nat_rew
    AUTO_REWRITE+  abs_neg_rew
    AUTO_REWRITE+  sgn_nat_rew

  END abs_rews


body:
  div: THEORY

  %------------------------------------------------------------------------
  % Defines natural and integer division  (Ada Style)
  %
  % There is no universally agreed semantics for integer division for a
  % negative argument.  For a negative argument, division can be defined
  % with truncation towards or away from zero.  The definition in this
  % theory truncates toward zero (i.e. div(-7,3) = -2).  This is 
  % simpler to compute because div(-i,m) = -div(i,m) and is the
  % method defined in tha Ada reference manual. The alternate method
  % (i.e. truncation away from zero: div(-7,3) = -3) is the approach
  % used in most number theory books.  This approach has the
  % advantage that div(i,m) = the greatest integer less than i/m.
  %
  % AUTHOR
  % ------
  % 
  %   Ricky W. Butler   		   email: r.w.butler@larc.nasa.gov
  %   Mail Stop 130			     fax: (804) 864-4234
  %   NASA Langley Research Center	   phone: (804) 864-6198
  %   Hampton, Virginia 23681-0001
  %------------------------------------------------------------------------


    BEGIN

    IMPORTING floor_div_lems, abs_rews


    i,k: VAR int
    n: VAR nat
    m: VAR posnat
    j: VAR nonzero_integer
    x: VAR real

    div(i,j): integer = sgn(i)*sgn(j)*floor(abs(i)/abs(j))

    div_nat:     LEMMA div(n,m) = floor(n/m)

    div_rew:     LEMMA div(n,m) = IF n < m THEN 0 ELSE 1 + div(n-m,m) ENDIF

    div_def:     LEMMA div(i,j) = IF i/j >= 0 THEN floor(i/j)
  				ELSE ceiling(i/j)
  				ENDIF    


    div_value:    LEMMA IF sgn(i) = sgn(j) THEN
                           i >= k*j AND i < (k+1)*j IMPLIES div(i,j) = k 
                        ELSE
                           i > (k-1)*j AND i <= k*j IMPLIES div(i,j) = k
                        ENDIF 


    div_neg:	LEMMA div(-i,j) = -div(i,j)

    div_neg_d:	LEMMA div(i,-j) = -div(i,j)
   
  % ================== div for special values =============================

    div_zero:	  LEMMA div(0,j) = 0
    
    div_one:	  LEMMA abs(j) > 1 IMPLIES div(1,j) = 0
    
    div_minus1:	  LEMMA abs(j) > 1 IMPLIES div(-1, j) = 0
    
    div_eq_arg:	  LEMMA div(j,j) = 1
    
    div_by_one:	  LEMMA div(i,1) = i
    
    div_eq_0:	  LEMMA div(i,j) = 0 IMPLIES abs(i) < abs(j)
    
    div_lt:	  LEMMA abs(i) < abs(j) IMPLIES div(i,j) = 0

    div_lt_nat:	  LEMMA n < m IMPLIES div(n,m) = 0

    div_is_0:       LEMMA div(i,j) = 0 IFF abs(i) < abs(j)
    
    div_parity:	  LEMMA (sgn(i) = sgn(j) AND abs(i) >= abs(j)) IMPLIES
  			  div(i,j) > 0
  		    
    div_parity_neg: LEMMA (sgn(i) /= sgn(j) AND abs(i) >= abs(j)) IMPLIES
                            div(i,j) < 0

    div_ge_0:       LEMMA (sgn(i) = sgn(j) IMPLIES div(i,j) >= 0) AND
                            (div(i,j) >= 0 IMPLIES 
                               abs(i) < abs(j) OR sgn(i) = sgn(j))

    div_le_0:       LEMMA (sgn(i) /= sgn(j) IMPLIES div(i,j) <= 0) AND
  			  (div(i,j) <= 0 IMPLIES 
                               abs(i) < abs(j) OR sgn(i) /= sgn(j))

    div_smaller:    LEMMA m * div(n,m) <= n 
   
    div_abs:        LEMMA abs(div(i,j)) = div(abs(i),abs(j))

    div_max:        LEMMA abs(j)*abs(div(i,j)) <= abs(i)

  % ================== div over addition =================================

    div_multiple:	  LEMMA div(k*j,j) = k   
    
    div_even:	  LEMMA integer_pred(i/j) IMPLIES i - j*div(i,j) = 0
    
    div_sum:	  LEMMA IF integer_pred(i/j) OR sgn(i+k*j) = sgn(i) THEN
  			   div(i+k*j,j) = div(i,j) + k
  			ELSE 
  			   div(i+k*j,j) = div(i,j) + k + sgn(i)*sgn(j)
  			ENDIF

    b: VAR nat
    div_sum_nat:	  LEMMA div(n+b*m,m) = div(n,m) + b

    nonposint: TYPE = {i: int | i <= 0} CONTAINING -1
    negint: TYPE = {i: int | i < 0} CONTAINING -1

    npi: VAR nonposint
    negi: VAR negint

    JUDGEMENT div(n,m) HAS_TYPE nat
    JUDGEMENT div(npi,m) HAS_TYPE  nonposint
    JUDGEMENT div(npi,negi) HAS_TYPE nat
    JUDGEMENT div(m,negi) HAS_TYPE nonposint

    div_0: LEMMA div(0,j) = 0

    AUTO_REWRITE+ div_0
    AUTO_REWRITE+ div_eq_arg              % LEMMA div(j,j) = 1
    AUTO_REWRITE+ div_by_one              % LEMMA div(i,1) = i
    AUTO_REWRITE+ div_multiple            % LEMMA div(k*j,j) = k   
    AUTO_REWRITE+ div_lt_nat              % LEMMA n < m IMPLIES div(n,m) = 0
    AUTO_REWRITE+ div_nat                 % LEMMA div(n,m) = floor(n/m)

    END div

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

  % Judgement subtype TCC generated (at line 120, column 12) for  div(n, m)
      % expected type  nat
  div_TCC1: OBLIGATION FORALL (m, n): div(n, m) >= 0;

  % Judgement subtype TCC generated (at line 121, column 12) for  div(npi, m)
      % expected type  nonposint
  div_TCC2: OBLIGATION FORALL (m, npi): div(npi, m) <= 0;

  % Subtype TCC generated (at line 122, column 20) for  negi
      % expected type  nonzero_integer
  div_TCC3: OBLIGATION FORALL (negi): negi /= 0;

  % Judgement subtype TCC generated (at line 122, column 12) for
      % div(npi, negi)
      % expected type  nat
  div_TCC4: OBLIGATION FORALL (negi, npi): div(npi, negi) >= 0;

  % Judgement subtype TCC generated (at line 123, column 12) for  div(m, negi)
      % expected type  nonposint
  div_TCC5: OBLIGATION FORALL (m, negi): div(m, negi) <= 0;


body:
  mod_lems: THEORY
  %------------------------------------------------------------------------
  % Develops useful lemmas about mod
  %
  %
  % AUTHOR
  % ------
  % 
  %   Ricky W. Butler   		   email: r.w.butler@larc.nasa.gov
  %   Mail Stop 130			     fax: (804) 864-4234
  %   NASA Langley Research Center	   phone: (804) 864-6198
  %   Hampton, Virginia 23681-0001
  %------------------------------------------------------------------------

    BEGIN
   
  %  IMPORTING mod    %% in prelude NOW
   
    i,j,k: VAR int
    m: VAR posnat
    n,a,b,c,x: VAR nat  
    jj: VAR nzint 

  % The following rule characterizes the property that incrementing
  % modulo m wraps around the zero point. 

    mod_0           : LEMMA mod(0,jj) = 0

    mod_1           : LEMMA j > 1 IMPLIES mod(1,j) = 1

    mod_by1         : LEMMA mod(i,1) = 0

    mod_to_rem      : LEMMA mod(i,m) = rem(m)(i)

    mod_0_divides   : LEMMA mod(i,jj) = 0 IFF divides(jj,i)

    mod_wrap_around : LEMMA n < m & (c <= m & c >= m-n) =>
                                mod(n+c, m) = n - (m-c)

    mod_wrap2       : LEMMA c < m IMPLIES mod(m+c, m) = c

  % Injection-like properties for mod for limited ranges

    mod_inj1        : LEMMA x < m AND n < m AND c < m AND
                         mod(x + n, m) = mod(x + c, m) IMPLIES n = c

    mod_inj2        : LEMMA x < m AND n < m AND c < m AND
                          mod(x - n, m) = mod(x - c, m) IMPLIES n = c

    mod_wrap_inj    : LEMMA
        x < m AND a < m AND b < m AND a > 0
          IMPLIES (mod(x + a, m) = mod(x - b, m)) = (a + b = m)

    kk, vv: VAR nat
    mod_neg_limited : LEMMA 0 <= kk AND  kk < m AND vv < m AND
                        vv - kk < 0 IMPLIES mod(vv - kk,m) = m + vv - kk

    mod_int_quot: LEMMA FORALL (k:nat, n:posnat): 
                 integer_pred((k-mod(k,n))/n) AND (k-mod(k,n))/n>=0

    floor_div_prod: LEMMA FORALL (n,m:posnat,i:nat):
  	floor(i / (n*m)) = floor(floor(i / m) / n)

    mod_mult_quot: LEMMA FORALL (n,m:posnat,i:nat): 
      mod(i, n * m) = mod(i, m) + m * mod((i - mod(i, m)) / m, n)

    AUTO_REWRITE+ mod_0
    AUTO_REWRITE+ mod_1
    AUTO_REWRITE+ mod_by1
    AUTO_REWRITE+ mod_eq_arg           %% mod(j,j) = 0
    AUTO_REWRITE+ mod_sum              %% mod(i+k*j,j) = mod(i,j)
    AUTO_REWRITE+ mod_of_mod           %% mod(i + mod(k,m), m) = mod(i+k, m)

  END mod_lems

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

  % Subtype TCC generated (at line 29, column 46) for  j
      % expected type  nonzero_integer
  mod_1_TCC1: OBLIGATION FORALL (j: int): j > 1 IMPLIES j /= 0;

  % Subtype TCC generated (at line 65, column 40) for  (i - mod(i, m)) / m
      % expected type  int
  mod_mult_quot_TCC1: OBLIGATION
    FORALL (m: posnat, i: nat): integer_pred((i - mod(i, m)) / m);


body:
  gcd: THEORY
  %------------------------------------------------------------------------------
  % Author: Alfons Geser, HTWK Leipzig, Germany
  %         Ricky W. Butler, NASA Langley
  % Date: May, 2009
  %
  %         Anthony N (March 2012)
  %------------------------------------------------------------------------------
  BEGIN

     IMPORTING divides_lems, mod_lems
     IMPORTING div              %% for proof


     n,m: VAR nat
     nn,mm: VAR posnat
     p, q, l: VAR posint

     i,j,k,ip,jp: VAR int
     ii,jj,kk: VAR nzint

     gcd(i:int,j: {jj:int| i=0 => jj /= 0}): 
           {k: posnat | divides(k,i) AND divides(k,j)}  
              = max({k: posnat | divides(k,i) AND divides(k,j)})


     gcd_divides: LEMMA (i /= 0 OR j /= 0) IMPLIES
                        divides(gcd(i,j),i) AND divides(gcd(i,j),j)

     gcd_is_max: LEMMA (i /= 0 OR j /= 0) AND divides(kk,i) AND divides(kk,j) 
                         IMPLIES kk <= gcd(i,j) 

     gcd_def    : LEMMA (i /= 0 OR j /= 0) IMPLIES
                        (gcd(i,j) = nn IFF
                             ( (divides(nn,i) AND divides(nn,j)) AND 
                               (FORALL mm: divides(mm,i) AND divides(mm,j) 
                                            IMPLIES mm <= nn))) 

     gcd_0_pos  : LEMMA gcd(0,mm) = mm

     gcd_abs    : LEMMA (i /= 0 OR j /= 0) IMPLIES gcd(i,j) = gcd(abs(i),abs(j))

     gcd_0_neg  : LEMMA gcd(0,-mm) = mm

     gcd_sym    : LEMMA (i /= 0 OR j /= 0) IMPLIES gcd(i,j) = gcd(j,i)

     gcd_lt_nat : LEMMA (n /= 0)  IMPLIES
                              gcd(n,m) <= n

     gcd_lt     : LEMMA (i /= 0 AND j /= 0) IMPLIES
                              gcd(i,j) <= min(abs(i),abs(j))




     gcd_0      : LEMMA gcd(0,ii) = abs(ii) 


     gcd_mod    : LEMMA (i /= 0) IMPLIES gcd(mod(j,i),i) = gcd(i,j) 

     gcd_mod_div: LEMMA (i /= 0) IMPLIES divides(gcd(i,j),mod(j,i))



     gcd_factors_nat: LEMMA (n /= 0 OR m /= 0) IMPLIES
                         EXISTS ip,jp: gcd(n,m) = ip*n + jp*m

     gcd_factors: LEMMA (i /= 0 OR j /= 0) IMPLIES
                            EXISTS ip,jp: gcd(i,j) = ip*i + jp*j

     divides_gcd: LEMMA (i /= 0 OR j /= 0) AND divides(kk,i) AND divides(kk,j) 
                        IMPLIES divides(kk,gcd(i,j))


     gcd_same : LEMMA gcd(p, p) = p

     gcd_minus: LEMMA p /= q IMPLIES gcd(p, q) = gcd(p, q - p)

     gcd_times: LEMMA gcd(p * l, q * l) = gcd(p, q) * l

  %
  %  relatively_prime
  %

     rel_prime(i:int,j: {jj:int| i=0 => jj /= 0}): bool = (gcd(i,j) = 1)

     rel_prime_lem: LEMMA (i /= 0 OR j /= 0) IMPLIES
                            ( rel_prime(i,j) 
                              IFF (EXISTS (n,m: int): 1 = m*i + n*j) )

  %   Bezouts: LEMMA gcd(a,b) = d IMPLIES
  %                     EXISTS (j,k: int): a*j+b*k = d

    rel_prime_div_prod: LEMMA (i/=0 OR j/=0) IMPLIES
      rel_prime(i,j) AND divides(i,j*k) IMPLIES divides(i,k)

    rel_prime_sym: LEMMA (i/=0 OR j/=0) IMPLIES rel_prime(i,j) = rel_prime(j,i)

    rel_prime_mult_right: LEMMA (i/=0 OR j/=0) AND (i/=0 OR k/=0)
      AND rel_prime(i,j) AND rel_prime(i,k) IMPLIES rel_prime(i,j*k)

    rel_prime_mult_left: LEMMA (i/=0 OR j/=0) AND (j/=0 OR k/=0)
      AND rel_prime(i,j) AND rel_prime(k,j) IMPLIES rel_prime(i*k,j)


  %
  %  Euclid's algorithm
  %

     compute_gcd(i:int,j:{jj:int| i=0 => jj /= 0}): RECURSIVE {kj: posnat | kj = gcd(i,j)} =
       IF    i<0 THEN compute_gcd(-i,j)
       ELSIF j<0 THEN compute_gcd(i,-j)
       ELSIF i=0 THEN j
       ELSIF j=0 THEN i
       ELSIF i<j THEN compute_gcd(j,i)
       ELSE
         (LET rem = mod(i,j) IN
           IF rem = 0 THEN j ELSE compute_gcd(j,rem) ENDIF)
       ENDIF
         MEASURE (IF i<0 AND j<0 THEN -i-j+3
         	        ELSIF i<0 THEN -i+j+2
  		ELSIF j<0 THEN i-j+2
  		ELSIF i<j THEN i+j+1
  		ELSE i+j ENDIF)

     % Inverse

     IMPORTING pigeonhole

     rel_prime_inverse: LEMMA 
       m>1 AND rel_prime(n,m) IMPLIES 
       FORALL (q:below(m)): EXISTS (k:below(m)): mod(n*k,m) = q


  END gcd

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

  % Subtype TCC generated (at line 24, column 18) for
      % {k: posnat | divides(k, i) AND divides(k, j)}
      % expected type  S:
                     %   {A: (nonempty?[posnat]) |
                     %            EXISTS UB: FORALL (y: (A)): y <= UB}
  gcd_TCC1: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      nonempty?[posnat]({k: posnat | divides(k, i) AND divides(k, j)}) AND
       (EXISTS UB:
          FORALL (y: ({k: posnat | divides(k, i) AND divides(k, j)})):
            y <= UB);

  % Subtype TCC generated (at line 28, column 36) for  j
      % expected type  {jj: int | i = 0 => jj /= 0}
  gcd_divides_TCC1: OBLIGATION
    FORALL (i, j: int): (i /= 0 OR j /= 0) IMPLIES i = 0 => j /= 0;

  % Subtype TCC generated (at line 41, column 71) for  abs(j)
      % expected type  {jj: int | abs(i) = 0 => jj /= 0}
  gcd_abs_TCC1: OBLIGATION
    FORALL (i, j: int): (i /= 0 OR j /= 0) IMPLIES abs(i) = 0 => abs(j) /= 0;

  % Subtype TCC generated (at line 48, column 34) for  m
      % expected type  {jj: int | n = 0 => jj /= 0}
  gcd_lt_nat_TCC1: OBLIGATION
    FORALL (m, n: nat): (n /= 0) IMPLIES n = 0 => m /= 0;

  % Subtype TCC generated (at line 51, column 34) for  j
      % expected type  {jj: int | i = 0 => jj /= 0}
  gcd_lt_TCC1: OBLIGATION
    FORALL (i, j: int): j /= 0 AND i /= 0 IMPLIES i = 0 => j /= 0;

  % Subtype TCC generated (at line 59, column 52) for  i
      % expected type  {jj: int | mod(j, i) = 0 => jj /= 0}
  gcd_mod_TCC1: OBLIGATION
    FORALL (i, j: int): (i /= 0) IMPLIES mod(j, i) = 0 => i /= 0;

  % Subtype TCC generated (at line 59, column 63) for  j
      % expected type  {jj: int | i = 0 => jj /= 0}
  gcd_mod_TCC2: OBLIGATION
    FORALL (i, j: int): (i /= 0) IMPLIES i = 0 => j /= 0;

  % Subtype TCC generated (at line 66, column 43) for  m
      % expected type  {jj: int | n = 0 => jj /= 0}
  gcd_factors_nat_TCC1: OBLIGATION
    FORALL (m, n: nat): (n /= 0 OR m /= 0) IMPLIES n = 0 => m /= 0;

  % Subtype TCC generated (at line 75, column 27) for  p
      % expected type  {jj: int | p = 0 => jj /= 0}
  gcd_same_TCC1: OBLIGATION FORALL (p: posint): p = 0 => p /= 0;

  % Subtype TCC generated (at line 79, column 31) for  q * l
      % expected type  {jj: int | p * l = 0 => jj /= 0}
  gcd_times_TCC1: OBLIGATION
    FORALL (l, p, q: posint): p * l = 0 => q * l /= 0;

  % Subtype TCC generated (at line 100, column 39) for  k
      % expected type  {jj: int | i = 0 => jj /= 0}
  rel_prime_mult_right_TCC1: OBLIGATION
    FORALL (i, j, k: int):
      (i /= 0 OR j /= 0) AND (i /= 0 OR k /= 0) AND rel_prime(i, j) IMPLIES
       i = 0 => k /= 0;

  % Subtype TCC generated (at line 100, column 62) for  j * k
      % expected type  {jj: int | i = 0 => jj /= 0}
  rel_prime_mult_right_TCC2: OBLIGATION
    FORALL (i, j, k: int):
      rel_prime(i, k) AND
       rel_prime(i, j) AND (i /= 0 OR k /= 0) AND (i /= 0 OR j /= 0)
       IMPLIES i = 0 => j * k /= 0;

  % Subtype TCC generated (at line 103, column 39) for  j
      % expected type  {jj: int | k = 0 => jj /= 0}
  rel_prime_mult_left_TCC1: OBLIGATION
    FORALL (i, j, k: int):
      (i /= 0 OR j /= 0) AND (j /= 0 OR k /= 0) AND rel_prime(i, j) IMPLIES
       k = 0 => j /= 0;

  % Subtype TCC generated (at line 103, column 64) for  j
      % expected type  {jj: int | i * k = 0 => jj /= 0}
  rel_prime_mult_left_TCC2: OBLIGATION
    FORALL (i, j, k: int):
      rel_prime(k, j) AND
       rel_prime(i, j) AND (j /= 0 OR k /= 0) AND (i /= 0 OR j /= 0)
       IMPLIES i * k = 0 => j /= 0;

  % Subtype TCC generated (at line 120, column 36) for  -i - j + 3
      % expected type  naturalnumber
  compute_gcd_TCC1: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      i < 0 AND j < 0 IMPLIES -i - j + 3 >= 0;

  % Subtype TCC generated (at line 121, column 31) for  -i + j + 2
      % expected type  naturalnumber
  compute_gcd_TCC2: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      i < 0 AND NOT (i < 0 AND j < 0) IMPLIES -i + j + 2 >= 0;

  % Subtype TCC generated (at line 122, column 17) for  i - j + 2
      % expected type  naturalnumber
  compute_gcd_TCC3: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      j < 0 AND NOT i < 0 AND NOT (i < 0 AND j < 0) IMPLIES i - j + 2 >= 0;

  % Subtype TCC generated (at line 123, column 17) for  i + j + 1
      % expected type  naturalnumber
  compute_gcd_TCC4: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      i < j AND NOT j < 0 AND NOT i < 0 AND NOT (i < 0 AND j < 0) IMPLIES
       i + j + 1 >= 0;

  % Subtype TCC generated (at line 124, column 7) for  i + j
      % expected type  naturalnumber
  compute_gcd_TCC5: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      NOT i < j AND NOT j < 0 AND NOT i < 0 AND NOT (i < 0 AND j < 0) IMPLIES
       i + j >= 0;

  % Subtype TCC generated (at line 111, column 35) for  j
      % expected type  {jj: int | -i = 0 => jj /= 0}
  compute_gcd_TCC6: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      i < 0 IMPLIES -i = 0 => j /= 0;

  % Termination TCC generated (at line 111, column 20) for  compute_gcd(-i, j)
  compute_gcd_TCC7: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      i < 0 IMPLIES
       (IF -i < 0 AND j < 0 THEN --i - j + 3
        ELSIF -i < 0 THEN --i + j + 2
        ELSIF j < 0 THEN -i - j + 2
        ELSIF -i < j THEN -i + j + 1
        ELSE -i + j
        ENDIF)
        <
        (IF i < 0 AND j < 0 THEN -i - j + 3
         ELSIF i < 0 THEN -i + j + 2
         ELSIF j < 0 THEN i - j + 2
         ELSIF i < j THEN i + j + 1
         ELSE i + j
         ENDIF);

  % Subtype TCC generated (at line 111, column 20) for  compute_gcd(-i, j)
      % expected type  {kj: posnat | kj = gcd(i, j)}
  compute_gcd_TCC8: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0},
            v:
              [d1:
                 {z: [i: int, {jj: int | i = 0 => jj /= 0}] |
                          (IF z`1 < 0 AND z`2 < 0 THEN -z`1 - z`2 + 3
                           ELSIF z`1 < 0 THEN -z`1 + z`2 + 2
                           ELSIF z`2 < 0 THEN z`1 - z`2 + 2
                           ELSIF z`1 < z`2 THEN z`1 + z`2 + 1
                           ELSE z`1 + z`2
                           ENDIF)
                           <
                           (IF i < 0 AND j < 0 THEN -i - j + 3
                            ELSIF i < 0 THEN -i + j + 2
                            ELSIF j < 0 THEN i - j + 2
                            ELSIF i < j THEN i + j + 1
                            ELSE i + j
                            ENDIF)} ->
                 {kj: posnat | kj = gcd(d1`1, d1`2)}]):
      i < 0 IMPLIES v(-i, j) = gcd(i, j);

  % Subtype TCC generated (at line 112, column 34) for  -j
      % expected type  {jj: int | i = 0 => jj /= 0}
  compute_gcd_TCC9: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      j < 0 AND NOT i < 0 IMPLIES i = 0 => -j /= 0;

  % Termination TCC generated (at line 112, column 20) for  compute_gcd(i, -j)
  compute_gcd_TCC10: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      j < 0 AND NOT i < 0 IMPLIES
       (IF i < 0 AND -j < 0 THEN -i - -j + 3
        ELSIF i < 0 THEN -i + -j + 2
        ELSIF -j < 0 THEN i - -j + 2
        ELSIF i < -j THEN i + -j + 1
        ELSE i + -j
        ENDIF)
        <
        (IF i < 0 AND j < 0 THEN -i - j + 3
         ELSIF i < 0 THEN -i + j + 2
         ELSIF j < 0 THEN i - j + 2
         ELSIF i < j THEN i + j + 1
         ELSE i + j
         ENDIF);

  % Subtype TCC generated (at line 112, column 20) for  compute_gcd(i, -j)
      % expected type  {kj: posnat | kj = gcd(i, j)}
  compute_gcd_TCC11: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0},
            v:
              [d1:
                 {z: [i: int, {jj: int | i = 0 => jj /= 0}] |
                          (IF z`1 < 0 AND z`2 < 0 THEN -z`1 - z`2 + 3
                           ELSIF z`1 < 0 THEN -z`1 + z`2 + 2
                           ELSIF z`2 < 0 THEN z`1 - z`2 + 2
                           ELSIF z`1 < z`2 THEN z`1 + z`2 + 1
                           ELSE z`1 + z`2
                           ENDIF)
                           <
                           (IF i < 0 AND j < 0 THEN -i - j + 3
                            ELSIF i < 0 THEN -i + j + 2
                            ELSIF j < 0 THEN i - j + 2
                            ELSIF i < j THEN i + j + 1
                            ELSE i + j
                            ENDIF)} ->
                 {kj: posnat | kj = gcd(d1`1, d1`2)}]):
      j < 0 AND NOT i < 0 IMPLIES v(i, -j) = gcd(i, j);

  % Subtype TCC generated (at line 113, column 20) for  j
      % expected type  {kj: posnat | kj = gcd(i, j)}
  compute_gcd_TCC12: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      i = 0 AND NOT j < 0 AND NOT i < 0 IMPLIES
       j >= 0 AND j > 0 AND j = gcd(i, j);

  % Subtype TCC generated (at line 114, column 20) for  i
      % expected type  {kj: posnat | kj = gcd(i, j)}
  compute_gcd_TCC13: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
      j = 0 AND NOT i = 0 AND NOT j < 0 AND NOT i < 0 IMPLIES
       i >= 0 AND i > 0 AND i = gcd(i, j);

  % Termination TCC generated (at line 115, column 20) for  compute_gcd(j, i)
  compute_gcd_TCC14: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
           i < j AND NOT j = 0 AND NOT i = 0 AND NOT j < 0 AND NOT i < 0
       IMPLIES
       (IF j < 0 AND i < 0 THEN -j - i + 3
        ELSIF j < 0 THEN -j + i + 2
        ELSIF i < 0 THEN j - i + 2
        ELSIF j < i THEN j + i + 1
        ELSE j + i
        ENDIF)
        <
        (IF i < 0 AND j < 0 THEN -i - j + 3
         ELSIF i < 0 THEN -i + j + 2
         ELSIF j < 0 THEN i - j + 2
         ELSIF i < j THEN i + j + 1
         ELSE i + j
         ENDIF);

  % Subtype TCC generated (at line 115, column 20) for  compute_gcd(j, i)
      % expected type  {kj: posnat | kj = gcd(i, j)}
  compute_gcd_TCC15: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0},
            v:
              [d1:
                 {z: [i: int, {jj: int | i = 0 => jj /= 0}] |
                          (IF z`1 < 0 AND z`2 < 0 THEN -z`1 - z`2 + 3
                           ELSIF z`1 < 0 THEN -z`1 + z`2 + 2
                           ELSIF z`2 < 0 THEN z`1 - z`2 + 2
                           ELSIF z`1 < z`2 THEN z`1 + z`2 + 1
                           ELSE z`1 + z`2
                           ENDIF)
                           <
                           (IF i < 0 AND j < 0 THEN -i - j + 3
                            ELSIF i < 0 THEN -i + j + 2
                            ELSIF j < 0 THEN i - j + 2
                            ELSIF i < j THEN i + j + 1
                            ELSE i + j
                            ENDIF)} ->
                 {kj: posnat | kj = gcd(d1`1, d1`2)}]):
           i < j AND NOT j = 0 AND NOT i = 0 AND NOT j < 0 AND NOT i < 0
       IMPLIES v(j, i) = gcd(i, j);

  % Subtype TCC generated (at line 118, column 25) for  j
      % expected type  {kj: posnat | kj = gcd(i, j)}
  compute_gcd_TCC16: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
           NOT i < j AND NOT j = 0 AND NOT i = 0 AND NOT j < 0 AND NOT i < 0
       IMPLIES
       (FORALL (rem: {k | abs(k) < abs(j)}):
          rem = 0 AND rem = mod(i, j) IMPLIES
           j >= 0 AND j > 0 AND j = gcd(i, j));

  % Subtype TCC generated (at line 118, column 46) for  rem
      % expected type  {jj: int | j = 0 => jj /= 0}
  compute_gcd_TCC17: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
           NOT i < j AND NOT j = 0 AND NOT i = 0 AND NOT j < 0 AND NOT i < 0
       IMPLIES
       (FORALL (rem: {k | abs(k) < abs(j)}):
          NOT rem = 0 AND rem = mod(i, j) IMPLIES j = 0 => rem /= 0);

  % Termination TCC generated (at line 118, column 32) for
      % compute_gcd(j, rem)
  compute_gcd_TCC18: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
           NOT i < j AND NOT j = 0 AND NOT i = 0 AND NOT j < 0 AND NOT i < 0
       IMPLIES
       (FORALL (rem: {k | abs(k) < abs(j)}):
          NOT rem = 0 AND rem = mod(i, j) IMPLIES
           (IF j < 0 AND rem < 0 THEN -j - rem + 3
            ELSIF j < 0 THEN -j + rem + 2
            ELSIF rem < 0 THEN j - rem + 2
            ELSIF j < rem THEN j + rem + 1
            ELSE j + rem
            ENDIF)
            <
            (IF i < 0 AND j < 0 THEN -i - j + 3
             ELSIF i < 0 THEN -i + j + 2
             ELSIF j < 0 THEN i - j + 2
             ELSIF i < j THEN i + j + 1
             ELSE i + j
             ENDIF));

  % Subtype TCC generated (at line 118, column 32) for  compute_gcd(j, rem)
      % expected type  {kj: posnat | kj = gcd(i, j)}
  compute_gcd_TCC19: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0},
            v:
              [d1:
                 {z: [i: int, {jj: int | i = 0 => jj /= 0}] |
                          (IF z`1 < 0 AND z`2 < 0 THEN -z`1 - z`2 + 3
                           ELSIF z`1 < 0 THEN -z`1 + z`2 + 2
                           ELSIF z`2 < 0 THEN z`1 - z`2 + 2
                           ELSIF z`1 < z`2 THEN z`1 + z`2 + 1
                           ELSE z`1 + z`2
                           ENDIF)
                           <
                           (IF i < 0 AND j < 0 THEN -i - j + 3
                            ELSIF i < 0 THEN -i + j + 2
                            ELSIF j < 0 THEN i - j + 2
                            ELSIF i < j THEN i + j + 1
                            ELSE i + j
                            ENDIF)} ->
                 {kj: posnat | kj = gcd(d1`1, d1`2)}]):
           NOT i < j AND NOT j = 0 AND NOT i = 0 AND NOT j < 0 AND NOT i < 0
       IMPLIES
       (FORALL (rem: {k | abs(k) < abs(j)}):
          NOT rem = 0 AND rem = mod(i, j) IMPLIES v(j, rem) = gcd(i, j));

  % Subtype TCC generated (at line 117, column 24) for  j
      % expected type  nonzero_integer
  compute_gcd_TCC20: OBLIGATION
    FORALL (i: int, j: {jj: int | i = 0 => jj /= 0}):
           NOT i < j AND NOT j = 0 AND NOT i = 0 AND NOT j < 0 AND NOT i < 0
       IMPLIES j /= 0;

  % Subtype TCC generated (at line 131, column 25) for  m
      % expected type  {jj: int | n = 0 => jj /= 0}
  rel_prime_inverse_TCC1: OBLIGATION
    FORALL (m, n: nat): m > 1 IMPLIES n = 0 => m /= 0;

  % Subtype TCC generated (at line 132, column 55) for  m
      % expected type  nonzero_integer
  rel_prime_inverse_TCC2: OBLIGATION
    FORALL (m, n: nat):
      rel_prime(n, m) AND m > 1 IMPLIES
       (FORALL (q: below(m), k: below(m)): m /= 0);


body:
  gcd_fractions: THEORY
  %------------------------------------------------------------------------------
  % Author: Alfons Geser, HTWK Leipzig, Germany
  % Date: May, 2009
  %------------------------------------------------------------------------------
  BEGIN

    IMPORTING gcd

    p, q, k: VAR posint
    r: VAR posrat

    div_by_gcd_prep: LEMMA FORALL (p: posint, q: posint):
      integer_pred(p / gcd(p, q)) AND p / gcd(p, q) >= 0 AND p / gcd(p, q) > 0;


    div_by_gcd(p, q): posint = p / gcd(p, q)

    gcd_div_by_gcd: LEMMA gcd(div_by_gcd(p, q), div_by_gcd(q, p)) = 1

    quotient_fully_cancelled: THEOREM
      EXISTS p, q: gcd(p, q) = 1 AND r = p / q

  END gcd_fractions

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

  % Subtype TCC generated (at line 14, column 28) for  q
      % expected type  {jj: int | p = 0 => jj /= 0}
  div_by_gcd_prep_TCC1: OBLIGATION
    FORALL (p: posint, q: posint): p = 0 => q /= 0;

  % Subtype TCC generated (at line 17, column 29) for  p / gcd(p, q)
      % expected type  posint
  div_by_gcd_TCC1: OBLIGATION
    FORALL (p: posint, q: posint):
      integer_pred(p / gcd(p, q)) AND
       p / gcd(p, q) >= 0 AND p / gcd(p, q) > 0;

  % Subtype TCC generated (at line 19, column 46) for  div_by_gcd(q, p)
      % expected type  {jj: int | div_by_gcd(p, q) = 0 => jj /= 0}
  gcd_div_by_gcd_TCC1: OBLIGATION
    FORALL (p, q: posint): div_by_gcd(p, q) = 0 => div_by_gcd(q, p) /= 0;


body:
  rem: THEORY
  %------------------------------------------------------------------------
  % Defines remainder (rem)   (Ada Style)
  %
  % This version of "rem" is based upon the Ada Reference Manual's
  % definition.  These depend upon the use of a division theory that truncates
  % toward zero on a negative argument.  
  %
  % AUTHORS
  % -------
  %   Ricky W. Butler   		   email: r.w.butler@larc.nasa.gov
  %   Mail Stop 130			     fax: (804) 864-4234
  %   NASA Langley Research Center	   phone: (804) 864-6198
  %   Hampton, Virginia 23681-0001
  %
  % NOTE: There is now a "rem" defined in the prelude that is different
  %       from this one.
  % 
  %------------------------------------------------------------------------

    BEGIN
   
    IMPORTING div
   
    i,k,cc: VAR int
    m: VAR posnat
    n,a,b,c: VAR nat   

    j: VAR nonzero_integer

  % ======================= define rem(i,m) ========================

    ml1: LEMMA n -  m * div(n,m) < m
    ml3: LEMMA abs(i -  m * div(i,m)) < m

    rem(i,j): {k| abs(k) < abs(j)} =  i - j*div(i,j)

    rem_neg:        LEMMA rem(-i,j) = -rem(i,j)

    rem_neg_d:      LEMMA rem(i,-j) = rem(i,j)

    rem_even:       LEMMA integer_pred(i/j) IMPLIES rem(i,j) = 0

    rem_eq_arg:     LEMMA rem(j,j) = 0

    rem_zero:       LEMMA rem(0,j) = 0

    rem_lt:         LEMMA abs(i) < abs(j) IMPLIES 
                          rem(i,j) = i 

    rem_it_is:      LEMMA a = b + m*c AND b < m IMPLIES
                          b = rem(a,m)

    rem_eq_0:       LEMMA rem(i,j) = 0 IMPLIES integer_pred(i/j)

    rem_one:        LEMMA rem(1,j) = IF abs(j) = 1 THEN 0
                                     ELSE 1
                                     ENDIF
   
    JUDGEMENT rem(n,m) HAS_TYPE below(m)

    END rem

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

  % Subtype TCC generated (at line 36, column 36) for  i - j * div(i, j)
      % expected type  {k | abs(k) < abs(j)}
  rem_TCC1: OBLIGATION
    FORALL (i: int, j: nonzero_integer): abs(i - j * div(i, j)) < abs(j);

  % Judgement subtype TCC generated (at line 60, column 12) for  rem(n, m)
      % expected type  below(m)
  rem_TCC2: OBLIGATION FORALL (m, n): rem(n, m) >= 0 AND rem(n, m) < m;


body:
  mod_div_lems: THEORY
  %------------------------------------------------------------------------
  %
  % Author: Rick Butler
  %
  %------------------------------------------------------------------------

  BEGIN

   
    IMPORTING rem

    i: VAR int
    j: VAR nonzero_integer

    n: VAR nat  
    m: VAR posnat

    mod_div         : LEMMA mod(n,m) = n - m*div(n,m)

    mod_rem: LEMMA mod(i,j)= IF sgn(i) = sgn(j) OR integer_pred(i/j) THEN
                                rem(i,j)
                             ELSE j + rem(i,j)
                             ENDIF

  END mod_div_lems


body:
  top: THEORY
  %------------------------------------------------------------------------
  % 
  %  Structures Library
  %  ------------------
  % 
  %  Authors:
  %
  %     Ricky W. Butler        NASA Langley Research Center
  %     David Griffioen        CWI (National Research Institute for 
  %                                 Mathematics and Computer Science
  %                                 and KUN (Catholic University Nijmegen),
  %                                 the Netherlands.
  %     Lee Pike               NASA Langley Research Center
  %
  %  Version 2.0               9/23/96
  %  Version 2.1               12/22/03   no longer needs TYPE+
  %  Version 2.2               Merged arrays and bags library into one
  %  Version 2.3               Pike greatly extended bags library
  %
  %  Maintained by:
  %
  %     Rick Butler            NASA Langley Research Center   
  %                            R.W.Butler@larc.nasa.gov
  %------------------------------------------------------------------------

  BEGIN

   IMPORTING           	
                          % -------------- functions -----------------

     const_fun_def,
     function_image_bis,        % Extra properties of image and inverse_image
     function_inverse_alt_aux,  % Extras for function inverse
     function_props_aux,        % inverse_image properties

                          % -------------- arrays -----------------
     top_array,
     min_array,       	% defines min function over an array
     max_array,       	% defines max function over an array 
     permutations,    	% permutations defined using arrays
     sort_array,      	% defines a sort function over arrays
     sort_array_lems, 	% relationship between sort and min and max
     array_ops,       	% array operations
     majority_array,  	% defines majority function over an array 

                      	% -------------- sequences -----------------
     top_seq,
     seqs,                
     max_seq,         	% defines max function over an sequence 
     min_seq,         	% defines min function over a sequence
     permutations_seq,	% permutations defined using arrays
     majority_seq,    	% defines majority function over finite sequences
     bubblesort,      	% bubble sort correctness theorem
     sort_seq,        	% defines a sort function over sequences
     sort_seq_lems,   	% relationship between sort and min and max
     set2seq,             % convert set to sequence
     minmax_set2seq,
     seq2set,          	% convert sequence to a set
     minmax_seq2set,
     seq_extras,          % extra-definitions that complements the prelude's finite sequences
     seq_pigeon,          % Pigeon hole principle for the prelude's finite sequences

                      	% -------------- bags -----------------
     top_bags,        
     bags,                % fundamental definitions and properties
     bags_aux,            % definition of filter, rest, and choose 
     bags_to_sets,        % converts bags to sets
     finite_bags,         % basic definitions and lemmas
     finite_bags_lems,    % lemmas need induction 
     finite_bags_aux,     % lemmas about filter, rest, and choose 
     finite_bags_inductions,  % induction schemes
     bag_filters,         % filtering linearly-ordered bags, pigeonhole,
                          %   majority pigeonhole results, and overlap 
                          %   existence proof
     majority_vote,       % defines a majority vote over finite bags
     middle_value_select, % defines middle value selection over finite bags
     fault_masking_vote,  % proves an equivalence between majority and middle
                          %   value selection
     finite_bags_minmax,  % defines the minimum and maximum of a finite
                          %   ordered bag.

                          % --------------- permutation -------------
     permutation,
     permutation_ops,

                          % --------------- lists -------------

     more_list_props,
     listn,
     array2list, 
     set_as_list,
     set_as_list_props,

                          % --------------- for loops and iterations -------------
     
     for_iterate,
     for_examples,
     big_ops_nat,
      
                          % --------------- arrays -------------
     arrays,
     arrays_examples,
  			% --------------- transition systems --------------

     runs, 
                     	% ----------- Alternate finite sequence (fseq) ----------

     fseqs,               % finite sequence using [nat -> T]
     fseqs_def,           % finite sequence using [nat -> T] with default parameter
     fseqs_ops,           % operations on finite sequence using [nat -> T]
     fseqs_ops_def,       % operations on finite sequence using [nat -> T] with default parameter
     fseqs_ops_real,      % operations on finite sequence using [nat -> real]
     max_fseq,         	% defines max function over an sequence 
     min_fseq,         	% defines min function over a sequence
     permutations_fseq,	% permutations defined using arrays
     majority_fseq,    	% defines majority function over finite sequences
     sort_fseq,        	% defines a sort function over sequences
     sort_fseq_lems,  	% relationship between sort and min and max
     fseq2set,         	% convert sequence to a set

     Maybe,               % Maybe[T] = Nothing + Just[T] ---------- 
     Unit,                % Unit is a type with only one element

     stack,               % Stacks
                          % --------------- Generic Branch and Bound algorithms
     branch_and_bound,    % Basic branch and bound  
     branch_and_bound_X,  % Advanced brand and bound

     fun_preds_partial    % ADDED rwb 2-8-2010

  END top


body:
  %------------------------------------------------------------------------------
  % partial order properties on functions
  %
  %     Author: David Lester, Manchester University
  %
  %     Version 1.0            14/06/09  Initial Version
  %------------------------------------------------------------------------------
  fun_preds_partial[T1,T2:TYPE,le1:(partial_order?[T1]),
                               le2:(partial_order?[T2])]: THEORY

  BEGIN

    f:   VAR [T1->T2]
    x,y: VAR T1
    a,b: VAR T2

    lt1(x,y)  : MACRO bool = le1(x,y) AND x /= y
    lt2(a,b)  : MACRO bool = le2(a,b) AND a /= b

    increasing?(f)        : bool = FORALL x, y : le1(x,y) IMPLIES le2(f(x),f(y))
    decreasing?(f)        : bool = FORALL x, y : le1(x,y) IMPLIES le2(f(y),f(x))
    strict_increasing?(f) : bool = FORALL x, y : lt1(x,y) IMPLIES lt2(f(x),f(y))
    strict_decreasing?(f) : bool = FORALL x, y : lt1(x,y) IMPLIES lt2(f(y),f(x))

    constant?(f)          : bool = FORALL x, y : f(x) = f(y)

    monotonic?(f)         : bool = increasing?(f) OR decreasing?(f)
    strict_monotonic?(f)  : bool = strict_increasing?(f) OR strict_decreasing?(f)

    strict_increasing_is_increasing:
          LEMMA strict_increasing?(f) IMPLIES increasing?(f)

    strict_decreasing_is_decreasing:
          LEMMA strict_decreasing?(f) IMPLIES decreasing?(f)

  END fun_preds_partial


body:
  Maybe[T:TYPE] : THEORY
  BEGIN

    Maybe: DATATYPE 
    BEGIN
      None : none?
      Some(val:T): some?
    END Maybe

    val2some(t:T) : MACRO Maybe = Some(t)

    CONVERSION val2some
   
    a : VAR Maybe

    Maybe_none : LEMMA
      none?(a) IFF
      a = None

    Maybe_some : LEMMA
      some?(a) IMPLIES
      EXISTS (t:T) : val(a) = t AND a = Some(t)

    Maybe_or : LEMMA
      none?(a) OR some?(a)

    Maybe_either: LEMMA
      a = None OR EXISTS (t:T) : val(a) = t AND a = Some(t)

  END Maybe

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

  Maybe_ord_defaxiom: AXIOM
    Maybe_ord(None) = 0 AND (FORALL (val: T): Maybe_ord(Some(val)) = 1);

  Maybe_None_extensionality: AXIOM
    FORALL (none?_var: (none?), none?_var2: (none?)): none?_var = none?_var2;

  Maybe_Some_extensionality: AXIOM
    FORALL (some?_var: (some?), some?_var2: (some?)):
      val(some?_var) = val(some?_var2) IMPLIES some?_var = some?_var2;

  Maybe_Some_eta: AXIOM
    FORALL (some?_var: (some?)): Some(val(some?_var)) = some?_var;

  Maybe_val_Some: AXIOM
    FORALL (Some1_var: T): val(Some(Some1_var)) = Some1_var;

  Maybe_inclusive: AXIOM
    FORALL (Maybe_var: Maybe): none?(Maybe_var) OR some?(Maybe_var);

  Maybe_induction: AXIOM
    FORALL (p: [Maybe -> boolean]):
      (p(None) AND (FORALL (Some1_var: T): p(Some(Some1_var)))) IMPLIES
       (FORALL (Maybe_var: Maybe): p(Maybe_var));

  Maybe_well_founded: AXIOM strict_well_founded?[Maybe](<<);

  Maybe: TYPE

  none?: [Maybe -> boolean]

  some?: [Maybe -> boolean]

  val: [(some?) -> T]

  Some: [T -> (some?)]

  Maybe_ord: [Maybe -> upto(1)]

  ord(x: Maybe): [Maybe -> upto(1)] =
      CASES x OF None: 0, Some(Some1_var): 1 ENDCASES

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

  reduce_nat(none?_fun: nat, some?_fun: [T -> nat]):  [Maybe -> nat] =
      LAMBDA (Maybe_adtvar: Maybe):
        LET red: [Maybe -> nat] = reduce_nat(none?_fun, some?_fun) IN
          CASES Maybe_adtvar
            OF None: none?_fun, Some(Some1_var): some?_fun(Some1_var)
            ENDCASES;

  REDUCE_nat(none?_fun: [Maybe -> nat], some?_fun: [[T, Maybe] -> nat]):
        [Maybe -> nat] =
      LAMBDA (Maybe_adtvar: Maybe):
        LET red: [Maybe -> nat] = REDUCE_nat(none?_fun, some?_fun) IN
          CASES Maybe_adtvar
            OF None: none?_fun(Maybe_adtvar),
               Some(Some1_var): some?_fun(Some1_var, Maybe_adtvar)
            ENDCASES;

  reduce_ordinal(none?_fun: ordinal, some?_fun: [T -> ordinal]):
        [Maybe -> ordinal] =
      LAMBDA (Maybe_adtvar: Maybe):
        LET red: [Maybe -> ordinal] = reduce_ordinal(none?_fun, some?_fun) IN
          CASES Maybe_adtvar
            OF None: none?_fun, Some(Some1_var): some?_fun(Some1_var)
            ENDCASES;

  REDUCE_ordinal(none?_fun: [Maybe -> ordinal],
                 some?_fun: [[T, Maybe] -> ordinal]):
        [Maybe -> ordinal] =
      LAMBDA (Maybe_adtvar: Maybe):
        LET red: [Maybe -> ordinal] = REDUCE_ordinal(none?_fun, some?_fun) IN
          CASES Maybe_adtvar
            OF None: none?_fun(Maybe_adtvar),
               Some(Some1_var): some?_fun(Some1_var, Maybe_adtvar)
            ENDCASES;

  None: (none?)

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

  % Subtype TCC generated (at line 28, column 35) for  a
      % expected type  (some?)
  Maybe_either_TCC1: OBLIGATION
    FORALL (a: Maybe): NOT a = None IMPLIES (FORALL (t: T): some?(a));


body:
  stack[T:TYPE] : THEORY
  BEGIN

     IMPORTING Maybe[T]

     stack : TYPE = list[T]

     pop(s:stack) : stack = IF null?(s) THEN s ELSE cdr(s) ENDIF
    
     top(s:stack) : Maybe[T] = IF null?(s) THEN None ELSE Some(car(s)) ENDIF
   
     push(t:T,s:stack) : stack = cons(t,s)

  END stack

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

  % Subtype TCC generated (at line 8, column 54) for  s
      % expected type  (cons?[T])
  pop_TCC1: OBLIGATION FORALL (s: stack): NOT null?(s) IMPLIES cons?[T](s);


body:
  branch_and_bound_X[ObjType, AnsType, DomainType, VarType: TYPE]: THEORY
  BEGIN

    IMPORTING stack

    %%%%%%% General Variables %%%%%%%

    maxdepth : VAR nat
    v        : VAR VarType
    dir      : VAR bool

    %%%%%%% Types %%%%%%%

    % ObjType - Type of objects, e.g., Bernstein Polynomials, Interval expressions, Etc.
    % AnsType - Output type, e.g. Minmax, Boxes, Minmaxes and Boxes, Etc.
    % DomainType - Domain type, e.g., List of variable domains
    % VarType - Type of variable representation, e.g., nat

    % Output information: answer, maximum depth, and number of subidivisions
    Output : TYPE = [#
      ans    : AnsType,
      exit   : bool,
      depth  : nat,
      splits : nat
    #]

    mk_out(ans:AnsType,exit:bool,depth,splits:nat): MACRO Output = (#
      ans     := ans,
      exit    := exit,
      depth   := depth,
      splits  := splits
    #)

    %%%%%%% Parameters to the Algorithm %%%%%%%
    %------------------------%
    AccType        : TYPE = Maybe[AnsType]
    DirVar         : TYPE = [bool,VarType]
    DirVarStack    : TYPE = [# length : nat,
                               stack  : {s:stack[DirVar] | length(s) = length}
                            #]
    LocalExitPred  : TYPE = [AnsType -> bool]  % localexit
    ExitPred       : TYPE = [DirVarStack,AnsType,AnsType -> bool] % globalexit, prune 
    Combiner       : TYPE = [VarType,AnsType,AnsType -> AnsType]  % combine
    		     	   			   	        % The combine function needs to depend on the variable
  							        % since splitting in one of the box variables
  							        % needs to be handled differently than splitting
  							        % in one of the other variables
    DirVarSelector : TYPE = [DirVarStack,AnsType,DomainType,ObjType -> DirVar] % R/L and Variable
    SoundPred	 : TYPE = [DomainType,ObjType,AnsType -> bool]
    Evaluator	 : TYPE = [DomainType,ObjType -> [AnsType,ObjType]] % E.g. computation of a minmax that is sound
    Brancher	 : TYPE = [VarType,ObjType -> [ObjType,ObjType]]
    SubdivDomain   : TYPE = [VarType,DomainType -> [DomainType,DomainType]]
    DenormAns	 : TYPE = [DirVar,AnsType -> AnsType]  % E.g. translating an element of
     		  	   	       		       % Minmax back to [0,1] from either
  						       % [0,1/2] or [1/2,1].
    Accumulator    : TYPE = [AnsType,AnsType -> AnsType] % Accumulate information from one branch into the other.

    %------------------------%
    obj,
    obj1,obj2  : VAR ObjType
    ans,
    ans1,ans2  : VAR AnsType
    acc        : VAR AccType
    dom        : VAR DomainType
    %------------------------%
    le         : VAR LocalExitPred
    ge         : VAR ExitPred
    prune      : VAR ExitPred
    select     : VAR DirVarSelector
    sound      : VAR SoundPred
    %------------------------%
    evaluate   : VAR Evaluator
    branch     : VAR Brancher
    subdivide  : VAR SubdivDomain
    denorm     : VAR DenormAns
    combine    : VAR Combiner
    dirvar     : VAR DirVar
    dirvars    : VAR DirVarStack
    accumulate : VAR Accumulator
    %------------------------%

    left(v)  : MACRO DirVar = (TRUE,v)
    right(v) : MACRO DirVar = (FALSE,v)

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

    emptyDirVars : DirVarStack = (#
      length := 0,
      stack := null
    #)

    length_empty : LEMMA
      length(emptyDirVars) = 0

    AUTO_REWRITE+ length_empty

    empty?(dirvars) : bool = length(dirvars) = 0
    nonempty?(dirvars) : bool = length(dirvars) > 0

    topDirVar(dirvars:(nonempty?)) : DirVar = val(top(stack(dirvars)))

    pushDirVar(dirvar,dirvars) : (nonempty?) = (#
      length := dirvars`length+1,
      stack  := push(dirvar,stack(dirvars))
    #)

    popDirVar(dirvars) : DirVarStack = 
      IF length(dirvars) = 0 THEN dirvars
      ELSE 
        (# length := dirvars`length - 1,
           stack  := pop(stack(dirvars))
        #)
     ENDIF

    %%%%%%% Predicates %%%%%%%

    sound_evaluate?(sound,evaluate,subdivide): bool =
      FORALL (dom,obj): 
        sound(dom,obj,evaluate(dom,obj)`1)

    le_subdivide?(subdivide,v)(dom1,dom2:DomainType): bool = 
      dom1 = subdivide(v,dom2)`1 OR    
      dom1 = subdivide(v,dom2)`2 

    sound_subdivide?(evaluate,subdivide): bool =
      FORALL (dom1,dom2:DomainType,obj,v):
       LET nobj = evaluate(dom2,obj)`2 IN
         le_subdivide?(subdivide,v)(dom1,dom2) IMPLIES 
         evaluate(dom1,obj)`1 = evaluate(dom1,nobj)`1

    sound_branch?(evaluate,branch) : bool =
      FORALL(dom,obj1,obj2,v):
        evaluate(dom, obj1)`1 = evaluate(dom, obj2)`1  IMPLIES
          evaluate(dom, branch(v, obj1)`1)`1 = evaluate(dom,branch(v,obj2)`1)`1 AND
          evaluate(dom, branch(v, obj1)`2)`1 = evaluate(dom,branch(v,obj2)`2)`1  

    presound_evaluate?(sound,evaluate) : bool =
      FORALL(dom,obj1,obj2,ans): 
        evaluate(dom, obj1)`1 = evaluate(dom, obj2)`1 AND
        sound(dom,obj1,ans) 
        IMPLIES
        sound(dom,obj2,ans)

    inv_branch?(sound,evaluate,branch) : bool =
      FORALL(dom,obj1,obj2,ans,v): 
      evaluate(dom, obj1)`1 = evaluate(dom, obj2)`1 AND
      sound(dom, branch(v, obj1)`1,ans) 
        IMPLIES
        sound(dom, branch(v, obj2)`1,ans)

    sound_dir(sddom:[DomainType,DomainType],sdobj:[ObjType,ObjType],dir,sound,ans) : bool =
      IF dir THEN sound(sddom`1,sdobj`1,ans) ELSE sound(sddom`2,sdobj`2,ans) ENDIF 

    presound_combine?(sound,subdivide,branch,denorm,combine): bool = 
      FORALL (v,dom,obj,dir,ans,ans1):
        LET sddom = subdivide(v,dom), sdobj = branch(v,obj) IN
        sound(dom,obj,ans) AND sound_dir(sddom,sdobj,dir,sound,ans1) IMPLIES
        sound(dom,obj,combine(v,denorm((dir,v),ans1),ans))

    sound_combine?(sound,subdivide,branch,denorm,combine): bool = 
      FORALL (v,dom,obj,ans1,ans2):
      LET sddom = subdivide(v,dom), sdobj = branch(v,obj) IN
          sound(sddom`1,sdobj`1,ans1) AND sound(sddom`2,sdobj`2,ans2) 
  	IMPLIES sound(dom,obj,combine(v,denorm(left(v),ans1),denorm(right(v),ans2)))

    %%%%%%% The Algorithm %%%%%%%

    branch_and_bound(evaluate,branch,subdivide,denorm,combine,prune,le,ge,select,accumulate,maxdepth)
                    (obj,dom,acc,(dirvars|length(dirvars) <= maxdepth)) : 
      RECURSIVE Output = 
      LET  (thisans,nobj) = evaluate(dom,obj),
  	 newacc1 = IF none?(acc) THEN thisans ELSE accumulate(val(acc),thisans) ENDIF,
           thisout = mk_out(thisans,ge(dirvars,newacc1,thisans),length(dirvars),0)
       IN
        IF length(dirvars)=maxdepth OR le(thisans) OR thisout`exit OR prune(dirvars,newacc1,thisans) THEN
           thisout
        ELSE
           LET
  	   (dir,v)     = select(dirvars,newacc1,dom,nobj),
  	   funsplit    = branch(v,nobj),
  	   domsplit    = subdivide(v,dom),
  	   (sp1,sp2)   = IF dir THEN (funsplit`1,funsplit`2) ELSE (funsplit`2,funsplit`1) ENDIF,
  	   (dom1,dom2) = IF dir THEN (domsplit`1,domsplit`2) ELSE (domsplit`2,domsplit`1) ENDIF,
  	   firstout    = branch_and_bound(evaluate,branch,subdivide,denorm,combine,
                                            prune,le,ge,select,accumulate,maxdepth)
  				         (sp1,dom1,newacc1,pushDirVar((dir,v),dirvars))
  	 IN
  	   IF firstout`exit THEN
  	     mk_out(combine(v,denorm((dir,v),firstout`ans),thisans),
                      TRUE,firstout`depth,firstout`splits+1)
  	   ELSE
  	     LET
  	       newacc2    = accumulate(newacc1,firstout`ans),
  	       secondout  = branch_and_bound(evaluate,branch,subdivide,denorm,combine,
                                               prune,le,ge,select,accumulate,maxdepth)
  			                    (sp2,dom2,newacc2,pushDirVar((NOT dir,v),dirvars)),
  	       (real1,real2) = IF dir THEN (firstout,secondout) ELSE (secondout,firstout) ENDIF
  	     IN
  	       mk_out(combine(v,denorm(left(v),real1`ans),denorm(right(v),real2`ans)),
                        secondout`exit,
                        max(firstout`depth,secondout`depth),
                        firstout`splits+secondout`splits+1)
  	   ENDIF
        ENDIF
      MEASURE maxdepth-length(dirvars)

    branch_and_bound_sound : THEOREM 
      FORALL(sound,evaluate,branch,subdivide,denorm,combine,prune,le,ge,select,accumulate,maxdepth):
          presound_evaluate?(sound,evaluate) AND
          sound_evaluate?(sound,evaluate,subdivide) AND
          sound_subdivide?(evaluate,subdivide) AND
  	sound_branch?(evaluate,branch) AND
          presound_combine?(sound,subdivide,branch,denorm,combine) AND
          sound_combine?(sound,subdivide,branch,denorm,combine) IMPLIES
        FORALL (obj,dom,acc,dirvars):
          length(dirvars) <= maxdepth IMPLIES
          LET bandb = branch_and_bound(evaluate,branch,subdivide,denorm,combine,
                                       prune,le,ge,select,accumulate,maxdepth)
                                      (obj,dom,acc,dirvars)
          IN sound(dom,obj,bandb`ans)

    b_and_b(evaluate,branch,subdivide,denorm,combine,prune,le,ge,select,accumulate,maxdepth,obj,dom) : Output =
      branch_and_bound(evaluate,branch,subdivide,denorm,combine,prune,le,ge,select,accumulate,maxdepth)
                      (obj,dom,None,emptyDirVars)

    b_and_b_sound : THEOREM 
      presound_evaluate?(sound,evaluate) AND
      sound_evaluate?(sound,evaluate,subdivide) AND
      sound_subdivide?(evaluate,subdivide) AND
      sound_branch?(evaluate,branch) AND
      presound_combine?(sound,subdivide,branch,denorm,combine) AND
      sound_combine?(sound,subdivide,branch,denorm,combine) IMPLIES
        sound(dom,obj,b_and_b(evaluate,branch,subdivide,denorm,combine,
                              prune,le,ge,select,accumulate,maxdepth,obj,dom)`ans)

  END branch_and_bound_X

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

  % Subtype TCC generated (at line 89, column 13) for  null
      % expected type  {s: stack[DirVar] | length(s) = 0}
  emptyDirVars_TCC1: OBLIGATION length[DirVar](null[DirVar]) = 0;

  % Subtype TCC generated (at line 100, column 48) for  top(stack(dirvars))
      % expected type  (some?[DirVar])
  topDirVar_TCC1: OBLIGATION
    FORALL (dirvars: (nonempty?)): some?[DirVar](top[DirVar](stack(dirvars)));

  % Subtype TCC generated (at line 104, column 14) for
      % push(dirvar, stack(dirvars))
      % expected type  {s: stack[DirVar] | length(s) = 1 + dirvars`length}
  pushDirVar_TCC1: OBLIGATION
    FORALL (dirvar: DirVar, dirvars: DirVarStack):
      length[DirVar](push[DirVar](dirvar, stack(dirvars))) =
       1 + dirvars`length;

  % Subtype TCC generated (at line 102, column 45) for
      % (# length := dirvars`length + 1,
      %    stack := push(dirvar, stack(dirvars)) #)
      % expected type  (nonempty?)
  pushDirVar_TCC2: OBLIGATION
    FORALL (dirvar: DirVar, dirvars: DirVarStack):
      nonempty?((# length := dirvars`length + 1,
                   stack := push[DirVar](dirvar, stack(dirvars)) #));

  % Subtype TCC generated (at line 110, column 19) for  dirvars`length - 1
      % expected type  nat
  popDirVar_TCC1: OBLIGATION
    FORALL (dirvars: DirVarStack):
      NOT length(dirvars) = 0 IMPLIES dirvars`length - 1 >= 0;

  % Subtype TCC generated (at line 111, column 19) for  pop(stack(dirvars))
      % expected type  {s: stack[DirVar] | length(s) = dirvars`length - 1}
  popDirVar_TCC2: OBLIGATION
    FORALL (dirvars: DirVarStack):
      NOT length(dirvars) = 0 IMPLIES
       length[DirVar](pop[DirVar](stack(dirvars))) = dirvars`length - 1;

  % Subtype TCC generated (at line 205, column 12) for
      % maxdepth - length(dirvars)
      % expected type  naturalnumber
  branch_and_bound_TCC1: OBLIGATION
    FORALL (evaluate: Evaluator, branch: Brancher, subdivide: SubdivDomain,
            denorm: DenormAns, combine: Combiner, select: DirVarSelector,
            accumulate: Accumulator, maxdepth: nat, obj: ObjType,
            dom: DomainType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth)):
      maxdepth - length(dirvars) >= 0;

  % Subtype TCC generated (at line 172, column 59) for  acc
      % expected type  (some?[AnsType])
  branch_and_bound_TCC2: OBLIGATION
    FORALL (evaluate: Evaluator, branch: Brancher, subdivide: SubdivDomain,
            denorm: DenormAns, combine: Combiner, select: DirVarSelector,
            accumulate: Accumulator, maxdepth: nat, obj: ObjType,
            dom: DomainType, acc: AccType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth),
            thisans: AnsType, nobj: ObjType):
      NOT none?(acc) AND
       nobj = evaluate(dom, obj)`2 AND thisans = evaluate(dom, obj)`1
       IMPLIES some?[AnsType](acc);

  % Subtype TCC generated (at line 186, column 31) for
      % pushDirVar((dir, v), dirvars)
      % expected type  {dirvars | length(dirvars) <= maxdepth}
  branch_and_bound_TCC3: OBLIGATION
    FORALL (evaluate: Evaluator, branch: Brancher, subdivide: SubdivDomain,
            denorm: DenormAns, combine: Combiner, prune: ExitPred,
            le: LocalExitPred, ge: ExitPred, select: DirVarSelector,
            accumulate: Accumulator, maxdepth: nat, obj: ObjType,
            dom: DomainType, acc: AccType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth),
            thisans: AnsType, nobj: ObjType):
      nobj = evaluate(dom, obj)`2 AND thisans = evaluate(dom, obj)`1 IMPLIES
       (FORALL (newacc1: AnsType):
          newacc1 =
           IF none?(acc) THEN thisans
           ELSE accumulate(val(acc), thisans)
           ENDIF
           IMPLIES
           (FORALL (thisout: Output):
                   NOT length(dirvars) = maxdepth AND NOT le(thisans)
               AND NOT thisout`exit AND NOT prune(dirvars, newacc1, thisans)
               AND thisout =
                    (# ans := thisans,
                       exit := ge(dirvars, newacc1, thisans),
                       depth := length(dirvars),
                       splits := 0 #)
               IMPLIES
               (FORALL (dir: bool, v: VarType):
                  v = select(dirvars, newacc1, dom, nobj)`2 AND
                   dir = select(dirvars, newacc1, dom, nobj)`1
                   IMPLIES
                   (FORALL (funsplit: [ObjType, ObjType]):
                      funsplit = branch(v, nobj) IMPLIES
                       (FORALL (domsplit: [DomainType, DomainType]):
                          domsplit = subdivide(v, dom) IMPLIES
                           (FORALL (sp1: ObjType, sp2: ObjType):
                              sp2 =
                               IF dir THEN (funsplit`1, funsplit`2)
                               ELSE (funsplit`2, funsplit`1)
                               ENDIF`2
                               AND
                               sp1 =
                                IF dir THEN (funsplit`1, funsplit`2)
                                ELSE (funsplit`2, funsplit`1)
                                ENDIF`1
                               IMPLIES
                               (FORALL (dom1: DomainType, dom2: DomainType):
                                  dom2 =
                                   IF dir THEN (domsplit`1, domsplit`2)
                                   ELSE (domsplit`2, domsplit`1)
                                   ENDIF`2
                                   AND
                                   dom1 =
                                    IF dir THEN (domsplit`1, domsplit`2)
                                    ELSE (domsplit`2, domsplit`1)
                                    ENDIF`1
                                   IMPLIES
                                   length(pushDirVar((dir, v), dirvars)) <=
                                    maxdepth)))))));

  % Termination TCC generated (at line 184, column 18) for
      % branch_and_bound(evaluate, branch, subdivide, denorm, combine, prune,
      %                  le, ge, select, accumulate, maxdepth)
      %                 (sp1, dom1, Some(newacc1),
      %                  pushDirVar((dir, v), dirvars))
  branch_and_bound_TCC4: OBLIGATION
    FORALL (evaluate: Evaluator, branch: Brancher, subdivide: SubdivDomain,
            denorm: DenormAns, combine: Combiner, prune: ExitPred,
            le: LocalExitPred, ge: ExitPred, select: DirVarSelector,
            accumulate: Accumulator, maxdepth: nat, obj: ObjType,
            dom: DomainType, acc: AccType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth),
            thisans: AnsType, nobj: ObjType):
      nobj = evaluate(dom, obj)`2 AND thisans = evaluate(dom, obj)`1 IMPLIES
       (FORALL (newacc1: AnsType):
          newacc1 =
           IF none?(acc) THEN thisans
           ELSE accumulate(val(acc), thisans)
           ENDIF
           IMPLIES
           (FORALL (thisout: Output):
                   NOT length(dirvars) = maxdepth AND NOT le(thisans)
               AND NOT thisout`exit AND NOT prune(dirvars, newacc1, thisans)
               AND thisout =
                    (# ans := thisans,
                       exit := ge(dirvars, newacc1, thisans),
                       depth := length(dirvars),
                       splits := 0 #)
               IMPLIES
               (FORALL (dir: bool, v: VarType):
                  v = select(dirvars, newacc1, dom, nobj)`2 AND
                   dir = select(dirvars, newacc1, dom, nobj)`1
                   IMPLIES
                   (FORALL (funsplit: [ObjType, ObjType]):
                      funsplit = branch(v, nobj) IMPLIES
                       (FORALL (domsplit: [DomainType, DomainType]):
                          domsplit = subdivide(v, dom) IMPLIES
                           (FORALL (sp1: ObjType, sp2: ObjType):
                              sp2 =
                               IF dir THEN (funsplit`1, funsplit`2)
                               ELSE (funsplit`2, funsplit`1)
                               ENDIF`2
                               AND
                               sp1 =
                                IF dir THEN (funsplit`1, funsplit`2)
                                ELSE (funsplit`2, funsplit`1)
                                ENDIF`1
                               IMPLIES
                               (FORALL (dom1: DomainType, dom2: DomainType):
                                  dom2 =
                                   IF dir THEN (domsplit`1, domsplit`2)
                                   ELSE (domsplit`2, domsplit`1)
                                   ENDIF`2
                                   AND
                                   dom1 =
                                    IF dir THEN (domsplit`1, domsplit`2)
                                    ELSE (domsplit`2, domsplit`1)
                                    ENDIF`1
                                   IMPLIES
                                   maxdepth -
                                    length(pushDirVar((dir, v), dirvars))
                                    < maxdepth - length(dirvars))))))));

  % Subtype TCC generated (at line 196, column 41) for
      % pushDirVar((NOT dir, v), dirvars)
      % expected type  {dirvars | length(dirvars) <= maxdepth}
  branch_and_bound_TCC5: OBLIGATION
    FORALL (evaluate: Evaluator, branch: Brancher, subdivide: SubdivDomain,
            denorm: DenormAns, combine: Combiner, prune: ExitPred,
            le: LocalExitPred, ge: ExitPred, select: DirVarSelector,
            accumulate: Accumulator, maxdepth: nat, obj: ObjType,
            dom: DomainType, acc: AccType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth),
            v1:
              [d1:
                 [Evaluator, Brancher, SubdivDomain, DenormAns, Combiner,
                  ExitPred, LocalExitPred, ExitPred, DirVarSelector,
                  Accumulator, nat] ->
                 [{z:
                     [ObjType, DomainType, AccType,
                      {dirvars | length(dirvars) <= d1`11}] |
                           d1`11 - length(z`4) <
                            maxdepth - length(dirvars)} ->
                    Output]],
            thisans: AnsType, nobj: ObjType):
      nobj = evaluate(dom, obj)`2 AND thisans = evaluate(dom, obj)`1 IMPLIES
       (FORALL (newacc1: AnsType):
          newacc1 =
           IF none?(acc) THEN thisans
           ELSE accumulate(val(acc), thisans)
           ENDIF
           IMPLIES
           (FORALL (thisout: Output):
                   NOT length(dirvars) = maxdepth AND NOT le(thisans)
               AND NOT thisout`exit AND NOT prune(dirvars, newacc1, thisans)
               AND thisout =
                    (# ans := thisans,
                       exit := ge(dirvars, newacc1, thisans),
                       depth := length(dirvars),
                       splits := 0 #)
               IMPLIES
               (FORALL (dir: bool, v: VarType):
                  v = select(dirvars, newacc1, dom, nobj)`2 AND
                   dir = select(dirvars, newacc1, dom, nobj)`1
                   IMPLIES
                   (FORALL (funsplit: [ObjType, ObjType]):
                      funsplit = branch(v, nobj) IMPLIES
                       (FORALL (domsplit: [DomainType, DomainType]):
                          domsplit = subdivide(v, dom) IMPLIES
                           (FORALL (sp1: ObjType, sp2: ObjType):
                              sp2 =
                               IF dir THEN (funsplit`1, funsplit`2)
                               ELSE (funsplit`2, funsplit`1)
                               ENDIF`2
                               AND
                               sp1 =
                                IF dir THEN (funsplit`1, funsplit`2)
                                ELSE (funsplit`2, funsplit`1)
                                ENDIF`1
                               IMPLIES
                               (FORALL (dom1: DomainType, dom2: DomainType):
                                  dom2 =
                                   IF dir THEN (domsplit`1, domsplit`2)
                                   ELSE (domsplit`2, domsplit`1)
                                   ENDIF`2
                                   AND
                                   dom1 =
                                    IF dir THEN (domsplit`1, domsplit`2)
                                    ELSE (domsplit`2, domsplit`1)
                                    ENDIF`1
                                   IMPLIES
                                   (FORALL (firstout: Output):
                                      NOT firstout`exit
                                      AND
                                      firstout
                                      =
                                      v1
                                      (evaluate,
                                       branch,
                                       subdivide,
                                       denorm,
                                       combine,
                                       prune,
                                       le,
                                       ge,
                                       select,
                                       accumulate,
                                       maxdepth)
                                      (sp1,
                                       dom1,
                                       Some(newacc1),
                                       pushDirVar((dir, v), dirvars))
                                      IMPLIES
                                      (FORALL
                                       (newacc2: AnsType):
                                       newacc2
                                       =
                                       accumulate(newacc1, firstout`ans)
                                       IMPLIES
                                       length
                                       (pushDirVar((NOT dir, v), dirvars))
                                       <=
                                       maxdepth)))))))));

  % Termination TCC generated (at line 194, column 21) for
      % branch_and_bound(evaluate, branch, subdivide, denorm, combine, prune,
      %                  le, ge, select, accumulate, maxdepth)
      %                 (sp2, dom2, Some(newacc2),
      %                  pushDirVar((NOT dir, v), dirvars))
  branch_and_bound_TCC6: OBLIGATION
    FORALL (evaluate: Evaluator, branch: Brancher, subdivide: SubdivDomain,
            denorm: DenormAns, combine: Combiner, prune: ExitPred,
            le: LocalExitPred, ge: ExitPred, select: DirVarSelector,
            accumulate: Accumulator, maxdepth: nat, obj: ObjType,
            dom: DomainType, acc: AccType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth),
            v1:
              [d1:
                 [Evaluator, Brancher, SubdivDomain, DenormAns, Combiner,
                  ExitPred, LocalExitPred, ExitPred, DirVarSelector,
                  Accumulator, nat] ->
                 [{z:
                     [ObjType, DomainType, AccType,
                      {dirvars | length(dirvars) <= d1`11}] |
                           d1`11 - length(z`4) <
                            maxdepth - length(dirvars)} ->
                    Output]],
            thisans: AnsType, nobj: ObjType):
      nobj = evaluate(dom, obj)`2 AND thisans = evaluate(dom, obj)`1 IMPLIES
       (FORALL (newacc1: AnsType):
          newacc1 =
           IF none?(acc) THEN thisans
           ELSE accumulate(val(acc), thisans)
           ENDIF
           IMPLIES
           (FORALL (thisout: Output):
                   NOT length(dirvars) = maxdepth AND NOT le(thisans)
               AND NOT thisout`exit AND NOT prune(dirvars, newacc1, thisans)
               AND thisout =
                    (# ans := thisans,
                       exit := ge(dirvars, newacc1, thisans),
                       depth := length(dirvars),
                       splits := 0 #)
               IMPLIES
               (FORALL (dir: bool, v: VarType):
                  v = select(dirvars, newacc1, dom, nobj)`2 AND
                   dir = select(dirvars, newacc1, dom, nobj)`1
                   IMPLIES
                   (FORALL (funsplit: [ObjType, ObjType]):
                      funsplit = branch(v, nobj) IMPLIES
                       (FORALL (domsplit: [DomainType, DomainType]):
                          domsplit = subdivide(v, dom) IMPLIES
                           (FORALL (sp1: ObjType, sp2: ObjType):
                              sp2 =
                               IF dir THEN (funsplit`1, funsplit`2)
                               ELSE (funsplit`2, funsplit`1)
                               ENDIF`2
                               AND
                               sp1 =
                                IF dir THEN (funsplit`1, funsplit`2)
                                ELSE (funsplit`2, funsplit`1)
                                ENDIF`1
                               IMPLIES
                               (FORALL (dom1: DomainType, dom2: DomainType):
                                  dom2 =
                                   IF dir THEN (domsplit`1, domsplit`2)
                                   ELSE (domsplit`2, domsplit`1)
                                   ENDIF`2
                                   AND
                                   dom1 =
                                    IF dir THEN (domsplit`1, domsplit`2)
                                    ELSE (domsplit`2, domsplit`1)
                                    ENDIF`1
                                   IMPLIES
                                   (FORALL (firstout: Output):
                                      NOT firstout`exit
                                      AND
                                      firstout
                                      =
                                      v1
                                      (evaluate,
                                       branch,
                                       subdivide,
                                       denorm,
                                       combine,
                                       prune,
                                       le,
                                       ge,
                                       select,
                                       accumulate,
                                       maxdepth)
                                      (sp1,
                                       dom1,
                                       Some(newacc1),
                                       pushDirVar((dir, v), dirvars))
                                      IMPLIES
                                      (FORALL
                                       (newacc2: AnsType):
                                       newacc2
                                       =
                                       accumulate(newacc1, firstout`ans)
                                       IMPLIES
                                       maxdepth
                                       -
                                       length
                                       (pushDirVar((NOT dir, v), dirvars))
                                       <
                                       maxdepth - length(dirvars))))))))));

  % Subtype TCC generated (at line 224, column 34) for  emptyDirVars
      % expected type  {dirvars | length(dirvars) <= maxdepth}
  b_and_b_TCC1: OBLIGATION
    FORALL (evaluate: Evaluator, branch: Brancher, subdivide: SubdivDomain,
            denorm: DenormAns, combine: Combiner, select: DirVarSelector,
            accumulate: Accumulator, maxdepth: nat, obj: ObjType,
            dom: DomainType):
      length(emptyDirVars) <= maxdepth;


body:
  branch_and_bound[ObjType, AnsType, DomainType, VarType: TYPE]: THEORY
  BEGIN

    IMPORTING stack

    %%%%%%% General Variables %%%%%%%

    maxdepth : VAR nat
    v        : VAR VarType
    dir      : VAR bool

    %%%%%%% Types %%%%%%%

    % ObjType - Type of objects, e.g., Bernstein Polynomials, Interval expressions, Etc.
    % AnsType - Output type, e.g. Minmax, Boxes, Minmaxes and Boxes, Etc.
    % DomainType - Domain type, e.g., List of variable domains
    % VarType - Type of variable representation, e.g., nat

    % Output information: answer, maximum depth, and number of subidivisions
    Output : TYPE = [#
      ans    : AnsType,
      exit   : bool,
      depth  : nat,
      splits : nat
    #]

    mk_out(ans:AnsType,exit:bool,depth,splits:nat): MACRO Output = (#
      ans     := ans,
      exit    := exit,
      depth   := depth,
      splits  := splits
    #)

    %%%%%%% Parameters to the Algorithm %%%%%%%
    %------------------------%
    AccType        : TYPE = Maybe[AnsType]
    Simplifier     : TYPE = [ObjType -> ObjType] % translist(polylist(x))
    DirVar         : TYPE = [bool,VarType]
    DirVarStack    : TYPE = [# length : nat,
                               stack  : {s:stack[DirVar] | length(s) = length}
                            #]
    LocalExitPred  : TYPE = [AnsType -> bool]  % localexit
    ExitPred       : TYPE = [DirVarStack,AnsType,AnsType -> bool] % globalexit, prune 
    Combiner       : TYPE = [VarType,AnsType,AnsType -> AnsType]  % combine
    		     	   			   	        % The combine function needs to depend on the variable
  							        % since splitting in one of the box variables
  							        % needs to be handled differently than splitting
  							        % in one of the other variables
    DirVarSelector : TYPE = [DirVarStack,AnsType,DomainType,ObjType -> DirVar] % R/L and Variable
    SoundPred	 : TYPE = [DomainType,ObjType,AnsType -> bool]
    Evaluator	 : TYPE = [DomainType,ObjType -> AnsType]       % E.g. computation of a minmax that is sound
    Brancher	 : TYPE = [VarType,ObjType -> [ObjType,ObjType]]
    SubdivDomain   : TYPE = [VarType,DomainType -> [DomainType,DomainType]]
    DenormAns	 : TYPE = [DirVar,AnsType -> AnsType]  % E.g. translating an element of
     		  	   	       		       % Minmax back to [0,1] from either
  						       % [0,1/2] or [1/2,1].
    Accumulator    : TYPE = [AnsType,AnsType -> AnsType] % Accumulate information from one branch into the other.

    %------------------------%
    obj        : VAR ObjType
    ans,
    ans1,ans2  : VAR AnsType
    acc        : VAR AccType
    dom        : VAR DomainType
    %------------------------%
    simplify   : VAR Simplifier
    le         : VAR LocalExitPred
    ge         : VAR ExitPred
    prune      : VAR ExitPred
    select     : VAR DirVarSelector
    sound      : VAR SoundPred
    %------------------------%
    evaluate   : VAR Evaluator
    branch     : VAR Brancher
    subdivide  : VAR SubdivDomain
    denorm     : VAR DenormAns
    combine    : VAR Combiner
    dirvar     : VAR DirVar
    dirvars    : VAR DirVarStack
    accumulate : VAR Accumulator
    %------------------------%

    left(v)  : MACRO DirVar = (TRUE,v)
    right(v) : MACRO DirVar = (FALSE,v)

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

    emptyDirVars : DirVarStack = (#
      length := 0,
      stack := null
    #)

    length_empty : LEMMA
      length(emptyDirVars) = 0

    AUTO_REWRITE+ length_empty

    empty?(dirvars) : bool = length(dirvars) = 0
    nonempty?(dirvars) : bool = length(dirvars) > 0

    topDirVar(dirvars:(nonempty?)) : DirVar = val(top(stack(dirvars)))

    pushDirVar(dirvar,dirvars) : (nonempty?) = (#
      length := dirvars`length+1,
      stack  := push(dirvar,stack(dirvars))
    #)

    popDirVar(dirvars) : DirVarStack = 
      IF length(dirvars) = 0 THEN dirvars
      ELSE 
        (# length := dirvars`length - 1,
           stack  := pop(stack(dirvars))
        #)
     ENDIF

    %%%%%%% Predicates %%%%%%%

    branch_simplify?(branch,simplify): bool =
      FORALL (v,obj): branch(v,simplify(obj)) = (simplify(branch(v,obj)`1),simplify(branch(v,obj)`2))

    simplify_invariant?(sound,simplify): bool =
      FORALL (dom,obj,ans): sound(dom,obj,ans) IFF sound(dom,simplify(obj),ans)

    evaluate_simplify?(evaluate,simplify): bool =
      FORALL (dom,obj): evaluate(dom,obj) = evaluate(dom,simplify(obj))

    accomodates?(sound,evaluate): bool =
      FORALL (dom,obj): sound(dom,obj,evaluate(dom,obj))

    sound_dir(sddom:[DomainType,DomainType],sdobj:[ObjType,ObjType],dir,sound,ans) : bool =
      IF dir THEN sound(sddom`1,sdobj`1,ans) ELSE sound(sddom`2,sdobj`2,ans) ENDIF 

    subdiv_presound?(sound,subdivide,branch,denorm,combine): bool = 
      FORALL (v,dom,obj,dir,ans,ans1):
        LET sddom = subdivide(v,dom), sdobj = branch(v,obj) IN
        sound(dom,obj,ans) AND sound_dir(sddom,sdobj,dir,sound,ans1) IMPLIES
        sound(dom,obj,combine(v,denorm((dir,v),ans1),ans))

    subdiv_sound?(sound,subdivide,branch,denorm,combine): bool = 
      FORALL (v,dom,obj,ans1,ans2):
      LET sddom = subdivide(v,dom), sdobj = branch(v,obj) IN
          sound(sddom`1,sdobj`1,ans1) AND sound(sddom`2,sdobj`2,ans2) 
  	IMPLIES sound(dom,obj,combine(v,denorm(left(v),ans1),denorm(right(v),ans2)))

    %%%%%%% The Algorithm %%%%%%%

    branch_and_bound(simplify,evaluate,branch,subdivide,denorm,combine,prune,le,ge,select,accumulate,maxdepth)
                    (obj,dom,acc,(dirvars|length(dirvars) <= maxdepth)) : 
      RECURSIVE Output = 
      LET  nobj    = simplify(obj),
  	 thisans = evaluate(dom,nobj),
  	 newacc1 = IF none?(acc) THEN thisans ELSE accumulate(val(acc),thisans) ENDIF,
           thisout = mk_out(thisans,ge(dirvars,newacc1,thisans),length(dirvars),0)
       IN
        IF length(dirvars)=maxdepth OR le(thisans) OR thisout`exit OR prune(dirvars,newacc1,thisans) THEN
           thisout
        ELSE
           LET
  	   (dir,v)     = select(dirvars,newacc1,dom,nobj),
  	   funsplit    = branch(v,nobj),
  	   domsplit    = subdivide(v,dom),
  	   (sp1,sp2)   = IF dir THEN (funsplit`1,funsplit`2) ELSE (funsplit`2,funsplit`1) ENDIF,
  	   (dom1,dom2) = IF dir THEN (domsplit`1,domsplit`2) ELSE (domsplit`2,domsplit`1) ENDIF,
  	   firstout    = branch_and_bound(simplify,evaluate,branch,subdivide,denorm,combine,
                                            prune,le,ge,select,accumulate,maxdepth)
  				         (sp1,dom1,newacc1,pushDirVar((dir,v),dirvars))
  	 IN
  	   IF firstout`exit THEN
  	     mk_out(combine(v,denorm((dir,v),firstout`ans),thisans),
                      TRUE,firstout`depth,firstout`splits+1)
  	   ELSE
  	     LET
  	       newacc2    = accumulate(newacc1,firstout`ans),
  	       secondout  = branch_and_bound(simplify,evaluate,branch,subdivide,denorm,combine,
                                               prune,le,ge,select,accumulate,maxdepth)
  			                    (sp2,dom2,newacc2,pushDirVar((NOT dir,v),dirvars)),
  	       (real1,real2) = IF dir THEN (firstout,secondout) ELSE (secondout,firstout) ENDIF
  	     IN
  	       mk_out(combine(v,denorm(left(v),real1`ans),denorm(right(v),real2`ans)),
                        secondout`exit,
                        max(firstout`depth,secondout`depth),
                        firstout`splits+secondout`splits+1)
  	   ENDIF
        ENDIF
      MEASURE maxdepth-length(dirvars)

    branch_and_bound_sound : THEOREM 
      FORALL(sound,simplify,evaluate,branch,subdivide,denorm,combine,prune,le,ge,select,accumulate,maxdepth):
          accomodates?(sound,evaluate) AND
          simplify_invariant?(sound,simplify) AND
          evaluate_simplify?(evaluate,simplify) AND
          subdiv_presound?(sound,subdivide,branch,denorm,combine) AND
          subdiv_sound?(sound,subdivide,branch,denorm,combine) AND
          branch_simplify?(branch,simplify) IMPLIES
        FORALL (obj,dom,acc,dirvars):
          length(dirvars) <= maxdepth IMPLIES
          LET bandb = branch_and_bound(simplify,evaluate,branch,subdivide,denorm,combine,
                                       prune,le,ge,select,accumulate,maxdepth)
                                      (obj,dom,acc,dirvars)
          IN sound(dom,obj,bandb`ans)

    b_and_b(simplify,evaluate,branch,subdivide,denorm,combine,prune,le,ge,select,accumulate,maxdepth,obj,dom) : Output =
      branch_and_bound(simplify,evaluate,branch,subdivide,denorm,combine,prune,le,ge,select,accumulate,maxdepth)
                      (obj,dom,None,emptyDirVars)

    b_and_b_sound : THEOREM 
      accomodates?(sound,evaluate) AND
      simplify_invariant?(sound,simplify) AND
      evaluate_simplify?(evaluate,simplify) AND
      subdiv_presound?(sound,subdivide,branch,denorm,combine) AND
      subdiv_sound?(sound,subdivide,branch,denorm,combine) AND
      branch_simplify?(branch,simplify) IMPLIES
        sound(dom,obj,b_and_b(simplify,evaluate,branch,subdivide,denorm,combine,
                              prune,le,ge,select,accumulate,maxdepth,obj,dom)`ans)

    b_and_b_id(evaluate,branch,subdivide,denorm,combine,prune,le,ge,select,accumulate,maxdepth,obj,dom) : Output =
      b_and_b(LAMBDA (obj):obj,evaluate,branch,subdivide,denorm,combine,prune,le,ge,select,accumulate,maxdepth,obj,dom)

    b_and_b_id_sound : THEOREM 
      accomodates?(sound,evaluate) AND
      subdiv_presound?(sound,subdivide,branch,denorm,combine) AND
      subdiv_sound?(sound,subdivide,branch,denorm,combine) IMPLIES
        sound(dom,obj,b_and_b_id(evaluate,branch,subdivide,denorm,combine,
                                 prune,le,ge,select,accumulate,maxdepth,obj,dom)`ans)

  END branch_and_bound

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

  % Subtype TCC generated (at line 90, column 13) for  null
      % expected type  {s: stack[DirVar] | length(s) = 0}
  emptyDirVars_TCC1: OBLIGATION length[DirVar](null[DirVar]) = 0;

  % Subtype TCC generated (at line 101, column 48) for  top(stack(dirvars))
      % expected type  (some?[DirVar])
  topDirVar_TCC1: OBLIGATION
    FORALL (dirvars: (nonempty?)): some?[DirVar](top[DirVar](stack(dirvars)));

  % Subtype TCC generated (at line 105, column 14) for
      % push(dirvar, stack(dirvars))
      % expected type  {s: stack[DirVar] | length(s) = 1 + dirvars`length}
  pushDirVar_TCC1: OBLIGATION
    FORALL (dirvar: DirVar, dirvars: DirVarStack):
      length[DirVar](push[DirVar](dirvar, stack(dirvars))) =
       1 + dirvars`length;

  % Subtype TCC generated (at line 103, column 45) for
      % (# length := dirvars`length + 1,
      %    stack := push(dirvar, stack(dirvars)) #)
      % expected type  (nonempty?)
  pushDirVar_TCC2: OBLIGATION
    FORALL (dirvar: DirVar, dirvars: DirVarStack):
      nonempty?((# length := dirvars`length + 1,
                   stack := push[DirVar](dirvar, stack(dirvars)) #));

  % Subtype TCC generated (at line 111, column 19) for  dirvars`length - 1
      % expected type  nat
  popDirVar_TCC1: OBLIGATION
    FORALL (dirvars: DirVarStack):
      NOT length(dirvars) = 0 IMPLIES dirvars`length - 1 >= 0;

  % Subtype TCC generated (at line 112, column 19) for  pop(stack(dirvars))
      % expected type  {s: stack[DirVar] | length(s) = dirvars`length - 1}
  popDirVar_TCC2: OBLIGATION
    FORALL (dirvars: DirVarStack):
      NOT length(dirvars) = 0 IMPLIES
       length[DirVar](pop[DirVar](stack(dirvars))) = dirvars`length - 1;

  % Subtype TCC generated (at line 185, column 12) for
      % maxdepth - length(dirvars)
      % expected type  naturalnumber
  branch_and_bound_TCC1: OBLIGATION
    FORALL (simplify: Simplifier, evaluate: Evaluator, branch: Brancher,
            subdivide: SubdivDomain, denorm: DenormAns, combine: Combiner,
            select: DirVarSelector, accumulate: Accumulator, maxdepth: nat,
            obj: ObjType, dom: DomainType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth)):
      maxdepth - length(dirvars) >= 0;

  % Subtype TCC generated (at line 152, column 59) for  acc
      % expected type  (some?[AnsType])
  branch_and_bound_TCC2: OBLIGATION
    FORALL (simplify: Simplifier, evaluate: Evaluator, branch: Brancher,
            subdivide: SubdivDomain, denorm: DenormAns, combine: Combiner,
            select: DirVarSelector, accumulate: Accumulator, maxdepth: nat,
            obj: ObjType, dom: DomainType, acc: AccType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth),
            nobj: ObjType):
      nobj = simplify(obj) IMPLIES
       (FORALL (thisans: AnsType):
          NOT none?(acc) AND thisans = evaluate(dom, nobj) IMPLIES
           some?[AnsType](acc));

  % Subtype TCC generated (at line 166, column 31) for
      % pushDirVar((dir, v), dirvars)
      % expected type  {dirvars | length(dirvars) <= maxdepth}
  branch_and_bound_TCC3: OBLIGATION
    FORALL (simplify: Simplifier, evaluate: Evaluator, branch: Brancher,
            subdivide: SubdivDomain, denorm: DenormAns, combine: Combiner,
            prune: ExitPred, le: LocalExitPred, ge: ExitPred,
            select: DirVarSelector, accumulate: Accumulator, maxdepth: nat,
            obj: ObjType, dom: DomainType, acc: AccType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth),
            nobj: ObjType):
      nobj = simplify(obj) IMPLIES
       (FORALL (thisans: AnsType):
          thisans = evaluate(dom, nobj) IMPLIES
           (FORALL (newacc1: AnsType):
              newacc1 =
               IF none?(acc) THEN thisans
               ELSE accumulate(val(acc), thisans)
               ENDIF
               IMPLIES
               (FORALL (thisout: Output):
                       NOT length(dirvars) = maxdepth AND NOT le(thisans)
                   AND NOT thisout`exit
                   AND NOT prune(dirvars, newacc1, thisans)
                   AND thisout =
                        (# ans := thisans,
                           exit := ge(dirvars, newacc1, thisans),
                           depth := length(dirvars),
                           splits := 0 #)
                   IMPLIES
                   (FORALL (dir: bool, v: VarType):
                      v = select(dirvars, newacc1, dom, nobj)`2 AND
                       dir = select(dirvars, newacc1, dom, nobj)`1
                       IMPLIES
                       (FORALL (funsplit: [ObjType, ObjType]):
                          funsplit = branch(v, nobj) IMPLIES
                           (FORALL (domsplit: [DomainType, DomainType]):
                              domsplit = subdivide(v, dom) IMPLIES
                               (FORALL (sp1: ObjType, sp2: ObjType):
                                  sp2 =
                                   IF dir THEN (funsplit`1, funsplit`2)
                                   ELSE (funsplit`2, funsplit`1)
                                   ENDIF`2
                                   AND
                                   sp1 =
                                    IF dir THEN (funsplit`1, funsplit`2)
                                    ELSE (funsplit`2, funsplit`1)
                                    ENDIF`1
                                   IMPLIES
                                   (FORALL (dom1: DomainType,
                                            dom2: DomainType):
                                      dom2
                                      =
                                      IF dir
                                      THEN (domsplit`1, domsplit`2)
                                      ELSE (domsplit`2, domsplit`1)
                                      ENDIF`2
                                      AND
                                      dom1
                                      =
                                      IF dir
                                      THEN (domsplit`1, domsplit`2)
                                      ELSE (domsplit`2, domsplit`1)
                                      ENDIF`1
                                      IMPLIES
                                      length(pushDirVar((dir, v), dirvars))
                                      <=
                                      maxdepth))))))));

  % Termination TCC generated (at line 164, column 18) for
      % branch_and_bound(simplify, evaluate, branch, subdivide, denorm,
      %                  combine, prune, le, ge, select, accumulate, maxdepth)
      %                 (sp1, dom1, Some(newacc1),
      %                  pushDirVar((dir, v), dirvars))
  branch_and_bound_TCC4: OBLIGATION
    FORALL (simplify: Simplifier, evaluate: Evaluator, branch: Brancher,
            subdivide: SubdivDomain, denorm: DenormAns, combine: Combiner,
            prune: ExitPred, le: LocalExitPred, ge: ExitPred,
            select: DirVarSelector, accumulate: Accumulator, maxdepth: nat,
            obj: ObjType, dom: DomainType, acc: AccType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth),
            nobj: ObjType):
      nobj = simplify(obj) IMPLIES
       (FORALL (thisans: AnsType):
          thisans = evaluate(dom, nobj) IMPLIES
           (FORALL (newacc1: AnsType):
              newacc1 =
               IF none?(acc) THEN thisans
               ELSE accumulate(val(acc), thisans)
               ENDIF
               IMPLIES
               (FORALL (thisout: Output):
                       NOT length(dirvars) = maxdepth AND NOT le(thisans)
                   AND NOT thisout`exit
                   AND NOT prune(dirvars, newacc1, thisans)
                   AND thisout =
                        (# ans := thisans,
                           exit := ge(dirvars, newacc1, thisans),
                           depth := length(dirvars),
                           splits := 0 #)
                   IMPLIES
                   (FORALL (dir: bool, v: VarType):
                      v = select(dirvars, newacc1, dom, nobj)`2 AND
                       dir = select(dirvars, newacc1, dom, nobj)`1
                       IMPLIES
                       (FORALL (funsplit: [ObjType, ObjType]):
                          funsplit = branch(v, nobj) IMPLIES
                           (FORALL (domsplit: [DomainType, DomainType]):
                              domsplit = subdivide(v, dom) IMPLIES
                               (FORALL (sp1: ObjType, sp2: ObjType):
                                  sp2 =
                                   IF dir THEN (funsplit`1, funsplit`2)
                                   ELSE (funsplit`2, funsplit`1)
                                   ENDIF`2
                                   AND
                                   sp1 =
                                    IF dir THEN (funsplit`1, funsplit`2)
                                    ELSE (funsplit`2, funsplit`1)
                                    ENDIF`1
                                   IMPLIES
                                   (FORALL (dom1: DomainType,
                                            dom2: DomainType):
                                      dom2
                                      =
                                      IF dir
                                      THEN (domsplit`1, domsplit`2)
                                      ELSE (domsplit`2, domsplit`1)
                                      ENDIF`2
                                      AND
                                      dom1
                                      =
                                      IF dir
                                      THEN (domsplit`1, domsplit`2)
                                      ELSE (domsplit`2, domsplit`1)
                                      ENDIF`1
                                      IMPLIES
                                      maxdepth
                                      -
                                      length(pushDirVar((dir, v), dirvars))
                                      <
                                      maxdepth - length(dirvars)))))))));

  % Subtype TCC generated (at line 176, column 41) for
      % pushDirVar((NOT dir, v), dirvars)
      % expected type  {dirvars | length(dirvars) <= maxdepth}
  branch_and_bound_TCC5: OBLIGATION
    FORALL (simplify: Simplifier, evaluate: Evaluator, branch: Brancher,
            subdivide: SubdivDomain, denorm: DenormAns, combine: Combiner,
            prune: ExitPred, le: LocalExitPred, ge: ExitPred,
            select: DirVarSelector, accumulate: Accumulator, maxdepth: nat,
            obj: ObjType, dom: DomainType, acc: AccType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth),
            v1:
              [d1:
                 [Simplifier, Evaluator, Brancher, SubdivDomain, DenormAns,
                  Combiner, ExitPred, LocalExitPred, ExitPred,
                  DirVarSelector, Accumulator, nat] ->
                 [{z:
                     [ObjType, DomainType, AccType,
                      {dirvars | length(dirvars) <= d1`12}] |
                           d1`12 - length(z`4) <
                            maxdepth - length(dirvars)} ->
                    Output]],
            nobj: ObjType):
      nobj = simplify(obj) IMPLIES
       (FORALL (thisans: AnsType):
          thisans = evaluate(dom, nobj) IMPLIES
           (FORALL (newacc1: AnsType):
              newacc1 =
               IF none?(acc) THEN thisans
               ELSE accumulate(val(acc), thisans)
               ENDIF
               IMPLIES
               (FORALL (thisout: Output):
                       NOT length(dirvars) = maxdepth AND NOT le(thisans)
                   AND NOT thisout`exit
                   AND NOT prune(dirvars, newacc1, thisans)
                   AND thisout =
                        (# ans := thisans,
                           exit := ge(dirvars, newacc1, thisans),
                           depth := length(dirvars),
                           splits := 0 #)
                   IMPLIES
                   (FORALL (dir: bool, v: VarType):
                      v = select(dirvars, newacc1, dom, nobj)`2 AND
                       dir = select(dirvars, newacc1, dom, nobj)`1
                       IMPLIES
                       (FORALL (funsplit: [ObjType, ObjType]):
                          funsplit = branch(v, nobj) IMPLIES
                           (FORALL (domsplit: [DomainType, DomainType]):
                              domsplit = subdivide(v, dom) IMPLIES
                               (FORALL (sp1: ObjType, sp2: ObjType):
                                  sp2 =
                                   IF dir THEN (funsplit`1, funsplit`2)
                                   ELSE (funsplit`2, funsplit`1)
                                   ENDIF`2
                                   AND
                                   sp1 =
                                    IF dir THEN (funsplit`1, funsplit`2)
                                    ELSE (funsplit`2, funsplit`1)
                                    ENDIF`1
                                   IMPLIES
                                   (FORALL (dom1: DomainType,
                                            dom2: DomainType):
                                      dom2
                                      =
                                      IF dir
                                      THEN (domsplit`1, domsplit`2)
                                      ELSE (domsplit`2, domsplit`1)
                                      ENDIF`2
                                      AND
                                      dom1
                                      =
                                      IF dir
                                      THEN (domsplit`1, domsplit`2)
                                      ELSE (domsplit`2, domsplit`1)
                                      ENDIF`1
                                      IMPLIES
                                      (FORALL
                                       (firstout: Output):
                                       NOT firstout`exit
                                       AND
                                       firstout
                                       =
                                       v1
                                       (simplify,
                                        evaluate,
                                        branch,
                                        subdivide,
                                        denorm,
                                        combine,
                                        prune,
                                        le,
                                        ge,
                                        select,
                                        accumulate,
                                        maxdepth)
                                       (sp1,
                                        dom1,
                                        Some(newacc1),
                                        pushDirVar((dir, v), dirvars))
                                       IMPLIES
                                       (FORALL
                                        (newacc2: AnsType):
                                        newacc2
                                        =
                                        accumulate(newacc1, firstout`ans)
                                        IMPLIES
                                        length
                                        (pushDirVar((NOT dir, v), dirvars))
                                        <=
                                        maxdepth))))))))));

  % Termination TCC generated (at line 174, column 21) for
      % branch_and_bound(simplify, evaluate, branch, subdivide, denorm,
      %                  combine, prune, le, ge, select, accumulate, maxdepth)
      %                 (sp2, dom2, Some(newacc2),
      %                  pushDirVar((NOT dir, v), dirvars))
  branch_and_bound_TCC6: OBLIGATION
    FORALL (simplify: Simplifier, evaluate: Evaluator, branch: Brancher,
            subdivide: SubdivDomain, denorm: DenormAns, combine: Combiner,
            prune: ExitPred, le: LocalExitPred, ge: ExitPred,
            select: DirVarSelector, accumulate: Accumulator, maxdepth: nat,
            obj: ObjType, dom: DomainType, acc: AccType,
            (dirvars: DirVarStack | length(dirvars) <= maxdepth),
            v1:
              [d1:
                 [Simplifier, Evaluator, Brancher, SubdivDomain, DenormAns,
                  Combiner, ExitPred, LocalExitPred, ExitPred,
                  DirVarSelector, Accumulator, nat] ->
                 [{z:
                     [ObjType, DomainType, AccType,
                      {dirvars | length(dirvars) <= d1`12}] |
                           d1`12 - length(z`4) <
                            maxdepth - length(dirvars)} ->
                    Output]],
            nobj: ObjType):
      nobj = simplify(obj) IMPLIES
       (FORALL (thisans: AnsType):
          thisans = evaluate(dom, nobj) IMPLIES
           (FORALL (newacc1: AnsType):
              newacc1 =
               IF none?(acc) THEN thisans
               ELSE accumulate(val(acc), thisans)
               ENDIF
               IMPLIES
               (FORALL (thisout: Output):
                       NOT length(dirvars) = maxdepth AND NOT le(thisans)
                   AND NOT thisout`exit
                   AND NOT prune(dirvars, newacc1, thisans)
                   AND thisout =
                        (# ans := thisans,
                           exit := ge(dirvars, newacc1, thisans),
                           depth := length(dirvars),
                           splits := 0 #)
                   IMPLIES
                   (FORALL (dir: bool, v: VarType):
                      v = select(dirvars, newacc1, dom, nobj)`2 AND
                       dir = select(dirvars, newacc1, dom, nobj)`1
                       IMPLIES
                       (FORALL (funsplit: [ObjType, ObjType]):
                          funsplit = branch(v, nobj) IMPLIES
                           (FORALL (domsplit: [DomainType, DomainType]):
                              domsplit = subdivide(v, dom) IMPLIES
                               (FORALL (sp1: ObjType, sp2: ObjType):
                                  sp2 =
                                   IF dir THEN (funsplit`1, funsplit`2)
                                   ELSE (funsplit`2, funsplit`1)
                                   ENDIF`2
                                   AND
                                   sp1 =
                                    IF dir THEN (funsplit`1, funsplit`2)
                                    ELSE (funsplit`2, funsplit`1)
                                    ENDIF`1
                                   IMPLIES
                                   (FORALL (dom1: DomainType,
                                            dom2: DomainType):
                                      dom2
                                      =
                                      IF dir
                                      THEN (domsplit`1, domsplit`2)
                                      ELSE (domsplit`2, domsplit`1)
                                      ENDIF`2
                                      AND
                                      dom1
                                      =
                                      IF dir
                                      THEN (domsplit`1, domsplit`2)
                                      ELSE (domsplit`2, domsplit`1)
                                      ENDIF`1
                                      IMPLIES
                                      (FORALL
                                       (firstout: Output):
                                       NOT firstout`exit
                                       AND
                                       firstout
                                       =
                                       v1
                                       (simplify,
                                        evaluate,
                                        branch,
                                        subdivide,
                                        denorm,
                                        combine,
                                        prune,
                                        le,
                                        ge,
                                        select,
                                        accumulate,
                                        maxdepth)
                                       (sp1,
                                        dom1,
                                        Some(newacc1),
                                        pushDirVar((dir, v), dirvars))
                                       IMPLIES
                                       (FORALL
                                        (newacc2: AnsType):
                                        newacc2
                                        =
                                        accumulate(newacc1, firstout`ans)
                                        IMPLIES
                                        maxdepth
                                        -
                                        length
                                        (pushDirVar((NOT dir, v), dirvars))
                                        <
                                        maxdepth - length(dirvars)))))))))));

  % Subtype TCC generated (at line 204, column 34) for  emptyDirVars
      % expected type  {dirvars | length(dirvars) <= maxdepth}
  b_and_b_TCC1: OBLIGATION
    FORALL (simplify: Simplifier, evaluate: Evaluator, branch: Brancher,
            subdivide: SubdivDomain, denorm: DenormAns, combine: Combiner,
            select: DirVarSelector, accumulate: Accumulator, maxdepth: nat,
            obj: ObjType, dom: DomainType):
      length(emptyDirVars) <= maxdepth;


body:
  %------------------------------------------------------------------------
  %
  %  max_array_def: foundation for max_array
  %  ---------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory provides a constructive definition of max (named Imax) to
  %  provide a means to discharge the TCC produced in max_array.  This 
  %  theory is not intended to be directly used.
  %
  %------------------------------------------------------------------------
  max_array_def[N: nat, T: TYPE, <= : (total_order?[T]) ]: THEORY

  BEGIN

    A,A1,A2: VAR ARRAY[below(N) -> T] 
    t, t1, t2: VAR T
    ii,jj,j: VAR below(N)
   
    amax(A,ii,jj): below(N) = IF A(ii) <= A(jj) THEN jj ELSE ii ENDIF

    imax_rec(A,ii,jj): RECURSIVE below(N) = 
          IF jj <= ii THEN ii
          ELSE amax(A,jj,imax_rec(A,ii,jj-1)) 
          ENDIF MEASURE (LAMBDA A,ii,jj: jj)

    imax_rec_lem: LEMMA  ii <= j AND j <= jj IMPLIES 
                               A(j) <= A(imax_rec(A,ii,jj))

    imax_rec_rng: LEMMA  ii <= jj IMPLIES ii <= imax_rec(A,ii,jj) AND
                                           imax_rec(A,ii,jj) <= jj

    abv(ii): TYPE = {i: nat | ii <= i AND i < N}

    Imax_rec(A,ii,(jj: abv(ii))): subrange(ii,jj) = 
                    imax_rec(A,ii,jj)       

    Imax(A,ii,(jj: abv(ii))): {i: subrange(ii,jj) | 
                                 (FORALL j: ii <= j AND j <= jj 
                                              IMPLIES A(j) <= A(i))}

    Imax_1:   LEMMA Imax(A,ii,ii) = ii

  END max_array_def

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

  % Subtype TCC generated (at line 25, column 37) for  jj - 1
      % expected type  below(N)
  imax_rec_TCC1: OBLIGATION
    FORALL (A: [below(N) -> T], ii: below(N), jj: below(N)):
      NOT jj <= ii IMPLIES jj - 1 >= 0 AND jj - 1 < N;

  % Termination TCC generated (at line 25, column 23) for
      % imax_rec(A, ii, jj - 1)
  imax_rec_TCC2: OBLIGATION
    FORALL (A: [below(N) -> T], ii: below(N), jj: below(N)):
      NOT jj <= ii IMPLIES jj - 1 < jj;

  % Subtype TCC generated (at line 37, column 32) for  jj
      % expected type  below(N)
  Imax_rec_TCC1: OBLIGATION
    FORALL (A: [below(N) -> T], ii: below(N), (jj: abv(ii))): jj < N;

  % Subtype TCC generated (at line 37, column 18) for  imax_rec(A, ii, jj)
      % expected type  subrange(ii, jj)
  Imax_rec_TCC2: OBLIGATION
    FORALL (A: [below(N) -> T], ii: below(N), (jj: abv(ii))):
      ii <= imax_rec(A, ii, jj) AND imax_rec(A, ii, jj) <= jj;

  % Subtype TCC generated (at line 41, column 62) for  i
      % expected type  below(N)
  Imax_TCC1: OBLIGATION
    FORALL (ii, (jj: abv(ii)), i: subrange(ii, jj), j):
      ii <= j AND j <= jj IMPLIES i < N;

  % Existence TCC generated (at line 39, column 2) for
      % Imax(A, ii, (jj: abv(ii))):
      %       {i: subrange(ii, jj) |
      %                (FORALL j: ii <= j AND j <= jj IMPLIES A(j) <= A(i))}
  Imax_TCC2: OBLIGATION
    EXISTS (x:
              [d: [[below(N) -> T], ii: below(N), abv(ii)] ->
                 {i: subrange(d`2, d`3) |
                          FORALL j:
                            d`2 <= j AND j <= d`3 IMPLIES
                             d`1(j) <= d`1(i)}]):
      TRUE;

  % Subtype TCC generated (at line 43, column 28) for  ii
      % expected type  abv(ii)
  Imax_1_TCC1: OBLIGATION FORALL (ii: below(N)): ii <= ii AND ii < N;


body:
  fsq[T: TYPE]: THEORY
  %------------------------------------------------------------------------
  %
  % This theory is scaffolding for the "fseqs" finite sequences theory
  %
  %------------------------------------------------------------------------
  BEGIN

    x,y	: VAR T

    fsq: TYPE = [# length: nat, seq: [nat -> T] #]

    cnvfsq(fs: fsq): MACRO [nat -> T] = fs`seq;
    CONVERSION cnvfsq;
    CONVERSION- finseq_appl;                   %% turn off prelude finseq conversion

    l(f: fsq): MACRO nat = f`length
    seqn(f: fsq): MACRO [nat -> T]= f`seq


    %% not empty fseqs
    ne_fsq: TYPE = {s: fsq  | length(s) > 0}

    in?(x: T, s: fsq): bool = 
                (EXISTS (ii: below(length(s))): x = seq(s)(ii))


    fsq1(t:T): fsq = (# length := 1,
                        seq := (LAMBDA (n: nat): t) #)

    const_fsq(n: nat,c:T): fsq = (# length := n,
                                    seq := (LAMBDA (n: nat): c) #)


  END fsq


body:
  fseqs [T: TYPE+]: THEORY
  %------------------------------------------------------------------------
  %
  % A new finite sequences theory
  %
  % This theory defines finite sequences as a simple record type. Unlike the prelude
  % version, this record is not a dependent type. The domain of all finite_sequences
  % are identical and therefore operators over them are greatly simplified.  However,
  % the built-in equality is no longer valid.  This theory provides a new equality
  % but unfortunately many PVS strategies and commands do not work with this new
  % equality.  Therefore, this theory should be considered highly experimental.
  %
  % Two finite sequences are concatenated with the operator 'o', and a
  % subsequence can be extracted with the operator '^'.  Note that ^
  % allows any natural numbers m and n to define the range; if m > n then
  % the empty sequence is returned
  %
  % This theory creates two levels of finite_sequence
  %   (1) fsq -- simple structure but equality reasoning not available (see fsq.pvs)
  %   (2) fseq -- adds mechanisms to make equality reasoning possible
  % though it is expected that most users will use only (2)
  %
  %
  % AUTHORS: Rick Butler and Jeff Maddalon
  %
  % Difference between this theory and prelude
  %    (1) domain fs`seq is "nat" rather than below[l(fs)]
  %    (2) ^ operator does not have "min" in the type
  %    (3) provides auxiliary functions such as fseq1, fseq2, const_seq, rev
  %    (4) provides ne_fseq: TYPE = {s: fseq  | length(s) > 0}
  %
  % Warning: The prelude "finseq_appl" conversion seems to take precedence over 
  %          cnvfsq it in many theories that import fseqs
  % Warning: sometimes seq(fs) is confused with prelude definitions. Use
  %           seqn(fs) in that case.
  %------------------------------------------------------------------------
  BEGIN

    IMPORTING fsq[T]

    default: T = choose({t:T | TRUE})
    barray(n: nat): TYPE = { f: [nat -> T] | FORALL (i: nat): i >= n IMPLIES f(i) = default}

    fseq: TYPE = [# length: nat, seq: barray(length) #]
    ne_fseq: TYPE = {s: fseq  | length(s) > 0}   %% non-empty fseqs

    member(x:T, fs:fseq): bool = EXISTS (i: below(fs`length)): x = fs`seq(i);

    empty_seq: fsq =
      (# length := 0,
         seq := (LAMBDA (x: nat): default ) #) 

    emptyseq: MACRO fsq = empty_seq 


    fseq_subtype  : JUDGEMENT fseq SUBTYPE_OF fsq[T]
    empty_seq_fseq: JUDGEMENT empty_seq HAS_TYPE fseq
    emptyseq_fseq : JUDGEMENT emptyseq HAS_TYPE fseq

    fs, fs1, fs2, fs3: VAR fseq
    m, n: VAR nat   


    %% singleton
    singleton(x:T): ne_fseq = 
      (# length := 1, seq := (LAMBDA (n: nat): IF n = 0 THEN x ELSE default ENDIF) #)

    singleton?(fs: fseq): bool = EXISTS (x: T): fs = singleton(x)


    tofs(f:[nat->T], len: nat): MACRO [nat -> T] = 
         (LAMBDA (i:nat): IF i < len THEN f(i) ELSE default ENDIF) ;


  %   deflt(f: fsq[T]): fseq = (# length := l(f),
  %                               seq := (LAMBDA (n: nat): IF n < l(f) THEN f`seq(n)
  %                                                        ELSE default
  %                                                        ENDIF)
  %                             #)

    tofseq(f: fsq[T]): fseq = (# length := l(f),
                                 seq := tofs(f`seq,l(f))
                              #)


    singleton_length: LEMMA singleton?(fs) IFF fs`length = 1


    % ---------- Equality ---------- 

    fseqs_eq: LEMMA fs1 = fs2 IFF fs1`length = fs2`length AND
              (FORALL (n:nat): n < fs1`length IMPLIES fs1`seq(n) = fs2`seq(n)) 

    fseq_length_zero: LEMMA fs`length = 0 IMPLIES fs = emptyseq ;


    %% ------------ Concatenation ---------

    o(fs1, fs2): fseq =
       LET l1 = fs1`length, l2 = fs2`length IN
          (# length := l1+l2,
              seq := (LAMBDA (n: nat):
                        IF n < l1 THEN fs1`seq(n)
                        ELSIF n < l1+l2 THEN fs2`seq(n-l1)
                        ELSE default
                        ENDIF) #);

    concat(fs1, fs2): MACRO fseq = o(fs1,fs2) 

    concat_length_add: LEMMA concat(fs1,fs2)`length = fs1`length + fs2`length

    % member and o

    x,y	: VAR T
    member_composition: LEMMA 
      member(x,fs1 o fs2) IFF member(x,fs1) OR member(x,fs2)

    concat_right_emptyseq: LEMMA
      fs o emptyseq = fs

    concat_left_emptyseq: LEMMA
      emptyseq o fs = fs

    member_singleton: LEMMA
      member(x,singleton(y)) IFF x = y

    %% ------------ Extraction ---------

    mmin(m,n:nat): MACRO nat = IF m > n THEN n ELSE m ENDIF ;

    ^(fs: fseq, p:[nat, nat]): fseq =
      LET (m, n) = p
       IN IF m > n OR m >= fs`length
          THEN empty_seq
          ELSE LET len = mmin(n - m + 1, fs`length - m) IN
               (# length := len,
                  seq := (LAMBDA (x: nat): IF x < len THEN fs`seq(x + m)
                                               ELSE default ENDIF) #)
          ENDIF

  %  p: VAR [nat, nat]
  %  hat_rewrite: LEMMA ^(fs, p) = tofseq(fs^^p)

    extract1(fs:{fs | fs`length = 1}): T = fs`seq(0)


    CONVERSION extract1


  %% GET AROUND bleed-in from prelude
  %%
  %% o_assoc: LEMMA fs1 o (fs2 o fs3) = (fs1 o fs2) o fs3

    o_assoc: LEMMA concat(fs1,concat(fs2,fs3)) = concat(concat(fs1,fs2),fs3)


  %% ----- Some Special Functions that operate on fseqs ----------

    fseq1(t:T): fseq = (# length := 1,
                          seq := (LAMBDA (n: nat): IF n < 1 THEN t ELSE default ENDIF) #)

    fseq2(u,v: T): fseq = (# length := 2,
                             seq := (LAMBDA (i: nat): IF i = 0 THEN u 
                                                      ELSIF i= 1 THEN v 
                                                      ELSE default ENDIF) #)

    fseq1_def: LEMMA fseq1(x)`seq(0) = x

    const_seq(n: nat,c:T): fseq = (# length := n,
                                     seq := (LAMBDA (i: nat): IF i < n THEN c ELSE default ENDIF)
                                  #)


    rev(fs:fseq): fseq = (# length := l(fs),
                             seq := (LAMBDA (i: nat): 
                                          IF i < l(fs) THEN seq(fs)(l(fs)-1-i)
                                          ELSE default ENDIF)
                           #)

    AUTO_REWRITE+ fseq1_def


  END fseqs

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

  % Subtype TCC generated (at line 41, column 22) for  {t: T | TRUE}
      % expected type  p: (nonempty?[T])
  default_TCC1: OBLIGATION nonempty?[T]({t: T | TRUE});

  % Judgement subtype TCC generated (at line 57, column 28) for  empty_seq
      % expected type  fseq
  empty_seq_fseq: OBLIGATION
    FORALL (i: nat): i >= empty_seq`length IMPLIES empty_seq`seq(i) = default;

  % Judgement subtype TCC generated (at line 58, column 28) for  emptyseq
      % expected type  fseq
  emptyseq_fseq: OBLIGATION
    FORALL (i: nat): i >= empty_seq`length IMPLIES empty_seq`seq(i) = default;

  % Subtype TCC generated (at line 66, column 28) for
      % (LAMBDA (n: nat): IF n = 0 THEN x ELSE default ENDIF)
      % expected type  barray(1)
  singleton_TCC1: OBLIGATION
    FORALL (x: T):
      FORALL (i: nat):
        i >= 1 IMPLIES IF i = 0 THEN x ELSE default ENDIF = default;

  % Subtype TCC generated (at line 72, column 8) for
      % LAMBDA (i: nat): IF i < f`length THEN f`seq(i) ELSE default ENDIF
      % expected type  barray(f`length)
  tofseq_TCC1: OBLIGATION
    FORALL (f: fsq[T]):
      FORALL (i_1: nat):
        i_1 >= f`length IMPLIES
         IF i_1 < f`length THEN f`seq(i_1) ELSE default ENDIF = default;

  % Subtype TCC generated (at line 104, column 51) for  n - l1
      % expected type  nat
  oh_TCC1: OBLIGATION
    FORALL (fs1: fseq, fs2: fseq, l1: nat):
      l1 = fs1`length IMPLIES
       (FORALL (l2: nat):
          l2 = fs2`length IMPLIES
           (FORALL (n: nat): n < l1 + l2 AND NOT n < l1 IMPLIES n - l1 >= 0));

  % Subtype TCC generated (at line 102, column 20) for
      % (LAMBDA (n: nat):
      %    IF n < l1 THEN fs1`seq(n)
      %    ELSIF n < l1 + l2 THEN fs2`seq(n - l1)
      %    ELSE default
      %    ENDIF)
      % expected type  barray(l1 + l2)
  oh_TCC2: OBLIGATION
    FORALL (fs1: fseq, fs2: fseq, l1: nat):
      l1 = fs1`length IMPLIES
       (FORALL (l2: nat):
          l2 = fs2`length IMPLIES
           (FORALL (i: nat):
              i >= l1 + l2 IMPLIES
               IF i < l1 THEN fs1`seq(i)
               ELSIF i < l1 + l2 THEN fs2`seq(i - l1)
               ELSE default
               ENDIF
                = default));

  % Subtype TCC generated (at line 135, column 39) for  fs`length - m
      % expected type  nat
  caret_TCC1: OBLIGATION
    FORALL (fs: fseq, p: [nat, nat], m: nat, n: nat):
           n - m + 1 > fs`length - m AND NOT m > n AND NOT m >= fs`length
       AND n = p`2 AND m = p`1
       IMPLIES fs`length - m >= 0;

  % Subtype TCC generated (at line 135, column 28) for  n - m + 1
      % expected type  nat
  caret_TCC2: OBLIGATION
    FORALL (fs: fseq, p: [nat, nat], m: nat, n: nat):
           NOT n - m + 1 > fs`length - m AND NOT m > n AND NOT m >= fs`length
       AND n = p`2 AND m = p`1
       IMPLIES n - m + 1 >= 0;

  % Subtype TCC generated (at line 137, column 24) for
      % (LAMBDA (x: nat): IF x < len THEN fs`seq(x + m) ELSE default ENDIF)
      % expected type  barray(len)
  caret_TCC3: OBLIGATION
    FORALL (fs: fseq, p: [nat, nat], m: nat, n: nat):
      NOT m > n AND NOT m >= fs`length AND n = p`2 AND m = p`1 IMPLIES
       (FORALL (len: nat):
          len =
           IF n - m + 1 > fs`length - m THEN fs`length - m
           ELSE n - m + 1
           ENDIF
           IMPLIES
           (FORALL (i: nat):
              i >= len IMPLIES
               IF i < len THEN fs`seq(i + m) ELSE default ENDIF = default));

  % Subtype TCC generated (at line 160, column 32) for
      % (LAMBDA (n: nat): IF n < 1 THEN t ELSE default ENDIF)
      % expected type  barray(1)
  fseq1_TCC1: OBLIGATION
    FORALL (t: T):
      FORALL (i: nat):
        i >= 1 IMPLIES IF i < 1 THEN t ELSE default ENDIF = default;

  % Subtype TCC generated (at line 163, column 35) for
      % (LAMBDA (i: nat):
      %    IF i = 0 THEN u ELSIF i = 1 THEN v ELSE default ENDIF)
      % expected type  barray(2)
  fseq2_TCC1: OBLIGATION
    FORALL (u, v: T):
      FORALL (i_1: nat):
        i_1 >= 2 IMPLIES
         IF i_1 = 0 THEN u ELSIF i_1 = 1 THEN v ELSE default ENDIF = default;

  % Subtype TCC generated (at line 170, column 43) for
      % (LAMBDA (i: nat): IF i < n THEN c ELSE default ENDIF)
      % expected type  barray(n)
  const_seq_TCC1: OBLIGATION
    FORALL (n: nat, c: T):
      FORALL (i_1: nat):
        i_1 >= n IMPLIES IF i_1 < n THEN c ELSE default ENDIF = default;

  % Subtype TCC generated (at line 176, column 66) for  fs`length - 1 - i
      % expected type  nat
  rev_TCC1: OBLIGATION
    FORALL (fs: fseq, i: nat): i < fs`length IMPLIES fs`length - 1 - i >= 0;

  % Subtype TCC generated (at line 175, column 35) for
      % (LAMBDA (i: nat):
      %    IF i < fs`length THEN seq(fs)(fs`length - 1 - i)
      %    ELSE default
      %    ENDIF)
      % expected type  barray(fs`length)
  rev_TCC2: OBLIGATION
    FORALL (fs: fseq):
      FORALL (i_1: nat):
        i_1 >= fs`length IMPLIES
         IF i_1 < fs`length THEN seq(fs)(fs`length - 1 - i_1)
         ELSE default
         ENDIF
          = default;


body:
  max_fseq[T: TYPE+, <= : (total_order?[T]) ]: THEORY
  %------------------------------------------------------------------------
  %
  %  max_fseq (basic definitions and properties)
  %  -------------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory defines the maximum function over a sequence of values
  %  from an ordered type. This is done in an implementation-independent
  %  manner. 
  %
  %      Imax(s,ii,jj)     = general definition of maximum of sequence s 
  %                          over the internal from ii to jj.  Returns the
  %                          index into the sequence.
  %
  %      imax(s)           = general definition of maximum of sequence s. 
  %                          Returns the index into the sequence.
  %
  %      max(s)            = general definition of maximum of sequence s. 
  %                          Returns the maximal element.
  %
  %  Notes:
  %     1. The properties of imax and max are readily obtained via 
  %        TYPEPRED "max" and TYPEPRED "imax" or through use of
  %        max_seq_lem and imax_seq_lem.
  %     2. Since there may be replicates in s, the return type of imax
  %        may not be a singleton set.
  %
  %------------------------------------------------------------------------

    EXPORTING ALL WITH fseqs[T],fsq[T]

  BEGIN

    IMPORTING fseqs[T]

  %  seqs: TYPE = {s: fseq[T]  | length(s) > 0}
  %  in?(x,s): bool = (EXISTS (ii: dom(s)): x = seq(s)(ii))

    s: VAR ne_fseq
    j,ii: VAR nat
    x: VAR T

    IMPORTING max_array_def

    dom(s): TYPE = below(length(s))
    abv(ii,s): TYPE = {i: nat | ii <= i AND i < length(s)}

    Imax(s, (ii: dom(s)),(jj: abv(ii,s))): 
         {i: subrange(ii,jj) | (FORALL j: ii <= j AND j <= jj 
                                       IMPLIES seq(s)(j) <= seq(s)(i))}

    Imax_1: LEMMA (FORALL (s: ne_fseq,ii: dom(s)): Imax(s,ii,ii) = ii)

    imax(s): {i: dom(s)| (FORALL (ii: dom(s)): seq(s)(ii) <= seq(s)(i))}

    max(s): { t: T | (FORALL (ii: dom(s)): seq(s)(ii) <= t) AND
                      (EXISTS (jj: dom(s)): seq(s)(jj) = t)} 

  % LEMMAs that follow immediately from TYPEPRED "imax" and TYPEPRED "max"

    max_seq_lem   : LEMMA (FORALL (ii: dom(s)): seq(s)(ii)<= max(s))

    max_seq_in?   : LEMMA in?(max(s),s)

    imax_seq_lem  : LEMMA seq(s)(imax(s)) = max(s)


    max_seq_def   : LEMMA FORALL (ii: dom(s)): seq(s)(ii) <= max(s) 
                          AND in?(max(s),s)

    max_seq_it_is : LEMMA (FORALL (ii: dom(s)): seq(s)(ii) <= x) AND in?(x,s)
                          IMPLIES max(s) = x


    imax_seq_1    : LEMMA length(s) = 1 IMPLIES imax(s) = 0

    max_seq_2     : LEMMA length(s) = 2 IMPLIES max(s) = 
                            IF seq(s)(0) <= seq(s)(1) THEN seq(s)(1)
                            ELSE seq(s)(0) ENDIF


  END max_fseq

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

  % Existence TCC generated (at line 50, column 2) for
      % Imax(s, (ii: dom(s)), (jj: abv(ii, s))):
      %       {i: subrange(ii, jj) |
      %                (FORALL j:
      %                   ii <= j AND j <= jj IMPLIES seq(s)(j) <= seq(s)(i))}
  Imax_TCC1: OBLIGATION
    EXISTS (x:
              [d: [s: ne_fseq[T], ii: dom(s), abv(ii, s)] ->
                 {i: subrange(d`2, d`3) |
                          FORALL j:
                            d`2 <= j AND j <= d`3 IMPLIES
                             seq(d`1)(j) <= seq(d`1)(i)}]):
      TRUE;

  % Subtype TCC generated (at line 54, column 59) for  ii
      % expected type  abv(ii, s)
  Imax_1_TCC1: OBLIGATION
    FORALL (s: ne_fseq[T], ii: dom(s)): ii <= ii AND ii < length(s);

  % Existence TCC generated (at line 56, column 2) for
      % imax(s): {i: dom(s) | (FORALL (ii: dom(s)): seq(s)(ii) <= seq(s)(i))}
  imax_TCC1: OBLIGATION
    EXISTS (x:
              [s: ne_fseq[T] ->
                 {i: dom(s) |
                          FORALL (ii: dom(s)): seq(s)(ii) <= seq(s)(i)}]):
      TRUE;

  % Existence TCC generated (at line 58, column 2) for
      % max(s):
      %       {t: T |
      %                (FORALL (ii: dom(s)): seq(s)(ii) <= t) AND
      %                 (EXISTS (jj: dom(s)): seq(s)(jj) = t)}
  max_TCC1: OBLIGATION
    EXISTS (x:
              [s: ne_fseq[T] ->
                 {t: T |
                          (FORALL (ii: dom(s)): seq(s)(ii) <= t) AND
                           (EXISTS (jj: dom(s)): seq(s)(jj) = t)}]):
      TRUE;


body:
  below_arrays[N: nat, T: TYPE]: THEORY
  BEGIN
    
     below_array: TYPE = [below(N) -> T]

     A: VAR below_array
     x: VAR T
     ii: VAR below(N)

     in?(x,A): bool = (EXISTS ii: x = A(ii))

  END below_arrays


body:
  %------------------------------------------------------------------------
  %
  %  min_array_def: foundation for min_array
  %  ---------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory provides a constructive definition of min (named Imin) to
  %  provide a means to discharge the TCC produced in min_array.  This 
  %  theory is not intended to be directly used.
  %
  %------------------------------------------------------------------------
  min_array_def[N: nat, T: TYPE, <= : (total_order?[T]) ]: THEORY

     EXPORTING ALL BUT >=, ge_total,     % i.e. DO NOT export max_array stuff
                IMP_max_array_def_TCC1   % because max is alias for min

  BEGIN

    IMPORTING below_arrays[N,T]

    A,A1,A2: VAR ARRAY[below(N) -> T] 
    x, t1, t2: VAR T
    ii,jj,j: VAR below(N)
    n: VAR {p: posnat | p <= N}

    >=(t1,t2): bool = t2 <= t1

    ge_total: LEMMA total_order?[T](>=)

    IMPORTING max_array_def[N,T,>=]

    abv(ii): TYPE = {i: nat | ii <= i AND i < N}

    Imin(A,ii,(jj: abv(ii))): {i: subrange(ii,jj) |
                                   (FORALL j: ii <= j AND j <= jj 
                                       IMPLIES A(i) <= A(j))}

    Imin_1: LEMMA Imin(A,ii,ii) = ii

  END min_array_def

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

  % Subtype TCC generated (at line 31, column 30) for  >=
      % expected type  (total_order?[T])
  IMP_max_array_def_TCC1: OBLIGATION total_order?[T](>=);

  % Subtype TCC generated (at line 37, column 47) for  i
      % expected type  below(N)
  Imin_TCC1: OBLIGATION
    FORALL (ii, (jj: abv(ii)), i: subrange(ii, jj), j):
      ii <= j AND j <= jj IMPLIES i < N;

  % Existence TCC generated (at line 35, column 2) for
      % Imin(A, ii, (jj: abv(ii))):
      %       {i: subrange(ii, jj) |
      %                (FORALL j: ii <= j AND j <= jj IMPLIES A(i) <= A(j))}
  Imin_TCC2: OBLIGATION
    EXISTS (x:
              [d: [[below(N) -> T], ii: below(N), abv(ii)] ->
                 {i: subrange(d`2, d`3) |
                          FORALL j:
                            d`2 <= j AND j <= d`3 IMPLIES
                             d`1(i) <= d`1(j)}]):
      TRUE;

  % Subtype TCC generated (at line 39, column 26) for  ii
      % expected type  abv(ii)
  Imin_1_TCC1: OBLIGATION FORALL (ii: below(N)): ii <= ii AND ii < N;


body:
  min_fseq[T: TYPE+, <= : (total_order?[T]) ]: THEORY
  %------------------------------------------------------------------------
  %
  %  min_fseq (basic definitions and properties)
  %  -------------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory defines the minimum function over a sequence of values
  %  from an ordered type. This is done in an implementation-independent
  %  manner. 
  %
  %      Imin(s,ii,jj)     = general definition of minimum of sequence s 
  %                          over the internal from ii to jj.  Returns the
  %                          index into the sequence.
  %
  %      imin(s)           = general definition of minimum of sequence s. 
  %                          Returns the index into the sequence.
  %
  %      min(s)            = general definition of minimum of sequence s. 
  %                          Returns the minimal element.
  %
  %  Notes:
  %     1. The properties of imin and min are readily obtained via 
  %        TYPEPRED "min" and TYPEPRED "imin" or through use of
  %        min_seq_lem and imin_seq_lem.
  %     2. Since there may be replicates in s, the return type of imin
  %        may not be a singleton set.
  %------------------------------------------------------------------------

    EXPORTING ALL WITH fseqs[T], fsq[T]

  BEGIN

    IMPORTING fseqs[T]

    ii,j: VAR nat
    s: VAR ne_fseq
    x: VAR T

    IMPORTING min_array_def

    dom(s): TYPE = below(length(s))
    abv(ii,s): TYPE = {i: nat | ii <= i AND i < length(s)}

    Imin(s, (ii: dom(s)),(jj: abv(ii,s))): 
         {i: subrange(ii,jj) | (FORALL j: ii <= j AND j <= jj 
                                       IMPLIES seq(s)(i) <= seq(s)(j))}

    Imin_seq_1: LEMMA (FORALL (s: ne_fseq,ii: dom(s)): Imin(s,ii,ii) = ii)

    imin(s): {i: dom(s)| (FORALL (ii: dom(s)): seq(s)(i) <= seq(s)(ii))}

    min(s): { t: T | (FORALL (ii: dom(s)): t <= seq(s)(ii)) AND
                      (EXISTS (jj: dom(s)): seq(s)(jj) = t)} 

  % LEMMAs that follow immediately from TYPEPRED "imin" and TYPEPRED "min"

    min_seq_lem   : LEMMA (FORALL (ii: dom(s)): min(s) <= seq(s)(ii))


    min_seq_in?   : LEMMA in?(min(s),s)

    min_seq_def   : LEMMA FORALL (ii: dom(s)): min(s) <= seq(s)(ii) 
                          AND in?(min(s),s)

    min_seq_it_is : LEMMA (FORALL (ii: dom(s)): x <= seq(s)(ii)) AND in?(x,s)
                          IMPLIES min(s) = x



    imin_seq_lem  : LEMMA seq(s)(imin(s)) = min(s)

    imin_seq_1    : LEMMA length(s) = 1 IMPLIES imin(s) = 0

    min_seq_2     : LEMMA length(s) = 2 IMPLIES min(s) = 
                      IF seq(s)(0) <= seq(s)(1) THEN seq(s)(0)
                      ELSE seq(s)(1) ENDIF


  END min_fseq

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

  % Existence TCC generated (at line 46, column 2) for
      % Imin(s, (ii: dom(s)), (jj: abv(ii, s))):
      %       {i: subrange(ii, jj) |
      %                (FORALL j:
      %                   ii <= j AND j <= jj IMPLIES seq(s)(i) <= seq(s)(j))}
  Imin_TCC1: OBLIGATION
    EXISTS (x:
              [d: [s: ne_fseq[T], ii: dom(s), abv(ii, s)] ->
                 {i: subrange(d`2, d`3) |
                          FORALL j:
                            d`2 <= j AND j <= d`3 IMPLIES
                             seq(d`1)(i) <= seq(d`1)(j)}]):
      TRUE;

  % Subtype TCC generated (at line 50, column 63) for  ii
      % expected type  abv(ii, s)
  Imin_seq_1_TCC1: OBLIGATION
    FORALL (s: ne_fseq[T], ii: dom(s)): ii <= ii AND ii < length(s);

  % Existence TCC generated (at line 52, column 2) for
      % imin(s): {i: dom(s) | (FORALL (ii: dom(s)): seq(s)(i) <= seq(s)(ii))}
  imin_TCC1: OBLIGATION
    EXISTS (x:
              [s: ne_fseq[T] ->
                 {i: dom(s) |
                          FORALL (ii: dom(s)): seq(s)(i) <= seq(s)(ii)}]):
      TRUE;

  % Existence TCC generated (at line 54, column 2) for
      % min(s):
      %       {t: T |
      %                (FORALL (ii: dom(s)): t <= seq(s)(ii)) AND
      %                 (EXISTS (jj: dom(s)): seq(s)(jj) = t)}
  min_TCC1: OBLIGATION
    EXISTS (x:
              [s: ne_fseq[T] ->
                 {t: T |
                          (FORALL (ii: dom(s)): t <= seq(s)(ii)) AND
                           (EXISTS (jj: dom(s)): seq(s)(jj) = t)}]):
      TRUE;


body:
  permutations_fseq[T: TYPE+, <= : (total_order?[T]) ]: THEORY
  %------------------------------------------------------------------------
  %
  %  permutations_fseq (basic definitions and properties)
  %  -------------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %
  %    permutation?(A1,A2): bool = (EXISTS (f: [below(N) -> below(N)]): 
  %                      bijective?(f) AND (FORALL ii: A1(ii) = A2(f(ii))))
  %  
  %
  %------------------------------------------------------------------------


  BEGIN

    IMPORTING fseqs[T]

    A,B,A1,A2,A3: VAR fsq[T]   %% or fseq 
    x, t: VAR T
    i,j: VAR nat

    permutation?(A,B): bool = (EXISTS (f: [below(length(A)) -> below(length(B))]): 
                       bijective?(f) AND 
                       (FORALL (ii: below(length(A))): seq(A)(ii) = seq(B)(f(ii))))

    IMPORTING finite_sets@finite_sets_card_eq, finite_sets@finite_sets_below

    perm_length   : LEMMA permutation?(A,B) IMPLIES length(A) = length(B)

    perm_reflexive: LEMMA permutation?(A,A)

    perm_symmetric: LEMMA permutation?(A,B) IMPLIES permutation?(B,A)

    perm_tran     : LEMMA permutation?(A1,A2) AND permutation?(A2,A3) 
                              IMPLIES permutation?(A1,A3)

    perm_in?      : LEMMA permutation?(A1,A2) IMPLIES 
                               (in?(x,A1) = in?(x,A2))




  END permutations_fseq


body:
  permutations[N: nat, T: TYPE]: THEORY
  %------------------------------------------------------------------------
  %
  % permutations of arrays
  %
  % Author: Rick Butler
  %
  %------------------------------------------------------------------------
  BEGIN

    A,A1,A2,A3: VAR ARRAY[below(N) -> T] 
    ii: VAR below[N]
    x: VAR T

    IMPORTING below_arrays[N,T]

    permutation_of?(A1,A2): bool = (EXISTS (f: [below(N) -> below(N)]): 
                        bijective?(f) AND (FORALL ii: A1(ii) = A2(f(ii))))

    perm_reflexive: LEMMA permutation_of?(A,A)

    perm_symmetric: LEMMA permutation_of?(A1,A2) IMPLIES permutation_of?(A2,A1)

    perm_tran     : LEMMA permutation_of?(A1,A2) AND permutation_of?(A2,A3) 
                              IMPLIES permutation_of?(A1,A3)

    perm_in?      : LEMMA permutation_of?(A1,A2) IMPLIES 
                               (in?(x,A1) = in?(x,A2))

  END permutations


body:
  %------------------------------------------------------------------------
  %
  %  sort_array_def: serves as a foundation for sort_array
  %  -----------------------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory provides a constructive definition of sort (named asort) to
  %  provide a means to discharge the TCC produced in sort_array.  This 
  %  theory is not intended to be directly used.
  %
  %------------------------------------------------------------------------
  sort_array_def[N: nat, T: TYPE, <= : (total_order?[T]) ]: THEORY
  BEGIN

    IMPORTING min_array_def[N,T,<=], permutations[N,T]

    A,A1,A2,A3: VAR below_array[N,T]
    x, t: VAR T
    ii,jj,n,i,j,ix: VAR below[N]


    P(A,jj): bool = (FORALL i,j: 0 <= i AND i < j AND j <= jj IMPLIES
                         A(i) <= A(j))

    Q(A,jj): bool = (FORALL i,j: 0 <= i AND i <= jj AND jj < j AND j < N
                         IMPLIES A(i) <= A(j))

    swap(A,jj): below_array =  A WITH [jj := A(Imin(A,jj,N-1)),
                         (Imin(A,jj,N-1)) := A(jj)]
     
    asort(A,jj): RECURSIVE below_array = 
                     (IF jj = 0 THEN swap(A,jj)
                      ELSE swap(asort(A,jj-1),jj) ENDIF)
                          MEASURE jj

    swap_perm    : LEMMA permutation_of?(A, swap(A,jj))

    asort_perm   : LEMMA permutation_of?(A,asort(A,jj))

    swap_P_and_Q : LEMMA P(A,j) AND Q(A,j) AND j < N-1 
                           IMPLIES P(swap(A,j+1),j+1) AND Q(swap(A,j+1),j+1)

    asort_P_and_Q: LEMMA P(asort(A,jj),jj) AND Q(asort(A,jj),jj)

  END sort_array_def

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

  % Subtype TCC generated (at line 29, column 55) for  N - 1
      % expected type  abv[N, T, <=](jj)
  swap_TCC1: OBLIGATION
    FORALL (A: below_array[N, T], jj: below[N]):
      N - 1 >= 0 AND jj <= N - 1 AND N - 1 < N;

  % Subtype TCC generated (at line 29, column 45) for  Imin(A, jj, N - 1)
      % expected type  below(N)
  swap_TCC2: OBLIGATION
    FORALL (A: below_array[N, T], jj: below[N]):
      Imin[N, T, <=](A, jj, N - 1) >= 0 AND Imin[N, T, <=](A, jj, N - 1) < N;

  % Subtype TCC generated (at line 34, column 38) for  jj - 1
      % expected type  below[N]
  asort_TCC1: OBLIGATION
    FORALL (jj: below[N]): NOT jj = 0 IMPLIES jj - 1 >= 0 AND jj - 1 < N;

  % Termination TCC generated (at line 34, column 30) for  asort(A, jj - 1)
  asort_TCC2: OBLIGATION
    FORALL (jj: below[N]): NOT jj = 0 IMPLIES jj - 1 < jj;

  % Subtype TCC generated (at line 42, column 42) for  j + 1
      % expected type  below[N]
  swap_P_and_Q_TCC1: OBLIGATION
    FORALL (A: below_array[N, T], j: below[N]):
      j < N - 1 AND Q(A, j) AND P(A, j) IMPLIES j + 1 < N;


