# TheoryBodies

body:
  %------------------------------------------------------------------------
  %
  %  sort_array (basic definitions and properties)
  %  -------------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory defines the sort function over an array of
  %  values. 
  %  
  %  Defines:
  %
  %    permutation_of?(A1,A2): bool = (EXISTS (f: [below(N) -> below(N)]): 
  %                      bijective?(f) AND (FORALL ii: A1(ii) = A2(f(ii))))
  %  
  %    sorted?(A): bool = (FORALL i,j: 0 <= i AND i < j AND j < N 
  %                                      IMPLIES A(i) <= A(j))
  %
  %    sort(A): {a: arrays | permutation_of?(A,a) AND sorted?(a)}
  %
  %  Note:
  %
  %     The properties of sort are readily obtained via 
  %     TYPEPRED "sort" or through use of sort_lem.
  %
  %------------------------------------------------------------------------
  sort_array[N: nat, T: TYPE, <= : (total_order?[T]) ]: THEORY

     EXPORTING sorted?, sort, sort_lem, sort_map, isort_map,
                sort_TCC1, sort_map_TCC1, isort_map_TCC1, 
                sort_map_def, sort_map_bij,
                isort_map_def, isort_map_bij

          WITH permutations[N,T], below_arrays[N,T]

  BEGIN

    IMPORTING sort_array_def[N,T,sort_array.<=], 
               permutations[N,T], below_arrays[N,T]

    A,a: VAR [below(N) -> T] 
    i,j: VAR below[N]
    x: VAR T

    sorted?(A): bool = (FORALL i,j: 0 <= i AND i < j AND j < N IMPLIES
                              A(i) <= A(j))

    sort(A): {a | permutation_of?(A,a) AND sorted?(a)}

    sort_lem     : LEMMA permutation_of?(A,sort(A)) AND sorted?(sort(A))
    
    sort_in?     : LEMMA in?(x,A) IFF in?(x,sort(A))

  % ------------------ NEW ------------------

    sort_map(A): { map: [below(N) -> below(N)] | bijective?(map) AND
                      (FORALL i: A(i) = sort(A)(map(i)))}

    sort_map_def: LEMMA A(i) = sort(A)(sort_map(A)(i))

    sort_map_bij: LEMMA bijective?(sort_map(A))


    isort_map(A): { map: [below(N) -> below(N)] | bijective?(map) AND
                      (FORALL i: A(map(i)) = sort(A)(i))}

    isort_map_def: LEMMA A(isort_map(A)(i)) = sort(A)(i)

    isort_map_bij: LEMMA bijective?(isort_map(A))


  END sort_array

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

  % Existence TCC generated (at line 48, column 2) for
      % sort(A): {a | permutation_of?(A, a) AND sorted?(a)}
  sort_TCC1: OBLIGATION
    EXISTS (x:
              [A: [below(N) -> T] ->
                 {a | permutation_of?[N, T](A, a) AND sorted?(a)}]):
      TRUE;

  % Existence TCC generated (at line 56, column 2) for
      % sort_map(A):
      %       {map: [below(N) -> below(N)] |
      %                bijective?(map) AND (FORALL i: A(i) = sort(A)(map(i)))}
  sort_map_TCC1: OBLIGATION
    EXISTS (x:
              [A: [below(N) -> T] ->
                 {map: [below(N) -> below(N)] |
                          bijective?[below(N), below(N)](map) AND
                           (FORALL i: A(i) = sort(A)(map(i)))}]):
      TRUE;

  % Existence TCC generated (at line 64, column 2) for
      % isort_map(A):
      %       {map: [below(N) -> below(N)] |
      %                bijective?(map) AND (FORALL i: A(map(i)) = sort(A)(i))}
  isort_map_TCC1: OBLIGATION
    EXISTS (x:
              [A: [below(N) -> T] ->
                 {map: [below(N) -> below(N)] |
                          bijective?[below(N), below(N)](map) AND
                           (FORALL i: A(map(i)) = sort(A)(i))}]):
      TRUE;


body:
  sort_fseq[T: TYPE+, <= : (total_order?[T]) ]: THEORY
  %------------------------------------------------------------------------
  %
  %  sort_fseq (basic definitions and properties)
  %  -------------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory defines the sort function over an seq of
  %  values.  Most of the text of this theory is scaffolding to
  %  demonstrate that the definition of "sort" is sound.  In particular,
  %  the function "asort" is a witness function and not intended
  %  to be used externally.
  %  
  %  The following definitions should be used exclusively:
  %
  %    is_permutation(A1,A2): bool = (EXISTS (f: [below(N) -> below(N)]): 
  %                      bijective?(f) AND (FORALL ii: A1(ii) = A2(f(ii))))
  %  
  %    increasing(A): bool = (FORALL i,j: 0 <= i AND i < j AND j < N 
  %                                 IMPLIES A(i) <= A(j))
  %
  %    sort(A): {a: seqs | is_permutation(A,a) AND increasing(a)}
  %
  %  Note:
  %     The properties of sort are readily obtained via
  %     TYPEPRED "sort" or through use of sort_lem.
  %
  %------------------------------------------------------------------------

    EXPORTING ALL BUT seq_to_array % i.e. do not export sort_array
          WITH permutations_fseq[T,<=], fseqs[T], fsq[T]

  BEGIN

    IMPORTING fseqs[T]


    s,s1,s2,ss: VAR fseq
    x, t: VAR T
    i,j: VAR nat 

  %%  <(x,y: T): bool = x <= y AND x /= y                         %% CAUSED SOME PROBLEMS

    IMPORTING sort_array, below_arrays, permutations_fseq

    seq_to_array(s): below_array[length(s),T] =
               (LAMBDA (i: below(length(s))): seq(s)(i))

    increasing?(s): bool = (FORALL i,j: 0 <= i AND i < j AND j < length(s)
                              IMPLIES seq(s)(i) <= seq(s)(j))

    strictly_increasing?(s): bool = (FORALL i,j: 0 <= i AND i < j AND j < length(s)
                              IMPLIES (seq(s)(i) <= seq(s)(j) AND seq(s)(i) /= seq(s)(j)))

    sort(s): {ss: fseq | permutation?[T,<=](s,ss) AND increasing?(ss)}

    sort_length  : LEMMA length(sort(s)) = length(s)

    AUTO_REWRITE+ sort_length

    sort_fseq_lem  : LEMMA permutation?[T,<=](s,sort(s)) AND increasing?(sort(s))

    sort_fseq_in?  : LEMMA in?(x,s) IFF in?(x,sort(s))

    sort_fseq_in   : LEMMA FORALL (ii: below(length(s))): 
                                       in?(seq(sort(s))(ii),s)

    sort_fseq_in2  : LEMMA FORALL (ii: below(length(s))): in?(seq(s)(ii),sort(s))

    sort_fseq_lt   : LEMMA FORALL (i,j: below(length(s))): 
                           sort(s)(i) <= sort(s)(j) AND sort(s)(i) /= sort(s)(j) IMPLIES i < j

    sort_singleton : LEMMA sort(singleton(x)) = singleton(x)

    member_sort	 : LEMMA member(x,s) IFF member(x,sort(s))


    %----------------- Strictly Sorting ----------------%

    strictly_sort(s): {ss: fseq | strictly_increasing?(ss) AND (FORALL (x:T): member(x,s) IFF member(x,ss))}

    strictly_sort_length: LEMMA strictly_sort(s)`length <= s`length

    strictly_sort_subint_eq: LEMMA LET sss = strictly_sort(s) IN increasing?(s) IMPLIES FORALL (ii:below(sss`length-1)):
    			   EXISTS (jj:below(s`length-1)): sss`seq(ii+1)=s`seq(jj+1) AND sss`seq(ii) = s`seq(jj)

    strictly_sort_map(s): {sq: [below(strictly_sort(s)`length)->below(s`length)] |
    			     LET sss = strictly_sort(s) IN
  			     (increasing?(s) AND sss`length >= 1 IMPLIES sq(sss`length-1) = s`length-1) AND
  			     (FORALL (ii:below(sss`length)): (sss`seq(ii) = s`seq(sq(ii)) AND
  			     (increasing?(s) AND ii<sss`length-1 IMPLIES sss`seq(ii+1) = s`seq(sq(ii)+1))))}

    strictly_sort_map_between: LEMMA LET sss = strictly_sort(s) IN
    			     	   FORALL (ii:below(sss`length-1)): FORALL (jj:below(s`length)):
  				   increasing?(s) AND strictly_sort_map(s)(ii)<jj AND jj<=strictly_sort_map(s)(ii+1) IMPLIES
  				   s`seq(strictly_sort_map(s)(ii+1)) = s`seq(jj)

    strictly_sort_map_increasing: LEMMA increasing?(s) IMPLIES FORALL (ii,jj:below(strictly_sort(s)`length)):
    				LET sq = strictly_sort_map(s) IN ii<jj IMPLIES sq(ii)<sq(jj)


  % ------------------ NEW ------------------%

    sort_map(s): { map: [below(length(s)) -> below(length(s))] | 
              bijective?(map) AND
                (FORALL (i: below(length(s))): seq(s)(i) = seq(sort(s))(map(i)))}

    sort_map_def: LEMMA FORALL (i: below(length(s))):
                              seq(s)(i) = seq(sort(s))(sort_map(s)(i))

    sort_map_bij: LEMMA bijective?(sort_map(s))




    isort_map(s: {ss: fseq | length(ss) > 0}):
         { map: [below(length(s)) -> below(length(s))] | 
               bijective?(map) AND
                 (FORALL (i:below(length(s))): seq(s)(map(i)) = seq(sort(s))(i))}

    isort_map_def: LEMMA FORALL (i: below(length(s))):
                               seq(s)(isort_map(s)(i)) = seq(sort(s))(i)

    isort_map_bij: LEMMA FORALL (s: {ss: fseq  | length(ss) > 0}):
                              bijective?(isort_map(s))




  END sort_fseq

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

  % Existence TCC generated (at line 56, column 2) for
      % sort(s): {ss: fseq | permutation?[T, <=](s, ss) AND increasing?(ss)}
  sort_TCC1: OBLIGATION
    EXISTS (x:
              [s: fseq[T] ->
                 {ss: fseq[T] |
                          permutation?[T, <=](s, ss) AND increasing?(ss)}]):
      TRUE;

  % Existence TCC generated (at line 81, column 2) for
      % strictly_sort(s):
      %       {ss: fseq |
      %                strictly_increasing?(ss) AND
      %                 (FORALL (x: T): member(x, s) IFF member(x, ss))}
  strictly_sort_TCC1: OBLIGATION
    EXISTS (x1:
              [s: fseq[T] ->
                 {ss: fseq[T] |
                          strictly_increasing?(ss) AND
                           (FORALL (x: T):
                              member[T](x, s) IFF member[T](x, ss))}]):
      TRUE;

  % Subtype TCC generated (at line 90, column 55) for  sss`length - 1
      % expected type  below(strictly_sort(s)`length)
  strictly_sort_map_TCC1: OBLIGATION
    FORALL (s, sq: [below(strictly_sort(s)`length) -> below(s`length)],
            sss:
              {ss: fseq[T] |
                       strictly_increasing?(ss) AND
                        (FORALL (x: T):
                           member[T](x, s) IFF member[T](x, ss))}):
      increasing?(s) AND sss`length >= 1 AND sss = strictly_sort(s) IMPLIES
       sss`length - 1 >= 0 AND sss`length - 1 < strictly_sort(s)`length;

  % Subtype TCC generated (at line 91, column 64) for  ii
      % expected type  below(strictly_sort(s)`length)
  strictly_sort_map_TCC2: OBLIGATION
    FORALL (s, sq: [below(strictly_sort(s)`length) -> below(s`length)],
            sss:
              {ss: fseq[T] |
                       strictly_increasing?(ss) AND
                        (FORALL (x: T):
                           member[T](x, s) IFF member[T](x, ss))}):
      (increasing?(s) AND sss`length >= 1 IMPLIES
        sq(sss`length - 1) = s`length - 1)
       AND sss = strictly_sort(s)
       IMPLIES (FORALL (ii: below(sss`length)): ii < strictly_sort(s)`length);

  % Existence TCC generated (at line 88, column 2) for
      % strictly_sort_map(s):
      %       {sq: [below(strictly_sort(s)`length) -> below(s`length)] |
      %                LET sss = strictly_sort(s) IN
      %                  (increasing?(s) AND sss`length >= 1 IMPLIES
      %                    sq(sss`length - 1) = s`length - 1)
      %                   AND
      %                   (FORALL (ii: below(sss`length)):
      %                      (sss`seq(ii) = s`seq(sq(ii)) AND
      %                        (increasing?(s) AND ii < sss`length - 1
      %                          IMPLIES
      %                          sss`seq(ii + 1) = s`seq(sq(ii) + 1))))}
  strictly_sort_map_TCC3: OBLIGATION
    EXISTS (x:
              [s: fseq[T] ->
                 {sq: [below(strictly_sort(s)`length) -> below(s`length)] |
                          (increasing?(s) AND strictly_sort(s)`length >= 1
                            IMPLIES
                            sq(strictly_sort(s)`length - 1) = s`length - 1)
                           AND
                           (FORALL (ii: below(strictly_sort(s)`length)):
                              (strictly_sort(s)`seq(ii) = s`seq(sq(ii)) AND
                                (increasing?(s) AND
                                  ii < strictly_sort(s)`length - 1
                                  IMPLIES
                                  strictly_sort(s)`seq(1 + ii) =
                                   s`seq(1 + sq(ii)))))}]):
      TRUE;

  % Subtype TCC generated (at line 96, column 47) for  ii
      % expected type  below(strictly_sort(s)`length)
  strictly_sort_map_between_TCC1: OBLIGATION
    FORALL (s: fseq[T],
            sss:
              {ss: fseq[T] |
                       strictly_increasing?(ss) AND
                        (FORALL (x: T):
                           member[T](x, s) IFF member[T](x, ss))}):
      sss = strictly_sort(s) IMPLIES
       (FORALL (ii: below(sss`length - 1), jj: below(s`length)):
          increasing?(s) IMPLIES ii < strictly_sort(s)`length);

  % Subtype TCC generated (at line 96, column 83) for  ii + 1
      % expected type  below(strictly_sort(s)`length)
  strictly_sort_map_between_TCC2: OBLIGATION
    FORALL (s: fseq[T],
            sss:
              {ss: fseq[T] |
                       strictly_increasing?(ss) AND
                        (FORALL (x: T):
                           member[T](x, s) IFF member[T](x, ss))}):
      sss = strictly_sort(s) IMPLIES
       (FORALL (ii: below(sss`length - 1), jj: below(s`length)):
          strictly_sort_map(s)(ii) < jj AND increasing?(s) IMPLIES
           ii + 1 < strictly_sort(s)`length);

  % Existence TCC generated (at line 105, column 2) for
      % sort_map(s):
      %       {map: [below(length(s)) -> below(length(s))] |
      %                bijective?(map) AND
      %                 (FORALL (i: below(length(s))):
      %                    seq(s)(i) = seq(sort(s))(map(i)))}
  sort_map_TCC1: OBLIGATION
    EXISTS (x:
              [s: fseq[T] ->
                 {map: [below(length(s)) -> below(length(s))] |
                          bijective?[below(length(s)), below(length(s))](map)
                           AND
                           (FORALL (i: below(length(s))):
                              seq(s)(i) = seq(sort(s))(map(i)))}]):
      TRUE;

  % Existence TCC generated (at line 117, column 2) for
      % isort_map(s: {ss: fseq | length(ss) > 0}):
      %       {map: [below(length(s)) -> below(length(s))] |
      %                bijective?(map) AND
      %                 (FORALL (i: below(length(s))):
      %                    seq(s)(map(i)) = seq(sort(s))(i))}
  isort_map_TCC1: OBLIGATION
    EXISTS (x:
              [s: {ss: fseq[T] | length(ss) > 0} ->
                 {map: [below(length(s)) -> below(length(s))] |
                          bijective?[below(length(s)), below(length(s))](map)
                           AND
                           (FORALL (i: below(length(s))):
                              seq(s)(map(i)) = seq(sort(s))(i))}]):
      TRUE;

  % Subtype TCC generated (at line 123, column 46) for  s
      % expected type  s: {ss: fseq | length(ss) > 0}
  isort_map_def_TCC1: OBLIGATION
    FORALL (s: fseq[T], i: below(length(s))): length(s) > 0;


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

    IMPORTING sort_fseq[T,<=], 
               min_fseq[T,<=], max_fseq[T,<=]


    s: VAR ne_fseq


    sort_seq_min : LEMMA seq(sort(s))(0) = min(s)

    sort_seq_max : LEMMA seq(sort(s))(length(s)-1) = max(s)
  	
  END sort_fseq_lems

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

  % Subtype TCC generated (at line 13, column 36) for  length(s) - 1
      % expected type  nat
  sort_seq_max_TCC1: OBLIGATION FORALL (s: ne_fseq[T]): length(s) - 1 >= 0;


body:
  fseq2set[T: TYPE+, <= : (total_order?[T]) ]: THEORY
  %----------------------------------------------------------------------------
  %
  % Utility functions for converting to/from sets and sequences
  %
  % Version 1.0, January, 2004
  % Author: Kristin Y. Rozier
  %----------------------------------------------------------------------------
  BEGIN

     IMPORTING sort_fseq_lems[T,<=],
               finite_sets@finite_sets_minmax[T,<=],
               ints@max_below

     fs: VAR fseq
     a,b,c,d,x,y,z: VAR T
     N: VAR nat

  %------------------------------------------------------------------------------
     seq2set(fs): finite_set[T] 
  	  = {s: T | (EXISTS (kk: below(length(fs))): fs`seq(kk) = s)}

     seq2set_lem: LEMMA (FORALL (ii: below(length(fs))): seq2set(fs)(fs`seq(ii)))

     card_seq2set: LEMMA card[T](seq2set(fs)) <= length(fs)

     ne_fs: VAR ne_fseq
     minmax_seq2set: LEMMA min[T,<=](seq2set(ne_fs)) = min(ne_fs) AND
                           max[T,<=](seq2set(ne_fs)) = max(ne_fs)

     ss: VAR ne_fseq  % length > 0
     JUDGEMENT seq2set(ss) HAS_TYPE (nonempty?[T]) 

  %------------------------------------------------------------------------------
  %    set2seq(S: finite_set[T]):  RECURSIVE fseq[T] =
  %         IF empty?[T](S) THEN empty_seq
  %         ELSE fseq1(choose[T](S)) o set2seq(rest[T](S)) 
  %         ENDIF 
  %       MEASURE card[T](S) 

    set2seq(S: finite_set[T]):  {fs: fseq |
         length(fs) = card(S) AND    
         (FORALL (ii: below(length(fs))): S(fs`seq(ii))) AND
         (FORALL (x:T): S(x) IMPLIES EXISTS (ii: below(length(fs))): fs`seq(ii) = x) AND
         (FORALL (ii,jj: below(length(fs))): 
                                 ii /= jj IMPLIES fs`seq(ii) /= fs`seq(jj)) }


     S: VAR finite_set[T]

     set2seq_length: LEMMA length(set2seq(S)) = card(S)

     set2seq_lem: LEMMA LET fs = set2seq(S) IN
                            FORALL (ii: below(length(fs))): S(fs`seq(ii))

     set2seq_exists: LEMMA LET fs = set2seq(S) IN
                          S(x) IMPLIES
                              EXISTS (ii: below(length(fs))): fs`seq(ii) = x

     AUTO_REWRITE+ set2seq_length

     minmax_set2seq: LEMMA card(S) > 0 IMPLIES
                             min(set2seq(S)) =  min[T,<=](S) AND
                             max(set2seq(S)) =  max[T,<=](S)

     set2seq_neq   : LEMMA LET fs = set2seq(S) IN
                       FORALL (ii,jj: below(length(fs))): 
                                 ii /= jj IMPLIES fs`seq(ii) /= fs`seq(jj)

     set2seq_all   : LEMMA LET fs = sort(set2seq(S)) IN
                            FORALL (ii: below(length(fs)-1)): 
                               fs`seq(ii) <= x AND x <= fs`seq(ii+1)  AND
                               fs`seq(ii) /= x AND x /= fs`seq(ii+1) 
                           IMPLIES
                               NOT S(x)

   
  END fseq2set

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

  % Subtype TCC generated (at line 21, column 5) for
      % {s: T | (EXISTS (kk: below(length(fs))): fs`seq(kk) = s)}
      % expected type  finite_set[T]
  seq2set_TCC1: OBLIGATION
    FORALL (fs: fseq[T]):
      is_finite[T]({s: T | EXISTS (kk: below(length(fs))): fs`seq(kk) = s});

  % Subtype TCC generated (at line 28, column 35) for  seq2set(ne_fs)
      % expected type  SS: non_empty_finite_set[T]
  minmax_seq2set_TCC1: OBLIGATION
    FORALL (ne_fs: ne_fseq[T]): NOT empty?[T](seq2set(ne_fs));

  % Judgement subtype TCC generated (at line 32, column 13) for  seq2set(ss)
      % expected type  (nonempty?[T])
  seq2set_TCC2: OBLIGATION FORALL (ss): nonempty?[T](seq2set(ss));

  % Existence TCC generated (at line 41, column 2) for
      % set2seq(S: finite_set[T]):
      %       {fs: fseq |
      %                length(fs) = card(S) AND
      %                 (FORALL (ii: below(length(fs))): S(fs`seq(ii))) AND
      %                  (FORALL (x: T):
      %                     S(x) IMPLIES
      %                      (EXISTS (ii: below(length(fs))):
      %                         fs`seq(ii) = x))
      %                   AND
      %                   (FORALL (ii, jj: below(length(fs))):
      %                      ii /= jj IMPLIES fs`seq(ii) /= fs`seq(jj))}
  set2seq_TCC1: OBLIGATION
    EXISTS (x1:
              [S: finite_set[T] ->
                 {fs: fseq[T] |
                          length(fs) = card[T](S) AND
                           (FORALL (ii: below(length(fs))): S(fs`seq(ii)))
                            AND
                            (FORALL (x: T):
                               S(x) IMPLIES
                                (EXISTS (ii: below(length(fs))):
                                   fs`seq(ii) = x))
                             AND
                             (FORALL (ii, jj: below(length(fs))):
                                ii /= jj IMPLIES
                                 fs`seq(ii) /= fs`seq(jj))}]):
      TRUE;

  % Subtype TCC generated (at line 63, column 31) for  set2seq(S)
      % expected type  s: ne_fseq[T]
  minmax_set2seq_TCC1: OBLIGATION
    FORALL (S: finite_set[T]): card(S) > 0 IMPLIES length(set2seq(S)) > 0;

  % Subtype TCC generated (at line 63, column 56) for  S
      % expected type  SS: non_empty_finite_set[T]
  minmax_set2seq_TCC2: OBLIGATION
    FORALL (S: finite_set[T]): card(S) > 0 IMPLIES NOT empty?[T](S);


body:
  majority_fseq[T: NONEMPTY_TYPE]: THEORY
  %------------------------------------------------------------------------
  %
  %  majority (basic definitions and properties)
  %  -------------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory defines the majority function over a finite sequence of
  %  values.  The following functions are defined:
  %           
  %           is_majority(mv,fs) -- predicate that is true IFF mv is
  %                                 the majority value of the sequence
  %
  %           maj_exists(fs)     -- predicate that us true IFF a majority
  %                                 exists
  %
  %           maj(fs)            -- function that returns the majority value
  %                                 if a majority exists.  If a majority does
  %                                 not exist, the function returns an
  %                                 unspecified value from the type T.
  %                                 This value may not be in the sequence.
  %
  %           inseq(x,fs)        -- predicate that is true IFF x is in
  %                                 the sequence
  %
  %   Note: the following function can be defined that will return
  %   a value from the sequence if a majority does not exist.
  %
  %     finseq: TYPE = {fs | length(fs) > 0}
  %
  %     fsq: VAR finseq
  %     Maj(fsq): {x: T | in_seq(x,fsq)} = IF maj_exists(fsq) THEN maj(fsq)
  %                                        ELSE choose({x: T | in_seq(x,fsq)})
  %                                        ENDIF 
  %
  %------------------------------------------------------------------------

  BEGIN

    IMPORTING finite_sets@finite_sets_below
    IMPORTING fseqs[T]

    fs: VAR fsq[T]
    mv, mv1, mv2, x: VAR T

    is_majority(mv: T, fs): bool = 
         2*card({i: below(length(fs)) | seq(fs)(i) = mv}) > length(fs) 

    maj_exists(fs): bool = (EXISTS (mv: T): is_majority(mv,fs))

    maj(fs): {mv | maj_exists(fs) => is_majority(mv,fs)}

    in_seq(x,fs): bool = (EXISTS (i: below(length(fs))): seq(fs)(i) = x)

    is_majority_unique: LEMMA is_majority(mv1,fs) AND is_majority(mv2,fs)
                              IMPLIES mv1 = mv2

    maj_lem:            LEMMA is_majority(mv,fs) IFF 
                              maj_exists(fs) AND maj(fs) = mv

    maj_subset:         LEMMA   (EXISTS (A: finite_set[below(length(fs))]):
                                 2*card(A) > length(fs)
                                 AND (FORALL (i: below(length(fs))): A(i) 
                                                IMPLIES seq(fs)(i) = mv))
                              IMPLIES is_majority(mv,fs)

    maj_in_seq:         LEMMA is_majority(mv,fs) IMPLIES in_seq(mv,fs)

  % ===================== Some Special Sequences ===================

    f1: VAR [below[1] -> T]


    n: VAR posnat
    c: VAR T

    length_eq_1: LEMMA maj(fseq1(c)) = c 

    constant_seq(n,c): fsq[T] = (# length := n,
                                    seq := (LAMBDA (i: nat): c) #)

    is_majority_const: LEMMA is_majority(c, constant_seq(n,c))
    
    maj_const:         LEMMA maj_exists(constant_seq(n,c)) AND
                             maj(constant_seq(n,c)) = c

  END majority_fseq

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

  % Subtype TCC generated (at line 48, column 14) for
      % {i: below(length(fs)) | seq(fs)(i) = mv}
      % expected type  S: finite_set[below(length(fs))]
  is_majority_TCC1: OBLIGATION
    FORALL (mv: T, fs: fsq[T]):
      is_finite[below(length(fs))]({i: below(length(fs)) | seq(fs)(i) = mv});

  % Existence TCC generated (at line 52, column 2) for
      % maj(fs): {mv | maj_exists(fs) => is_majority(mv, fs)}
  maj_TCC1: OBLIGATION
    EXISTS (x: [fs: fsq[T] -> {mv | maj_exists(fs) => is_majority(mv, fs)}]):
      TRUE;


body:
  fseqs_ops [T: TYPE+]: THEORY
  %------------------------------------------------------------------------
  %
  %  Defines some convenient operations over finite sequences
  %
  %  EXPERIMENTAL
  %
  %------------------------------------------------------------------------
  BEGIN

    IMPORTING  fseqs[T]

    fs: VAR fseq
    nefs: VAR ne_fseq
    i,n: VAR nat
    x: VAR T

    first(fs): T = fs`seq(0)

    rest(fs): fseq = fs^(1,l(fs))

    delete(n, nefs): fseq = IF n < l(nefs) THEN
                                   (# length := l(nefs) - 1,
                                      seq := (LAMBDA i: (IF i < n THEN nefs(i) 
                                                      ELSE nefs(i + 1) ENDIF))
                                    #)
                               ELSE nefs
                               ENDIF


    insert(x, n, fs): fseq = IF n <= l(fs) THEN 
                                  (# length := l(fs) + 1,
      			           seq := (LAMBDA i: IF i < n THEN fs(i)
      			                            ELSIF i = n THEN x
      			                            ELSE fs(i - 1) ENDIF)
                                   #)
                                ELSE
                                   fs
                                ENDIF

    add(x, fs): fseq = insert(x, 0, fs)


    addend(x:T,fs:fseq): fseq = (# length := l(fs) + 1,
                                       seq := (LAMBDA (ii: nat):
                                         IF ii < l(fs) THEN seq(fs)(ii) 
                                         ELSIF ii < l(fs) + 1 THEN  x 
                                         ELSE default ENDIF)
                                      #)



    insert_delete: LEMMA n < l(nefs) IMPLIES
                            insert(nefs`seq(n), n, delete(n, nefs)) = nefs

    add_first_rest: LEMMA add(first(nefs), rest(nefs)) = nefs


    p: VAR pred[T]
    every(p)(fs): bool = (FORALL n: n < l(fs) IMPLIES p(fs(n)))

    every(p, fs): bool = (FORALL n: n < l(fs) IMPLIES p(fs(n)))

    some(p)(fs): bool = (EXISTS n: n < l(fs) IMPLIES p(fs(n)))

    some(p, fs): bool = (EXISTS n: n < l(fs) IMPLIES p(fs(n)))


    % This definition looks a little strange. The following lemma can be easily proved.

    some_p_trivial: LEMMA some(p,fs)


    F: VAR [T -> T]

    map(F,fs): fseq = (# length := length(fs),
                              seq := (LAMBDA i: IF i < length(fs) THEN
                                                   F(fs`seq(i))
                                                ELSE
                                                   default
                                                ENDIF)
                            #)

  END fseqs_ops

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

  % Subtype TCC generated (at line 23, column 46) for  nefs`length - 1
      % expected type  nat
  delete_TCC1: OBLIGATION
    FORALL (n: nat, nefs: ne_fseq[T]):
      n < nefs`length IMPLIES nefs`length - 1 >= 0;

  % Subtype TCC generated (at line 24, column 44) for
      % (LAMBDA i: (IF i < n THEN nefs`seq(i) ELSE nefs`seq(i + 1) ENDIF))
      % expected type  barray[T](nefs`length - 1)
  delete_TCC2: OBLIGATION
    FORALL (n: nat, nefs: ne_fseq[T]):
      n < nefs`length IMPLIES
       (FORALL (i_1: nat):
          i_1 >= nefs`length - 1 IMPLIES
           (IF i_1 < n THEN nefs`seq(i_1) ELSE nefs`seq(i_1 + 1) ENDIF) =
            default[T]);

  % Subtype TCC generated (at line 35, column 43) for  i - 1
      % expected type  nat
  insert_TCC1: OBLIGATION
    FORALL (n: nat, fs: fseq[T]):
      n <= fs`length IMPLIES
       (FORALL (i): NOT i = n AND NOT i < n IMPLIES i - 1 >= 0);

  % Subtype TCC generated (at line 33, column 26) for
      % (LAMBDA i:
      %    IF i < n THEN fs`seq(i)
      %    ELSIF i = n THEN x
      %    ELSE fs`seq(i - 1)
      %    ENDIF)
      % expected type  barray[T](1 + fs`length)
  insert_TCC2: OBLIGATION
    FORALL (x: T, n: nat, fs: fseq[T]):
      n <= fs`length IMPLIES
       (FORALL (i_1: nat):
          i_1 >= 1 + fs`length IMPLIES
           IF i_1 < n THEN fs`seq(i_1)
           ELSIF i_1 = n THEN x
           ELSE fs`seq(i_1 - 1)
           ENDIF
            = default[T]);

  % Subtype TCC generated (at line 45, column 45) for
      % (LAMBDA (ii: nat):
      %    IF ii < fs`length THEN seq(fs)(ii)
      %    ELSIF ii < fs`length + 1 THEN x
      %    ELSE default
      %    ENDIF)
      % expected type  barray[T](1 + fs`length)
  addend_TCC1: OBLIGATION
    FORALL (x: T, fs: fseq[T]):
      FORALL (i: nat):
        i >= 1 + fs`length IMPLIES
         IF i < fs`length THEN seq(fs)(i)
         ELSIF i < fs`length + 1 THEN x
         ELSE default[T]
         ENDIF
          = default[T];

  % Subtype TCC generated (at line 77, column 36) for
      % (LAMBDA i: IF i < length(fs) THEN F(fs`seq(i)) ELSE default ENDIF)
      % expected type  barray[T](length(fs))
  map_TCC1: OBLIGATION
    FORALL (F: [T -> T], fs: fseq[T]):
      FORALL (i_1: nat):
        i_1 >= length(fs) IMPLIES
         IF i_1 < length(fs) THEN F(fs`seq(i_1)) ELSE default[T] ENDIF =
          default[T];


body:
  fseqs_ops_real: THEORY
  %------------------------------------------------------------------------
  %
  %  Defines some convenient operations over finite sequences of reals
  %
  %  EXPERIMENTAL
  %
  %------------------------------------------------------------------------
  BEGIN

    IMPORTING  fseqs_ops[real]

    fs,gs: VAR fseq
    nefs: VAR ne_fseq
    i,n: VAR nat
    x: VAR real

    nn_fseq: TYPE = {fs: fseq | FORALL (n: nat): n < l(fs) IMPLIES fs`seq(n) >= 0} 
    pos_fseq: TYPE = {fs: fseq | FORALL (n: nat): n < l(fs) IMPLIES fs`seq(n) > 0} 
    neg_fseq: TYPE = {fs: fseq | FORALL (n: nat): n < l(fs) IMPLIES fs`seq(n) < 0} 
    nz_fseq: TYPE = {fs: fseq | FORALL (n: nat): n < l(fs) IMPLIES fs`seq(n) /= 0} 

  % ------------ pointwise addition, subtraction, and multiplication

    mmin(m,n:nat): MACRO nat = IF m > n THEN n ELSE m ENDIF ;

    +(fs,gs): fseq = LET len = mmin(l(fs),l(gs)) IN
                      (# length := len,
                        seq := (LAMBDA n: IF n < len THEN fs(n) + gs(n) 
                                          ELSE default
                                          ENDIF)
                      #) ;


    -(fs,gs): fseq = LET len = mmin(l(fs),l(gs)) IN
                      (# length := len,
                        seq := (LAMBDA n: IF n < len THEN fs(n) - gs(n) 
                                          ELSE default
                                          ENDIF)
                      #) ;


    *(fs,gs): fseq = LET len = mmin(l(fs),l(gs)) IN
                      (# length := len,
                        seq := (LAMBDA n: IF n < len THEN fs(n) * gs(n) 
                                          ELSE default
                                          ENDIF)
                      #) ;

    nzgs: VAR nz_fseq ;

    /(fs,nzgs): fseq = LET len = mmin(l(fs),l(nzgs)) IN
                      (# length := len,
                        seq := (LAMBDA n: IF n < len THEN fs(n) / nzgs(n) 
                                          ELSE default
                                          ENDIF)
                      #) ;


  END fseqs_ops_real

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

  % Subtype TCC generated (at line 29, column 30) for
      % (LAMBDA n: IF n < len THEN fs`seq(n) + gs`seq(n) ELSE default ENDIF)
      % expected type  barray[real](len)
  plus_TCC1: OBLIGATION
    FORALL (fs: fseq[real], gs: fseq[real], len: nat):
      len = IF fs`length > gs`length THEN gs`length ELSE fs`length ENDIF
       IMPLIES
       (FORALL (i: nat):
          i >= len IMPLIES
           IF i < len THEN fs`seq(i) + gs`seq(i) ELSE default[real] ENDIF =
            default[real]);

  % Subtype TCC generated (at line 37, column 30) for
      % (LAMBDA n: IF n < len THEN fs`seq(n) - gs`seq(n) ELSE default ENDIF)
      % expected type  barray[real](len)
  difference_TCC1: OBLIGATION
    FORALL (fs: fseq[real], gs: fseq[real], len: nat):
      len = IF fs`length > gs`length THEN gs`length ELSE fs`length ENDIF
       IMPLIES
       (FORALL (i: nat):
          i >= len IMPLIES
           IF i < len THEN fs`seq(i) - gs`seq(i) ELSE default[real] ENDIF =
            default[real]);

  % Subtype TCC generated (at line 45, column 30) for
      % (LAMBDA n: IF n < len THEN fs`seq(n) * gs`seq(n) ELSE default ENDIF)
      % expected type  barray[real](len)
  times_TCC1: OBLIGATION
    FORALL (fs: fseq[real], gs: fseq[real], len: nat):
      len = IF fs`length > gs`length THEN gs`length ELSE fs`length ENDIF
       IMPLIES
       (FORALL (i: nat):
          i >= len IMPLIES
           IF i < len THEN fs`seq(i) * gs`seq(i) ELSE default[real] ENDIF =
            default[real]);

  % Subtype TCC generated (at line 54, column 64) for  nzgs`seq(n)
      % expected type  nznum
  divide_TCC1: OBLIGATION
    FORALL (fs: fseq[real], nzgs: nz_fseq, len: nat):
      len = IF fs`length > nzgs`length THEN nzgs`length ELSE fs`length ENDIF
       IMPLIES (FORALL (n): n < len IMPLIES nzgs`seq(n) /= 0);

  % Subtype TCC generated (at line 54, column 30) for
      % (LAMBDA n: IF n < len THEN fs`seq(n) / nzgs`seq(n) ELSE default ENDIF)
      % expected type  barray[real](len)
  divide_TCC2: OBLIGATION
    FORALL (fs: fseq[real], nzgs: nz_fseq, len: nat):
      len = IF fs`length > nzgs`length THEN nzgs`length ELSE fs`length ENDIF
       IMPLIES
       (FORALL (i: nat):
          i >= len IMPLIES
           IF i < len THEN fs`seq(i) / nzgs`seq(i) ELSE default[real] ENDIF =
            default[real]);


body:
  fseqs_def [T: TYPE, default: T]: 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]

    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) ;

    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_def

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

  % Judgement subtype TCC generated (at line 55, 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 56, 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 64, 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 70, 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 95, 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 93, 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 126, 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 126, 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 128, 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 151, 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 154, 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 161, 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 167, 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 166, 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:
  fseqs_ops_def [T: TYPE, default:T]: THEORY
  %------------------------------------------------------------------------
  %
  %  Defines some convenient operations over finite sequences
  %
  %  EXPERIMENTAL
  %
  %------------------------------------------------------------------------
  BEGIN

    IMPORTING  fseqs_def[T,default]

    fs: VAR fseq
    nefs: VAR ne_fseq
    i,n: VAR nat
    x: VAR T

    first(fs): T = fs`seq(0)

    rest(fs): fseq = fs^(1,l(fs))

    delete(n, nefs): fseq = IF n < l(nefs) THEN
                                   (# length := l(nefs) - 1,
                                      seq := (LAMBDA i: (IF i < n THEN nefs(i) 
                                                      ELSE nefs(i + 1) ENDIF))
                                    #)
                               ELSE nefs
                               ENDIF


    insert(x, n, fs): fseq = IF n <= l(fs) THEN 
                                  (# length := l(fs) + 1,
      			           seq := (LAMBDA i: IF i < n THEN fs(i)
      			                            ELSIF i = n THEN x
      			                            ELSE fs(i - 1) ENDIF)
                                   #)
                                ELSE
                                   fs
                                ENDIF

    add(x, fs): fseq = insert(x, 0, fs)


    addend(x:T,fs:fseq): fseq = (# length := l(fs) + 1,
                                       seq := (LAMBDA (ii: nat):
                                         IF ii < l(fs) THEN seq(fs)(ii) 
                                         ELSIF ii < l(fs) + 1 THEN  x 
                                         ELSE default ENDIF)
                                      #)



    insert_delete: LEMMA n < l(nefs) IMPLIES
                            insert(nefs`seq(n), n, delete(n, nefs)) = nefs

    add_first_rest: LEMMA add(first(nefs), rest(nefs)) = nefs


    p: VAR pred[T]
    every(p)(fs): bool = (FORALL n: n < l(fs) IMPLIES p(fs(n)))

    every(p, fs): bool = (FORALL n: n < l(fs) IMPLIES p(fs(n)))

    some(p)(fs): bool = (EXISTS n: n < l(fs) IMPLIES p(fs(n)))

    some(p, fs): bool = (EXISTS n: n < l(fs) IMPLIES p(fs(n)))


    % This definition looks a little strange. The following lemma can be easily proved.

    some_p_trivial: LEMMA some(p,fs)


    F: VAR [T -> T]

    map(F,fs): fseq = (# length := length(fs),
                              seq := (LAMBDA i: IF i < length(fs) THEN
                                                   F(fs`seq(i))
                                                ELSE
                                                   default
                                                ENDIF)
                            #)

  END fseqs_ops_def

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

  % Subtype TCC generated (at line 23, column 46) for  nefs`length - 1
      % expected type  nat
  delete_TCC1: OBLIGATION
    FORALL (n: nat, nefs: ne_fseq[T, default]):
      n < nefs`length IMPLIES nefs`length - 1 >= 0;

  % Subtype TCC generated (at line 24, column 44) for
      % (LAMBDA i: (IF i < n THEN nefs`seq(i) ELSE nefs`seq(i + 1) ENDIF))
      % expected type  barray[T, default](nefs`length - 1)
  delete_TCC2: OBLIGATION
    FORALL (n: nat, nefs: ne_fseq[T, default]):
      n < nefs`length IMPLIES
       (FORALL (i_1: nat):
          i_1 >= nefs`length - 1 IMPLIES
           (IF i_1 < n THEN nefs`seq(i_1) ELSE nefs`seq(i_1 + 1) ENDIF) =
            default);

  % Subtype TCC generated (at line 35, column 43) for  i - 1
      % expected type  nat
  insert_TCC1: OBLIGATION
    FORALL (x: T, n: nat, fs: fseq[T, default]):
      n <= fs`length IMPLIES
       (FORALL (i): NOT i = n AND NOT i < n IMPLIES i - 1 >= 0);

  % Subtype TCC generated (at line 33, column 26) for
      % (LAMBDA i:
      %    IF i < n THEN fs`seq(i)
      %    ELSIF i = n THEN x
      %    ELSE fs`seq(i - 1)
      %    ENDIF)
      % expected type  barray[T, default](1 + fs`length)
  insert_TCC2: OBLIGATION
    FORALL (x: T, n: nat, fs: fseq[T, default]):
      n <= fs`length IMPLIES
       (FORALL (i_1: nat):
          i_1 >= 1 + fs`length IMPLIES
           IF i_1 < n THEN fs`seq(i_1)
           ELSIF i_1 = n THEN x
           ELSE fs`seq(i_1 - 1)
           ENDIF
            = default);

  % Subtype TCC generated (at line 45, column 45) for
      % (LAMBDA (ii: nat):
      %    IF ii < fs`length THEN seq(fs)(ii)
      %    ELSIF ii < fs`length + 1 THEN x
      %    ELSE default
      %    ENDIF)
      % expected type  barray[T, default](1 + fs`length)
  addend_TCC1: OBLIGATION
    FORALL (x: T, fs: fseq[T, default]):
      FORALL (i: nat):
        i >= 1 + fs`length IMPLIES
         IF i < fs`length THEN seq(fs)(i)
         ELSIF i < fs`length + 1 THEN x
         ELSE default
         ENDIF
          = default;

  % Subtype TCC generated (at line 77, column 36) for
      % (LAMBDA i: IF i < length(fs) THEN F(fs`seq(i)) ELSE default ENDIF)
      % expected type  barray[T, default](length(fs))
  map_TCC1: OBLIGATION
    FORALL (F: [T -> T], fs: fseq[T, default]):
      FORALL (i_1: nat):
        i_1 >= length(fs) IMPLIES
         IF i_1 < length(fs) THEN F(fs`seq(i_1)) ELSE default ENDIF = default;


body:
  % Taken from Vlad Rusu, Verifying a Sliding Window Protocol using PVS. FORTE 2001: 251-268.
  runs[State      : TYPE, 
       initial    : PRED[State], 
       transition : PRED[[State, State]]] : THEORY

  BEGIN

    % Runs are infinite sequences of transition-related states,  
    % starting in an initial state

    run_fragment: pred[sequence[State]] =  
      {r : sequence[State] | FORALL (n : nat): transition(r(n),r(n+1))}

    run : pred[(run_fragment)] =  {r : (run_fragment) | initial(r(0))}

    r: VAR (run)
    p :VAR pred[[State]]  
    % The first parameter is the current state
    % The second parameter is the initial state

    invariant(p) : bool = FORALL (r : (run), n:nat ): p(r(n))

    invariant_rule : THEOREM
      (FORALL (r : (run)) : p(r(0)) AND 
        FORALL (n : nat) : p(r(n)) IMPLIES p(r(n+1)))
       IMPLIES invariant(p)

  END runs


body:
  arrays[N:nat] : THEORY
  BEGIN

    Index : TYPE = below(N)

    Reals : TYPE = ARRAY[Index->real]
    Booleans : TYPE = ARRAY[Index->boolean]
    Bools : TYPE = Booleans
    Strings : TYPE = ARRAY[Index->string]
    Nats : TYPE = ARRAY[Index->nat]
    Ints : TYPE = ARRAY[Index->int]
    Rats : TYPE = ARRAY[Index->rat]
    ArrayOf[T:TYPE] : TYPE = ARRAY[Index->T]
    
    i : VAR Index

    length(r:Reals) : nat = N
    init_with(r:real) : Reals = LAMBDA(i):r

    length(q:Rats) : nat = N
    init_with(q:rat) : Rats = LAMBDA(i):q

    length(z:Ints) : nat = N
    init_with(z:int) : Ints = LAMBDA(i):z

    length(n:Nats) : nat = N
    init_with(n:nat) : Nats = LAMBDA(i):n
    init : MACRO Nats = init_with(0)

    length(b:Bools) : nat = N
    init_with(b:bool) : Bools = LAMBDA(i):b
    init : MACRO Bools = init_with(false)

    length(s:Strings) : nat = N
    init_with(s:string) : Strings = LAMBDA(i):s
    init : MACRO Strings = init_with("")

    length[T:TYPE](a:ArrayOf[T]) : nat = N
    init_with[T:TYPE](t:T) : ArrayOf[T] = LAMBDA(i):t

  END arrays

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

  % Subtype TCC generated (at line 28, column 22) for  init_with(0)
      % expected type  Nats
  init_TCC1: OBLIGATION
    FORALL (x1: Index):
      rational_pred(init_with(0)(x1)) AND
       integer_pred(init_with(0)(x1)) AND init_with(0)(x1) >= 0;


body:
  arrays_examples: THEORY
  BEGIN
    
    IMPORTING arrays

    R0 : Reals[10] = init   % Initializes an array of 10 reals with 0
    R1 : Reals[10] = init_with(1)  % Initializes an array of 10 reals with 1
    B0 : Bools[10] = init   % Initializes an array of 10 Booleans with FALSE
    B1 : Bools[10] = init_with(TRUE) % Initializes an array of 10 Booleans with TRUE
    S0 : Strings[10] = init % Initializes an array of 10 strings with ""
    S1 : Strings[10] = init_with("X") % Initializes an array of 10 strings with "X"
    N : Nats[10] = init     % Initializes an array of 10 natural numbers with 0
    Z : Ints[10] = init     % Initializes an array of 10 integers with 0
    Q : Rats[10] = init     % Initializes an array of 10 rational numbers with 0

    NS0 : ArrayOf[10][[nat,string]] = init_with[10][[nat,string]]((0,""))  % Initializes an array of 10 pairs [nat,string] with (0,"")
    NS1 : ArrayOf[10][[nat,string]] = NS0 WITH [`1 := (1,"")] % Same as NS0 except that it has (1,"") in 1st position
    
    GridPoint : TYPE = [# x,y:int #] 
    origin : GridPoint = (# x := 0, y := 0 #)
    RR0 : ArrayOf[10][GridPoint] = init_with[10][GridPoint](origin) % Initializes an array of 10 grid points with origin
    RR1 : ArrayOf[10][GridPoint] = RR0 WITH [`1 := (# x := 1, y:= 0 #)] % Same as RR0 except that it has the point (1,0) in 1st position

  END arrays_examples


body:
  for_iterate[T:TYPE] : THEORY
  BEGIN

    %% Defines f(j,f(...f(i+1,f(i,a))...))
    for_def(i,j:int,a:T,f:[[int,T]->T]) : RECURSIVE T =
      IF i > j THEN a
      ELSE f(j,for_def(i,j-1,a,f))
      ENDIF
    MEASURE max(j-i+1,0)

    for_def_inv : LEMMA
      FORALL(i:int,n:nat,a:T,f:[[int,T]->T]):
        for_def(i,n+i,a,f) = for_def(1+i,n+i,f(i,a),f)

    for_shift : LEMMA
      FORALL(i,j:int,shift:int,a:T,f:[[int,T]->T]):
        for_def(i,j,a,f) = for_def(i+shift,j+shift,a,LAMBDA (k:int,t:T): f(k-shift,t))

    for_def_ext : LEMMA
      FORALL(i,j:int,a:T,f,g:[[int,T]->T]) :
        (FORALL (x:subrange(i,j),t:T) : f(x,t) = g(x,t)) 
        IMPLIES
        for_def(i,j,a,f) = for_def(i,j,a,g)

    %% The pair (n,t) satisifies an invariant propertiy P if P is true on t at iteration n

    for_def_induction : LEMMA
      FORALL(i,j:int,a:T,f:[[int,T]->T],inv:PRED[[nat,T]]):
        (inv(0,a) AND
         FORALL (k:subrange(0,j-i),ak:T) : inv(k,ak) IMPLIES inv(k+1,f(i+k,ak)))
        IMPLIES
        inv(max(0,j-i+1),for_def(i,j,a,f))

    ForBody(upfrom,upto:int) : TYPE = [[subrange(upfrom,upto),T]->T]

    ext2int(upfrom,upto:int,f:ForBody(upfrom,upto))(i:int,a:T) : T =
      IF upfrom <= i AND i <= upto THEN f(i,a)
      ELSE a
      ENDIF

    for_it(upfrom:int,i:upfrom(upfrom),upto:int,a:T,f:ForBody(upfrom,upto)) : RECURSIVE 
      {t : T | t = for_def(i,upto,a,ext2int(upfrom,upto,f))} =
      IF i > upto THEN a
      ELSE for_it(upfrom,i+1,upto,f(i,a),f)
      ENDIF
    MEASURE max(upto-i+1,0)

    %% local a : T := init;
    %% local i : int;
    %% for (i := m; i <= n; i++) {
    %%   a := f(i,a);
    %% }
    %% return a; 
    for(m,n:int,init:T,f:ForBody(m,n)) : T =
      for_it(m,m,n,init,f)

    for_eq : LEMMA
      FORALL(i,j:int,a:T,f:ForBody(i,j)) :
        for(i,j,a,f) = for_def(i,j,a,ext2int(i,j,f))

    for_induction : THEOREM
      FORALL(m:int,(n:int| n >= m-1),init:T,f:ForBody(m,n),inv:PRED[[upto(n-m+1),T]]):
        (inv(0,init) AND
         FORALL (k:subrange(0,n-m),ak:T) : inv(k,ak) IMPLIES inv(k+1,f(m+k,ak)))
        IMPLIES
        inv(n-m+1,for(m,n,init,f))

    %% Defines f(j,f(...f(i-1,f(i,a))...))
    for_down_def(i,j:int,a:T,f:[[int,T]->T]) : RECURSIVE T =
      IF i < j THEN a
      ELSE f(j,for_down_def(i,j+1,a,f))
      ENDIF
    MEASURE max(i-j+1,0)

    for_down_def_ext : LEMMA
      FORALL(i,j:int,a:T,f,g:[[int,T]->T]) :
        (FORALL (x:subrange(j,i),t:T) : f(x,t) = g(x,t)) 
        IMPLIES
        for_down_def(i,j,a,f) = for_down_def(i,j,a,g)

    for_down_up : LEMMA
      FORALL(i,j:int,a:T,f:[[int,T]->T]):
        for_down_def(i,j,a,f) = for_def(j,i,a,LAMBDA(k:int,t:T):f(i-k+j,t))

    for_down_def_induction : LEMMA
      FORALL(i,j:int,a:T,f:[[int,T]->T],inv:PRED[[nat,T]]):
        (inv(0,a) AND
         FORALL (k:subrange(0,i-j),ak:T) : inv(k,ak) IMPLIES inv(k+1,f(i-k,ak)))
        IMPLIES
        inv(max(0,i-j+1),for_down_def(i,j,a,f))

    %% local a : T := init;
    %% local i : int;
    %% for (i := n; i >= m; i--) {
    %%   a := f(i,a);
    %% } 
    for_down(n,m:int,init:T,f:ForBody(m,n)) : T =
      for(m,n,init,LAMBDA(k:subrange(m,n),a:T): f(n+m-k,a))

    for_down_induction : THEOREM
      FORALL(n:int,(m:int| m <= n+1),init:T,f:ForBody(m,n),inv:PRED[[upto(n-m+1),T]]):
        (inv(0,init) AND
         FORALL (k:subrange(0,n-m),ak:T) : inv(k,ak) IMPLIES inv(k+1,f(n-k,ak)))
        IMPLIES
        inv(n-m+1,for_down(n,m,init,f))

    for_down_eq : LEMMA
      FORALL(i,j:int,a:T,f:ForBody(j,i)):
        for_down(i,j,a,f) = for_down_def(i,j,a,ext2int(j,i,f)) 
     
    %% Defines (... ((f(i) o f(i+1)) o f(i+2)) o .... f(j))
    iterate_left_def(i:int,j:upfrom(i),f:[int->T],o:[[T,T]->T]) : RECURSIVE T =
      IF i = j THEN f(i) 
      ELSE iterate_left_def(i,j-1,f,o) o f(j)
      ENDIF
    MEASURE j-i

    iterate_left_def_ext : LEMMA
      FORALL(i:int,j:upfrom(i),f,g:[int->T],o:[[T,T]->T]) :
        (FORALL (x:subrange(i,j)) : f(x) = g(x)) 
        IMPLIES
        iterate_left_def(i,j,f,o) = iterate_left_def(i,j,g,o)

    IterateBody(upfrom,upto:int) : TYPE = [subrange(upfrom,upto)->T]

    ext2int(upfrom,upto:int,a:T,f:IterateBody(upfrom,upto))(i:int) : T =
      IF upfrom <= i AND i <= upto THEN f(i)
      ELSE a
      ENDIF

    iterate_left_id(i:int,j:int,f:IterateBody(i,j),o:[[T,T]->T],id:T) : MACRO T =
      for(i,j,id,LAMBDA(k:subrange(i,j),t:T):t o f(k))

    %% local a : T = f(m);
    %% local i : int;
    %% for (i := m+1; i <= n; i++) {
    %%   a := a o f(i)
    %% }
    %% return a;
    iterate_left(m:int,n:upfrom(m),f:IterateBody(m,n),o:[[T,T]->T]) : T =
      iterate_left_id(m+1,n,LAMBDA(k:subrange(m+1,n)):f(k),o,f(m))

    iterate_left_eq : LEMMA
      FORALL(i:int,j:upfrom(i),f:IterateBody(i,j),o:[[T,T]->T]) :
        iterate_left(i,j,f,o) = iterate_left_def(i,j,ext2int(i,j,f(i),f),o)

    iterate_left_induction : THEOREM
      FORALL(m:int,n:upfrom(m),f:IterateBody(m,n),o:[[T,T]->T],inv:PRED[[upto(n-m),T]]):
        (inv(0,f(m)) AND
         FORALL (k:below(n-m),ak:T) : inv(k,ak) IMPLIES inv(k+1,ak o f(m+k+1)))
        IMPLIES
        inv(n-m,iterate_left(m,n,f,o))

    %% Defines f(i) o (... (f(j-2) o (f(j-1) o f(j))) ...)
    iterate_right_def(i:int,j:upfrom(i),f:[int->T],o:[[T,T]->T]) : RECURSIVE T =
      IF i = j THEN f(j) 
      ELSE f(i) o iterate_right_def(i+1,j,f,o) 
      ENDIF
    MEASURE j-i

    iterate_right_def_ext : LEMMA
      FORALL(i:int,j:upfrom(i),f,g:[int->T],o:[[T,T]->T]) :
        (FORALL (x:subrange(i,j)) : f(x) = g(x)) 
        IMPLIES
        iterate_right_def(i,j,f,o) = iterate_right_def(i,j,g,o)

    iterate_right_id(i,j:int,f:IterateBody(i,j),o:[[T,T]->T],id:T) : MACRO T =
      for_down(j,i,id,LAMBDA(k:subrange(i,j),t:T):f(k) o t)    

    %% local a : T = f(n);
    %% local i : int;
    %% for (i := n-1; i >= m; i--) {
    %%   a := f(i) o a
    %% }
    %% return a;
    iterate_right(m:int,n:upfrom(m),f:IterateBody(m,n),o:[[T,T]->T]) : T =
      iterate_right_id(m,n-1,LAMBDA(k:subrange(m,n-1)):f(k),o,f(n))

    iterate_right_eq : LEMMA
      FORALL(i:int,j:upfrom(i),f:IterateBody(i,j),o:[[T,T]->T]) :
        iterate_right(i,j,f,o) = iterate_right_def(i,j,ext2int(i,j,f(j),f),o)

    iterate_right_induction : THEOREM
      FORALL(m:int,n:upfrom(m),f:IterateBody(m,n),o:[[T,T]->T],inv:PRED[[upto(n-m),T]]):
        (inv(0,f(n)) AND
         FORALL (k:below(n-m),ak:T) : inv(k,ak) IMPLIES inv(k+1,f(n-k-1) o ak))
        IMPLIES
        inv(n-m,iterate_right(m,n,f,o))

  END for_iterate

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

  % Subtype TCC generated (at line 9, column 10) for  max(j - i + 1, 0)
      % expected type  naturalnumber
  for_def_TCC1: OBLIGATION
    FORALL (i, j: int, a: T, f: [[int, T] -> T]): max(j - i + 1, 0) >= 0;

  % Termination TCC generated (at line 7, column 13) for
      % for_def(i, j - 1, a, f)
  for_def_TCC2: OBLIGATION
    FORALL (i, j: int, a: T, f: [[int, T] -> T]):
      NOT i > j IMPLIES max(j - 1 - i + 1, 0) < max(j - i + 1, 0);

  % Subtype TCC generated (at line 30, column 45) for  k
      % expected type  nat
  for_def_induction_TCC1: OBLIGATION
    FORALL (i, j: int, a: T, f: [[int, T] -> T], inv: PRED[[nat, T]]):
      inv(0, a) IMPLIES (FORALL (k: subrange(0, j - i), ak: T): k >= 0);

  % Subtype TCC generated (at line 30, column 63) for  k + 1
      % expected type  nat
  for_def_induction_TCC2: OBLIGATION
    FORALL (i, j: int, a: T, f: [[int, T] -> T], inv: PRED[[nat, T]]):
      inv(0, a) IMPLIES
       (FORALL (k: subrange(0, j - i), ak: T): inv(k, ak) IMPLIES k + 1 >= 0);

  % Subtype TCC generated (at line 32, column 10) for  max(0, j - i + 1)
      % expected type  nat
  for_def_induction_TCC3: OBLIGATION
    FORALL (i, j: int, a: T, f: [[int, T] -> T], inv: PRED[[nat, T]]):
      (inv(0, a) AND
        (FORALL (k: subrange(0, j - i), ak: T):
           inv(k, ak) IMPLIES inv(k + 1, f(i + k, ak))))
       IMPLIES max(0, j - i + 1) >= 0;

  % Subtype TCC generated (at line 37, column 40) for  i
      % expected type  subrange(upfrom, upto)
  ext2int_TCC1: OBLIGATION
    FORALL (upfrom, upto: int, f: ForBody(upfrom, upto), i: int, a: T):
      upfrom <= i AND i <= upto IMPLIES upfrom <= i AND i <= upto;

  % Subtype TCC generated (at line 46, column 10) for  max(upto - i + 1, 0)
      % expected type  naturalnumber
  for_it_TCC1: OBLIGATION
    FORALL (upfrom: int, i: upfrom(upfrom), upto: int, a: T,
            f: ForBody(upfrom, upto)):
      max(upto - i + 1, 0) >= 0;

  % Subtype TCC generated (at line 43, column 21) for  a
      % expected type  {t: T |
                     %          t =
                     %           for_def(i,
                     %                   upto,
                     %                   a,
                     %                   ext2int(upfrom, upto, f))}
  for_it_TCC2: OBLIGATION
    FORALL (upfrom: int, i: upfrom(upfrom), upto: int, a: T,
            f: ForBody(upfrom, upto)):
      i > upto IMPLIES a = for_def(i, upto, a, ext2int(upfrom, upto, f));

  % Subtype TCC generated (at line 44, column 23) for  i + 1
      % expected type  upfrom(upfrom)
  for_it_TCC3: OBLIGATION
    FORALL (upfrom: int, i: upfrom(upfrom), upto: int, a: T,
            f: ForBody(upfrom, upto)):
      NOT i > upto IMPLIES i + 1 >= upfrom;

  % Subtype TCC generated (at line 44, column 34) for  i
      % expected type  subrange(upfrom, upto)
  for_it_TCC4: OBLIGATION
    FORALL (upfrom: int, i: upfrom(upfrom), upto: int, a: T,
            f: ForBody(upfrom, upto)):
      NOT i > upto IMPLIES upfrom <= i AND i <= upto;

  % Termination TCC generated (at line 44, column 9) for
      % for_it(upfrom, i + 1, upto, f(i, a), f)
  for_it_TCC5: OBLIGATION
    FORALL (upfrom: int, i: upfrom(upfrom), upto: int, a: T,
            f: ForBody(upfrom, upto)):
      NOT i > upto IMPLIES max(upto - (i + 1) + 1, 0) < max(upto - i + 1, 0);

  % Subtype TCC generated (at line 44, column 9) for
      % for_it(upfrom, i + 1, upto, f(i, a), f)
      % expected type  {t: T |
                     %          t =
                     %           for_def(i,
                     %                   upto,
                     %                   a,
                     %                   ext2int(upfrom, upto, f))}
  for_it_TCC6: OBLIGATION
    FORALL (upfrom: int, i: upfrom(upfrom), upto: int,
            v:
              [d1:
                 {z:
                    [upfrom: int, upfrom(upfrom), upto: int, T,
                     ForBody(upfrom, upto)] |
                          max(z`3 - z`2 + 1, 0) < max(upto - i + 1, 0)} ->
                 {t: T |
                          t =
                           for_def(d1`2, d1`3, d1`4,
                                   ext2int(d1`1, d1`3, d1`5))}],
            a: T, f: ForBody(upfrom, upto)):
      NOT i > upto IMPLIES
       v(upfrom, i + 1, upto, f(i, a), f) =
        for_def(i, upto, a, ext2int(upfrom, upto, f));

  % Subtype TCC generated (at line 55, column 13) for  m
      % expected type  upfrom(m)
  for_TCC1: OBLIGATION FORALL (m, n: int, init: T, f: ForBody(m, n)): m >= m;

  % Subtype TCC generated (at line 63, column 11) for  0
      % expected type  upto(1 + n - m)
  for_induction_TCC1: OBLIGATION
    FORALL (m: int, (n: int | n >= m - 1), init: T, f: ForBody(m, n)):
      0 <= 1 + n - m;

  % Subtype TCC generated (at line 64, column 45) for  k
      % expected type  upto(1 + n - m)
  for_induction_TCC2: OBLIGATION
    FORALL (m: int, (n: int | n >= m - 1), init: T, f: ForBody(m, n),
            inv: PRED[[upto(n - m + 1), T]]):
      inv(0, init) IMPLIES
       (FORALL (k: subrange(0, n - m), ak: T): k >= 0 AND k <= 1 + n - m);

  % Subtype TCC generated (at line 64, column 63) for  k + 1
      % expected type  upto(1 + n - m)
  for_induction_TCC3: OBLIGATION
    FORALL (m: int, (n: int | n >= m - 1), init: T, f: ForBody(m, n),
            inv: PRED[[upto(n - m + 1), T]]):
      inv(0, init) IMPLIES
       (FORALL (k: subrange(0, n - m), ak: T):
          inv(k, ak) IMPLIES k + 1 >= 0 AND k + 1 <= 1 + n - m);

  % Subtype TCC generated (at line 64, column 69) for  m + k
      % expected type  subrange(m, n)
  for_induction_TCC4: OBLIGATION
    FORALL (m: int, (n: int | n >= m - 1), init: T, f: ForBody(m, n),
            inv: PRED[[upto(n - m + 1), T]]):
      inv(0, init) IMPLIES
       (FORALL (k: subrange(0, n - m), ak: T):
          inv(k, ak) IMPLIES m <= m + k AND m + k <= n);

  % Subtype TCC generated (at line 66, column 10) for  n - m + 1
      % expected type  upto(1 + n - m)
  for_induction_TCC5: OBLIGATION
    FORALL (m: int, (n: int | n >= m - 1), init: T, f: ForBody(m, n),
            inv: PRED[[upto(n - m + 1), T]]):
      (inv(0, init) AND
        (FORALL (k: subrange(0, n - m), ak: T):
           inv(k, ak) IMPLIES inv(k + 1, f(m + k, ak))))
       IMPLIES n - m + 1 >= 0 AND n - m + 1 <= 1 + n - m;

  % Subtype TCC generated (at line 73, column 10) for  max(i - j + 1, 0)
      % expected type  naturalnumber
  for_down_def_TCC1: OBLIGATION
    FORALL (i, j: int, a: T, f: [[int, T] -> T]): max(i - j + 1, 0) >= 0;

  % Termination TCC generated (at line 71, column 13) for
      % for_down_def(i, j + 1, a, f)
  for_down_def_TCC2: OBLIGATION
    FORALL (i, j: int, a: T, f: [[int, T] -> T]):
      NOT i < j IMPLIES max(i - (j + 1) + 1, 0) < max(i - j + 1, 0);

  % Subtype TCC generated (at line 88, column 45) for  k
      % expected type  nat
  for_down_def_induction_TCC1: OBLIGATION
    FORALL (i, j: int, a: T, f: [[int, T] -> T], inv: PRED[[nat, T]]):
      inv(0, a) IMPLIES (FORALL (k: subrange(0, i - j), ak: T): k >= 0);

  % Subtype TCC generated (at line 88, column 63) for  k + 1
      % expected type  nat
  for_down_def_induction_TCC2: OBLIGATION
    FORALL (i, j: int, a: T, f: [[int, T] -> T], inv: PRED[[nat, T]]):
      inv(0, a) IMPLIES
       (FORALL (k: subrange(0, i - j), ak: T): inv(k, ak) IMPLIES k + 1 >= 0);

  % Subtype TCC generated (at line 90, column 10) for  max(0, i - j + 1)
      % expected type  nat
  for_down_def_induction_TCC3: OBLIGATION
    FORALL (i, j: int, a: T, f: [[int, T] -> T], inv: PRED[[nat, T]]):
      (inv(0, a) AND
        (FORALL (k: subrange(0, i - j), ak: T):
           inv(k, ak) IMPLIES inv(k + 1, f(i - k, ak))))
       IMPLIES max(0, i - j + 1) >= 0;

  % Subtype TCC generated (at line 98, column 48) for  n + m - k
      % expected type  subrange(m, n)
  for_down_TCC1: OBLIGATION
    FORALL (n, m: int, init: T, f: ForBody(m, n), k: subrange(m, n), a: T):
      m <= n + m - k AND n + m - k <= n;

  % Subtype TCC generated (at line 102, column 11) for  0
      % expected type  upto(1 + n - m)
  for_down_induction_TCC1: OBLIGATION
    FORALL (n: int, (m: int | m <= n + 1), init: T, f: ForBody(m, n)):
      0 <= 1 + n - m;

  % Subtype TCC generated (at line 103, column 45) for  k
      % expected type  upto(1 + n - m)
  for_down_induction_TCC2: OBLIGATION
    FORALL (n: int, (m: int | m <= n + 1), init: T, f: ForBody(m, n),
            inv: PRED[[upto(n - m + 1), T]]):
      inv(0, init) IMPLIES
       (FORALL (k: subrange(0, n - m), ak: T): k >= 0 AND k <= 1 + n - m);

  % Subtype TCC generated (at line 103, column 63) for  k + 1
      % expected type  upto(1 + n - m)
  for_down_induction_TCC3: OBLIGATION
    FORALL (n: int, (m: int | m <= n + 1), init: T, f: ForBody(m, n),
            inv: PRED[[upto(n - m + 1), T]]):
      inv(0, init) IMPLIES
       (FORALL (k: subrange(0, n - m), ak: T):
          inv(k, ak) IMPLIES k + 1 >= 0 AND k + 1 <= 1 + n - m);

  % Subtype TCC generated (at line 103, column 69) for  n - k
      % expected type  subrange(m, n)
  for_down_induction_TCC4: OBLIGATION
    FORALL (n: int, (m: int | m <= n + 1), init: T, f: ForBody(m, n),
            inv: PRED[[upto(n - m + 1), T]]):
      inv(0, init) IMPLIES
       (FORALL (k: subrange(0, n - m), ak: T):
          inv(k, ak) IMPLIES m <= n - k AND n - k <= n);

  % Subtype TCC generated (at line 105, column 10) for  n - m + 1
      % expected type  upto(1 + n - m)
  for_down_induction_TCC5: OBLIGATION
    FORALL (n: int, (m: int | m <= n + 1), init: T, f: ForBody(m, n),
            inv: PRED[[upto(n - m + 1), T]]):
      (inv(0, init) AND
        (FORALL (k: subrange(0, n - m), ak: T):
           inv(k, ak) IMPLIES inv(k + 1, f(n - k, ak))))
       IMPLIES n - m + 1 >= 0 AND n - m + 1 <= 1 + n - m;

  % Subtype TCC generated (at line 116, column 10) for  j - i
      % expected type  naturalnumber
  iterate_left_def_TCC1: OBLIGATION
    FORALL (i: int, j: upfrom(i), f: [int -> T], O: [[T, T] -> T]):
      j - i >= 0;

  % Subtype TCC generated (at line 114, column 28) for  j - 1
      % expected type  upfrom(i)
  iterate_left_def_TCC2: OBLIGATION
    FORALL (i: int, j: upfrom(i), f: [int -> T], O: [[T, T] -> T]):
      NOT i = j IMPLIES j - 1 >= i;

  % Termination TCC generated (at line 114, column 9) for
      % iterate_left_def(i, j - 1, f, o)
  iterate_left_def_TCC3: OBLIGATION
    FORALL (i: int, j: upfrom(i), f: [int -> T], O: [[T, T] -> T]):
      NOT i = j IMPLIES j - 1 - i < j - i;

  % Subtype TCC generated (at line 127, column 40) for  i
      % expected type  subrange(upfrom, upto)
  ext2int_TCC2: OBLIGATION
    FORALL (upfrom, upto: int, a: T, f: IterateBody(upfrom, upto), i: int):
      upfrom <= i AND i <= upto IMPLIES upfrom <= i AND i <= upto;

  % Subtype TCC generated (at line 141, column 54) for  k
      % expected type  subrange(m, n)
  iterate_left_TCC1: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T],
            k: subrange(m + 1, n)):
      m <= k AND k <= n;

  % Subtype TCC generated (at line 141, column 61) for  m
      % expected type  subrange(m, n)
  iterate_left_TCC2: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T]):
      m <= m AND m <= n;

  % Subtype TCC generated (at line 149, column 11) for  0
      % expected type  upto(n - m)
  iterate_left_induction_TCC1: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T]):
      0 <= n - m;

  % Subtype TCC generated (at line 150, column 40) for  k
      % expected type  upto(n - m)
  iterate_left_induction_TCC2: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T],
            inv: PRED[[upto(n - m), T]]):
      inv(0, f(m)) IMPLIES (FORALL (k: below(n - m), ak: T): k <= n - m);

  % Subtype TCC generated (at line 150, column 58) for  k + 1
      % expected type  upto(n - m)
  iterate_left_induction_TCC3: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T],
            inv: PRED[[upto(n - m), T]]):
      inv(0, f(m)) IMPLIES
       (FORALL (k: below(n - m), ak: T): inv(k, ak) IMPLIES k + 1 <= n - m);

  % Subtype TCC generated (at line 150, column 69) for  m + k + 1
      % expected type  subrange(m, n)
  iterate_left_induction_TCC4: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T],
            inv: PRED[[upto(n - m), T]]):
      inv(0, f(m)) IMPLIES
       (FORALL (k: below(n - m), ak: T):
          inv(k, ak) IMPLIES m <= m + k + 1 AND m + k + 1 <= n);

  % Subtype TCC generated (at line 152, column 10) for  n - m
      % expected type  upto(n - m)
  iterate_left_induction_TCC5: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T],
            inv: PRED[[upto(n - m), T]]):
      (inv(0, f(m)) AND
        (FORALL (k: below(n - m), ak: T):
           inv(k, ak) IMPLIES inv(k + 1, ak o f(m + k + 1))))
       IMPLIES n - m >= 0 AND n - m <= n - m;

  % Subtype TCC generated (at line 157, column 38) for  j
      % expected type  upfrom(1 + i)
  iterate_right_def_TCC1: OBLIGATION
    FORALL (i: int, j: upfrom(i), f: [int -> T], O: [[T, T] -> T]):
      NOT i = j IMPLIES j >= 1 + i;

  % Termination TCC generated (at line 157, column 16) for
      % iterate_right_def(i + 1, j, f, o)
  iterate_right_def_TCC2: OBLIGATION
    FORALL (i: int, j: upfrom(i), f: [int -> T], O: [[T, T] -> T]):
      NOT i = j IMPLIES j - (i + 1) < j - i;

  % Subtype TCC generated (at line 177, column 55) for  k
      % expected type  subrange(m, n)
  iterate_right_TCC1: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T],
            k: subrange(m, n - 1)):
      m <= k AND k <= n;

  % Subtype TCC generated (at line 177, column 62) for  n
      % expected type  subrange(m, n)
  iterate_right_TCC2: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T]):
      m <= n AND n <= n;

  % Subtype TCC generated (at line 186, column 40) for  k
      % expected type  upto(n - m)
  iterate_right_induction_TCC1: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T],
            inv: PRED[[upto(n - m), T]]):
      inv(0, f(n)) IMPLIES (FORALL (k: below(n - m), ak: T): k <= n - m);

  % Subtype TCC generated (at line 186, column 58) for  k + 1
      % expected type  upto(n - m)
  iterate_right_induction_TCC2: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T],
            inv: PRED[[upto(n - m), T]]):
      inv(0, f(n)) IMPLIES
       (FORALL (k: below(n - m), ak: T): inv(k, ak) IMPLIES k + 1 <= n - m);

  % Subtype TCC generated (at line 186, column 64) for  n - k - 1
      % expected type  subrange(m, n)
  iterate_right_induction_TCC3: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T],
            inv: PRED[[upto(n - m), T]]):
      inv(0, f(n)) IMPLIES
       (FORALL (k: below(n - m), ak: T):
          inv(k, ak) IMPLIES m <= n - k - 1 AND n - k - 1 <= n);

  % Subtype TCC generated (at line 188, column 10) for  n - m
      % expected type  upto(n - m)
  iterate_right_induction_TCC4: OBLIGATION
    FORALL (m: int, n: upfrom(m), f: IterateBody(m, n), O: [[T, T] -> T],
            inv: PRED[[upto(n - m), T]]):
      (inv(0, f(n)) AND
        (FORALL (k: below(n - m), ak: T):
           inv(k, ak) IMPLIES inv(k + 1, f(n - k - 1) o ak)))
       IMPLIES n - m >= 0 AND n - m <= n - m;


body:
  big_ops_nat[T:Type,o:(associative?[T]),id: {tid: T | FORALL (t:T): tid o t = t AND t o tid = t}]: THEORY

  BEGIN

    IMPORTING for_iterate[T]

    F,G : VAR [nat->T]
    i   : VAR nat
    j   : VAR int
    z   : VAR nat
    p   : VAR int
    rel : VAR (preorder?[T])
    c   : VAR T

    big_ops_nat(i,j,F): T =
      for(i,j,id,LAMBDA(k:subrange(i,j),t:T):t o F(k))

    big_ops_nat_eq: LEMMA (FORALL (k:nat): i<=k AND k<=j IMPLIES F(k)=G(k))
      IMPLIES big_ops_nat(i,j,F) = big_ops_nat(i,j,G)

    big_ops_nat_expand_right: LEMMA
      big_ops_nat(i,j,F) = (IF i <= j THEN big_ops_nat(i,j-1,F) o F(j) ELSE id ENDIF)

    big_ops_nat_expand_left: LEMMA
      big_ops_nat(i,j,F) = (IF i <= j THEN F(i) o big_ops_nat(i+1,j,F) ELSE id ENDIF)

    big_ops_nat_split: LEMMA
      i-1<=z AND z<=j IMPLIES
      big_ops_nat(i,j,F) = big_ops_nat(i,z,F) o big_ops_nat(z+1,j,F)

    big_ops_nat_shift: LEMMA
      i+p>=0 IMPLIES 
      big_ops_nat(i+p,j+p,F) = big_ops_nat(i,j,LAMBDA (k:nat): IF k+p>=0 THEN F(k+p) ELSE id ENDIF)

    big_ops_nat_reverse: LEMMA
      commutative?[T](o) IMPLIES
      big_ops_nat(i,j,F) = big_ops_nat(i,j,LAMBDA (k:nat): IF i+j-k>=0 THEN F(i+j-k) ELSE id ENDIF)

    big_ops_nat_id : LEMMA
      (FORALL (k:nat): i<=k AND k<=j IMPLIES F(k) = id) IMPLIES big_ops_nat(i,j,F)=id

    big_ops_nat_comp: LEMMA
      commutative?[T](o) IMPLIES
      big_ops_nat(i,j,F) o big_ops_nat(i,j,G) = big_ops_nat(i,j,LAMBDA (k:nat): F(k) o G(k))

    ; * : VAR [[T,T]->T]

    big_ops_nat_distrib: LEMMA
      i<=j AND
      (FORALL (t1,t2,t3:T): t1 * (t2 o t3) = (t1 * t2) o (t1 * t3)) IMPLIES
      c * big_ops_nat(i,j,F) = big_ops_nat(i,j,LAMBDA (k:nat): c * F(k))

  END big_ops_nat

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

  % Subtype TCC generated (at line 16, column 49) for  k
      % expected type  nat
  big_ops_nat_TCC1: OBLIGATION
    FORALL (i: nat, j: int, F: [nat -> T], k: subrange(i, j), t: T): k >= 0;

  % Subtype TCC generated (at line 22, column 66) for  j
      % expected type  nat
  big_ops_nat_expand_right_TCC1: OBLIGATION
    FORALL (i: nat, j: int): i <= j IMPLIES j >= 0;


body:
  for_examples : THEORY
  BEGIN
    
    IMPORTING for_iterate,
              ints@factorial
    
    %% a = 1;
    %% for (i=1; i <= n; i++) {
    %%   a = a*x;
    %% }

    expit(x:real,n:nat): real =
      for[real](1,n,1,LAMBDA(i:subrange(1,n),a:real):a*x)

    expit_test : LEMMA
      expit(2,10) = 1024

    %% Proved using for_induction. 
    %% Invariant is LAMBDA(i:upto(n),a:nat): a = x^i
    expit_sound : LEMMA
      FORALL(x:real,n:nat): expit(x,n) = x^n

    %% a = 1;
    %% for (i=n; i >= 1; i--) {
    %%   a = a*i;
    %% }

    factit(n:nat) : nat =
      for_down[nat](n,1,1,LAMBDA(i:subrange(1,n),a:nat):a*i)

    factit_test : LEMMA
      factit(10) = 3628800

    %% Proved using for_down_induction. 
    %% Invariant is LAMBDA(i:upto(n),a:nat): a = factorial(n)/factorial(n-i)
    factit_sound : LEMMA
      FORALL(n:nat): factit(n) = factorial(n)

    %% a = nth(l,0);
    %% for (i=1;i<=length(l)-1;i++) {
    %%   a = max(a,nth(l,i))
    %% }

    maxit(l:(cons?[real])) : real =
      iterate_left(0,length(l)-1,LAMBDA(i:below(length(l))):nth(l,i),max)
   
    maxit_test : LEMMA
      maxit((:2,3,4,1,2:)) = 4

    %% Proved using iterate_left_induction. 
    %% Invariant is LAMBDA(n:below(length(l)),a:real):FORALL(k:upto(n)) : nth(l,k) <= a
    maxit_sound : LEMMA
      FORALL (l:(cons?[real]),i:below(length(l))) :
        nth(l,i) <= maxit(l) 

    %% a = nth(l,0);
    %% for (i=1;i<=length(l)-1;i++) {
    %%   a = min(nth(l,i),a)
    %% }

    minit(l:(cons?[real])) : real =
      iterate_right(0,length(l)-1,LAMBDA(i:below(length(l))):nth(l,i),min)
   
    minit_test : LEMMA
      minit((:2,3,4,1,2:)) = 1

    %% Proved using iterate_right_induction. 
    %% Invariant is LAMBDA(n:below(length(l)),a:real): LET ll = length(l)-1 IN 
    %% FORALL(k:subrange(ll-n,ll)) :a <= nth(l,k)
    minit_sound : LEMMA
      FORALL (l:(cons?[real]),i:below(length(l))) :
         minit(l) <= nth(l,i) 

  END for_examples

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

  % Subtype TCC generated (at line 21, column 41) for  n
      % expected type  {i: int | x /= 0 OR i >= 0}
  expit_sound_TCC1: OBLIGATION FORALL (x: real, n: nat): x /= 0 OR n >= 0;

  % Subtype TCC generated (at line 45, column 19) for  length(l) - 1
      % expected type  upfrom(0)
  maxit_TCC1: OBLIGATION FORALL (l: (cons?[real])): length[real](l) - 1 >= 0;

  % Subtype TCC generated (at line 45, column 31) for
      % LAMBDA (i: below(length(l))): nth(l, i)
      % expected type  IterateBody[real](0, length(l) - 1)
  maxit_TCC2: OBLIGATION
    FORALL (l: (cons?[real])):
      FORALL (x: int):
        x >= 0 AND x < length[real](l) IFF
         0 <= x AND x <= length[real](l) - 1;


body:
  % Computable finite sets by Pierre Neron (Ecole Polytechnique)

  set_as_list[T:TYPE] : THEORY
  BEGIN

    IMPORTING list[T], list_adt[T], finite_sets[T]

    x, y: VAR T

    l, l1, l2: VAR list[T]

    empty_sl?(l): bool = (l = null)

    empty_sl_is_empty: LEMMA empty_sl?(l) IFF FORALL x: not member(x,l)

    emptyset_sl: list[T] = null

    nonempty_sl?(l): bool = NOT empty_sl?(l)

    subset_sl?(l1, l2): RECURSIVE {b : bool | b IFF FORALL x: member(x, l1) => member(x, l2) } =
    CASES l1 OF
    	null : true,
  	cons(a,q) : member(a,l2) AND subset_sl?(q,l2)
    ENDCASES
    MEASURE l1 BY <<

    add_sl(x, l): RECURSIVE { ll : (nonempty_sl?) | FORALL y: member(y,ll) IFF (x = y OR member(y, l))} =
    CASES l OF
    	null : (:x:),
  	cons(a,q) : IF x = a THEN l ELSE cons(a,add_sl(x,q)) ENDIF
    ENDCASES
    MEASURE l BY <<

    remove_sl(x,l) : RECURSIVE { ll : list[T] | FORALL y: member(y, ll) IFF (x /= y AND member(y, l))} =
    CASES l OF
    	null : null,
  	cons(a,q) : IF x = a THEN remove_sl(x,q) ELSE cons(a,remove_sl(x,q)) ENDIF
    ENDCASES
    MEASURE l BY <<

    equal_sl(l1,l2): {b : bool | b IFF FORALL x: member(x, l1) IFF member(x, l2)} =
    	subset_sl?(l1,l2) AND subset_sl?(l2,l1)

    strict_subset_sl?(l1, l2): { b : bool | b IFF subset_sl?(l1, l2) & NOT equal_sl(l2,l1) } = subset_sl?(l1, l2) & NOT subset_sl?(l2,l1) 

    union_sl(l1, l2): RECURSIVE {ll : list[T] | FORALL x: member(x,ll) IFF (member(x, l1) OR member(x, l2))} =
    CASES l1 OF
    	null : l2,
  	cons(a,q) : add_sl(a,union_sl(q,l2))
    ENDCASES
    MEASURE l1 BY <<

    intersection_sl(l1, l2): RECURSIVE {ll : list[T] | FORALL x: member(x,ll) IFF (member(x,l1) AND member(x,l2))} =
    CASES l1 OF
    	null : null,
  	cons(a,q) : IF member(a,l2) THEN cons(a,intersection_sl(q,l2)) ELSE intersection_sl(q,l2) ENDIF
    ENDCASES
    MEASURE l1 BY <<
    
    disjoint_sl?(l1, l2): bool = empty_sl?(intersection_sl(l1,l2))

    difference_sl(l1, l2): RECURSIVE {ll : list[T] | FORALL x: member(x,ll) IFF (member(x, l1) AND NOT member(x, l2))} =
    CASES l1 OF
    	null : null,
  	cons(a,q) : IF member(a,l2) THEN difference_sl(q,l2) ELSE cons(a,difference_sl(q,l2)) ENDIF
    ENDCASES
    MEASURE l1 BY <<

    symmetric_difference_sl(l1, l2): list[T] =
      union_sl(difference_sl(l1, l2), difference_sl(l2, l1))

    list2set(l) : RECURSIVE { s: finite_set[T] | s = { x | member(x,l)}} =
    CASES l OF 
    	null : emptyset,
  	cons(a,q) : add(a,list2set(q))
    ENDCASES
    MEASURE l BY <<

    card_sl(l) : RECURSIVE {n : nat | n = Card(list2set(l)) } =
    CASES l OF
    	null : 0,
  	cons(a,q) : IF member(a,q) THEN card_sl(q) ELSE 1 + card_sl(q) ENDIF
    ENDCASES
    MEASURE l BY <<
    
    reduce_sl(l) : RECURSIVE {ll : list[T] | equal_sl[T](l,ll) & card_sl(ll) = length(ll)} =
    CASES l OF
    	null : null,
  	cons(a,q) : IF member(a,q) THEN reduce_sl(q) ELSE cons(a,reduce_sl(q)) ENDIF
    ENDCASES
    MEASURE l BY <<

    equal_sl_card : LEMMA FORALL l1,l2: equal_sl(l1,l2) IMPLIES card_sl(l1) = card_sl(l2)

  END set_as_list

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

  % Subtype TCC generated (at line 22, column 10) for  TRUE
      % expected type  {b: bool |
                     %          b IFF
                     %           (FORALL x: member(x, l1) => member(x, l2))}
  subset_sl?_TCC1: OBLIGATION
    FORALL (l1: list[T], l2: list[T]):
      l1 = null IMPLIES
       (TRUE IFF (FORALL x: member[T](x, l1) => member[T](x, l2)));

  % Termination TCC generated (at line 23, column 30) for  subset_sl?(q, l2)
  subset_sl?_TCC2: OBLIGATION
    FORALL (l1: list[T], l2: list[T], a: T, q: list[T]):
      member(a, l2) AND l1 = cons(a, q) IMPLIES <<[T](q, l1);

  % Subtype TCC generated (at line 23, column 13) for
      % member(a, l2) AND subset_sl?(q, l2)
      % expected type  {b: bool |
                     %          b IFF
                     %           (FORALL x: member(x, l1) => member(x, l2))}
  subset_sl?_TCC3: OBLIGATION
    FORALL (l1: list[T],
            v:
              [d1: {z: [list[T], list[T]] | z`1 << l1} ->
                 {b: bool |
                          b IFF
                           (FORALL x: member(x, d1`1) => member(x, d1`2))}],
            l2: list[T], a: T, q: list[T]):
      l1 = cons(a, q) IMPLIES
       (member[T](a, l2) AND v(q, l2) IFF
         (FORALL x: member[T](x, l1) => member[T](x, l2)));

  % Subtype TCC generated (at line 29, column 10) for  (: x :)
      % expected type  {ll: (nonempty_sl?) |
                     %          FORALL y:
                     %            member(y, ll) IFF (x = y OR member(y, l))}
  add_sl_TCC1: OBLIGATION
    FORALL (x: T, l: list[T]):
      l = null IMPLIES
       nonempty_sl?((: x :)) AND
        (FORALL y: member[T](y, (: x :)) IFF (x = y OR member[T](y, l)));

  % Subtype TCC generated (at line 30, column 27) for  l
      % expected type  {ll: (nonempty_sl?) |
                     %          FORALL y:
                     %            member(y, ll) IFF (x = y OR member(y, l))}
  add_sl_TCC2: OBLIGATION
    FORALL (x: T, l: list[T], a: T, q: list[T]):
      x = a AND l = cons(a, q) IMPLIES
       nonempty_sl?(l) AND
        (FORALL y: member[T](y, l) IFF (x = y OR member[T](y, l)));

  % Termination TCC generated (at line 30, column 41) for  add_sl(x, q)
  add_sl_TCC3: OBLIGATION
    FORALL (x: T, l: list[T], a: T, q: list[T]):
      NOT x = a AND l = cons(a, q) IMPLIES <<[T](q, l);

  % Subtype TCC generated (at line 30, column 34) for  cons(a, add_sl(x, q))
      % expected type  {ll: (nonempty_sl?) |
                     %          FORALL y:
                     %            member(y, ll) IFF (x = y OR member(y, l))}
  add_sl_TCC4: OBLIGATION
    FORALL (x: T, l: list[T],
            v:
              [d1: {z: [T, list[T]] | z`2 << l} ->
                 {ll: (nonempty_sl?) |
                          FORALL y:
                            member(y, ll) IFF
                             (d1`1 = y OR member(y, d1`2))}],
            a: T, q: list[T]):
      NOT x = a AND l = cons(a, q) IMPLIES
       nonempty_sl?(cons[T](a, v(x, q))) AND
        (FORALL y:
           member[T](y, cons[T](a, v(x, q))) IFF (x = y OR member[T](y, l)));

  % Subtype TCC generated (at line 36, column 10) for  null
      % expected type  {ll: list[T] |
                     %          FORALL y:
                     %            member(y, ll) IFF (x /= y AND member(y, l))}
  remove_sl_TCC1: OBLIGATION
    FORALL (x: T, l: list[T]):
      l = null IMPLIES
       (FORALL y: member[T](y, null[T]) IFF (x /= y AND member[T](y, l)));

  % Termination TCC generated (at line 37, column 27) for  remove_sl(x, q)
  remove_sl_TCC2: OBLIGATION
    FORALL (x: T, l: list[T], a: T, q: list[T]):
      x = a AND l = cons(a, q) IMPLIES <<[T](q, l);

  % Subtype TCC generated (at line 37, column 27) for  remove_sl(x, q)
      % expected type  {ll: list[T] |
                     %          FORALL y:
                     %            member(y, ll) IFF (x /= y AND member(y, l))}
  remove_sl_TCC3: OBLIGATION
    FORALL (x: T, l: list[T], a: T, q: list[T]):
      x = a AND l = cons(a, q) IMPLIES
       (FORALL y,
               (v:
                  [d1: {z: [T, list[T]] | <<[T](z`2, l)} ->
                     {ll: list[T] |
                              FORALL (y_1: T):
                                member[T](y_1, ll) IFF
                                 (d1`1 /= y_1 AND member[T](y_1, d1`2))}]):
          member[T](y, v(x, q)) IFF (x /= y AND member[T](y, l)));

  % Subtype TCC generated (at line 37, column 47) for
      % cons(a, remove_sl(x, q))
      % expected type  {ll: list[T] |
                     %          FORALL y:
                     %            member(y, ll) IFF (x /= y AND member(y, l))}
  remove_sl_TCC4: OBLIGATION
    FORALL (x: T, l: list[T], a: T, q: list[T]):
      NOT x = a AND l = cons(a, q) IMPLIES
       (FORALL y,
               (v:
                  [d1: {z: [T, list[T]] | <<[T](z`2, l)} ->
                     {ll: list[T] |
                              FORALL (y_1: T):
                                member[T](y_1, ll) IFF
                                 (d1`1 /= y_1 AND member[T](y_1, d1`2))}]):
          member[T](y, cons[T](a, v(x, q))) IFF (x /= y AND member[T](y, l)));

  % Subtype TCC generated (at line 42, column 3) for
      % subset_sl?(l1, l2) AND subset_sl?(l2, l1)
      % expected type  {b: bool |
                     %          b IFF
                     %           (FORALL x: member(x, l1) IFF member(x, l2))}
  equal_sl_TCC1: OBLIGATION
    FORALL (l1: list[T], l2: list[T]):
      subset_sl?(l1, l2) AND subset_sl?(l2, l1) IFF
       (FORALL x: member[T](x, l1) IFF member[T](x, l2));

  % Subtype TCC generated (at line 44, column 93) for
      % subset_sl?(l1, l2) & NOT subset_sl?(l2, l1)
      % expected type  {b: bool |
                     %          b IFF
                     %           subset_sl?(l1, l2) & NOT equal_sl(l2, l1)}
  strict_subset_sl?_TCC1: OBLIGATION
    FORALL (l1: list[T], l2: list[T]):
      subset_sl?(l1, l2) & NOT subset_sl?(l2, l1) IFF
       subset_sl?(l1, l2) & NOT equal_sl(l2, l1);

  % Subtype TCC generated (at line 48, column 10) for  l2
      % expected type  {ll: list[T] |
                     %          FORALL x:
                     %            member(x, ll) IFF
                     %             (member(x, l1) OR member(x, l2))}
  union_sl_TCC1: OBLIGATION
    FORALL (l1: list[T], l2: list[T]):
      l1 = null IMPLIES
       (FORALL x:
          member[T](x, l2) IFF (member[T](x, l1) OR member[T](x, l2)));

  % Termination TCC generated (at line 49, column 22) for  union_sl(q, l2)
  union_sl_TCC2: OBLIGATION
    FORALL (l1: list[T], a: T, q: list[T]):
      l1 = cons(a, q) IMPLIES <<[T](q, l1);

  % Subtype TCC generated (at line 49, column 13) for
      % add_sl(a, union_sl(q, l2))
      % expected type  {ll: list[T] |
                     %          FORALL x:
                     %            member(x, ll) IFF
                     %             (member(x, l1) OR member(x, l2))}
  union_sl_TCC3: OBLIGATION
    FORALL (l1: list[T], l2: list[T], a: T, q: list[T]):
      l1 = cons(a, q) IMPLIES
       (FORALL x,
               (v:
                  [d1: {z: [list[T], list[T]] | <<[T](z`1, l1)} ->
                     {ll: list[T] |
                              FORALL (x_1: T):
                                member[T](x_1, ll) IFF
                                 (member[T](x_1, d1`1) OR
                                   member[T](x_1, d1`2))}]):
          member[T](x, add_sl(a, v(q, l2))) IFF
           (member[T](x, l1) OR member[T](x, l2)));

  % Subtype TCC generated (at line 55, column 10) for  null
      % expected type  {ll: list[T] |
                     %          FORALL x:
                     %            member(x, ll) IFF
                     %             (member(x, l1) AND member(x, l2))}
  intersection_sl_TCC1: OBLIGATION
    FORALL (l1: list[T], l2: list[T]):
      l1 = null IMPLIES
       (FORALL x:
          member[T](x, null[T]) IFF (member[T](x, l1) AND member[T](x, l2)));

  % Subtype TCC generated (at line 56, column 34) for
      % cons(a, intersection_sl(q, l2))
      % expected type  {ll: list[T] |
                     %          FORALL x:
                     %            member(x, ll) IFF
                     %             (member(x, l1) AND member(x, l2))}
  intersection_sl_TCC2: OBLIGATION
    FORALL (l1: list[T], l2: list[T], a: T, q: list[T]):
      member(a, l2) AND l1 = cons(a, q) IMPLIES
       (FORALL x,
               (v:
                  [d1: {z: [list[T], list[T]] | <<[T](z`1, l1)} ->
                     {ll: list[T] |
                              FORALL (x_1: T):
                                member[T](x_1, ll) IFF
                                 (member[T](x_1, d1`1) AND
                                   member[T](x_1, d1`2))}]):
          member[T](x, cons[T](a, v(q, l2))) IFF
           (member[T](x, l1) AND member[T](x, l2)));

  % Subtype TCC generated (at line 56, column 69) for  intersection_sl(q, l2)
      % expected type  {ll: list[T] |
                     %          FORALL x:
                     %            member(x, ll) IFF
                     %             (member(x, l1) AND member(x, l2))}
  intersection_sl_TCC3: OBLIGATION
    FORALL (l1: list[T], l2: list[T], a: T, q: list[T]):
      NOT member(a, l2) AND l1 = cons(a, q) IMPLIES
       (FORALL x,
               (v:
                  [d1: {z: [list[T], list[T]] | <<[T](z`1, l1)} ->
                     {ll: list[T] |
                              FORALL (x_1: T):
                                member[T](x_1, ll) IFF
                                 (member[T](x_1, d1`1) AND
                                   member[T](x_1, d1`2))}]):
          member[T](x, v(q, l2)) IFF (member[T](x, l1) AND member[T](x, l2)));

  % Subtype TCC generated (at line 64, column 10) for  null
      % expected type  {ll: list[T] |
                     %          FORALL x:
                     %            member(x, ll) IFF
                     %             (member(x, l1) AND NOT member(x, l2))}
  difference_sl_TCC1: OBLIGATION
    FORALL (l1: list[T], l2: list[T]):
      l1 = null IMPLIES
       (FORALL x:
          member[T](x, null[T]) IFF
           (member[T](x, l1) AND NOT member[T](x, l2)));

  % Subtype TCC generated (at line 65, column 34) for  difference_sl(q, l2)
      % expected type  {ll: list[T] |
                     %          FORALL x:
                     %            member(x, ll) IFF
                     %             (member(x, l1) AND NOT member(x, l2))}
  difference_sl_TCC2: OBLIGATION
    FORALL (l1: list[T], l2: list[T], a: T, q: list[T]):
      member(a, l2) AND l1 = cons(a, q) IMPLIES
       (FORALL x,
               (v:
                  [d1: {z: [list[T], list[T]] | <<[T](z`1, l1)} ->
                     {ll: list[T] |
                              FORALL (x_1: T):
                                member[T](x_1, ll) IFF
                                 (member[T](x_1, d1`1) AND
                                   NOT member[T](x_1, d1`2))}]):
          member[T](x, v(q, l2)) IFF
           (member[T](x, l1) AND NOT member[T](x, l2)));

  % Subtype TCC generated (at line 65, column 59) for
      % cons(a, difference_sl(q, l2))
      % expected type  {ll: list[T] |
                     %          FORALL x:
                     %            member(x, ll) IFF
                     %             (member(x, l1) AND NOT member(x, l2))}
  difference_sl_TCC3: OBLIGATION
    FORALL (l1: list[T], l2: list[T], a: T, q: list[T]):
      NOT member(a, l2) AND l1 = cons(a, q) IMPLIES
       (FORALL x,
               (v:
                  [d1: {z: [list[T], list[T]] | <<[T](z`1, l1)} ->
                     {ll: list[T] |
                              FORALL (x_1: T):
                                member[T](x_1, ll) IFF
                                 (member[T](x_1, d1`1) AND
                                   NOT member[T](x_1, d1`2))}]):
          member[T](x, cons[T](a, v(q, l2))) IFF
           (member[T](x, l1) AND NOT member[T](x, l2)));

  % Subtype TCC generated (at line 74, column 10) for  emptyset
      % expected type  {s: finite_set[T] | s = ({x | member(x, l)})}
  list2set_TCC1: OBLIGATION
    FORALL (l: list[T]):
      l = null IMPLIES emptyset[T] = ({x | member[T](x, l)});

  % Subtype TCC generated (at line 75, column 13) for  add(a, list2set(q))
      % expected type  {s: finite_set[T] | s = ({x | member(x, l)})}
  list2set_TCC2: OBLIGATION
    FORALL (l: list[T],
            v:
              [l1: {z: list[T] | z << l} ->
                 {s: finite_set[T] | s = ({x | member(x, l1)})}],
            a: T, q: list[T]):
      l = cons(a, q) IMPLIES add[T](a, v(q)) = ({x | member[T](x, l)});

  % Subtype TCC generated (at line 81, column 10) for  0
      % expected type  {n: nat | n = Card(list2set(l))}
  card_sl_TCC1: OBLIGATION
    FORALL (l: list[T]): l = null IMPLIES 0 = Card[T](list2set(l));

  % Subtype TCC generated (at line 82, column 33) for  card_sl(q)
      % expected type  {n: nat | n = Card(list2set(l))}
  card_sl_TCC2: OBLIGATION
    FORALL (l: list[T],
            v:
              [l1: {z: list[T] | z << l} ->
                 {n: nat | n = Card(list2set(l1))}],
            a: T, q: list[T]):
      member(a, q) AND l = cons(a, q) IMPLIES v(q) = Card[T](list2set(l));

  % Subtype TCC generated (at line 82, column 49) for  1 + card_sl(q)
      % expected type  {n: nat | n = Card(list2set(l))}
  card_sl_TCC3: OBLIGATION
    FORALL (l: list[T],
            v:
              [l1: {z: list[T] | z << l} ->
                 {n: nat | n = Card(list2set(l1))}],
            a: T, q: list[T]):
      NOT member(a, q) AND l = cons(a, q) IMPLIES
       1 + v(q) = Card[T](list2set(l));

  % Subtype TCC generated (at line 88, column 10) for  null
      % expected type  {ll: list[T] |
                     %          equal_sl[T](l, ll) & card_sl(ll) = length(ll)}
  reduce_sl_TCC1: OBLIGATION
    FORALL (l: list[T]):
      l = null IMPLIES
       equal_sl[T](l, null[T]) & card_sl(null[T]) = length[T](null[T]);

  % Subtype TCC generated (at line 89, column 33) for  reduce_sl(q)
      % expected type  {ll: list[T] |
                     %          equal_sl[T](l, ll) & card_sl(ll) = length(ll)}
  reduce_sl_TCC2: OBLIGATION
    FORALL (l: list[T],
            v:
              [l1: {z: list[T] | z << l} ->
                 {ll: list[T] |
                          equal_sl[T](l1, ll) & card_sl(ll) = length(ll)}],
            a: T, q: list[T]):
      member(a, q) AND l = cons(a, q) IMPLIES
       equal_sl[T](l, v(q)) & card_sl(v(q)) = length[T](v(q));

  % Subtype TCC generated (at line 89, column 51) for  cons(a, reduce_sl(q))
      % expected type  {ll: list[T] |
                     %          equal_sl[T](l, ll) & card_sl(ll) = length(ll)}
  reduce_sl_TCC3: OBLIGATION
    FORALL (l: list[T],
            v:
              [l1: {z: list[T] | z << l} ->
                 {ll: list[T] |
                          equal_sl[T](l1, ll) & card_sl(ll) = length(ll)}],
            a: T, q: list[T]):
      NOT member(a, q) AND l = cons(a, q) IMPLIES
       equal_sl[T](l, cons[T](a, v(q))) &
        card_sl(cons[T](a, v(q))) = length[T](cons[T](a, v(q)));


body:
  % Computable finite sets by Pierre Neron (Ecole Polytechnique)

  set_as_list_props[T:TYPE] : THEORY
  BEGIN

    IMPORTING set_as_list[T]

    strict_subset_card_lt : LEMMA FORALL (s1,s2 : finite_set) : strict_subset?(s1,s2) IMPLIES card(s1) < card(s2)

    x, y: VAR T

    l, l1, l2: VAR list[T]

    empty_l2s : LEMMA empty_sl?(l) IFF empty?(list2set(l))

    emptyset_l2s : LEMMA list2set(emptyset_sl) = emptyset

    nonempty_l2s : LEMMA nonempty_sl?(l) IFF nonempty?(list2set(l))

    subset_l2s : LEMMA subset_sl?(l1,l2) IFF subset?(list2set(l1),list2set(l2))

    remove_l2s : LEMMA list2set(remove_sl(x,l)) = remove(x,list2set(l))

    equal_l2s : LEMMA equal_sl(l1,l2) IFF list2set(l1) = list2set(l2)

    strict_subset_l2s : LEMMA strict_subset_sl?(l1,l2) IFF strict_subset?(list2set(l1),list2set(l2))

    union_l2s : LEMMA list2set(union_sl(l1,l2)) = union(list2set(l1),list2set(l2))

    intersection_l2s : LEMMA list2set(intersection_sl(l1,l2)) = intersection(list2set(l1),list2set(l2))

    disjoint_l2s : LEMMA disjoint_sl?(l1,l2) IFF disjoint?(list2set(l1),list2set(l2))

    difference_l2s : LEMMA list2set(difference_sl(l1,l2)) = difference(list2set(l1),list2set(l2))

    symmetric_difference_l2s : LEMMA 
    		list2set(symmetric_difference_sl(l1,l2)) = symmetric_difference(list2set(l1),list2set(l2))

    subset_sl_emptyset_sl: LEMMA subset_sl?(emptyset_sl, l)

    subset_sl_reflexive: LEMMA subset_sl?(l, l)

    subset_sl_transitive: LEMMA
      subset_sl?(l1, l) AND subset_sl?(l,l2) IMPLIES subset_sl?(l1,l2)

    subset_sl_preorder: LEMMA preorder?(subset_sl?[T])

    subset_sl_is_preorder: JUDGEMENT
      subset_sl?[T] HAS_TYPE (preorder?[list[T]])

    equal_sl_reflexive: LEMMA equal_sl(l,l)

    equal_sl_transitive: LEMMA equal_sl(l1,l) AND equal_sl(l,l2) => equal_sl(l1,l2)

    equal_sl_symmetric: LEMMA equal_sl(l1,l2) IFF equal_sl(l2,l1)
    
    strict_subset_sl_irreflexive: LEMMA NOT strict_subset_sl?(l, l)

    strict_subset_sl_transitive: LEMMA
      strict_subset_sl?(l1, l) AND strict_subset_sl?(l, l2) IMPLIES
       strict_subset_sl?(l1, l2)

    strict_subset_sl_strict_order: LEMMA strict_order?(strict_subset_sl?[T])

    strict_subset_sl_is_strict_order: JUDGEMENT
      strict_subset_sl?[T] HAS_TYPE (strict_order?[list[T]])

    strict_subset_sl_wf: LEMMA well_founded?(strict_subset_sl?)

    strict_subset_sl_is_wf : JUDGEMENT 
      strict_subset_sl?[T] HAS_TYPE (well_founded?[list[T]])
    			     

    

  END set_as_list_props

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

  % Judgement subtype TCC generated (at line 49, column 4) for  subset_sl?[T]
      % expected type  (preorder?[list[T]])
  subset_sl_is_preorder: OBLIGATION preorder?[list[T]](subset_sl?[T]);

  % Judgement subtype TCC generated (at line 66, column 4) for
      % strict_subset_sl?[T]
      % expected type  (strict_order?[list[T]])
  strict_subset_sl_is_strict_order: OBLIGATION
    strict_order?[list[T]](strict_subset_sl?[T]);

  % Judgement subtype TCC generated (at line 71, column 4) for
      % strict_subset_sl?[T]
      % expected type  (well_founded?[list[T]])
  strict_subset_sl_is_wf: OBLIGATION
    well_founded?[list[T]](strict_subset_sl?[T]);


body:
  %------------------------------------------------------------------------
  %
  % This theory defines additional properties of lists.
  %
  %    Author: Kristin Y. Rozier,
  %                      Formal Methods Group, NASA Langley Research Center
  %            with thanks to Paul Miner and Ben Di Vito for their helpful
  %                 comments and suggestions
  %            Cesar Munoz 2012, Anthony Narkawicz 2013
  %------------------------------------------------------------------------

  more_list_props   [ T : TYPE ]
  		: THEORY

    BEGIN

    m, n: VAR nat
    L: VAR list[T]
    p: VAR PRED[T]
    A: VAR finite_set[T]
    B: VAR list[T]
    X, Y: VAR list[T]
    l1, l2, l3: VAR list[T]
    pair: VAR [nat, nat]
    t: VAR T

  %
  % Functions
  %

    prefix?(x: list[T], 
            y: list[T]): RECURSIVE bool = 
      IF length(y) < length(x) THEN FALSE 
      ELSE 
        CASES x OF
          null: TRUE,
          cons(sigma_x, x1):
            CASES y OF
              null: FALSE,
  	    cons(sigma_y, y1): 
                IF sigma_x = sigma_y AND prefix?(x1, y1) THEN TRUE
                ELSE FALSE
                ENDIF
            ENDCASES
        ENDCASES
      ENDIF
      MEASURE length(x)


    suffix?(x: list[T], 
            y: list[T]): RECURSIVE bool = 
      IF length(y) < length(x) THEN FALSE 
      ELSE 
        CASES reverse(x) OF
          null: TRUE,
          cons(sigma_x, x1):
            CASES reverse(y) OF
              null: FALSE,
  	    cons(sigma_y, y1): 
                IF sigma_x = sigma_y AND suffix?(x1, y1) THEN TRUE
                ELSE FALSE
                ENDIF
            ENDCASES
        ENDCASES
      ENDIF
      MEASURE length(x)


  %Multiple concatenation of a list: w^3 means (: w  w  w :).
  ;
    ^(l1, n): RECURSIVE list[T] = 
      IF n = 0 THEN (null)
      ELSE append( l1, ^(l1, n-1) )
      ENDIF
      MEASURE n


  % Just like for sequences, a sub-list 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.
  ;
    ^(l1, pair): RECURSIVE list[T] =
      LET (m, n) = pair
       IN IF m > n OR m >= length(l1) OR m < 0
          THEN null
          ELSIF m = n THEN cons( nth(l1, m), null)
          ELSE cons( nth(l1, m), ^(l1, (m+1, n)))
          ENDIF
    MEASURE IF pair`2 > pair`1 THEN pair`2 - pair`1 ELSE 0 ENDIF


  %
  % Lemmas and Theorems
  %

    prefix_length: LEMMA
      prefix?(X,Y) IMPLIES length(X) <= length(Y)

    suffix_length: LEMMA
      suffix?(X,Y) IMPLIES length(X) <= length(Y)

    every_forall: LEMMA
      every(p)(L) IFF FORALL (n:below(length(L))): p(nth(L,n))

    some_exists: LEMMA
      some(p)(L) IFF EXISTS (n:below(length(L))): p(nth(L,n))

    list_extensionality : LEMMA
      l1=l2 IFF length(l1) = length(l2) AND FORALL(n:below(length(l1))): nth(l1,n) = nth(l2,n)


    %If the length of the list of elements from set A is greater than the 
    %cardinality of the set, then there is at least one repeated element
    %in the list.
    list_pigeonhole: THEOREM
        every(A)(B) AND 
        length(B) > card(A)
      IMPLIES
        EXISTS (n:below[length(B)], m:below[length(B)]):
           n /= m 
           AND nth(B, n) = nth(B, m)  

     nth_append : LEMMA
       FORALL(i:nat): i < length(l1)+length(l2) IMPLIES
         nth(append(l1,l2),i) = IF i < length(l1) THEN nth(l1,i)
                                ELSE nth(l2,i-length(l1))
                                ENDIF

    length_null : LEMMA
      length(null[T]) = 0

    length_singleton : LEMMA
      length((:t:)) = 1

    AUTO_REWRITE+ length_singleton
    AUTO_REWRITE+ length_null

    length_null_list: LEMMA
      length(L)=0 IFF null?(L)

    reverse_def: LEMMA FORALL (j:nat): 
      j<length(L) IMPLIES nth(reverse(L),j) = nth(L,length(L)-1-j)

    cons_append: LEMMA
      cons(t,L) = append((: t :),L)

    expand_list: LEMMA
      null?(L) OR L = cons(car(L),cdr(L))

    append_null_left: LEMMA append(null,L) = L

    END more_list_props

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

  % Termination TCC generated (at line 41, column 39) for  prefix?(x1, y1)
  prefix?_TCC1: OBLIGATION
    FORALL (x, y: list[T]):
      NOT length(y) < length(x) IMPLIES
       (FORALL (sigma_x: T, x1: list[T]):
          x = cons(sigma_x, x1) IMPLIES
           (FORALL (sigma_y: T, y1: list[T]):
              sigma_x = sigma_y AND y = cons(sigma_y, y1) IMPLIES
               length[T](x1) < length[T](x)));

  % Termination TCC generated (at line 60, column 39) for  suffix?(x1, y1)
  suffix?_TCC1: OBLIGATION
    FORALL (x, y: list[T]):
      NOT length(y) < length(x) IMPLIES
       (FORALL (sigma_x: T, x1: list[T]):
          reverse(x) = cons(sigma_x, x1) IMPLIES
           (FORALL (sigma_y: T, y1: list[T]):
              sigma_x = sigma_y AND reverse(y) = cons(sigma_y, y1) IMPLIES
               length[T](x1) < length[T](x)));

  % Subtype TCC generated (at line 73, column 27) for  n - 1
      % expected type  nat
  caret_TCC1: OBLIGATION FORALL (n: nat): NOT n = 0 IMPLIES n - 1 >= 0;

  % Termination TCC generated (at line 73, column 21) for  ^(l1, n - 1)
  caret_TCC2: OBLIGATION FORALL (n: nat): NOT n = 0 IMPLIES n - 1 < n;

  % Subtype TCC generated (at line 89, column 34) for  pair`2 - pair`1
      % expected type  naturalnumber
  caret_TCC3: OBLIGATION
    FORALL (pair: [nat, nat]): pair`2 > pair`1 IMPLIES pair`2 - pair`1 >= 0;

  % Subtype TCC generated (at line 86, column 39) for  m
      % expected type  below[length[T](l1)]
  caret_TCC4: OBLIGATION
    FORALL (l1: list[T], pair: [nat, nat], m: nat, n: nat):
           m = n AND NOT m > n AND NOT m >= length(l1) AND NOT m < 0
       AND n = pair`2 AND m = pair`1
       IMPLIES m < length[T](l1);

  % Subtype TCC generated (at line 87, column 27) for  m
      % expected type  below[length[T](l1)]
  caret_TCC5: OBLIGATION
    FORALL (l1: list[T], pair: [nat, nat], m: nat, n: nat):
           NOT m = n AND NOT m > n AND NOT m >= length(l1) AND NOT m < 0
       AND n = pair`2 AND m = pair`1
       IMPLIES m < length[T](l1);

  % Termination TCC generated (at line 87, column 31) for  ^(l1, (m + 1, n))
  caret_TCC6: OBLIGATION
    FORALL (l1: list[T], pair: [nat, nat], m: nat, n: nat):
           NOT m = n AND NOT m > n AND NOT m >= length(l1) AND NOT m < 0
       AND n = pair`2 AND m = pair`1
       IMPLIES
       IF n > m + 1 THEN n - (m + 1) ELSE 0 ENDIF <
        IF pair`2 > pair`1 THEN pair`2 - pair`1 ELSE 0 ENDIF;

  % Subtype TCC generated (at line 109, column 90) for  n
      % expected type  below[length[T](l2)]
  list_extensionality_TCC1: OBLIGATION
    FORALL (l1, l2: list[T]):
      length(l1) = length(l2) IMPLIES
       (FORALL (n: below(length[T](l1))): n < length[T](l2));

  % Subtype TCC generated (at line 125, column 25) for  i
      % expected type  below[length[T](append(l1, l2))]
  nth_append_TCC1: OBLIGATION
    FORALL (l1, l2: list[T], i: nat):
      i < length(l1) + length(l2) IMPLIES i < length[T](append[T](l1, l2));

  % Subtype TCC generated (at line 126, column 42) for  i - length(l1)
      % expected type  below[length[T](l2)]
  nth_append_TCC2: OBLIGATION
    FORALL (l1, l2: list[T], i: nat):
      NOT i < length(l1) AND i < length(l1) + length(l2) IMPLIES
       i - length[T](l1) >= 0 AND i - length[T](l1) < length[T](l2);

  % Subtype TCC generated (at line 142, column 39) for  j
      % expected type  below[length[T](reverse(L))]
  reverse_def_TCC1: OBLIGATION
    FORALL (L: list[T], j: nat):
      j < length(L) IMPLIES j < length[T](reverse[T](L));

  % Subtype TCC generated (at line 142, column 50) for  length(L) - 1 - j
      % expected type  below[length[T](L)]
  reverse_def_TCC2: OBLIGATION
    FORALL (L: list[T], j: nat):
      j < length(L) IMPLIES
       length[T](L) - 1 - j >= 0 AND length[T](L) - 1 - j < length[T](L);

  % Subtype TCC generated (at line 148, column 29) for  L
      % expected type  (cons?[T])
  expand_list_TCC1: OBLIGATION
    FORALL (L: list[T]): NOT null?(L) IMPLIES cons?[T](L);


body:
  listn[T:TYPE] : THEORY
  BEGIN

    IMPORTING list[T]

    listn?(n:nat)(l:list) : MACRO bool = length(l)=n

    listn(n:nat) : TYPE = (listn?(n))

    listn_ext : LEMMA
      FORALL(n:nat,l1:listn(n),l2:listn(n)):
        (FORALL (i:below(n)): nth(l1,i) = nth(l2,i)) IMPLIES l1 = l2

    listn_0 : JUDGEMENT
      null HAS_TYPE listn(0)

    setnth(l:list,n:nat,f:[T->T]) : RECURSIVE 
      {sl : listn(length(l)) | 
            FORALL (i:below(length(l))) : IF i=n THEN nth(sl,i) = f(nth(l,i)) 
                                          ELSE nth(sl,i) = nth(l,i)
                                          ENDIF} =
      CASES l OF
        null : null,
        cons(a,r) : IF n=0 THEN cons(f(a),r)
                    ELSE cons(a,setnth(r,n-1,f))
                    ENDIF
      ENDCASES
    MEASURE l BY <<

    finseqn?(n:nat)(f:finseq[T]) : MACRO bool = f`length = n

    Finseqn(n:nat) : TYPE = (finseqn?(n))

    normalize_fseq(f:finseq[T]): {fsn: Finseqn(f`length)|fsn = f} =
      LET fslist = finseq2list(f)
      IN  list2finseq(fslist)

    normalize_fseq_def: LEMMA FORALL (f:finseq[T]): normalize_fseq(f) = f


  END listn

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

  % Subtype TCC generated (at line 12, column 35) for  i
      % expected type  below[length[T](l1)]
  listn_ext_TCC1: OBLIGATION
    FORALL (n: nat, l1: listn(n), l2: listn(n), i: below(n)):
      i < length[T](l1);

  % Subtype TCC generated (at line 12, column 47) for  i
      % expected type  below[length[T](l2)]
  listn_ext_TCC2: OBLIGATION
    FORALL (n: nat, l1: listn(n), l2: listn(n), i: below(n)):
      i < length[T](l2);

  % Judgement subtype TCC generated (at line 15, column 4) for  null
      % expected type  listn(0)
  listn_0: OBLIGATION length[T](null[T]) = 0;

  % Subtype TCC generated (at line 19, column 59) for  i
      % expected type  below[length[T](sl)]
  setnth_TCC1: OBLIGATION
    FORALL (l: list, n: nat, sl: listn(length[T](l)),
            i: below(length[T](l))):
      i = n IMPLIES i < length[T](sl);

  % Subtype TCC generated (at line 20, column 52) for  i
      % expected type  below[length[T](sl)]
  setnth_TCC2: OBLIGATION
    FORALL (l: list, n: nat, sl: listn(length[T](l)),
            i: below(length[T](l))):
      NOT i = n IMPLIES i < length[T](sl);

  % Subtype TCC generated (at line 23, column 13) for  null
      % expected type  {sl: listn(length(l)) |
                     %          FORALL (i: below(length(l))):
                     %            IF i = n THEN nth(sl, i) = f(nth(l, i))
                     %            ELSE nth(sl, i) = nth(l, i)
                     %            ENDIF}
  setnth_TCC3: OBLIGATION
    FORALL (l: list[T], n: nat, f: [T -> T]):
      l = null IMPLIES
       (FORALL (i: below(length[T](l))):
          IF i = n THEN nth[T](null[T], i) = f(nth[T](l, i))
          ELSE nth[T](null[T], i) = nth[T](l, i)
          ENDIF)
        AND length[T](null[T]) = length[T](l);

  % Subtype TCC generated (at line 24, column 30) for  cons(f(a), r)
      % expected type  {sl: listn(length(l)) |
                     %          FORALL (i: below(length(l))):
                     %            IF i = n THEN nth(sl, i) = f(nth(l, i))
                     %            ELSE nth(sl, i) = nth(l, i)
                     %            ENDIF}
  setnth_TCC4: OBLIGATION
    FORALL (l: list[T], n: nat, f: [T -> T], a: T, r: list[T]):
      n = 0 AND l = cons(a, r) IMPLIES
       length[T](cons[T](f(a), r)) = length[T](l) AND
        (FORALL (i: below(length[T](l))):
           IF i = n THEN nth[T](cons[T](f(a), r), i) = f(nth[T](l, i))
           ELSE nth[T](cons[T](f(a), r), i) = nth[T](l, i)
           ENDIF);

  % Subtype TCC generated (at line 25, column 39) for  n - 1
      % expected type  nat
  setnth_TCC5: OBLIGATION
    FORALL (l: list[T], n: nat, f: [T -> T], a: T, r: list[T]):
      NOT n = 0 AND l = cons(a, r) IMPLIES n - 1 >= 0;

  % Termination TCC generated (at line 25, column 30) for  setnth(r, n - 1, f)
  setnth_TCC6: OBLIGATION
    FORALL (l: list[T], n: nat, f: [T -> T], a: T, r: list[T]):
      NOT n = 0 AND l = cons(a, r) IMPLIES <<[T](r, l);

  % Subtype TCC generated (at line 25, column 23) for
      % cons(a, setnth(r, n - 1, f))
      % expected type  {sl: listn(length(l)) |
                     %          FORALL (i: below(length(l))):
                     %            IF i = n THEN nth(sl, i) = f(nth(l, i))
                     %            ELSE nth(sl, i) = nth(l, i)
                     %            ENDIF}
  setnth_TCC7: OBLIGATION
    FORALL (l: list[T],
            v:
              [d1: {z: [list[T], nat, [T -> T]] | z`1 << l} ->
                 {sl: listn(length(d1`1)) |
                          FORALL (i: below(length(d1`1))):
                            IF i = d1`2 THEN nth(sl, i) = d1`3(nth(d1`1, i))
                            ELSE nth(sl, i) = nth(d1`1, i)
                            ENDIF}],
            n: nat, f: [T -> T], a: T, r: list[T]):
      NOT n = 0 AND l = cons(a, r) IMPLIES
       length[T](cons[T](a, v(r, n - 1, f))) = length[T](l) AND
        (FORALL (i: below(length[T](l))):
           IF i = n
             THEN nth[T](cons[T](a, v(r, n - 1, f)), i) = f(nth[T](l, i))
           ELSE nth[T](cons[T](a, v(r, n - 1, f)), i) = nth[T](l, i)
           ENDIF);

  % Subtype TCC generated (at line 36, column 8) for  list2finseq(fslist)
      % expected type  {fsn: Finseqn(f`length) | fsn = f}
  normalize_fseq_TCC1: OBLIGATION
    FORALL (f: finseq[T], fslist: list[T]):
      fslist = finseq2list(f) IMPLIES
       list2finseq[T](fslist)`length = f`length AND
        list2finseq[T](fslist) = f;


body:
  array2list[T:TYPE+] : THEORY
  BEGIN

    IMPORTING listn[T], 
              more_list_props

    array2list_it(a:[nat->T],n:nat,i:upto(n)) : RECURSIVE 
      {l:listn(n-i) | FORALL (j:subrange(i,n-1)) : a(j) = nth(l,j-i)} =
      IF i = n THEN null
      ELSE cons(a(i),array2list_it(a,n,i+1))
      ENDIF
      MEASURE n-i

    array2list(n:nat)(a:[nat->T]) : 
      {l:listn(n) | FORALL (i:below(n)) : a(i) = nth(l,i)} =
      array2list_it(a,n,0)

    list2array(t:T)(l:list)(i:nat) : RECURSIVE T =
      IF null?(l) THEN t
      ELSIF i=0 THEN car(l)  
      ELSE list2array(t)(cdr(l))(i-1)
      ENDIF
    MEASURE l BY <<

    list2array_sound : LEMMA
      FORALL(l:list,t:T,i:nat) : 
        list2array(t)(l)(i) = 
          IF i < length(l) THEN nth(l,i)
          ELSE t
        ENDIF 

    default : T = choose({t:T|true})

    list2array_default(l:list) : MACRO [nat->T] =
      list2array(default)(l)

    array2list_inv : LEMMA
      FORALL (a:[nat->T],t:T,n:nat,i:below(n)) :      
        list2array(t)(array2list(n)(a))(i) = a(i)

    list2array_inv : LEMMA
      FORALL (l:list,t:T,i:below(length(l))) :      
        nth(array2list(length(l))(list2array(t)(l)),i) = nth(l,i)

    list2array_inv_ext : LEMMA
      FORALL (l:list,t:T) :
        array2list(length(l))(list2array(t)(l)) = l

    fill(t:T,n:nat) : 
      {l:listn(n) | FORALL (i:below(n)) : nth(l,i) = t} =
      array2list(n)(LAMBDA(n:nat):t)

  END array2list

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

  % Subtype TCC generated (at line 8, column 51) for  j
      % expected type  nat
  array2list_it_TCC1: OBLIGATION
    FORALL (n: nat, i: upto(n), l: listn[T](n - i), j: subrange(i, n - 1)):
      j >= 0;

  % Subtype TCC generated (at line 8, column 62) for  j - i
      % expected type  below[length[T](l)]
  array2list_it_TCC2: OBLIGATION
    FORALL (n: nat, i: upto(n), l: listn[T](n - i), j: subrange(i, n - 1)):
      j - i >= 0 AND j - i < length[T](l);

  % Subtype TCC generated (at line 12, column 12) for  n - i
      % expected type  naturalnumber
  array2list_it_TCC3: OBLIGATION FORALL (n: nat, i: upto(n)): n - i >= 0;

  % Subtype TCC generated (at line 9, column 18) for  null
      % expected type  {l: listn(n - i) |
                     %          FORALL (j: subrange(i, n - 1)):
                     %            a(j) = nth(l, j - i)}
  array2list_it_TCC4: OBLIGATION
    FORALL (a: [nat -> T], n: nat, i: upto(n)):
      i = n IMPLIES
       (FORALL (j: subrange(i, n - 1)): a(j) = nth[T](null[T], j - i)) AND
        length[T](null[T]) = n - i;

  % Subtype TCC generated (at line 10, column 37) for  i + 1
      % expected type  upto(n)
  array2list_it_TCC5: OBLIGATION
    FORALL (n: nat, i: upto(n)): NOT i = n IMPLIES i + 1 <= n;

  % Termination TCC generated (at line 10, column 19) for
      % array2list_it(a, n, i + 1)
  array2list_it_TCC6: OBLIGATION
    FORALL (n: nat, i: upto(n)): NOT i = n IMPLIES n - (i + 1) < n - i;

  % Subtype TCC generated (at line 10, column 9) for
      % cons(a(i), array2list_it(a, n, i + 1))
      % expected type  {l: listn(n - i) |
                     %          FORALL (j: subrange(i, n - 1)):
                     %            a(j) = nth(l, j - i)}
  array2list_it_TCC7: OBLIGATION
    FORALL (a: [nat -> T], n: nat, i: upto(n),
            v:
              [d1: {z: [[nat -> T], n: nat, upto(n)] | z`2 - z`3 < n - i} ->
                 {l: listn(d1`2 - d1`3) |
                          FORALL (j: subrange(d1`3, d1`2 - 1)):
                            d1`1(j) = nth(l, j - d1`3)}]):
      NOT i = n IMPLIES
       length[T](cons[T](a(i), v(a, n, i + 1))) = n - i AND
        (FORALL (j: subrange(i, n - 1)):
           a(j) = nth[T](cons[T](a(i), v(a, n, i + 1)), j - i));

  % Subtype TCC generated (at line 15, column 53) for  i
      % expected type  below[length[T](l)]
  array2list_TCC1: OBLIGATION
    FORALL (n: nat, l: listn[T](n), i: below(n)): i < length[T](l);

  % Subtype TCC generated (at line 16, column 22) for  0
      % expected type  upto(n)
  array2list_TCC2: OBLIGATION FORALL (n: nat): 0 <= n;

  % Subtype TCC generated (at line 16, column 4) for  array2list_it(a, n, 0)
      % expected type  {l: listn(n) | FORALL (i: below(n)): a(i) = nth(l, i)}
  array2list_TCC3: OBLIGATION
    FORALL (n: nat, a: [nat -> T]):
      FORALL (i: below(n)): a(i) = nth[T](array2list_it(a, n, 0), i);

  % Subtype TCC generated (at line 20, column 23) for  l
      % expected type  (cons?[T])
  list2array_TCC1: OBLIGATION
    FORALL (l: list[T], i: nat): i = 0 AND NOT null?(l) IMPLIES cons?[T](l);

  % Subtype TCC generated (at line 21, column 27) for  l
      % expected type  (cons?[T])
  list2array_TCC2: OBLIGATION
    FORALL (l: list[T], i: nat):
      NOT i = 0 AND NOT null?(l) IMPLIES cons?[T](l);

  % Termination TCC generated (at line 21, column 9) for
      % list2array(t)(cdr(l))
  list2array_TCC3: OBLIGATION
    FORALL (l: list[T], i: nat):
      NOT i = 0 AND NOT null?(l) IMPLIES <<[T](cdr[T](l), l);

  % Subtype TCC generated (at line 21, column 31) for  i - 1
      % expected type  nat
  list2array_TCC4: OBLIGATION
    FORALL (l: list[T], i: nat):
      NOT i = 0 AND NOT null?(l) IMPLIES i - 1 >= 0;

  % Subtype TCC generated (at line 32, column 23) for  {t: T | TRUE}
      % expected type  p: (nonempty?[T])
  default_TCC1: OBLIGATION nonempty?[T]({t: T | TRUE});

  % Subtype TCC generated (at line 43, column 50) for  i
      % expected type  below
                     %     [length[T]
                     %          (array2list(length(l))(list2array(t)(l)))]
  list2array_inv_TCC1: OBLIGATION
    FORALL (l: list[T], t: T, i: below(length[T](l))):
      i < length[T](array2list(length[T](l))(list2array(t)(l)));

  % Subtype TCC generated (at line 51, column 4) for
      % array2list(n)(LAMBDA (n: nat): t)
      % expected type  {l: listn(n) | FORALL (i: below(n)): nth(l, i) = t}
  fill_TCC1: OBLIGATION
    FORALL (t: T, n: nat):
      FORALL (i: below(n)): nth[T](array2list(n)(LAMBDA (n: nat): t), i) = t;


body:
  permutation[N: nat]: THEORY
  %----------------------------------------------------------------------------
  % the theory of bijective mappings from below(N) to below(N)
  %
  % Author: Alfons Geser, National Institute of Aerospace, Hampton, VA, 2003
  %----------------------------------------------------------------------------
  BEGIN

    permutation: TYPE+ = {pi: [below(N) -> below(N)] | bijective?(pi)}
                 CONTAINING id

    i,j,k  : VAR below(N)
    m      : VAR below(N+1)
    pi, rho: VAR permutation

    inverse_id         : LEMMA N > 0 IMPLIES inverse[below(N),below(N)](id) = id

    inverse_composition: LEMMA N > 0 IMPLIES inverse(pi o rho) = inverse(rho) o inverse(pi)

    transpose(i,j): permutation = 
            LAMBDA k: IF k = j THEN i ELSIF k = i THEN j ELSE k ENDIF

    involutorian_transpose: LEMMA transpose(i,j)(transpose(i,j)(k)) = k

  END permutation

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

  % Existence TCC generated (at line 16, column 43) for
      % inverse[below(N), below(N)]
  inverse_id_TCC1: OBLIGATION N > 0 IMPLIES (EXISTS (x: below(N)): TRUE);

  % Subtype TCC generated (at line 21, column 10) for
      % LAMBDA k: IF k = j THEN i ELSIF k = i THEN j ELSE k ENDIF
      % expected type  permutation
  transpose_TCC1: OBLIGATION
    FORALL (i: below(N), j: below(N)):
      bijective?[below(N), below(N)]
          (LAMBDA k: IF k = j THEN i ELSIF k = i THEN j ELSE k ENDIF);


body:
  permutation_ops[N: posnat]: THEORY
  %----------------------------------------------------------------------------
  % the theory of bijective mappings from below(N) to below(N)
  %
  % Author: Alfons Geser, National Institute of Aerospace, Hampton, VA, 2003
  %----------------------------------------------------------------------------
  BEGIN

    IMPORTING permutation[N], sort_array[N,below(N),<=]

    i,j,k  : VAR below(N)
    m      : VAR below(N+1)
    pi, rho: VAR permutation

    sorted_iff_id_lem  : LEMMA (FORALL i: i >= m => pi(i) = i) &
                             (FORALL (i,j): i < j => pi(i) <= pi(j)) IMPLIES
                                pi(i) = i

    % a permutation is sorted iff it is the identity

    sorted_iff_id      : THEOREM  sorted?(pi) <=> pi = id

  END permutation_ops


body:
  bags [T: TYPE] : THEORY
  %------------------------------------------------------------------------
  %
  %  Fundamental definitions and properties of bags.
  %
  %    Authors: Rick Butler      NASA Langley
  %             Lee Pike         NASA Langley
  %------------------------------------------------------------------------

   BEGIN
    x,y,t: VAR T

    bag: TYPE = [T -> nat]
    a,b,c: VAR bag
    n: VAR nat

    count(x,b): nat = b(x)

    emptybag         : bag = (LAMBDA t: 0)

    singleton_bag(t) : bag = (LAMBDA (x: T): IF x = t THEN 1 ELSE 0 ENDIF)

    insert(x,b)      : bag = (LAMBDA t: IF x = t THEN b(t) + 1 ELSE b(t) ENDIF)

    purge(x,b)       : bag = (LAMBDA t: IF x = t THEN 0 ELSE b(t) ENDIF)

    delete(x,b,n)    : bag = (LAMBDA t: IF x = t THEN
                                          IF b(t) >= n THEN b(t) - n ELSE 0 ENDIF 
                                        ELSE b(t) ENDIF)

    extract(x,b)     : bag = (LAMBDA t: IF x = t THEN b(t) ELSE 0 ENDIF)

    plus(a,b)        : bag = (LAMBDA t: a(t) + b(t))

    union(a,b)       : bag = (LAMBDA t: max(a(t),b(t))) 

    intersection(a,b): bag = (LAMBDA t: min(a(t),b(t)))

    % --------- some predicates over bags ------------

    member(x,b)        : bool = b(x) > 0

    empty?(b)          : bool = (FORALL x: b(x) = 0)

    nonempty_bag?(b)   : bool = NOT empty?(b)

    eqmult(x,a,b)      : bool = (a(x) = b(x))
     
    subbag?(a,b)       : bool = (FORALL x: a(x) <= b(x))

    proper_subbag?(a,b): bool = (FORALL x: a(x) < b(x))

    disjoint?(a, b)    : bool = empty?(intersection(a, b))

  % ---------- useful lemmas ----------

    emptybag_is_empty?    : LEMMA empty?(b) IFF b = emptybag

    delete_purge          : LEMMA n >= b(x) IMPLIES delete(x,b,n) = purge(x,b)

    insert_unique         : LEMMA insert(x,a) = insert(x,b) IMPLIES a = b

    insert_exchange       : LEMMA insert(x,insert(y,b)) = insert(y,insert(x,b))

    delete_insert         : LEMMA n > 0 IMPLIES
                                    (delete(x,insert(x,b),n) = delete(x,b,n-1))

    insert_delete         : LEMMA b(x) > 0 IMPLIES insert(x,delete(x,b,1)) = b 

    delete_insert_diff    : LEMMA x /= y IMPLIES
                              (delete(x,insert(y,b),n) = insert(y,delete(x,b,n)))

    decomposition         : LEMMA NOT empty?(b) IMPLIES 
                                    (EXISTS a,x: b = insert(x,a))

    bag_equality          : LEMMA a = b IFF (FORALL x: eqmult(x,a,b))

    subbag_empty          : LEMMA subbag?(emptybag,a)

    subbag_equality       : LEMMA a = b IFF subbag?(a,b) AND subbag?(b,a)

    subbag_trans          : LEMMA subbag?(a,b) AND subbag?(b,c) IMPLIES subbag?(a,c)

  % because of empty types the following is not provable -- look into it later 
  % proper_subbag_rew     : LEMMA proper_subbag?(a,b) IMPLIES subbag?(a,b) AND a /= b

    bag_plus_union        : LEMMA plus(union(a,b),intersection(a,b)) = plus(a,b) 
    
    bag_plus_comm         : LEMMA plus(a,b) = plus(b,a)   
     
    plus_emptybag         : LEMMA plus(emptybag,a) = a
    
    bag_plus_insert       : LEMMA plus(insert(x,a),b) = insert(x,plus(a,b))

    bag_distributive      : LEMMA intersection(a,union(b,c)) = 
                                    union(intersection(a,b),intersection(a,c))

    extract_subbag        : LEMMA subbag?(extract(x,a), a) 
    
    extract_disj          : LEMMA x /= y IMPLIES disjoint?(extract(x,a), extract(y,a))

    bag_disj_comm         : LEMMA disjoint?(a,b) = disjoint?(b,a)

    bag_union_comm        : LEMMA union(a,b) = union(b,a)

    bag_union_fix_pt      : LEMMA union(a,a) = a 


    bag_purge_extract       : LEMMA a = union(purge(x,a), extract(x,a))

    bag_disj_extract_perge  : LEMMA disjoint?(extract(x,a), purge(x,a))

    bag_extract_union_subbag: LEMMA x /= y IMPLIES subbag?(union(extract(x,a),extract(y,a)),a) 

    union_upper_bound       : LEMMA subbag?(a, c) and subbag?(b, c) IMPLIES 
                                      subbag?(union(a, b), c)

  END bags

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

  % Subtype TCC generated (at line 28, column 58) for  b(t) - n
      % expected type  nat
  delete_TCC1: OBLIGATION
    FORALL (x: T, b: bag, n: nat, t):
      b(t) >= n AND x = t IMPLIES b(t) - n >= 0;

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


body:
  bags_to_sets [T:TYPE]: THEORY
  %------------------------------------------------------------------------
  %
  % This theory defines a function bag_to_set that collapses a bag
  % to a set eliminating the count.
  %
  %    Authors:  Rick Butler               (NASA Langley)
  %              David Griffioen           (CWI Amsterdam and KUN)
  %              Lee Pike                  (NASA Langley)
  %------------------------------------------------------------------------

  BEGIN
    
    IMPORTING bags[T]
    
    t: VAR T
    A,B,b: VAR bag

    bag_to_set(b): set[T] = {t: T | b(t) > 0}

    strict_subbag?(A,B): bool = strict_subset?(bag_to_set(A), bag_to_set(B))

    insert_bag_lem       : LEMMA bag_to_set(insert(t, B)) = add(t,bag_to_set(B))

    purge_bag_lem        : LEMMA bag_to_set(purge(t, B)) = remove(t,bag_to_set(B))

    bag_union_lem        : LEMMA bag_to_set(union(A, B)) = 
                                   union(bag_to_set(A), bag_to_set(B))

    bag_intersection_lem : LEMMA bag_to_set(intersection(A,B)) = 
                                   intersection(bag_to_set(A),bag_to_set(B))

    subbag_lem           : LEMMA subbag?(A,B) IMPLIES 
                                   subset?(bag_to_set(A),bag_to_set(B))

    bag_to_set_emptybag  : LEMMA bag_to_set(emptybag) = emptyset

    empty_bts_bag        : LEMMA empty?(bag_to_set(b)) IMPLIES empty?(b)

    bag_intersection_commutative: LEMMA intersection(A,B) = intersection(B, A)

    bag_union_commutative: LEMMA union(A,B) = union(B, A)

    bag_plus_lem         : LEMMA bag_to_set(plus(A,B)) = 
                                   union(bag_to_set(A),bag_to_set(B))

    extract_empty_or_singlton_set: 
                         LEMMA singleton?(bag_to_set(extract(t,A))) OR
                                 empty?(bag_to_set(extract(t,A))) 

    extract_singleton  : LEMMA singleton?(bag_to_set(extract(t,A))) IMPLIES 
                                 singleton(t) = bag_to_set(extract(t,A))

    bag_disj_set       : LEMMA disjoint?(A,B) IMPLIES disjoint?(bag_to_set(A),bag_to_set(B))

    bag_set_dist_union : LEMMA bag_to_set(union(A,B)) = union(bag_to_set(A),bag_to_set(B)) 

    bag_non_empty      : LEMMA NOT empty?(A) IMPLIES nonempty?(bag_to_set(A))

  END bags_to_sets


body:
  bags_aux[T:TYPE]:THEORY
  %------------------------------------------------------------------------
  %
  %  Additional properties about bags  
  %
  %     Author: David Griffioen      (CWI Amsterdam and KUN)
  %
  %------------------------------------------------------------------------
  BEGIN


    IMPORTING bags[T], bags_to_sets[T]


    x,y,e: VAR T
    b:     VAR bag
    n,xn:  VAR nat
    p,q: VAR pred[T]

  %% ===== choose and rest for bags =====

    choose(b: (nonempty_bag?)):T = choose(bag_to_set(b))

    rest(b):bag = IF empty?(b) THEN b ELSE delete(choose(b),b,1) ENDIF

    choose_gt_zero:     LEMMA nonempty_bag?(b) => b(choose(b)) > 0 

    insert_choose_rest: LEMMA nonempty_bag?(b) => insert(choose(b),rest(b)) = b 

  %% ===== on filters =====
  % Definition of filter for bags, it takes a bag and a predicate and
  % returns the bag of those elements that satisfy the predicate.

    filter(b,p):bag   = (LAMBDA x: IF p(x) THEN b(x) ELSE 0 ENDIF)

    filter_emptybag:    THEOREM filter(emptybag,p) = emptybag

    filter_insert:      LEMMA filter(insert(x,b),p) = 
                                 IF p(x) THEN insert(x,filter(b,p)) 
                                         ELSE filter(b,p) ENDIF

    filter_delete:      LEMMA filter(delete(x,b,n),p) = delete(x,filter(b,p),n)

    filter_prop:        LEMMA (FORALL x: p(x) => q(x)) => 
                              subbag?(filter(b,p),filter(b,q))

  END bags_aux

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

  % Subtype TCC generated (at line 22, column 40) for  bag_to_set(b)
      % expected type  p: (nonempty?[T])
  choose_TCC1: OBLIGATION
    FORALL (b: (nonempty_bag?[T])): nonempty?[T](bag_to_set[T](b));

  % Subtype TCC generated (at line 24, column 55) for  b
      % expected type  (nonempty_bag?)
  rest_TCC1: OBLIGATION
    FORALL (b: bag[T]): NOT empty?(b) IMPLIES nonempty_bag?[T](b);


body:
  finite_bags[T: TYPE]: THEORY
  %------------------------------------------------------------------------
  %
  % This theory defines finite bags and its cardinality
  %
  %    Authors:  Rick Butler              (NASA Langley)
  %              David.Griffioen          (CWI Amsterdam and KUN)
  %              Lee Pike                 (NASA Langley)
  %------------------------------------------------------------------------
  BEGIN

     IMPORTING bags[T], 
               finite_sets@finite_sets_sum_real[T],
               finite_sets@finite_sets_inductions[T], bags_to_sets[T]

     x,y,t,e: VAR T
     b: VAR bag
     n,xn: VAR nat

     %%  bag_to_set(b): set[T] = {t: T | b(t) > 0}

     is_finite(b): bool = is_finite(bag_to_set(b)) 
     
     finite_bag: TYPE = {b: bag | is_finite(b)}

     nonempty_finite_bag: TYPE = {b: finite_bag | NOT empty?(b)}

     A,B,C: VAR finite_bag

     JUDGEMENT bag_to_set(B) HAS_TYPE finite_set 

  %  The card_TCC1: OBLIGATION relies on a JUDGEMENT in finite_sets_sum_real
  %  that is no longer firing.  Since it is unnamed it is difficult to fix it.


     card(B): nat = sum(bag_to_set(B),(LAMBDA t: B(t)))

     finite_bag          : THEOREM is_finite(B) IMPLIES is_finite(LAMBDA x: B(x) > 0)

     finite_emptybag     : THEOREM is_finite(emptybag[T]);

     finite_singleton_bag: THEOREM is_finite(singleton_bag(t))

     finite_insert       : THEOREM is_finite(insert(t, B))

     finite_purge        : THEOREM is_finite(purge(t, B))

     finite_delete       : THEOREM is_finite(delete[T](t, B, n))

     finite_bag_union    : THEOREM is_finite(union(A, B))

     finite_bag_intersection: THEOREM is_finite(intersection[T](A, B))

     finite_bag_plus     : LEMMA is_finite(plus(A,B))    

     finite_update       : LEMMA is_finite(B WITH [x := xn])

     finite_set          : THEOREM is_finite(bag_to_set(A))

     finite_extract      : THEOREM is_finite(extract(x,B)) 


    JUDGEMENT nonempty_finite_bag SUBTYPE_OF (nonempty_bag?[T])

    JUDGEMENT singleton_bag(x) HAS_TYPE finite_bag

    JUDGEMENT union(A,B), intersection(A,B), plus(A,B) 
                       HAS_TYPE finite_bag

    NA,NB: VAR nonempty_finite_bag
    JUDGEMENT union(A,NB), plus(A,NB) HAS_TYPE nonempty_finite_bag

    JUDGEMENT union(NA,B), plus(NA,B) HAS_TYPE nonempty_finite_bag

    JUDGEMENT insert(x,A)   HAS_TYPE nonempty_finite_bag

    JUDGEMENT purge(x,A)    HAS_TYPE finite_bag

    JUDGEMENT delete(x,A,n) HAS_TYPE finite_bag

    JUDGEMENT emptybag      HAS_TYPE finite_bag

    JUDGEMENT extract(x,A) HAS_TYPE finite_bag 

  %  ---------- Some Useful Lemmas ----------

     card_emptybag      : THEOREM card(emptybag[T]) = 0

     card_bag_empty?    : THEOREM (card(B) = 0) = empty?(B)
   
     card_singleton_bag : THEOREM card(singleton_bag(t)) = 1

     card_subbag?       : THEOREM subbag?(A,B) IMPLIES card(A) <= card(B)

     card_bag_particular: THEOREM card(B WITH [x := xn]) = card(B) - B(x) + xn  

     card_bag_delete    : LEMMA card(delete(e,B,n)) = card(B) - min(B(e),n)
   
     card_bag_insert    : LEMMA card(insert(x,B)) = card(B) + 1

     card_nonempty_bag? : LEMMA card(B) > 0 IFF nonempty_bag?(B)
   
     card_disj_intersection : LEMMA disjoint?(A,B) IMPLIES
                                      card(intersection(A,B)) = 0

     sum_bag_disj_union     : LEMMA disjoint?(A,B) IMPLIES
                                      sum(bag_to_set(A),(LAMBDA (t:T): union(A,B)(t)))
                                        = sum(bag_to_set(A), (LAMBDA (t:T): A(t)))

     card_extract           : LEMMA card(extract(x,A)) <= card(A)

     card_extract_bag       : LEMMA card(extract(x,A)) = A(x)

     card_disjoint_add      : LEMMA disjoint?(A,B) IMPLIES 
                                    card(union(A,B)) = card(A) + card(B)
    
     card_purge_extract     : LEMMA card(purge(x,A)) = card(A) - card(extract(x,A))

     card_union_extract_add : LEMMA x /= y IMPLIES 
                                    card(union(extract(x,A),extract(y,A))) = A(x) + A(y)

     card_union_extract     : LEMMA x /= y IMPLIES 
                                    card(union(extract(x,A),extract(y,A))) <= card(A)

     card_geq_count         : LEMMA A(x) <= card(A) 

     card_geq_count_add     : LEMMA x /= y IMPLIES A(x) + A(y) <= card(A)


  END finite_bags

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

  % Judgement subtype TCC generated (at line 30, column 13) for  bag_to_set(B)
      % expected type  finite_set[T]
  bag_to_set_TCC1: OBLIGATION FORALL (B): is_finite[T](bag_to_set[T](B));

  % Judgement subtype TCC generated (at line 63, column 12) for  x
      % expected type  (nonempty_bag?[T])
  subtype_TCC1: OBLIGATION
    FORALL (x: nonempty_finite_bag): nonempty_bag?[T](x);

  % Judgement subtype TCC generated (at line 65, column 12) for
      % singleton_bag(x)
      % expected type  finite_bag
  singleton_bag_TCC1: OBLIGATION FORALL (x): is_finite(singleton_bag[T](x));

  % Judgement subtype TCC generated (at line 67, column 12) for  union(A, B)
      % expected type  finite_bag
  union_TCC1: OBLIGATION FORALL (A, B): is_finite(union[T](A, B));

  % Judgement subtype TCC generated (at line 67, column 24) for
      % intersection(A, B)
      % expected type  finite_bag
  intersection_TCC1: OBLIGATION
    FORALL (A, B): is_finite(intersection[T](A, B));

  % Judgement subtype TCC generated (at line 67, column 43) for  plus(A, B)
      % expected type  finite_bag
  plus_TCC1: OBLIGATION FORALL (A, B): is_finite(plus[T](A, B));

  % Judgement subtype TCC generated (at line 71, column 12) for  union(A, NB)
      % expected type  nonempty_finite_bag
  union_TCC2: OBLIGATION FORALL (A, NB): NOT empty?[T](union[T](A, NB));

  % Judgement subtype TCC generated (at line 71, column 25) for  plus(A, NB)
      % expected type  nonempty_finite_bag
  plus_TCC2: OBLIGATION FORALL (A, NB): NOT empty?[T](plus[T](A, NB));

  % Judgement subtype TCC generated (at line 73, column 12) for  union(NA, B)
      % expected type  nonempty_finite_bag
  union_TCC3: OBLIGATION FORALL (B, NA): NOT empty?[T](union[T](NA, B));

  % Judgement subtype TCC generated (at line 73, column 25) for  plus(NA, B)
      % expected type  nonempty_finite_bag
  plus_TCC3: OBLIGATION FORALL (B, NA): NOT empty?[T](plus[T](NA, B));

  % Judgement subtype TCC generated (at line 75, column 12) for  insert(x, A)
      % expected type  nonempty_finite_bag
  insert_TCC1: OBLIGATION
    FORALL (A, x):
      is_finite(insert[T](x, A)) AND NOT empty?[T](insert[T](x, A));

  % Judgement subtype TCC generated (at line 77, column 12) for  purge(x, A)
      % expected type  finite_bag
  purge_TCC1: OBLIGATION FORALL (A, x): is_finite(purge[T](x, A));

  % Judgement subtype TCC generated (at line 79, column 12) for
      % delete(x, A, n)
      % expected type  finite_bag
  delete_TCC1: OBLIGATION FORALL (A, n, x): is_finite(delete[T](x, A, n));

  % Judgement subtype TCC generated (at line 81, column 12) for  emptybag
      % expected type  finite_bag
  emptybag_TCC1: OBLIGATION is_finite(emptybag[T]);

  % Judgement subtype TCC generated (at line 83, column 12) for  extract(x, A)
      % expected type  finite_bag
  extract_TCC1: OBLIGATION FORALL (A, x): is_finite(extract[T](x, A));

  % Subtype TCC generated (at line 95, column 37) for  B WITH [x := xn]
      % expected type  finite_bag
  card_bag_particular_TCC1: OBLIGATION
    FORALL (B: finite_bag, x: T, xn: nat): is_finite((B WITH [x := xn]));


body:
  finite_bags_aux[T: TYPE]: THEORY
  %-------------------------------------------------------------------------
  %
  % Additional properties of finite bags. 
  %
  %    Author: David Griffioen   (CWI Amsterdam and KUN)
  %
  %-------------------------------------------------------------------------
  BEGIN  

    IMPORTING finite_bags[T], bags_aux[T] 

    x,e:  VAR T
    b:    VAR finite_bag
    p:    VAR pred[T]
    n,xn: VAR nat

    finite_bag_rest: LEMMA is_finite(rest[T](b))

    JUDGEMENT rest(b) HAS_TYPE finite_bag

    card_bag_rest      : LEMMA nonempty_bag?(b) IMPLIES
  				 card(b) = card(rest(b)) + 1 

    %% ===== on finite bags and filters =====

    finite_filter      : THEOREM is_finite(filter(b,p))

    JUDGEMENT filter(b,p) HAS_TYPE finite_bag

    card_filter_insert: LEMMA card(filter(insert(x,b),p)) =
                                 card(filter(b,p)) + IF p(x) THEN 1 ELSE 0 ENDIF

    card_filter_delete: LEMMA card(filter(delete(x,b,n),p)) =
                                 card(filter(b,p)) - IF p(x) THEN min(b(x),n) 
                                                      ELSE 0 ENDIF

  END finite_bags_aux

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

  % Judgement subtype TCC generated (at line 20, column 12) for  rest(b)
      % expected type  finite_bag[T]
  rest_TCC1: OBLIGATION FORALL (b): is_finite[T](rest[T](b));

  % Judgement subtype TCC generated (at line 29, column 12) for  filter(b, p)
      % expected type  finite_bag[T]
  filter_TCC1: OBLIGATION FORALL (b, p): is_finite[T](filter[T](b, p));


body:
  finite_bags_inductions[T: TYPE]: THEORY
  %-------------------------------------------------------------------------
  %
  %  Induction scheme for finite bags, plural in name of this theory is 
  %  misleading at this moment.
  %
  %    Author:  David Griffioen.      (CWI Amsterdam and KUN)
  %
  %-------------------------------------------------------------------------
  BEGIN

    IMPORTING finite_bags_aux[T]

    x:  VAR T
    b:  VAR finite_bag
    pb: VAR pred[finite_bag[T]]
    n:  VAR nat

    cardinal_induction: LEMMA
       (FORALL b : pb(b)) IFF (FORALL n, b : card(b) = n IMPLIES pb(b)) 

    finite_bag_induction: THEOREM
            (FORALL pb: (pb(emptybag[T]) AND 
                        (FORALL x,b: pb(b) IMPLIES pb(insert(x,b))))
                        IMPLIES (FORALL b: pb(b)))

  END finite_bags_inductions


body:
  %----------------------------------------------------------------------------
  % Lee Pike 
  % lee.s.pike@nasa.gov
  % Formal Methods Group, NASA Langley Research Center
  %
  % PVS Version 3.1
  %
  % PURPOSE: 
  % Define the minimum and maximum for ordered finite bags.
  %----------------------------------------------------------------------------

  finite_bags_minmax[T: NONEMPTY_TYPE, 
                     leq: (total_order?[T])]: THEORY

  BEGIN 

  IMPORTING
    finite_bags[T],
    finite_sets@finite_sets_minmax[T, leq],
    finite_bags_inductions[T]

    D              : VAR nonempty_finite_bag

    max(D)         : T = max(bag_to_set(D))

    min(D)         : T = min(bag_to_set(D)) 

    max_member     : LEMMA member(max(D), D)

    min_member     : LEMMA member(min(D), D)

  END finite_bags_minmax

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

  % Subtype TCC generated (at line 24, column 27) for  bag_to_set(D)
      % expected type  SS: non_empty_finite_set[T]
  max_TCC1: OBLIGATION
    FORALL (D: nonempty_finite_bag[T]): NOT empty?[T](bag_to_set[T](D));


body:
  finite_bags_lems[T: TYPE]: THEORY
  %------------------------------------------------------------------------
  %
  % This theory establishes some more useful lemmas about finite bags
  %
  %    Authors:  Rick Butler               NASA Langley
  %              David Griffioen           (CWI Amsterdam and KUN)
  %              Lee Pike                  NASA Langley
  %------------------------------------------------------------------------
  BEGIN

     IMPORTING finite_bags[T], finite_bags_inductions[T]

     A,B : VAR finite_bag
     x   : VAR T

     card_bag_plus       : THEOREM card(plus(A,B)) = card(A) + card(B)

     card_bag_union      : THEOREM card(union(A,B)) = card(A) + card(B) -
                                                 card(intersection(A,B))
   
     card_bag_disj_union : THEOREM disjoint?(A,B) IMPLIES 
                                      card(union(A,B)) = card(A) + card(B)

     card_subbag_strict  : THEOREM subbag?(A,B) AND member(x, B) AND NOT member(x, A) IMPLIES
                                     card(A) < card(B)

     card_subbag_strict2 : THEOREM subbag?(A,B) AND A(x) < B(x) IMPLIES
                                     card(A) < card(B)
    

  END finite_bags_lems


body:
  %------------------------------------------------------------------------------
  % Lee Pike 
  % lee.s.pike@nasa.gov
  % Formal Methods Group, NASA Langley Research Center
  %
  % PVS Version 3.1
  %
  % PURPOSE: 
  % This theory presents two functions, l_filter and 
  % u_filter, and some of their properties.  The 
  % functions take a linearly-ordered bag and a value and 
  % return a bag with all the elements larger and smaller,
  % respectively, filtered out.  
  %------------------------------------------------------------------------------

  bag_filters[T: NONEMPTY_TYPE, 
              leq: (total_order?[T])]: 
  THEORY

  BEGIN 

  IMPORTING
    finite_bags[T],
    finite_bags_minmax[T, leq],
    finite_bags_lems[T],
    finite_sets@finite_sets_minmax[T, leq],
    finite_bags_inductions[T],
    finite_sets@finite_sets_pred[T]

  %  str_prelude_aux           %% same as finite_sets_pred_aux in sets_aux


    X        : VAR bag
    A,B,C    : VAR finite_bag
    D        : VAR nonempty_finite_bag
    x, i, v  : VAR T  

    %------ functions ----------------------

    l_filter(X, v): bag =  LAMBDA i: 
                             IF leq(i, v) THEN X(i) 
                             ELSE 0 ENDIF

    u_filter(X, v): bag =  LAMBDA i: 
                             IF leq(v, i) THEN X(i)
                             ELSE 0 ENDIF

    %------ propositions -------------------

    finite_l_filter      : LEMMA is_finite(A) IMPLIES is_finite(l_filter(A, i))

    finite_u_filter      : LEMMA is_finite(A) IMPLIES is_finite(u_filter(A, i))

    JUDGEMENT l_filter(A, i)  HAS_TYPE finite_bag

    JUDGEMENT u_filter(A, i)  HAS_TYPE finite_bag

    l_filter_extract     : LEMMA subbag?(extract(v, X), l_filter(X, v))

    u_filter_extract     : LEMMA subbag?(extract(v, X), u_filter(X, v))

    l_filter_singleton   : LEMMA l_filter(singleton_bag(v), v) = singleton_bag(v)

    u_filter_singleton   : LEMMA u_filter(singleton_bag(v), v) = singleton_bag(v)

    l_filter_subbag      : LEMMA subbag?(l_filter(X, v), X)

    u_filter_subbag      : LEMMA subbag?(u_filter(X, v), X)

    l_filter_orders      : LEMMA leq(i, v) IMPLIES 
                                      subbag?(l_filter(X, i), l_filter(X, v))

    u_filter_orders      : LEMMA leq(v, i) IMPLIES 
                                      subbag?(u_filter(X, i), u_filter(X, v))

    l_filter_orders_2    : LEMMA (leq(i, v) AND i /= v ) IMPLIES 
                                      subbag?(l_filter(X, i), 
                                              purge(v, l_filter(X, v)))

    u_filter_orders_2    : LEMMA (leq(v, i) AND i /= v ) IMPLIES 
                                      subbag?(u_filter(X, i), 
                                              purge(v, u_filter(X, v)))

    l_filter_insert_assoc: LEMMA l_filter(insert(i, X), i) 
                                    = insert(i, l_filter(X, i))

    u_filter_insert_assoc: LEMMA u_filter(insert(i, X), i) = 
                                      insert(i, u_filter(X, i))

    l_filter_insert      : LEMMA subbag?(l_filter(X,v), l_filter(insert(i,X), v))

    u_filter_insert      : LEMMA subbag?(u_filter(X,v), u_filter(insert(i,X), v))

    l_filter_purge       : LEMMA (leq(i, v) AND i /= v) IMPLIES 
                                     subbag?(l_filter(X, i), purge(v, X))

    u_filter_purge       : LEMMA (leq(i, v) AND i /= v) IMPLIES 
                                     subbag?(u_filter(X, v), purge(i, X))

    l_u_diff_disj        : LEMMA (leq(v, i) AND i /= v) IMPLIES
                                     disjoint?(l_filter(X, v), u_filter(X, i))

    l_u_fullset          : LEMMA union(purge(i, l_filter(X, i)), 
                                    u_filter(X, i)) = X

    l_u_fullset2         : LEMMA union(purge(i, u_filter(X, i)), 
                                    l_filter(X, i)) = X

    l_u_diff             : LEMMA card(l_filter(A, i)) + card(u_filter(A, i)) 
                                    = card(A) + A(i)

    subset_diff_elements : LEMMA (leq(v, i) AND i /= v) IMPLIES
                                     subbag?(union(l_filter(X, v), 
                                                u_filter(X, i)), X)

    card_diff_elements   : LEMMA (leq(v, i) AND i /= v) IMPLIES 
                                     card(l_filter(A, v)) + card(u_filter(A, i)) 
                                        <= card(A)

    card_plus            : LEMMA card(A) + card(B) = 
                                     card(union(A, B)) + card(intersection(A,B))

    pigeonhole           : LEMMA card(A) + card(B) > card(union(A,B)) IMPLIES
                                     EXISTS x: member(x,A) AND member(x,B)

    maj_pigeonhole       : LEMMA 2 * card(A) > card(C) AND 
                                     subbag?(A,C) AND
                                     2 * card(B) >= card(C) AND 
                                     subbag?(B,C) IMPLIES
                                       EXISTS x: member(x,A) AND member(x,B)

    l_filter_nonempty    : LEMMA 2 * card(l_filter(A, i)) > card(A) IMPLIES
                                      NOT empty?(l_filter(A, i)) 

    u_filter_nonempty    : LEMMA 2 * card(u_filter(A, i)) > card(A) IMPLIES
                                      NOT empty?(u_filter(A, i)) 

    l_filter_max         : LEMMA NOT empty?(l_filter(A, i)) IMPLIES 
                                      l_filter(A, i) = 
                                        l_filter(A, max(l_filter(A, i)))
      
    u_filter_min         : LEMMA NOT empty?(u_filter(A, i)) IMPLIES 
                                      u_filter(A, i) = 
                                        u_filter(A, min(u_filter(A, i)))

    l_filter_max_purge   : LEMMA NOT empty?(purge(i, l_filter(A, i))) IMPLIES
                                      l_filter(A, max(purge(i, l_filter(A, i))))
                                        = purge(i, l_filter(A, i))

    u_filter_min_purge   : LEMMA NOT empty?(purge(i, u_filter(A, i))) IMPLIES
                                      u_filter(A, min(purge(i, u_filter(A, i))))
                                        = purge(i, u_filter(A, i))

    filter_exists        :  LEMMA (EXISTS i: 2 * card(l_filter(A, i)) > card(A) 
                                        AND 2 * card(u_filter(A, i)) >= card(A))
                                  OR empty?(A)

  END bag_filters

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

  % Judgement subtype TCC generated (at line 54, column 12) for  l_filter(A, i)
      % expected type  finite_bag[T]
  l_filter_TCC1: OBLIGATION FORALL (A, i): is_finite[T](l_filter(A, i));

  % Judgement subtype TCC generated (at line 56, column 12) for  u_filter(A, i)
      % expected type  finite_bag[T]
  u_filter_TCC1: OBLIGATION FORALL (A, i): is_finite[T](u_filter(A, i));


body:
  %------------------------------------------------------------------------------
  % Lee Pike 
  % lee.s.pike@nasa.gov
  % Formal Methods Group, NASA Langley Research Center
  %
  % PVS Version 3.1
  %
  % PURPOSE: 
  % To model a middle-value selection over bags.
  %------------------------------------------------------------------------------

  middle_value_select[T: NONEMPTY_TYPE, 
                    leq: (total_order?[T])]: THEORY

  BEGIN 

    IMPORTING bag_filters[T, leq]

    A                 : VAR finite_bag
    i, v              : VAR T  

    mid_val?(A)(v)    : bool = 2 * card(l_filter(A, v)) > card(A) AND
                               2 * card(u_filter(A, v)) >= card(A) 

    mid_val(A)        : T = epsilon(mid_val?(A))

    mid_val_singleton : LEMMA NOT empty?(A) IMPLIES singleton?(mid_val?(A))

  END middle_value_select


body:
  %------------------------------------------------------------------------------
  % Lee Pike 
  % lee.s.pike@nasa.gov
  % Formal Methods Group, NASA Langley Research Center
  %
  % PVS Version 3.1
  %
  % PURPOSE: 
  % To model a majority vote over bags.
  %------------------------------------------------------------------------------
  majority_vote[T: NONEMPTY_TYPE]: THEORY

  BEGIN 

    IMPORTING finite_bags[T]

    A           : VAR finite_bag
    i, v        : VAR T  

    no_majority : T

    maj?(A)(v)  : bool = 2 * A(v) > card(A)

    maj(A)      : T = IF empty?(maj?(A)) 
                      THEN no_majority 
                      ELSE epsilon(maj?(A)) ENDIF 


    maj_size           : LEMMA 2 * A(v) > card(A) IMPLIES 
                                      2 * card(purge(v, A)) < card(A)

    maj_single_or_empty: LEMMA singleton?(maj?(A)) OR empty?(maj?(A))

    maj_unique         : LEMMA maj?(A)(v) IMPLIES maj(A) = v

    maj_pigeonhole     : LEMMA maj?(A)(v) AND maj?(A)(i) IMPLIES v = i

    maj_is_extraction  : LEMMA maj?(A)(v) IMPLIES  
                                      maj?(A) = bag_to_set(extract(v, A))


  END majority_vote


body:
  %------------------------------------------------------------------------------
  % Lee Pike 
  % lee.s.pike@nasa.gov
  % Formal Methods Group, NASA Langley Research Center
  %
  % PVS Version 3.1
  %
  % PURPOSE: 
  % To prove the equivalence of a majority vote and a middle value
  % selection over a bag in the case that a majority value exists.
  %------------------------------------------------------------------------------

  fault_masking_vote[T: NONEMPTY_TYPE, 
                     leq: (total_order?[T])]: THEORY

  BEGIN 

    IMPORTING  majority_vote[T],
               middle_value_select[T, leq]

    A              : VAR finite_bag

    IMPORTING bag_filters[T,leq]   %% RWB

    mid_val_is_maj : LEMMA maj(A) /= no_majority IMPLIES
                              mid_val(A) = maj(A)

  END fault_masking_vote


body:
  top_bags: THEORY
  %-------------------------------------------------------------------------
  %
  %  Theory of bags and finite bags.   Version 2.0       2/23/04
  %
  %    Authors: Rick 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
  %
  %    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 tghe minimum and maximum of a finite
  %                               ordered bag.
  %------------------------------------------------------------------------
  BEGIN

      IMPORTING   bags_aux, bags_to_sets, finite_bags_lems, 
                  finite_bags_aux, finite_bags_inductions, 
                  fault_masking_vote, finite_bags_minmax
   

  END top_bags


body:
  seq_pigeon[T: TYPE, (IMPORTING finite_sets@finite_sets_below, 
                                    finite_sets@finite_sets_card_eq)
                S: finite_set[T]]: THEORY

  BEGIN

     w: VAR finseq[(S)]

     seq_pigeon_lem: LEMMA 
            (FORALL (i,j: below(length(w))): i /= j IMPLIES w(i) /= w(j)) IMPLIES
                length(w) <= card(S)

     seq_pigeon_hole: THEOREM length(w) > card(S) IMPLIES 
                        (EXISTS (i,j: below(length(w))): i /= j AND w(i) = w(j))

  END seq_pigeon


body:
  set2seq[T: TYPE]: THEORY
  %----------------------------------------------------------------------------
  %
  % Utility functions for converting from sets to sequences
  %
  % Author: Kristin Y. Rozier
  %----------------------------------------------------------------------------
  BEGIN

     IMPORTING finite_sets@finite_sets_inductions[T]

     fs: VAR finite_sequence[T]
     x : VAR T

     #(t:T): finite_sequence[T] =  (# length := 1,
                                      seq := (LAMBDA (x: below[1]): t) #)

     gen_seq_lem: LEMMA #(x)(0) = x

     set2seq(S: finite_set[T]):  RECURSIVE finite_sequence[T] =
          IF empty?[T](S) THEN empty_seq
          ELSE #(choose[T](S)) o set2seq(rest[T](S)) 
          ENDIF 
        MEASURE card[T](S) 

     S: VAR finite_set[T]

     set2seq_length: LEMMA length(set2seq(S)) = card(S)

     set2seq_lem: LEMMA LET fs = set2seq(S) IN
                            FORALL (ii: below(length(fs))): S(fs(ii))

     set2seq_exists: LEMMA LET fs = set2seq(S) IN
                          S(x) IMPLIES
                              EXISTS (ii: below(length(fs))): fs(ii) = x

     AUTO_REWRITE+ set2seq_length

     set2seq_neq   : LEMMA LET fs = set2seq(S) IN
                       FORALL (ii,jj: below(length(fs))): 
                                 ii /= jj IMPLIES fs(ii) /= fs(jj)
   
  END set2seq

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

  % Subtype TCC generated (at line 18, column 27) for  0
      % expected type  below[length( #(x))]
  gen_seq_lem_TCC1: OBLIGATION FORALL (x: T): 0 < length( #(x));

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

  % Termination TCC generated (at line 22, column 31) for  set2seq(rest[T](S))
  set2seq_TCC2: OBLIGATION
    FORALL (S: finite_set[T]):
      NOT empty?[T](S) IMPLIES card[T](rest[T](S)) < card[T](S);


body:
  %%----------------------------------------------------------------------------
  %% Authors         : Andre Luiz Galdino 
  %%                   Universidade Federal de Goiás - Brasil
  %%
  %%                         and 
  %%
  %%                   Mauricio Ayala Rincon  
  %%                   Universidade de Brasília - Brasil  
  %%                   
  %%----------------------------------------------------------------------------


  seq_extras[T: TYPE]: THEORY
    BEGIN

     IMPORTING finite_sequences[T],
               finite_sets@finite_sets_inductions[T]

                     i, n: VAR nat
                        j: VAR int
                     x, y: VAR T
               seq, seq1, 
         seq2, seq3, seq4: VAR finseq

            not_empty_seq: TYPE = {seq: finseq | length(seq) /= 0}
                    
                fs_len(n): TYPE = {seq: finseq | length(seq) = n}


  %%%%%%%%%%%% Definition: Elements of sequences %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


    first(seq: not_empty_seq): T = seq(0)

    last(seq: not_empty_seq): T = seq(seq`length - 1)

    rest(seq): finseq = IF seq`length = 0 
                        THEN seq
                        ELSE ^(seq,(1, seq`length - 1))
                        ENDIF

    delete(seq, (n: below[length(seq)])): finseq =
      (IF seq`length = 0
       THEN 
         seq
       ELSE
         (# length := seq`length - 1,
               seq := (LAMBDA (i: below[seq`length - 1]):
                                 (IF i < n THEN seq(i)
                                  ELSE seq(i + 1) 
                                  ENDIF)) #)
          ENDIF)



    insert?(x, seq, (n: upto[length(seq)])): finseq =
            (# length := seq`length + 1,
                  seq := (LAMBDA (i: below[seq`length + 1]):
                              (IF i < n THEN seq(i)
                               ELSIF i = n THEN x
                               ELSE seq(i - 1) ENDIF)) #)


    add_first(x, seq): finseq = insert?(x, seq, 0)

    add_last(seq, x): finseq = insert?(x, seq, length(seq))

  %%%%%%%%%%%% Definition: replace x in a seq %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


    replace(x, seq, (n: below[length(seq)])): finseq = 
          (IF seq`length = 0 THEN seq
           ELSE
            (# length := seq`length,
                  seq := (LAMBDA (i: below[seq`length]):
                              (IF i < n THEN seq(i)
                               ELSIF i = n THEN x
                               ELSE seq(i) ENDIF)) #)
           ENDIF)


  %%%%%%%%%%%% Definition: replace seq1 in a seq2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%


     replace_seq(seq1, seq2): finseq = 
          (IF seq2`length = 0 THEN seq2
           ELSE
            (# length := seq2`length,
                  seq := (LAMBDA (i: below[seq2`length]):
                              (IF i < seq1`length
                               THEN seq1(i)
                               ELSE seq2(i) ENDIF)) #)
           ENDIF);

  %%%%%%%%%%%% Equivatent sequences %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

   different_elements(seq): bool = 
             FORALL (i, j: below[seq`length]): 
                   i /= j => seq(i) /= seq(j)

   equivalent(seq1, seq2): bool = 
                           seq1`length = seq2`length &
                           different_elements(seq1)   &
                           different_elements(seq2)   &
                           FORALL (i: below[seq1`length]):
                             EXISTS (j: below[seq2`length]): seq1(i) = seq2(j)

  %%%%%% Utility functions for converting from sets and sequences           %%%

  IMPORTING set2seq[T] 

  %%%%%%%%%%%% Properties %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   

    empty_0: LEMMA length(seq) = 0 <=> seq = empty_seq

    empty_o_seq: LEMMA empty_seq o seq = seq

    seq_o_empty: LEMMA seq o empty_seq = seq

    length_rest: LEMMA seq`length /= 0 IMPLIES length(rest(seq)) < length(seq)

    length_delete: LEMMA seq`length /= 0 IMPLIES
                            length(delete(seq, length(seq) - 1)) < length(seq)

    seq_empty: LEMMA seq1 o seq2 = empty_seq IMPLIES 
                                           length(seq1) = 0 AND length(seq2) = 0

    seq_first_rest: LEMMA seq`length /= 0 IMPLIES 
                           seq = add_first(first(seq), rest(seq))

    seq_first_rest_1: LEMMA seq`length /= 0 IMPLIES 
                           seq = #(first(seq)) o rest(seq)
   
    add_first_empty_seq: LEMMA  add_first(x, empty_seq) = #(x)

    
    length_rest_0: LEMMA seq`length /= 0 AND length(rest(seq)) = 0 
                         IFF  length(seq) = 1

    rest_add_first: LEMMA rest(add_first(x, seq)) = seq

    first_add: LEMMA first(add_first(x,seq)) = x

    nth_add_first: LEMMA FORALL (i: below[seq`length + 1]):
                        IF i = 0 
                        THEN add_first(x, seq)(i) = x 
                        ELSE add_first(x, seq)(i) = seq(i - 1)
                        ENDIF
   
    first_add_last: LEMMA seq`length /= 0 IMPLIES
                              first(add_last(seq, x)) = first(seq)

    rest_add_last: LEMMA seq`length /= 0 IMPLIES
                             rest(add_last(seq, x)) = add_last(rest(seq), x)

    add_first_last_commute:LEMMA 
                  add_first(x, add_last(seq, y)) = add_last(add_first(x, seq), y)

    add_first_last: LEMMA seq`length /= 0 IMPLIES
           add_first(first(seq), add_last(rest(seq), x)) = add_last(seq, x)

    
    add_last_delete: LEMMA seq`length /= 0 IMPLIES
                        seq = add_last(delete(seq, seq`length - 1), last(seq))

    add_last_delete_is_o: LEMMA seq`length /= 0 IMPLIES
       add_last(delete(seq, seq`length - 1), last(seq)) =
                          delete(seq, seq`length - 1)o#(seq(seq`length - 1))


    nth_add_last: LEMMA FORALL (i: below[seq`length + 1]):
                        IF i =  seq`length
                        THEN add_last(seq, x)(i) = x 
                        ELSE add_last(seq, x)(i) = seq(i)
                        ENDIF

   
    add_first_compo: LEMMA  add_first(x, seq2) o seq3 = add_first(x, seq2 o seq3)


    first_compo: LEMMA seq1`length /= 0 IMPLIES first(seq1 o seq2) = first(seq1)

   
    rest_compo: LEMMA seq1`length /= 0 IMPLIES 
                                           rest(seq1 o seq2) = rest(seq1) o seq2

    rest_pos: LEMMA rest(seq)`length /= 0 IMPLIES 
                FORALL (i: below[length(seq) - 1]): seq(i + 1) = rest(seq)(i)


    delete_is_empty: LEMMA seq`length = 1  IMPLIES
                           delete(seq, 0) = empty_seq


    delete_pos: LEMMA seq`length /= 0  IMPLIES
     FORALL (i: below[length(seq) - 1]): seq(i) = delete(seq, length(seq) - 1)(i)



    insert_delete: LEMMA seq`length /= 0 IMPLIES
                          FORALL (n: below[seq`length]): 
                                        insert?(seq(n), delete(seq, n), n) = seq

    
   add_first_delete: LEMMA seq`length /= 0 IMPLIES
      FORALL (n: below[seq`length]): n /= 0 
          => add_first(seq(0), rest(delete(seq, n))) = delete(seq, n)
                                       
   delete_rest: LEMMA FORALL (n: below[seq`length]): 
                        IF n = 0
                        THEN
                          delete(seq, 0) = rest(seq)
                        ELSE
                          delete(rest(seq), n - 1) = rest(delete(seq, n))
                        ENDIF


   first_equal: LEMMA add_first(x, seq1) = add_first(y, seq2) IMPLIES 
                                                           x = y AND seq1 = seq2

                                                      
   nth_x: LEMMA 
           FORALL (n: below[length(seq)]): replace(x, seq, n)(n) = x

   replace_nth: LEMMA 
           FORALL (n: below[length(seq)]):replace(seq(n), seq, n) = seq

   replace_n2: LEMMA length(seq) /= 0 IMPLIES FORALL (n: below[length(seq)]): 
                          replace(x, replace(y, seq, n), n) = replace(x, seq, n)

   delete_equivalent: LEMMA  
           FORALL (i: below[seq1`length]), (j: below[seq2`length]):
              equivalent(seq1, seq2) & 
              seq1(i) = seq2(j) 
                         =>
                  equivalent(delete(seq1, i), delete(seq2, j))


   equal_prefix : LEMMA
      seq o seq1 = seq o seq2 IMPLIES seq1 = seq2

   o_equals_o : LEMMA
      seq1 o seq2 = seq3 o seq4 AND length(seq1) = length(seq3)
       IMPLIES seq1 = seq3

   o_length_o : LEMMA
      seq1 o seq2 = seq3 o seq4 AND length(seq1) < length(seq3)
         IMPLIES EXISTS seq: seq3 = seq1 o seq

   add_last_is_o : LEMMA
      add_last(seq, x) = seq o #(x)

   add_first_is_o : LEMMA
      add_first(x, seq) = #(x) o seq
    
  END seq_extras

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

  % Subtype TCC generated (at line 33, column 37) for  0
      % expected type  below[length(seq)]
  first_TCC1: OBLIGATION FORALL (seq: not_empty_seq): 0 < length(seq);

  % Subtype TCC generated (at line 35, column 36) for  seq`length - 1
      % expected type  below[length(seq)]
  last_TCC1: OBLIGATION
    FORALL (seq: not_empty_seq):
      seq`length - 1 >= 0 AND seq`length - 1 < length(seq);

  % Subtype TCC generated (at line 39, column 37) for  seq`length - 1
      % expected type  nat
  rest_TCC1: OBLIGATION
    FORALL (seq: finseq[T]): NOT seq`length = 0 IMPLIES seq`length - 1 >= 0;

  % Subtype TCC generated (at line 49, column 50) for  i
      % expected type  below[length(seq)]
  delete_TCC1: OBLIGATION
    FORALL (seq: finseq[T], (n: below[length(seq)])):
      NOT seq`length = 0 IMPLIES
       (FORALL (i: below[seq`length - 1]): i < n IMPLIES i < length(seq));

  % Subtype TCC generated (at line 50, column 41) for  i + 1
      % expected type  below[length(seq)]
  delete_TCC2: OBLIGATION
    FORALL (seq: finseq[T], (n: below[length(seq)])):
      NOT seq`length = 0 IMPLIES
       (FORALL (i: below[seq`length - 1]):
          NOT i < n IMPLIES i + 1 < length(seq));

  % Subtype TCC generated (at line 59, column 47) for  i
      % expected type  below[length(seq)]
  insert?_TCC1: OBLIGATION
    FORALL (x: T, seq: finseq[T], (n: upto[length(seq)]),
            i: below[seq`length + 1]):
      i < n IMPLIES i < length(seq);

  % Subtype TCC generated (at line 61, column 38) for  i - 1
      % expected type  below[length(seq)]
  insert?_TCC2: OBLIGATION
    FORALL (x: T, seq: finseq[T], (n: upto[length(seq)]),
            i: below[seq`length + 1]):
      NOT i = n AND NOT i < n IMPLIES i - 1 >= 0 AND i - 1 < length(seq);

  % Subtype TCC generated (at line 64, column 46) for  0
      % expected type  upto[length(seq)]
  add_first_TCC1: OBLIGATION FORALL (x: T, seq: finseq[T]): 0 <= length(seq);

  % Subtype TCC generated (at line 66, column 45) for  length(seq)
      % expected type  upto[length(seq)]
  add_last_TCC1: OBLIGATION
    FORALL (seq: finseq[T], x: T): length(seq) <= length(seq);

  % Subtype TCC generated (at line 124, column 45) for  length(seq) - 1
      % expected type  below[length(seq)]
  length_delete_TCC1: OBLIGATION
    FORALL (seq: finseq[T]):
      seq`length /= 0 IMPLIES
       length(seq) - 1 >= 0 AND length(seq) - 1 < length(seq);

  % Subtype TCC generated (at line 143, column 25) for  add_first(x, seq)
      % expected type  not_empty_seq
  first_add_TCC1: OBLIGATION
    FORALL (seq: finseq[T], x: T): length(add_first(x, seq)) /= 0;

  % Subtype TCC generated (at line 147, column 45) for  i
      % expected type  below[length(add_first(x, seq))]
  nth_add_first_TCC1: OBLIGATION
    FORALL (seq: finseq[T], x: T, i: below[1 + seq`length]):
      i = 0 IMPLIES i < length(add_first(x, seq));

  % Subtype TCC generated (at line 148, column 45) for  i
      % expected type  below[length(add_first(x, seq))]
  nth_add_first_TCC2: OBLIGATION
    FORALL (seq: finseq[T], x: T, i: below[1 + seq`length]):
      NOT i = 0 IMPLIES i < length(add_first(x, seq));

  % Subtype TCC generated (at line 148, column 54) for  i - 1
      % expected type  below[length(seq)]
  nth_add_first_TCC3: OBLIGATION
    FORALL (seq: finseq[T], i: below[1 + seq`length]):
      NOT i = 0 IMPLIES i - 1 >= 0 AND i - 1 < length(seq);

  % Subtype TCC generated (at line 152, column 34) for  add_last(seq, x)
      % expected type  not_empty_seq
  first_add_last_TCC1: OBLIGATION
    FORALL (seq: finseq[T], x: T):
      seq`length /= 0 IMPLIES length(add_last(seq, x)) /= 0;

  % Subtype TCC generated (at line 174, column 44) for  i
      % expected type  below[length(add_last(seq, x))]
  nth_add_last_TCC1: OBLIGATION
    FORALL (seq: finseq[T], x: T, i: below[1 + seq`length]):
      i = seq`length IMPLIES i < length(add_last(seq, x));

  % Subtype TCC generated (at line 175, column 44) for  i
      % expected type  below[length(add_last(seq, x))]
  nth_add_last_TCC2: OBLIGATION
    FORALL (seq: finseq[T], x: T, i: below[1 + seq`length]):
      NOT i = seq`length IMPLIES i < length(add_last(seq, x));

  % Subtype TCC generated (at line 175, column 53) for  i
      % expected type  below[length(seq)]
  nth_add_last_TCC3: OBLIGATION
    FORALL (seq: finseq[T], i: below[1 + seq`length]):
      NOT i = seq`length IMPLIES i < length(seq);

  % Subtype TCC generated (at line 182, column 52) for  seq1 o seq2
      % expected type  not_empty_seq
  first_compo_TCC1: OBLIGATION
    FORALL (seq1, seq2: finseq[T]):
      seq1`length /= 0 IMPLIES length(o[T](seq1, seq2)) /= 0;

  % Subtype TCC generated (at line 189, column 31) for  length(seq) - 1
      % expected type  nat
  rest_pos_TCC1: OBLIGATION
    FORALL (seq: finseq[T]):
      rest(seq)`length /= 0 IMPLIES length(seq) - 1 >= 0;

  % Subtype TCC generated (at line 189, column 54) for  i + 1
      % expected type  below[length(seq)]
  rest_pos_TCC2: OBLIGATION
    FORALL (seq: finseq[T]):
      rest(seq)`length /= 0 IMPLIES
       (FORALL (i: below[length(seq) - 1]): i + 1 < length(seq));

  % Subtype TCC generated (at line 189, column 73) for  i
      % expected type  below[length(rest(seq))]
  rest_pos_TCC3: OBLIGATION
    FORALL (seq: finseq[T]):
      rest(seq)`length /= 0 IMPLIES
       (FORALL (i: below[length(seq) - 1]): i < length(rest(seq)));

  % Subtype TCC generated (at line 193, column 37) for  0
      % expected type  below[length(seq)]
  delete_is_empty_TCC1: OBLIGATION
    FORALL (seq: finseq[T]): seq`length = 1 IMPLIES 0 < length(seq);

  % Subtype TCC generated (at line 197, column 43) for  i
      % expected type  below[length(seq)]
  delete_pos_TCC1: OBLIGATION
    FORALL (seq: finseq[T]):
      seq`length /= 0 IMPLIES
       (FORALL (i: below[length(seq) - 1]): i < length(seq));

  % Subtype TCC generated (at line 197, column 77) for  i
      % expected type  below[length(delete(seq, length(seq) - 1))]
  delete_pos_TCC2: OBLIGATION
    FORALL (seq: finseq[T]):
      seq`length /= 0 IMPLIES
       (FORALL (i: below[length(seq) - 1]):
          i < length(delete(seq, length(seq) - 1)));

  % Subtype TCC generated (at line 203, column 70) for  n
      % expected type  upto[length(delete(seq, n))]
  insert_delete_TCC1: OBLIGATION
    FORALL (seq: finseq[T]):
      seq`length /= 0 IMPLIES
       (FORALL (n: below[seq`length]): n <= length(delete(seq, n)));

  % Subtype TCC generated (at line 208, column 25) for  0
      % expected type  below[length(seq)]
  add_first_delete_TCC1: OBLIGATION
    FORALL (seq: finseq[T]):
      seq`length /= 0 IMPLIES
       (FORALL (n: below[seq`length]): n /= 0 IMPLIES 0 < length(seq));

  % Subtype TCC generated (at line 213, column 36) for  0
      % expected type  below[length(seq)]
  delete_rest_TCC1: OBLIGATION
    FORALL (seq: finseq[T], n: below[seq`length]):
      n = 0 IMPLIES 0 < length(seq);

  % Subtype TCC generated (at line 215, column 42) for  n - 1
      % expected type  below[length(rest(seq))]
  delete_rest_TCC2: OBLIGATION
    FORALL (seq: finseq[T], n: below[seq`length]):
      NOT n = 0 IMPLIES n - 1 >= 0 AND n - 1 < length(rest(seq));

  % Subtype TCC generated (at line 224, column 60) for  n
      % expected type  below[length(replace(x, seq, n))]
  nth_x_TCC1: OBLIGATION
    FORALL (seq: finseq[T], x: T, n: below[length(seq)]):
      n < length(replace(x, seq, n));


body:
  seqs[T: TYPE]: THEORY
  BEGIN

    l(f: finite_sequence[T]): MACRO nat = f`length

    ne_seqs: TYPE = {s: finite_sequence[T]  | length(s) > 0}


    in?(x: T, s: finite_sequence[T]): bool = 
                (EXISTS (ii: below(length(s))): x = seq(s)(ii))

    const_seq(n: nat,c:T): finite_sequence[T] = (# length := n,
                                                   seq := (LAMBDA (i: below(n)): c) #)

    seq1(t:T): ne_seqs = (# length := 1,
                            seq := (LAMBDA (n: below(1)): t)
                          #)


    seq2(a,b:T): ne_seqs = (# length := 2,
                            seq := (LAMBDA (n: below(2)): IF n < 1 THEN a 
                                                          ELSE b ENDIF)
                           #)

    t: VAR T
    seq1_def: LEMMA seq1(t)`seq(0) = t

    AUTO_REWRITE+ seq1_def

    fs: VAR finite_sequence[T]
    rev(fs): finite_sequence[T] = (# length := l(fs),
                             seq := (LAMBDA (i: below(l(fs))): seq(fs)(l(fs)-1-i))
                          #)


    add1(fs,t): finite_sequence[T] = (# length := l(fs) + 1,
                                 seq := (LAMBDA (ii: below(l(fs)+1)):
                                      IF ii < l(fs) THEN seq(fs)(ii) 
                                      ELSE t 
                                      ENDIF)
                               #)


  END seqs

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

  % Subtype TCC generated (at line 26, column 30) for  0
      % expected type  below[seq1(t)`length]
  seq1_def_TCC1: OBLIGATION FORALL (t: T): 0 < seq1(t)`length;

  % Subtype TCC generated (at line 32, column 69) for  fs`length - 1 - i
      % expected type  below[fs`length]
  rev_TCC1: OBLIGATION
    FORALL (fs: finite_sequence[T], i: below(fs`length)):
      fs`length - 1 - i >= 0 AND fs`length - 1 - i < fs`length;


body:
  seq2set[T: TYPE]: THEORY
  %----------------------------------------------------------------------------
  %
  % Utility functions for converting to/from sets and sequences
  %
  % Version 1.0, January, 2004
  % Author: Kristin Y. Rozier
  %----------------------------------------------------------------------------
  BEGIN

     IMPORTING seqs[T]

     fs: VAR finite_sequence[T]

     seq2set(fs): finite_set[T] 
  	  = {s: T | (EXISTS (kk: below(length(fs))): fs(kk) = s)}

     seq2set_lem: LEMMA (FORALL (ii: below(length(fs))): seq2set(fs)(fs(ii)))

     card_seq2set: LEMMA card[T](seq2set(fs)) <= length(fs)

     ss: VAR ne_seqs  % length > 0

     JUDGEMENT seq2set(ss) HAS_TYPE (nonempty?[T]) 

  END seq2set

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

  % Subtype TCC generated (at line 16, column 5) for
      % {s: T | (EXISTS (kk: below(length(fs))): finseq_appl[T](fs)(kk) = s)}
      % expected type  finite_set[T]
  seq2set_TCC1: OBLIGATION
    FORALL (fs: finite_sequence[T]):
      is_finite[T]
          ({s: T |
              EXISTS (kk: below(length(fs))): finseq_appl[T](fs)(kk) = s});

  % Judgement subtype TCC generated (at line 24, column 13) for  seq2set(ss)
      % expected type  (nonempty?[T])
  seq2set_TCC2: OBLIGATION FORALL (ss): nonempty?[T](seq2set(ss));


body:
  max_seq[T: TYPE, <= : (total_order?[T]) ]: THEORY
  %------------------------------------------------------------------------
  %
  %  max_seq (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 seqs[T]

  BEGIN

    IMPORTING seqs[T]

  %  seqs: TYPE = {s: finite_sequence[T]  | length(s) > 0}
  %  in?(x,s): bool = (EXISTS (ii: dom(s)): x = seq(s)(ii))

    s: VAR ne_seqs
    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_seqs,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_seq

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

  % Subtype TCC generated (at line 52, column 52) for  j
      % expected type  below[s`length]
  Imax_TCC1: OBLIGATION
    FORALL (s, (ii: dom(s)), (jj: abv(ii, s)), i: subrange(ii, jj), j):
      ii <= j AND j <= jj IMPLIES j < s`length;

  % Subtype TCC generated (at line 52, column 65) for  i
      % expected type  below[s`length]
  Imax_TCC2: OBLIGATION
    FORALL (s, (ii: dom(s)), (jj: abv(ii, s)), i: subrange(ii, jj), j):
      ii <= j AND j <= jj IMPLIES i < s`length;

  % 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_TCC3: OBLIGATION
    EXISTS (x:
              [d: [s: ne_seqs[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_seqs[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_seqs[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_seqs[T] ->
                 {t: T |
                          (FORALL (ii: dom(s)): seq(s)(ii) <= t) AND
                           (EXISTS (jj: dom(s)): seq(s)(jj) = t)}]):
      TRUE;

  % Subtype TCC generated (at line 80, column 36) for  0
      % expected type  below[s`length]
  max_seq_2_TCC1: OBLIGATION
    FORALL (s: ne_seqs[T]): length(s) = 2 IMPLIES 0 < s`length;

  % Subtype TCC generated (at line 80, column 49) for  1
      % expected type  below[s`length]
  max_seq_2_TCC2: OBLIGATION
    FORALL (s: ne_seqs[T]): length(s) = 2 IMPLIES 1 < s`length;


body:
  min_seq[T: TYPE+, <= : (total_order?[T]) ]: THEORY
  %------------------------------------------------------------------------
  %
  %  min_seq (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 seqs[T]

  BEGIN

    IMPORTING seqs[T]

  %  seqs: TYPE = {s: finite_sequence[T]  | length(s) > 0}
  %  in?(x,s): bool = (EXISTS (ii: dom(s)): x = seq(s)(ii))


    ii,j: VAR nat
    s: VAR ne_seqs
    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_seqs,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_seq

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

  % Subtype TCC generated (at line 52, column 52) for  i
      % expected type  below[s`length]
  Imin_TCC1: OBLIGATION
    FORALL (s, (ii: dom(s)), (jj: abv(ii, s)), i: subrange(ii, jj), j):
      ii <= j AND j <= jj IMPLIES i < s`length;

  % Subtype TCC generated (at line 52, column 65) for  j
      % expected type  below[s`length]
  Imin_TCC2: OBLIGATION
    FORALL (s, (ii: dom(s)), (jj: abv(ii, s)), i: subrange(ii, jj), j):
      ii <= j AND j <= jj IMPLIES j < s`length;

  % Existence TCC generated (at line 50, 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_TCC3: OBLIGATION
    EXISTS (x:
              [d: [s: ne_seqs[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 54, column 63) for  ii
      % expected type  abv(ii, s)
  Imin_seq_1_TCC1: OBLIGATION
    FORALL (s: ne_seqs[T], ii: dom(s)): ii <= ii AND ii < length(s);

  % Existence TCC generated (at line 56, 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_seqs[T] ->
                 {i: dom(s) |
                          FORALL (ii: dom(s)): seq(s)(i) <= seq(s)(ii)}]):
      TRUE;

  % Existence TCC generated (at line 58, 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_seqs[T] ->
                 {t: T |
                          (FORALL (ii: dom(s)): t <= seq(s)(ii)) AND
                           (EXISTS (jj: dom(s)): seq(s)(jj) = t)}]):
      TRUE;

  % Subtype TCC generated (at line 81, column 30) for  0
      % expected type  below[s`length]
  min_seq_2_TCC1: OBLIGATION
    FORALL (s: ne_seqs[T]): length(s) = 2 IMPLIES 0 < s`length;

  % Subtype TCC generated (at line 81, column 43) for  1
      % expected type  below[s`length]
  min_seq_2_TCC2: OBLIGATION
    FORALL (s: ne_seqs[T]): length(s) = 2 IMPLIES 1 < s`length;


body:
  permutations_seq[T: TYPE, <= : (total_order?[T]) ]: THEORY
  %------------------------------------------------------------------------
  %
  %  permutations_seq (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

    A,B,A1,A2,A3: VAR finite_sequence[T]
    x, t: VAR T
    i,j: VAR nat

    in?(A)(x): bool = (EXISTS (ii: below(length(A))): seq(A)(ii) = x)


    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?(A1)(x) = in?(A2)(x))




  END permutations_seq


body:
  sort_seq[T: TYPE, <= : (total_order?[T]) ]: THEORY
  %------------------------------------------------------------------------
  %
  %  sort_seq (basic definitions and properties)
  %  -------------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory defines the sort function over an seq of
  %  values.  Most of the text of this theory is scaffolding to
  %  demonstrate that the definition of "sort" is sound.  In particular,
  %  the function "asort" is a witness function and not intended
  %  to be used externally.
  %  
  %  The following definitions should be used exclusively:
  %
  %    is_permutation(A1,A2): bool = (EXISTS (f: [below(N) -> below(N)]): 
  %                      bijective?(f) AND (FORALL ii: A1(ii) = A2(f(ii))))
  %  
  %    increasing(A): bool = (FORALL i,j: 0 <= i AND i < j AND j < N 
  %                                 IMPLIES A(i) <= A(j))
  %
  %    sort(A): {a: seqs | is_permutation(A,a) AND increasing(a)}
  %
  %  Note:
  %     The properties of sort are readily obtained via 
  %     TYPEPRED "sort" or through use of sort_lem.
  %
  %------------------------------------------------------------------------

    EXPORTING ALL BUT seq_to_array % i.e. do not export sort_array
          WITH permutations_seq[T,<=], seqs[T]

  BEGIN

  %  

    seqs: TYPE = finite_sequence[T]

    s,s1,s2,ss: VAR seqs
    x, t: VAR T
    i,j: VAR nat

    IMPORTING sort_array, below_arrays, permutations_seq, seqs[T]

    seq_to_array(s): below_array[length(s),T] =
               (LAMBDA (i: below(length(s))): seq(s)(i))

    increasing?(s): bool = (FORALL i,j: 0 <= i AND i < j AND j < length(s)
                              IMPLIES seq(s)(i) <= seq(s)(j))
    
    sort(s): {ss: seqs | permutation?[T,<=](s,ss) AND increasing?(ss)}

    sort_length  : LEMMA length(sort(s)) = length(s)

    AUTO_REWRITE+ sort_length

    sort_seq_lem : LEMMA permutation?[T,<=](s,sort(s)) AND increasing?(sort(s))

    sort_seq_in?  : LEMMA in?(x,s) IFF in?(x,sort(s))

    sort_seq_in   : LEMMA FORALL (ii: below(length(s))): 
                                       in?(seq(sort(s))(ii),s)

    sort_seq_in2   : LEMMA FORALL (ii: below(length(s))): in?(seq(s)(ii),sort(s))



  % ------------------ NEW ------------------

    sort_map(s): { map: [below(length(s)) -> below(length(s))] | 
              bijective?(map) AND
                (FORALL (i: below(length(s))): seq(s)(i) = seq(sort(s))(map(i)))}

    sort_map_def: LEMMA FORALL (i: below(length(s))):
                              seq(s)(i) = seq(sort(s))(sort_map(s)(i))

    sort_map_bij: LEMMA bijective?(sort_map(s))




    isort_map(s: {ss: finite_sequence[T]  | length(ss) > 0}):
         { map: [below(length(s)) -> below(length(s))] | 
               bijective?(map) AND
                 (FORALL (i:below(length(s))): seq(s)(map(i)) = seq(sort(s))(i))}

    isort_map_def: LEMMA FORALL (i: below(length(s))):
                               seq(s)(isort_map(s)(i)) = seq(sort(s))(i)

    isort_map_bij: LEMMA FORALL (s: {ss: finite_sequence[T]  | length(ss) > 0}):
                              bijective?(isort_map(s))




  END sort_seq

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

  % Subtype TCC generated (at line 50, column 43) for  i
      % expected type  below[s`length]
  increasing?_TCC1: OBLIGATION
    FORALL (s: seqs, i, j):
      0 <= i AND i < j AND j < length(s) IMPLIES i < s`length;

  % Existence TCC generated (at line 52, column 2) for
      % sort(s): {ss: seqs | permutation?[T, <=](s, ss) AND increasing?(ss)}
  sort_TCC1: OBLIGATION
    EXISTS (x:
              [s: seqs ->
                 {ss: seqs |
                          permutation?[T, <=](s, ss) AND increasing?(ss)}]):
      TRUE;

  % Subtype TCC generated (at line 63, column 54) for  ii
      % expected type  below[sort(s)`length]
  sort_seq_in_TCC1: OBLIGATION
    FORALL (s: seqs, ii: below(length(s))): ii < sort(s)`length;

  % Subtype TCC generated (at line 73, column 70) for  map(i)
      % expected type  below[sort(s)`length]
  sort_map_TCC1: OBLIGATION
    FORALL (s, map: [below(length(s)) -> below(length(s))]):
      bijective?(map) IMPLIES
       (FORALL (i: below(length(s))): map(i) < sort(s)`length);

  % Existence TCC generated (at line 71, column 2) for
      % sort_map(s):
      %       {map: [below(length(s)) -> below(length(s))] |
      %                bijective?(map) AND
      %                 (FORALL (i: below(length(s))):
      %                    seq(s)(i) = seq(sort(s))(map(i)))}
  sort_map_TCC2: OBLIGATION
    EXISTS (x:
              [s: seqs ->
                 {map: [below(length(s)) -> below(length(s))] |
                          bijective?[below(length(s)), below(length(s))](map)
                           AND
                           (FORALL (i: below(length(s))):
                              seq(s)(i) = seq(sort(s))(map(i)))}]):
      TRUE;

  % Subtype TCC generated (at line 76, column 53) for  sort_map(s)(i)
      % expected type  below[sort(s)`length]
  sort_map_def_TCC1: OBLIGATION
    FORALL (s: seqs, i: below(length(s))): sort_map(s)(i) < sort(s)`length;

  % Existence TCC generated (at line 83, column 2) for
      % isort_map(s: {ss: finite_sequence[T] | length(ss) > 0}):
      %       {map: [below(length(s)) -> below(length(s))] |
      %                bijective?(map) AND
      %                 (FORALL (i: below(length(s))):
      %                    seq(s)(map(i)) = seq(sort(s))(i))}
  isort_map_TCC1: OBLIGATION
    EXISTS (x:
              [s: {ss: finite_sequence[T] | length(ss) > 0} ->
                 {map: [below(length(s)) -> below(length(s))] |
                          bijective?[below(length(s)), below(length(s))](map)
                           AND
                           (FORALL (i: below(length(s))):
                              seq(s)(map(i)) = seq(sort(s))(i))}]):
      TRUE;

  % Subtype TCC generated (at line 89, column 46) for  s
      % expected type  s: {ss: finite_sequence[T] | length(ss) > 0}
  isort_map_def_TCC1: OBLIGATION
    FORALL (s: seqs, i: below(length(s))): length(s) > 0;


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

    IMPORTING sort_seq[T,<=], 
              min_seq[T,<=], max_seq[T,<=]


    s: VAR ne_seqs


    sort_seq_min : LEMMA seq(sort(s))(0) = min(s)

    sort_seq_max : LEMMA seq(sort(s))(length(s)-1) = max(s)
  	
  END sort_seq_lems

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

  % Subtype TCC generated (at line 11, column 36) for  0
      % expected type  below[sort(s)`length]
  sort_seq_min_TCC1: OBLIGATION
    FORALL (s: ne_seqs[T]): 0 < sort[T, <=](s)`length;

  % Subtype TCC generated (at line 13, column 36) for  length(s) - 1
      % expected type  below[sort(s)`length]
  sort_seq_max_TCC1: OBLIGATION
    FORALL (s: ne_seqs[T]):
      length(s) - 1 >= 0 AND length(s) - 1 < sort[T, <=](s)`length;


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

     IMPORTING sort_seq_lems[T,<=],
               finite_sets@finite_sets_minmax[T,<=],
               seq2set[T]

     ne_fs: VAR ne_seqs[T]

     minmax_seq2set: LEMMA min[T,<=](seq2set(ne_fs)) = min(ne_fs) AND
                           max[T,<=](seq2set(ne_fs)) = max(ne_fs)

  END minmax_seq2set

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

  % Subtype TCC generated (at line 37, column 35) for  seq2set(ne_fs)
      % expected type  SS: non_empty_finite_set[T]
  minmax_seq2set_TCC1: OBLIGATION
    FORALL (ne_fs: ne_seqs[T]): NOT empty?[T](seq2set[T](ne_fs));


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

    IMPORTING sort_seq_lems[T,<=],
              finite_sets@finite_sets_minmax[T,<=],
              set2seq[T]

    S: VAR finite_set[T]

    minmax_set2seq: LEMMA card(S) > 0 IMPLIES
                             min(set2seq(S)) =  min[T,<=](S) AND
                             max(set2seq(S)) =  max[T,<=](S)

  END minmax_set2seq

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

  % Subtype TCC generated (at line 55, column 31) for  set2seq(S)
      % expected type  s: ne_seqs[T]
  minmax_set2seq_TCC1: OBLIGATION
    FORALL (S: finite_set[T]): card(S) > 0 IMPLIES length(set2seq[T](S)) > 0;

  % Subtype TCC generated (at line 55, column 56) for  S
      % expected type  SS: non_empty_finite_set[T]
  minmax_set2seq_TCC2: OBLIGATION
    FORALL (S: finite_set[T]): card(S) > 0 IMPLIES NOT empty?[T](S);


body:
  sort_inversions[N: posnat, T: TYPE, <= : (total_order?[T]) ]: THEORY
  %----------------------------------------------------------------------------
  % inversions, i.e., index pairs i < j such that A(i) > A(j)
  % are witnessses that array A is not sorted.
  % transposition of adjacent elements A(j) > A(j+1) decrease
  % the number of inversions. This is the basis of bubble sort.
  %
  % Author: Alfons Geser, National Institute of Aerospace, 2003
  %----------------------------------------------------------------------------

  BEGIN

    index_pair: TYPE = [below(N),below(N)]

    IMPORTING sort_array[N,T,<=],
              finite_sets[index_pair],
              permutation_ops[N]

    A    : VAR [below(N) -> T]
    inv  : VAR finite_set[index_pair]
    i,j,k: VAR below(N)
    x    : VAR T

    % to discharge the TCC for inversions
    finite_inversions: LEMMA
      is_finite[index_pair]({(i, j) | i < j & NOT A(i) <= A(j)})

    % the set of inversions, i.e, of index pairs (i,j) such that
    % A(i) and A(j) are not in sorted order
    inversions(A): finite_set[index_pair] =
      {(i,j) | i < j & NOT A(i) <= A(j)}

    pi: VAR permutation

    % to discharge the TCC for ap(pi,inv) below
    finite_ap: LEMMA
      is_finite[index_pair](LAMBDA (i, j): inv(pi(i), pi(j)))

    % apply a permutation pi to a set of index pairs
    ap(pi,inv): finite_set[index_pair] = LAMBDA (i,j): inv(pi(i),pi(j))

    % applying a permutation does not change the number of index pairs
    card_ap: LEMMA
      card[index_pair](ap(pi,inv)) = card[index_pair](inv)

    inversions_transpose: LEMMA
      j < N-1 & NOT A(j) <= A(j+1) =>
        inversions(A o transpose(j,j+1)) =
          ap(transpose(j,j+1),remove((j,j+1),inversions(A)))

    % main results:
    % 1) if (j,j+1) is an inversion then exchanging j with j+1 decreases
    %    the number of inversions by one
    % 2) if there are no inversions then A is sorted
    % 3) if there are inversions then there are inversions of the form (j,j+1)

    card_inversions_transpose: THEOREM
      j < N-1 & NOT A(j) <= A(j+1) =>
        card(inversions(A)) = 1 + card(inversions(A o transpose(j,j+1)))

    sorted_iff_no_inversions: THEOREM
      sorted?(A) <=> empty?(inversions(A))

    d: VAR nat

    successive_inversion_lem: LEMMA
      (EXISTS i: i < i+d & i+d < N & NOT A(i) <= A(i+d)) =>
      (EXISTS j: j < N-1 & NOT A(j) <= A(j+1))

    successive_inversion_exists: THEOREM
      NOT sorted?(A) => EXISTS j: j < N-1 & NOT A(j) <= A(j+1)
   
  END sort_inversions

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

  % Subtype TCC generated (at line 31, column 4) for
      % {i, j | i < j & NOT A(i) <= A(j)}
      % expected type  finite_set[index_pair]
  inversions_TCC1: OBLIGATION
    FORALL (A: [below(N) -> T]):
      is_finite[index_pair]({i, j | i < j & NOT A(i) <= A(j)});

  % Subtype TCC generated (at line 40, column 39) for
      % LAMBDA (i, j): inv(pi(i), pi(j))
      % expected type  finite_set[index_pair]
  ap_TCC1: OBLIGATION
    FORALL (pi: permutation[N], inv: finite_set[index_pair]):
      is_finite[index_pair](LAMBDA (i, j): inv(pi(i), pi(j)));

  % Subtype TCC generated (at line 47, column 28) for  j + 1
      % expected type  below(N)
  inversions_transpose_TCC1: OBLIGATION
    FORALL (j: below(N)): j < N - 1 IMPLIES j + 1 < N;


body:
  bubblesort[N: posnat, T: TYPE, <= : (total_order?[T]) ]: THEORY
  %----------------------------------------------------------------------------
  % The bubblesort algorithm and its correctness.
  %
  % Author: Alfons Geser, National Institute of Aerospace, 2003
  %----------------------------------------------------------------------------
  BEGIN

    IMPORTING sort_inversions[N,T,<=]

    A: VAR [below(N) -> T]
    inv: VAR finite_set[index_pair]
    i,j,k: VAR below(N)
    x: VAR T

    epsilon_lem  : LEMMA NOT sorted?(A) &
                         (j = epsilon! j: j < N - 1 & NOT A(j) <= A(j+1)) =>
                                j < N - 1 & NOT A(j) <= A(j+1)

    bubblesort(A): RECURSIVE [below(N) -> T] =
                        IF sorted?(A) THEN A
                        ELSE
                          LET j = epsilon! j: j < N-1 & NOT A(j) <= A(j+1) IN
                          bubblesort(A o transpose(j,j+1))
                        ENDIF
                     MEASURE card(inversions(A))

    sorted_bubblesort: THEOREM sorted?(bubblesort(A))

  END bubblesort

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

  % Subtype TCC generated (at line 17, column 66) for  j + 1
      % expected type  below(N)
  epsilon_lem_TCC1: OBLIGATION
    FORALL (A: [below(N) -> T]):
      NOT sorted?(A) IMPLIES (FORALL (j): j < N - 1 IMPLIES j + 1 < N);

  % Existence TCC generated (at line 17, column 28) for  epsilon
  epsilon_lem_TCC2: OBLIGATION
    FORALL (A: [below(N) -> T]):
      NOT sorted?(A) IMPLIES (EXISTS (x: below(N)): TRUE);

  % Subtype TCC generated (at line 24, column 51) for  j + 1
      % expected type  below(N)
  bubblesort_TCC1: OBLIGATION
    FORALL (A: [below(N) -> T]):
      NOT sorted?(A) IMPLIES
       (FORALL (j: below(N)):
          j =
           epsilon! (j_1: below(N)): j_1 < N - 1 & NOT A(j_1) <= A(j_1 + 1)
           IMPLIES j + 1 < N);

  % Termination TCC generated (at line 24, column 24) for
      % bubblesort(A o transpose(j, j + 1))
  bubblesort_TCC2: OBLIGATION
    FORALL (A: [below(N) -> T]):
      NOT sorted?(A) IMPLIES
       (FORALL (j: below(N)):
          j =
           epsilon! (j_1: below(N)): j_1 < N - 1 & NOT A(j_1) <= A(j_1 + 1)
           IMPLIES
           card[index_pair[N, T, <=]]
               (inversions[N, T, <=]
                    (o[below(N), below(N), T](A, transpose[N](j, j + 1))))
            < card[index_pair[N, T, <=]](inversions[N, T, <=](A)));


body:
  majority_seq[T: NONEMPTY_TYPE]: THEORY
  %------------------------------------------------------------------------
  %
  %  majority (basic definitions and properties)
  %  -------------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory defines the majority function over a finite sequence of
  %  values.  The following functions are defined:
  %           
  %           is_majority(mv,fs) -- predicate that is true IFF mv is
  %                                 the majority value of the sequence
  %
  %           maj_exists(fs)     -- predicate that us true IFF a majority
  %                                 exists
  %
  %           maj(fs)            -- function that returns the majority value
  %                                 if a majority exists.  If a majority does
  %                                 not exist, the function returns an
  %                                 unspecified value from the type T.
  %                                 This value may not be in the sequence.
  %
  %           inseq(x,fs)        -- predicate that is true IFF x is in
  %                                 the sequence
  %
  %   Note: the following function can be defined that will return
  %   a value from the sequence if a majority does not exist.
  %
  %     finseq: TYPE = {fs | length(fs) > 0}
  %
  %     fsq: VAR finseq
  %     Maj(fsq): {x: T | in_seq(x,fsq)} = IF maj_exists(fsq) THEN maj(fsq)
  %                                        ELSE choose({x: T | in_seq(x,fsq)})
  %                                        ENDIF 
  %
  %------------------------------------------------------------------------

  BEGIN

    IMPORTING seqs[T], finite_sets@finite_sets_below

    fs: VAR finite_sequence[T]
    mv, mv1, mv2, x: VAR T

    is_majority(mv: T, fs): bool = 
         2*card({i: below(length(fs)) | seq(fs)(i) = mv}) > length(fs) 

    maj_exists(fs): bool = (EXISTS (mv: T): is_majority(mv,fs))

    maj(fs): {mv | maj_exists(fs) => is_majority(mv,fs)}

    in_seq(x,fs): bool = (EXISTS (i: below(length(fs))): seq(fs)(i) = x)

    is_majority_unique: LEMMA is_majority(mv1,fs) AND is_majority(mv2,fs)
                              IMPLIES mv1 = mv2

    maj_lem:            LEMMA is_majority(mv,fs) IFF 
                              maj_exists(fs) AND maj(fs) = mv

    maj_subset:         LEMMA   (EXISTS (A: finite_set[below(length(fs))]):
                                 2*card(A) > length(fs)
                                 AND (FORALL (i: below(length(fs))): A(i) 
                                                IMPLIES seq(fs)(i) = mv))
                              IMPLIES is_majority(mv,fs)

    maj_in_seq:         LEMMA is_majority(mv,fs) IMPLIES in_seq(mv,fs)

  % ===================== Some Special Sequences ===================

    f1: VAR [below[1] -> T]

    length_eq_1: LEMMA maj( (# length := 1, seq := f1 #) ) = f1(0) 

    n: VAR posnat
    c: VAR T

  %  const_seq(n,c): finite_sequence[T] = (# length := n,
  %                           seq := (LAMBDA (i: below(n)): c) #)

    is_majority_const: LEMMA is_majority(c, const_seq(n,c))
    
    maj_const:         LEMMA maj_exists(const_seq(n,c)) AND
                             maj(const_seq(n,c)) = c

  END majority_seq

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

  % Subtype TCC generated (at line 47, column 14) for
      % {i: below(length(fs)) | seq(fs)(i) = mv}
      % expected type  S: finite_set[below(length(fs))]
  is_majority_TCC1: OBLIGATION
    FORALL (mv: T, fs: finite_sequence[T]):
      is_finite[below(length(fs))]({i: below(length(fs)) | seq(fs)(i) = mv});

  % Existence TCC generated (at line 51, column 2) for
      % maj(fs): {mv | maj_exists(fs) => is_majority(mv, fs)}
  maj_TCC1: OBLIGATION
    EXISTS (x:
              [fs: finite_sequence[T] ->
                 {mv | maj_exists(fs) => is_majority(mv, fs)}]):
      TRUE;


body:
  top_seq: THEORY
  BEGIN
     IMPORTING
       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
       seq2set,          	% convert sequence to a set
       seq_extras,        % extra-definitions that complements the prelude's finite sequences
       seq_pigeon         % Pigeon hole principle for the prelude's finite sequences

  END top_seq


body:
  %------------------------------------------------------------------------
  %
  %  majority_array (basic definitions and properties)
  %  -------------------------------------------
  %
  %    This theory defines the majority function over an array of
  %    values.  
  %
  %  Defines:
  %           
  %           is_majority(mv,A) -- predicate that is true IFF mv is
  %                                the majority value of the array A.
  %
  %           maj_exists(A)     -- predicate that is true IFF a majority
  %                                of A exists.
  %
  %           maj(A)            -- function that returns the majority value
  %                                of A if a majority exists.  If a majority
  %                                does not exist, the function returns an
  %                                unspecified value from the type T.
  %                                This value may not be in the array.
  %
  %           inseq(x,A)        -- predicate that is true IFF x is in
  %                                the array A.
  %
  %------------------------------------------------------------------------
  majority_array[N: posnat, T: NONEMPTY_TYPE]: THEORY

  BEGIN


    IMPORTING finite_sets@finite_sets_below[N], below_arrays[N,T]
  	
    A: VAR ARRAY[below[N] -> T] 
    mv, mv1, mv2, x, c: VAR T
    ii: VAR below[N]

    is_majority(mv, A): bool = 2*card({ii | A(ii) = mv}) > N

    maj_exists(A): bool = (EXISTS (mv: T): is_majority(mv,A))

    maj(A): {mv | maj_exists(A) => is_majority(mv,A)}

    is_majority_unique: LEMMA is_majority(mv1,A) AND is_majority(mv2,A)
                              IMPLIES mv1 = mv2

    maj_lem:            LEMMA is_majority(mv,A) IFF 
                              maj_exists(A) AND maj(A) = mv

    maj_subset:         LEMMA   (EXISTS (IDS: finite_set[below(N)]):
                                     2*card(IDS) > N
                                 AND (FORALL ii: IDS(ii) IMPLIES A(ii) = mv))
                              IMPLIES is_majority(mv,A)

    maj_in_array:       LEMMA is_majority(mv,A) IMPLIES 
                                 (EXISTS ii: A(ii) = mv)

  % ===================== Some Special Arrays ===================

    constant_array(c): below_array = (LAMBDA ii: c)

    is_majority_const: LEMMA is_majority(c, constant_array(c))
    
    maj_const:         LEMMA maj_exists(constant_array(c)) AND
                             maj(constant_array(c)) = c

  END majority_array

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

  % Subtype TCC generated (at line 38, column 36) for  {ii | A(ii) = mv}
      % expected type  S: finite_set[below[N]]
  is_majority_TCC1: OBLIGATION
    FORALL (mv: T, A: [below[N] -> T]):
      is_finite[below[N]]({ii | A(ii) = mv});

  % Existence TCC generated (at line 42, column 2) for
      % maj(A): {mv | maj_exists(A) => is_majority(mv, A)}
  maj_TCC1: OBLIGATION
    EXISTS (x:
              [A: [below[N] -> T] ->
                 {mv | maj_exists(A) => is_majority(mv, A)}]):
      TRUE;


body:
  concat_arrays [n:nat, m:nat, T: TYPE]: THEORY
  %------------------------------------------------------------------------
  %
  % This theory defines the concatenation operator o for arrays
  %
  %------------------------------------------------------------------------

  BEGIN

    IMPORTING below_arrays

    a_n: VAR below_array[n,T]
    a_m: VAR below_array[m,T]
    nm : VAR below(n+m)

    o(a_n, a_m): below_array[n+m,T] = (LAMBDA nm: IF nm < n THEN a_n(nm)
                                                   ELSE a_m(nm - n)
                                                   ENDIF)

    i: VAR below(n)
    j: VAR {i: int | i >= n AND i < n+m}

    concat_array_bot0: THEOREM m = 0 IMPLIES a_n o a_m = a_n 

    concat_array_top0: THEOREM n = 0 IMPLIES a_n o a_m = a_m

    concat_array_bot : THEOREM (a_n o a_m)(i) = a_n(i)

    concat_array_top : THEOREM (a_n o a_m)(j) = a_m(j-n)

  END concat_arrays  

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

  % Subtype TCC generated (at line 17, column 58) for  nm - n
      % expected type  below(m)
  oh_TCC1: OBLIGATION
    FORALL (a_n: below_array[n, T], a_m: below_array[m, T], nm):
      NOT nm < n IMPLIES nm - n >= 0 AND nm - n < m;

  % Subtype TCC generated (at line 23, column 55) for  a_n
      % expected type  below_array[n + m, T]
  concat_array_bot0_TCC1: OBLIGATION
    m = 0 IMPLIES (FORALL (x: nat): x < n IFF x < m + n);

  % Subtype TCC generated (at line 25, column 55) for  a_m
      % expected type  below_array[n + m, T]
  concat_array_top0_TCC1: OBLIGATION
    n = 0 IMPLIES (FORALL (x: nat): x < m IFF x < m + n);

  % Subtype TCC generated (at line 27, column 41) for  i
      % expected type  below(n + m)
  concat_array_bot_TCC1: OBLIGATION FORALL (i: below(n)): i < m + n;

  % Subtype TCC generated (at line 29, column 41) for  j
      % expected type  below(n + m)
  concat_array_top_TCC1: OBLIGATION
    FORALL (j: {i: int | i >= n AND i < m + n}): j >= 0 AND j < m + n;

  % Subtype TCC generated (at line 29, column 50) for  j - n
      % expected type  below(m)
  concat_array_top_TCC2: OBLIGATION
    FORALL (j: {i: int | i >= n AND i < m + n}): j - n >= 0 AND j - n < m;


body:
  empty_array_def[T: TYPE]: THEORY

  BEGIN

    IMPORTING below_arrays

    empty_array: below_array[0,T]  % (LAMBDA (x: below[0]): epsilon! (t:T): true)

  END empty_array_def

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

  % Existence TCC generated (at line 7, column 2) for
      % empty_array: below_array[0, T]
  empty_array_TCC1: OBLIGATION EXISTS (x: below_array[0, T]): TRUE;


body:
  caret_arrays [N:nat, T: TYPE]: THEORY

  BEGIN

    IMPORTING below_arrays, empty_array_def


    A: VAR below_array[N,T]
    m, n: VAR nat
    p: VAR [nat, below[N]]


    ^(A, p): below_array[LET (m, n) = p IN
                            IF m > n THEN 0
                            ELSE n - m + 1 ENDIF,T] =
        LET (m, n) = p IN
          IF m <= n THEN (LAMBDA (x: below[n-m+1]): A(x + m))
          ELSE empty_array 
          ENDIF


    i,j,k: VAR below(N)

    caret_all : LEMMA N > 0 IMPLIES A^(0,N-1) = A

    caret_ii_0: LEMMA (A^(i,i))(0) = A(i)

    caret_elim: LEMMA i <= j AND k < i - j + 1
                                IMPLIES  (A ^ (i, j))(k) = A(j+k)
                      
  END caret_arrays 

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

  % Subtype TCC generated (at line 13, column 11) for
      % below_array[LET (m, n) = p IN IF m > n THEN 0 ELSE n - m + 1 ENDIF, T]
      % expected type  nat
  caret_TCC1: OBLIGATION FORALL (p): NOT p`1 > p`2 IMPLIES 1 - p`1 + p`2 >= 0;

  % Subtype TCC generated (at line 17, column 45) for  1 + n - m
      % expected type  nat
  caret_TCC2: OBLIGATION
    FORALL (A: below_array[N, T], p: [nat, below[N]], m: nat, n: below[N]):
      m <= n AND n = p`2 AND m = p`1 IMPLIES 1 + n - m >= 0;

  % Subtype TCC generated (at line 17, column 52) for  x + m
      % expected type  below(N)
  caret_TCC3: OBLIGATION
    FORALL (A: below_array[N, T], p: [nat, below[N]], m: nat, n: below[N]):
      m <= n AND n = p`2 AND m = p`1 IMPLIES
       (FORALL (x: below[n - m + 1]): n = p`2 AND m = p`1 IMPLIES x + m < N);

  % Subtype TCC generated (at line 17, column 24) for
      % (LAMBDA (x: below[n - m + 1]): A(x + m))
      % expected type  below_array
                     %     [LET (m, n) = p IN
                     %        IF m > n THEN 0 ELSE n - m + 1 ENDIF,
                     %      T]
  caret_TCC4: OBLIGATION
    FORALL (A: below_array[N, T], p: [nat, below[N]], m: nat, n: below[N]):
      m <= n AND n = p`2 AND m = p`1 IMPLIES
       (FORALL (x: nat):
          x < 1 + n - m IFF x < IF p`1 > p`2 THEN 0 ELSE 1 - p`1 + p`2 ENDIF);

  % Subtype TCC generated (at line 18, column 13) for  empty_array
      % expected type  below_array
                     %     [LET (m, n) = p IN
                     %        IF m > n THEN 0 ELSE n - m + 1 ENDIF,
                     %      T]
  caret_TCC5: OBLIGATION
    FORALL (A: below_array[N, T], p: [nat, below[N]], m: nat, n: below[N]):
      NOT m <= n AND n = p`2 AND m = p`1 IMPLIES
       (FORALL (x: nat):
          NOT x < IF p`1 > p`2 THEN 0 ELSE 1 - p`1 + p`2 ENDIF);

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

  % Subtype TCC generated (at line 24, column 46) for  A
      % expected type  below_array[IF 0 > N - 1 THEN 0 ELSE N ENDIF, T]
  caret_all_TCC2: OBLIGATION
    N > 0 IMPLIES
     (FORALL (x: nat): x < N IFF x < IF 0 > N - 1 THEN 0 ELSE N ENDIF);

  % Subtype TCC generated (at line 29, column 52) for  k
      % expected type  below(IF i > j THEN 0 ELSE 1 + j - i ENDIF)
  caret_elim_TCC1: OBLIGATION
    FORALL (i, j, k: below(N)):
      k < i - j + 1 AND i <= j IMPLIES
       k < IF i > j THEN 0 ELSE 1 + j - i ENDIF;

  % Subtype TCC generated (at line 29, column 59) for  j + k
      % expected type  below(N)
  caret_elim_TCC2: OBLIGATION
    FORALL (i, j, k: below(N)): k < i - j + 1 AND i <= j IMPLIES j + k < N;


body:
  array_ops[T: TYPE]: THEORY
  BEGIN

    IMPORTING below_arrays, caret_arrays, concat_arrays

    t: VAR T
    n,m,i,j: VAR nat

    barr(n): TYPE = below_array[n,T]

    fill(n: nat, t: T): below_array[n,T] = (LAMBDA (ii: below(n)): t) 
    
    caret_fill0	   : LEMMA FORALL (j: below(n)):
  			      i <= j IMPLIES fill(n,t)^(i,j) = fill(j-i+1,t)
   
    caret_fill1	   : LEMMA FORALL (j: below(n)):
  			      i <= j IMPLIES fill(n,t)^(i,j) = fill(j-i+1,t)
   
    caret_concat_bot : LEMMA FORALL (j: below(n), A_n: barr(n), B_m: barr(m)):
  			        j < n IMPLIES (A_n o B_m)^(i,j) = A_n^(i,j)
   
    caret_concat_top : LEMMA FORALL (A_n: barr(n), B_m: barr(m)):
  			        i >= n AND j >= n AND j < n + m
  				  IMPLIES (A_n o B_m)^(i,j) = B_m^(i-n, j-n)
   
    caret_concat_all : LEMMA FORALL (j: below(n), A_n: barr(n), B_m: barr(m)):
  			i <= n AND n <= j IMPLIES 
  				(A_n o B_m)^(i,j) = A_n^(0,i-n) o B_m^(j,n-1) 

    array_decomp     : LEMMA FORALL (n: posnat, k: below(n-1), A_n:barr(n)): 
                                       (A_n^(0,k)) o (A_n^(k+1,n-1)) = A_n

   
    caret_bot_all    : LEMMA FORALL (n: posnat, A_n: barr(n), B_m: barr(m)):
                                        (A_n o B_m)^(0,n-1) = A_n
   
    caret_top_all	   : LEMMA FORALL (A_n: barr(n), B_m: barr(m)):
                                 n+m > 0 IMPLIES (A_n o B_m)^(n,n+m-1) = B_m


  % ===== (below_array,o,1) is a monoid =====================================


    concat_array_bot  : THEOREM (FORALL (i: below(m),
                                           a_m:below_array[m,T],
                                           a_n:below_array[n,T]):
                                             (a_m o a_n)(i) = a_m(i))

    concat_array_top  : THEOREM (FORALL (j: {i: int | i >= m AND i < n+m},
                                          a_m:below_array[m,T],
                                          a_n:below_array[n,T]):
                                             (a_m o a_n)(j) = a_n(j-m))

    concat_array_r    : THEOREM (FORALL (a_n:below_array[n,T]): 
                                             a_n o empty_array[T] = a_n)

    concat_array_l    : THEOREM (FORALL (a_n:below_array[n,T]):
                                             empty_array[T] o a_n = a_n)


    concat_array_assoc: THEOREM (FORALL (a_m:below_array[m,T]),
                                         (a_n:below_array[n,T]),
                                         (a_j:below_array[j,T]):
                                             a_m o (a_n o a_j) = (a_m o a_n) o a_j)

  END array_ops

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

  % Subtype TCC generated (at line 14, column 47) for  j - i + 1
      % expected type  nat
  caret_fill0_TCC1: OBLIGATION
    FORALL (i, n: nat, j: below(n)): i <= j IMPLIES j - i + 1 >= 0;

  % Subtype TCC generated (at line 14, column 42) for  fill(j - i + 1, t)
      % expected type  below_array[IF i > j THEN 0 ELSE 1 + j - i ENDIF, T]
  caret_fill0_TCC2: OBLIGATION
    FORALL (i, n: nat, j: below(n)):
      i <= j IMPLIES
       (FORALL (x: nat):
          x < 1 + j - i IFF x < IF i > j THEN 0 ELSE 1 + j - i ENDIF);

  % Subtype TCC generated (at line 20, column 40) for  j
      % expected type  below[m + n]
  caret_concat_bot_TCC1: OBLIGATION
    FORALL (m, n: nat, j: below(n), A_n: barr(n), B_m: barr(m)):
      j < n IMPLIES j < m + n;

  % Subtype TCC generated (at line 24, column 29) for  j
      % expected type  below[m + n]
  caret_concat_top_TCC1: OBLIGATION
    FORALL (i, j, m, n: nat, A_n: barr(n), B_m: barr(m)):
      i >= n AND j >= n AND j < n + m IMPLIES j < m + n;

  % Subtype TCC generated (at line 24, column 39) for  i - n
      % expected type  nat
  caret_concat_top_TCC2: OBLIGATION
    FORALL (i, j, m, n: nat, A_n: barr(n), B_m: barr(m)):
      i >= n AND j >= n AND j < n + m IMPLIES i - n >= 0;

  % Subtype TCC generated (at line 24, column 44) for  j - n
      % expected type  below[m]
  caret_concat_top_TCC3: OBLIGATION
    FORALL (i, j, m, n: nat, A_n: barr(n), B_m: barr(m)):
      i >= n AND j >= n AND j < n + m IMPLIES j - n >= 0 AND j - n < m;

  % Subtype TCC generated (at line 24, column 34) for  B_m ^ (i - n, j - n)
      % expected type  below_array[IF i > j THEN 0 ELSE 1 + j - i ENDIF, T]
  caret_concat_top_TCC4: OBLIGATION
    FORALL (i, j, m, n: nat, A_n: barr(n), B_m: barr(m)):
      i >= n AND j >= n AND j < n + m IMPLIES
       (FORALL (x: nat):
          x < IF i - n > j - n THEN 0 ELSE 1 + j - i ENDIF IFF
           x < IF i > j THEN 0 ELSE 1 + j - i ENDIF);

  % Subtype TCC generated (at line 28, column 19) for  j
      % expected type  below[m + n]
  caret_concat_all_TCC1: OBLIGATION
    FORALL (i, m, n: nat, j: below(n), A_n: barr(n), B_m: barr(m)):
      i <= n AND n <= j IMPLIES j < m + n;

  % Subtype TCC generated (at line 28, column 31) for  i - n
      % expected type  below[n]
  caret_concat_all_TCC2: OBLIGATION
    FORALL (i, m, n: nat, j: below(n), A_n: barr(n), B_m: barr(m)):
      i <= n AND n <= j IMPLIES i - n >= 0 AND i - n < n;

  % Subtype TCC generated (at line 28, column 45) for  n - 1
      % expected type  below[m]
  caret_concat_all_TCC3: OBLIGATION
    FORALL (i, m, n: nat, j: below(n), A_n: barr(n), B_m: barr(m)):
      i <= n AND n <= j IMPLIES n - 1 >= 0 AND n - 1 < m;

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

  % Subtype TCC generated (at line 28, column 45) for  n - j
      % expected type  nat
  caret_concat_all_TCC5: OBLIGATION
    FORALL (i, m, n: nat, j: below(n), A_n: barr(n), B_m: barr(m)):
      NOT j > n - 1 AND i <= n AND n <= j IMPLIES n - j >= 0;

  % Subtype TCC generated (at line 28, column 24) for
      % A_n ^ (0, i - n) o B_m ^ (j, n - 1)
      % expected type  below_array[IF i > j THEN 0 ELSE 1 + j - i ENDIF, T]
  caret_concat_all_TCC6: OBLIGATION
    FORALL (i, m, n: nat, j: below(n), A_n: barr(n), B_m: barr(m)):
      i <= n AND n <= j IMPLIES
       (FORALL (x: nat):
          x <
           IF j > n - 1 THEN 0 ELSE n - j ENDIF +
            IF 0 > i - n THEN 0 ELSE 1 + i - n ENDIF
           IFF x < IF i > j THEN 0 ELSE 1 + j - i ENDIF);

  % Subtype TCC generated (at line 31, column 45) for  k
      % expected type  below[n]
  array_decomp_TCC1: OBLIGATION
    FORALL (n: posnat, k: below(n - 1), A_n: barr(n)): k < n;

  % Subtype TCC generated (at line 31, column 61) for  n - 1
      % expected type  below[n]
  array_decomp_TCC2: OBLIGATION
    FORALL (n: posnat, k: below(n - 1), A_n: barr(n)):
      n - 1 >= 0 AND n - 1 < n;

  % Subtype TCC generated (at line 31, column 61) for  n - 1 - k
      % expected type  nat
  array_decomp_TCC3: OBLIGATION
    FORALL (n: posnat, k: below(n - 1), A_n: barr(n)):
      NOT 1 + k > n - 1 IMPLIES n - 1 - k >= 0;

  % Subtype TCC generated (at line 31, column 69) for  A_n
      % expected type  below_array
                     %     [IF 1 + k > n - 1 THEN 0 ELSE n - 1 - k ENDIF +
                     %       IF 0 > k THEN 0 ELSE 1 + k ENDIF,
                     %      T]
  array_decomp_TCC4: OBLIGATION
    FORALL (n: posnat, k: below(n - 1), A_n: barr(n)):
      FORALL (x: nat):
        x < n IFF
         x <
          IF 1 + k > n - 1 THEN 0 ELSE n - 1 - k ENDIF +
           IF 0 > k THEN 0 ELSE 1 + k ENDIF;

  % Subtype TCC generated (at line 35, column 53) for  n - 1
      % expected type  below[n + m]
  caret_bot_all_TCC1: OBLIGATION
    FORALL (m: nat, n: posnat, A_n: barr(n), B_m: barr(m)):
      n - 1 >= 0 AND n - 1 < n + m;

  % Subtype TCC generated (at line 35, column 60) for  A_n
      % expected type  below_array[IF 0 > n - 1 THEN 0 ELSE n ENDIF, T]
  caret_bot_all_TCC2: OBLIGATION
    FORALL (m: nat, n: posnat, A_n: barr(n), B_m: barr(m)):
      FORALL (x: nat): x < n IFF x < IF 0 > n - 1 THEN 0 ELSE n ENDIF;

  % Subtype TCC generated (at line 38, column 62) for  n + m - 1
      % expected type  below[m + n]
  caret_top_all_TCC1: OBLIGATION
    FORALL (m, n: nat, A_n: barr(n), B_m: barr(m)):
      n + m > 0 IMPLIES n + m - 1 >= 0 AND n + m - 1 < m + n;

  % Subtype TCC generated (at line 38, column 71) for  B_m
      % expected type  below_array[IF n > m + n - 1 THEN 0 ELSE m ENDIF, T]
  caret_top_all_TCC2: OBLIGATION
    FORALL (m, n: nat, A_n: barr(n), B_m: barr(m)):
      n + m > 0 IMPLIES
       (FORALL (x: nat): x < m IFF x < IF n > m + n - 1 THEN 0 ELSE m ENDIF);

  % Subtype TCC generated (at line 47, column 55) for  i
      % expected type  below(m + n)
  concat_array_bot_TCC1: OBLIGATION
    FORALL (m, n: nat, i: below(m), a_m: below_array[m, T],
            a_n: below_array[n, T]):
      i < m + n;

  % Subtype TCC generated (at line 52, column 55) for  j
      % expected type  below(m + n)
  concat_array_top_TCC1: OBLIGATION
    FORALL (m, n: nat, j: {i: int | i >= m AND i < m + n},
            a_m: below_array[m, T], a_n: below_array[n, T]):
      j >= 0 AND j < m + n;

  % Subtype TCC generated (at line 52, column 64) for  j - m
      % expected type  below(n)
  concat_array_top_TCC2: OBLIGATION
    FORALL (m, n: nat, j: {i: int | i >= m AND i < m + n},
            a_m: below_array[m, T], a_n: below_array[n, T]):
      j - m >= 0 AND j - m < n;


body:
  max_array[N: posnat, T: TYPE, <= : (total_order?[T]) ]: THEORY
  %------------------------------------------------------------------------
  %
  %  max (basic definitions and properties)
  %  -------------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory defines the maximum function over an array of values
  %  from an ordered type. This is done in an implementation-independent
  %  manner.  However, a recursive executable form is included to 
  %  demonstrate that the definition is sound.
  %
  %  The following functions are defined:
  %           
  %      Imax(A,ii,jj)     = general definition of maximum of array A 
  %                          over the internal range from ii to jj. 
  %                          Returns the index into the array.
  %
  %      imax(A)           = general definition of maximum of array A. 
  %                          Returns the index into the array.
  %
  %      max(A)            = general definition of maximum of array A. 
  %                          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_lem and imax_lem.
  %     2. Since there may be replicates in A, the return type of imax
  %        may not be a singleton set.
  %------------------------------------------------------------------------

    EXPORTING ALL WITH below_arrays[N,T]

  BEGIN

    A,A1,A2: VAR ARRAY[below(N) -> T] 
    x: VAR T
    ii,jj,j: VAR below(N)

    IMPORTING below_arrays[N,T], max_array_def[N,T,<=]
   
    imax(A): {i: below(N)| (FORALL ii: A(ii) <= A(i))}

    max(A): { t: T | (FORALL ii: A(ii) <= t) AND
                      (EXISTS jj: A(jj) = t)} 

  % LEMMAs that follow immediately from TYPEPRED "imax" and TYPEPRED "max"

    max_lem   : LEMMA A(ii) <= max(A)

    max_in?   : LEMMA in?(max(A),A)

    imax_lem  : LEMMA A(imax(A)) = max(A)

    max_def   : LEMMA (FORALL ii: A(ii) <= max(A)) AND in?(max(A),A)

    max_it_is : LEMMA (FORALL ii: A(ii) <= x) AND in?(x,A) IMPLIES
                          max(A) = x

    imax_1    : LEMMA N = 1 IMPLIES imax(A) = 0

    max_2     : LEMMA N = 2 IMPLIES max(A) = IF A(0) <= A(1) THEN A(1)
                                             ELSE A(0) ENDIF

  END max_array

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

  % Existence TCC generated (at line 44, column 2) for
      % imax(A): {i: below(N) | (FORALL ii: A(ii) <= A(i))}
  imax_TCC1: OBLIGATION
    EXISTS (x:
              [A: [below(N) -> T] ->
                 {i: below(N) | FORALL ii: A(ii) <= A(i)}]):
      TRUE;

  % Existence TCC generated (at line 46, column 2) for
      % max(A): {t: T | (FORALL ii: A(ii) <= t) AND (EXISTS jj: A(jj) = t)}
  max_TCC1: OBLIGATION
    EXISTS (x:
              [A: [below(N) -> T] ->
                 {t: T |
                          (FORALL ii: A(ii) <= t) AND
                           (EXISTS jj: A(jj) = t)}]):
      TRUE;

  % Subtype TCC generated (at line 64, column 48) for  0
      % expected type  below(N)
  max_2_TCC1: OBLIGATION N = 2 IMPLIES 0 < N;

  % Subtype TCC generated (at line 64, column 56) for  1
      % expected type  below(N)
  max_2_TCC2: OBLIGATION N = 2 IMPLIES 1 < N;


body:
  min_array[N: posnat, T: TYPE, <= : (total_order?[T]) ]: THEORY
  %------------------------------------------------------------------------
  %
  %  min (basic definitions and properties)
  %  -------------------------------------------
  %
  %      Author: Ricky W. Butler
  %
  %  This theory defines the minimum function over an array of values
  %  from an ordered type. This is done in an implementation-independent
  %  manner. 
  %
  %      Imin(A,ii,jj)     = general definition of minimum of array A 
  %                          over the internal from ii to jj.  Returns the
  %                          index into the array.
  %
  %      imin(A)           = general definition of minimum of array A. 
  %                          Returns the index into the array.
  %
  %      min(A)            = general definition of minimum of array A. 
  %                          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_lem and imin_lem.
  %     2. Since there may be replicates in A, the return type of imin
  %        may not be a singleton set.
  %
  %------------------------------------------------------------------------

    EXPORTING ALL WITH below_arrays[N,T]

  BEGIN

    IMPORTING min_array_def[N,T,<=], below_arrays[N,T]

    A: VAR ARRAY[below(N) -> T] 
    x: VAR T
    ii,jj: VAR below(N)

    imin(A): {i: below(N)| (FORALL ii: A(i) <= A(ii))}

    min(A): { t: T | (FORALL ii: t <= A(ii)) AND
                      (EXISTS jj: A(jj) = t)} 

  % LEMMAs that follow immediately from TYPEPRED "imin" and TYPEPRED "min"

    min_lem   : LEMMA min(A) <= A(ii)

    min_in?   : LEMMA in?(min(A),A)

    min_def   : LEMMA (FORALL ii: min(A) <= A(ii)) AND in?(min(A),A)

    min_it_is : LEMMA (FORALL ii: x <= A(ii)) AND in?(x,A) IMPLIES
                          min(A) = x

    imin_lem  : LEMMA A(imin(A)) = min(A)

    imin_1    : LEMMA N = 1 IMPLIES imin(A) = 0

    min_2     : LEMMA N = 2 IMPLIES min(A) = IF A(0) <= A(1) THEN A(0)
                                             ELSE A(1) ENDIF

  END min_array

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

  % Existence TCC generated (at line 42, column 2) for
      % imin(A): {i: below(N) | (FORALL ii: A(i) <= A(ii))}
  imin_TCC1: OBLIGATION
    EXISTS (x:
              [A: [below(N) -> T] ->
                 {i: below(N) | FORALL ii: A(i) <= A(ii)}]):
      TRUE;

  % Existence TCC generated (at line 44, column 2) for
      % min(A): {t: T | (FORALL ii: t <= A(ii)) AND (EXISTS jj: A(jj) = t)}
  min_TCC1: OBLIGATION
    EXISTS (x:
              [A: [below(N) -> T] ->
                 {t: T |
                          (FORALL ii: t <= A(ii)) AND
                           (EXISTS jj: A(jj) = t)}]):
      TRUE;

  % Subtype TCC generated (at line 62, column 48) for  0
      % expected type  below(N)
  min_2_TCC1: OBLIGATION N = 2 IMPLIES 0 < N;

  % Subtype TCC generated (at line 62, column 56) for  1
      % expected type  below(N)
  min_2_TCC2: OBLIGATION N = 2 IMPLIES 1 < N;


body:
  sort_array_lems[N: posnat, T: TYPE, <= : (total_order?[T]) ]: THEORY
  BEGIN

    IMPORTING sort_array[N,T,sort_array_lems.<=],
               min_array[N,T,sort_array_lems.<=], 
               max_array[N,T,sort_array_lems.<=]

    A: VAR below_array

  % sort_sort: LEMMA sort(sort(A)) = sort(A)

    sort_min:  LEMMA sort(A)(0) = min(A)

    sort_max:  LEMMA sort(A)(N-1) = max(A)

  END sort_array_lems

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

  % Subtype TCC generated (at line 12, column 27) for  0
      % expected type  below(N)
  sort_min_TCC1: OBLIGATION 0 < N;

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


body:
  top_array: THEORY
  BEGIN

    IMPORTING           	% -------------- arrays -----------------
       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 

  END top_array


body:
  % Additions to standard prelude theories function_props, and function_props_alt
  %
  % David Lester, Manchester University, NIA, Université Perpignan 8/6/06


  function_props_aux[T1,T2,T3:TYPE]: THEORY

  BEGIN

    f1: VAR [T1->T2]
    f2: VAR [T2->T3]
    Y:  VAR set[T3]

    inverse_image_composition: LEMMA
      inverse_image(f1, inverse_image(f2,Y)) = inverse_image(f2 o f1, Y)


    composition_inverse_alt: LEMMA FORALL (f1:(bijective?[T1,T2]),
                                           f2:(bijective?[T2,T3])):
                                   inverse_alt(f2 o f1)
                                            = inverse_alt(f1) o inverse_alt(f2)

  END function_props_aux

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

  % Assuming TCC generated (at line 1370, column 3) for
      % function_inverse_alt[T1, T3]
      % generated from assumption function_inverse_alt.inverse_types
  composition_inverse_alt_TCC1: OBLIGATION
    FORALL (f1: (bijective?[T1, T2]), f2: (bijective?[T2, T3])):
      (EXISTS (d: T1): TRUE) OR (FORALL (r: T3): FALSE);

  % Assuming TCC generated (at line 1370, column 3) for
      % function_inverse_alt[T1, T2]
      % generated from assumption function_inverse_alt.inverse_types
  composition_inverse_alt_TCC2: OBLIGATION
    FORALL (f1: (bijective?[T1, T2]), f2: (bijective?[T2, T3])):
      (EXISTS (d: T1): TRUE) OR (FORALL (r: T2): FALSE);

  % Assuming TCC generated (at line 1370, column 3) for
      % function_inverse_alt[T2, T3]
      % generated from assumption function_inverse_alt.inverse_types
  composition_inverse_alt_TCC3: OBLIGATION
    FORALL (f1: (bijective?[T1, T2]), f2: (bijective?[T2, T3])):
      (EXISTS (d: T2): TRUE) OR (FORALL (r: T3): FALSE);


body:
  % Additions to standard prelude theory function_inverse_alt
  %
  % David Lester, Manchester University, NIA, Université Perpignan 8/6/06

  function_inverse_alt_aux[D,R:TYPE]: THEORY

  BEGIN

      ASSUMING
        inverse_types: ASSUMPTION (EXISTS (d: D): TRUE) OR (FORALL (r: R): FALSE)
      ENDASSUMING

    f: VAR [D -> R]

    inverse_inverse_alt: LEMMA bijective?[D,R](f) =>
                                                  inverse_alt(inverse_alt(f)) = f

  END function_inverse_alt_aux

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

  % Assuming TCC generated (at line 1370, column 3) for
      % function_inverse_alt[D, R]
      % generated from assumption function_inverse_alt.inverse_types
  inverse_inverse_alt_TCC1: OBLIGATION
    FORALL (f: [D -> R]):
      bijective?[D, R](f) IMPLIES
       (EXISTS (d: D): TRUE) OR (FORALL (r: R): FALSE);

  % Assuming TCC generated (at line 1370, column 3) for
      % function_inverse_alt[R, D]
      % generated from assumption function_inverse_alt.inverse_types
  inverse_inverse_alt_TCC2: OBLIGATION
    FORALL (f: [D -> R]):
      bijective?[D, R](f) IMPLIES
       (EXISTS (d: R): TRUE) OR (FORALL (r: D): FALSE);


body:
  % Additions to standard prelude theory function_image
  %
  % David Lester, Manchester University, NIA, Université Perpignan 8/6/06

  function_image_bis[D,R:TYPE]: THEORY

  BEGIN

    IMPORTING function_image[D,R]

    f:    VAR [D->R]
    X:    VAR set[D]
    Y:    VAR set[R]
    inj:  VAR (injective?[D,R])
    surj: VAR (surjective?[D,R])
    bij:  VAR (bijective?[D,R])

    image_emptyset: LEMMA image(f,emptyset[D]) = emptyset[R]

    inverse_image_emptyset: LEMMA inverse_image(f,emptyset[R]) = emptyset[D]

    surjective_image_inverse_image: LEMMA image(surj,inverse_image(surj,Y)) = Y

    injective_inverse_image_image:  LEMMA inverse_image(inj,image(inj,X))   = X

    bijective_image_iff_inverse_image: LEMMA
       image(bij,X) = Y IFF inverse_image(bij,Y) = X

  % I'm not sure that this last item belongs in this particular library.

    bijective_image_inverse_alt: LEMMA FORALL (bij:(bijective?[D,R])):
       inverse_image(bij,Y) = IF empty?(Y) THEN emptyset[D]
                              ELSE image(inverse_alt(bij),Y) ENDIF

  END function_image_bis

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

  % Assuming TCC generated (at line 1370, column 3) for
      % function_inverse_alt[D, R]
      % generated from assumption function_inverse_alt.inverse_types
  bijective_image_inverse_alt_TCC1: OBLIGATION
    FORALL (Y: set[R], bij: (bijective?[D, R])):
      NOT empty?(Y) IMPLIES (EXISTS (d: D): TRUE) OR (FORALL (r: R): FALSE);


body:
  %------------------------------------------------------------------------------
  % Generalised constant functions
  %
  % Generalises real constant functions.
  %
  %     Author: David Lester, Manchester University, NIA, Université Perpignan
  %
  %     Version 1.0            8/10/04  Initial Version
  %     Version 1.0            8/10/04  Generalised (inverse-)image
  %------------------------------------------------------------------------------

  const_fun_def[S,T:TYPE]: THEORY

  BEGIN

    x: VAR S
    a: VAR T
    X: VAR set[S]
    Y: VAR set[T]

    const_fun(a): [S->T] = LAMBDA x : a

    constant?(f:[S->T]):bool = EXISTS a: f = const_fun(a)

    image_const: LEMMA
       image(const_fun(a),X)
          = IF empty?(X) THEN emptyset[T] ELSE singleton(a) ENDIF

    inverse_image_const: LEMMA
       inverse_image(const_fun(a),Y)
          = IF Y(a) THEN fullset[S] ELSE emptyset[S] ENDIF

  END const_fun_def


body:
  %%% ADT file generated from Unit

  Unit_adt: THEORY
   BEGIN

    Unit: TYPE

    unit?: [Unit -> boolean]

    unit: (unit?)

    Unit_ord: [Unit -> upto(0)]

    Unit_ord_defaxiom: AXIOM Unit_ord(unit) = 0;

    ord(x: Unit): [Unit -> upto(0)] = CASES x OF unit: 0 ENDCASES

    Unit_inclusive: AXIOM FORALL (Unit_var: Unit): unit?(Unit_var);

    Unit_induction: AXIOM
      FORALL (p: [Unit -> boolean]):
        p(unit) IMPLIES (FORALL (Unit_var: Unit): p(Unit_var));

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

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

    Unit_well_founded: AXIOM strict_well_founded?[Unit](<<);
   END Unit_adt


body:
  Unit_adt_reduce[range: TYPE]: THEORY
   BEGIN

    IMPORTING Unit_adt

    reduce(unit?_fun: range):  [Unit -> range] =
        LAMBDA (Unit_adtvar: Unit):
          LET red: [Unit -> range] = reduce(unit?_fun) IN
            CASES Unit_adtvar OF unit: unit?_fun ENDCASES;

    REDUCE(unit?_fun: [Unit -> range]):  [Unit -> range] =
        LAMBDA (Unit_adtvar: Unit):
          LET red: [Unit -> range] = REDUCE(unit?_fun) IN
            CASES Unit_adtvar OF unit: unit?_fun(Unit_adtvar) ENDCASES;
   END Unit_adt_reduce


body:
  top: THEORY
  %------------------------------------------------------------------------
  % Elementary properties of reals and operations over reals
  %
  %  top_sigma      -- provides a family of summation functions
  %                    over functions [T FROM int -> real]
  %  min_max        -- properties on min,max
  %  abs_lems       -- additional properties of abs
  %  product_real   -- defines product over functions [int -> real]
  %  bounded_reals  -- defines sup, inf, max, min
  %  real_sets      -- properties of sup, inf, max, min
  %  real_fun_ops,  -- adding, subtracting, etc on functions
  %  real_fun_preds -- increasing?, decreasing?, etc on functions
  %  real_fun_props -- properties about defs in real_fun_preds
  %  exponent_props -- additional properties of expt
  %  sqrt           -- properties of square root
  %  sqrt_rew       -- REVISED with AUTO_REWRITE+ statements
  %                    (See also new strategies (sqrt-rew) and (sqrt-rew-off)
  %  sqrt_approx    -- definitions of sqrt_newton and sqrt_bisect
  %                    (newton and bisection methods for computing square roots).
  %  sq             -- square function and properties
  %  sq_rew         -- installs useful AUTO_REWRITE+s
  %  sign           -- properties of sign function
  %  sign3          -- properties of sign3 function
  %  quadratic      -- solution of quadratic equations
  %  quadratic_2b   -- a better solution of quadratic equations for 2b
  %  quad_minmax    -- minimum and Maximum of quadratic equations
  %  binomial,      -- binomial coefficient       
  %  polynomials	  -- polynomials		  
  %  more_polynomial_props
  %
  %  Version 2.5   1/24/08
  %
  %  CHANGES:
  %
  %     8/1/01:
  %        sqrt_exists    -- existence proof of sqrt
  %        sqrt_approx    -- theory added (by Fleuriot/Geser)
  %
  %     8/7/01
  %        sigma_with, sigma_zero added to sigma
  %
  %     2/26/02
  %        duplications with PVS 2.4 prelude removed
  %        predicates over functions given names with ?, e.g. increasing?
  %    
  %     3/14/02: Added quadratic_ax
  %
  %     2/26/03: Added AUTO_REWRITE+ commands to automate some routine stuff
  %
  %     3/7/03:  Added quadratic_minmax, new lemmas added to abs_lems
  %
  %     4/14/03: Duplicate theory problem resolved
  %
  %     11/3/03: binomial added                    (Lester)
  %
  %     11/28/03: quadratic_ax is gone (use quadratic instead) 
  %
  %     2/13/04: turned on more auto-rewrites in sq and sqrt
  %              (if old proofs fail, add the following to your old proof:
  %        (STOP-REWRITE "sq_sqrt" "sq_0" "sq_1" "sq_abs" "sq_abs_neg")
  %        (STOP-REWRITE "sqrt_0" "sqrt_1" "sqrt_square" "sqrt_sq" "sqrt_sq_neg")
  %     7/8/04:  Added auto-rewrites in factorial
  %     3/28/05: Added log_nat and moved bolzano.pvs to Interval package
  %              by C. Munoz
  %     4/15/05: polynomials moved here from trig_fnd
  %     3/27/06: sigma theories generalized by Paul Miner
  %     10/28/07: quad_minmax improved, circles_and_lines added 
  %     11/7/07: sigma theories improved
  %     1/24/08: product operator theories added
  %        
  %------------------------------------------------------------------------

  BEGIN
   
    IMPORTING top_sigma,         % set of summation theories
              mixed_products,  
              mixed_sigmas,
              old_sigma,
              abs_lems,          % additional properties about absolute value
              binomial,          % Binomial coefficient       
              bound_defs,        % upper_bound, lowerbound, lub, glb
              bounded_reals,     % defines sup, inf, max, min
              circles_and_lines, % intersection of dynamic line and a circle
              exponent_props,    % additional properties of expt
              expt_rew,          % usedful auto-rewrites for expt
              factorial_props,   % additional properties of factorial function
              harmonic_polynomials,
  	    log_nat,           % Natural and real part of a logarithm 
              base_repr,         % Base n representation of natural numbers (A. Dutle)
              min_max,           % Min,max properties
              polynomials,       % polynomials
              more_polynomial_props,
              poly_rew,
              bernstein_polynomials,
              quadratic,         % Solution of quadratic equations
  	    quadratic_2b,      % A better solution of quadratic equations for 2b
              quad_minmax,       % easier to use quadratic_minmax
  	    convex_functions,  % properties of convex functions
              real_orders,       % real orders <, <=, >=, >
  	    real_order_ep,     % order defined by floor(abs(x)/epsil) < floor(abs(y)/epsil)
              reals_complete_more, % some additional completness properties
              real_fun_ops,      % adding, subtracting, etc on functions
              real_fun_ops_aux,  % min, max over functions
              real_fun_preds,    % increasing?, decreasing?, etc on functions
              real_fun_orders,   % <, <=, >, >= over functions[T-> real]
              real_fun_props,    % properties about defs in real_fun_preds
              real_sets,         % more properties of bounded sets of reals
              real_facts,        % archimedian field properties, lub, glb
              sign,              % properties of the 2-value sign function
              sign3,             % properties of the 3-value sign function
              sq,                % square function
              sqrt,              % non-axiomatic version of sqrt
              sq_rew,            % useful auto-rewrites for square function
              sqrt_rew,          % useful auto rewrite for sqrt
              sqrt_approx,       % approximation to sqrt
              sqrt_rew,          % auto-rewrites for sqrt
              intervals_real,    % open_intv, closed_intv:  (a,b) or [a,b]

  	    product,              % generic theory
  	    product_below,
  	    product_int,
  	    product_nat,
  	    product_posnat,
  	    product_upto,

              product_seq,       % old theory for products over finite sequence 
              product_fseq,
              product_fseq_posnat,

              connected_set,
  	    RealInt            % Real intervals


  %   easy: LEMMA sqrt(2) <= 3/2

  END top


body:
  %%% Real Intervals %%%
  RealInt : THEORY
  BEGIN

    RealInt : TYPE = [# lb: real,
           	     ub: real,
  		     bounded_below: bool,
  		     bounded_above: bool,
  		     closed_below: bool,
  		     closed_above: bool #]

    I   : VAR RealInt
    x,y : VAR real

    contains?(I)(x): bool =
      (I`bounded_below IMPLIES
        (IF I`closed_below THEN I`lb<=x ELSE I`lb<x ENDIF)) AND
      (I`bounded_above IMPLIES
        (IF I`closed_above THEN x<=I`ub ELSE x<I`ub ENDIF))


    mk_realint(x,y:real,bb,ba,cb,ca:bool) : MACRO RealInt =
      (# lb:=x,ub:=y,bounded_below:=bb,bounded_above:=ba,closed_below:=cb,closed_above:=ca #)

    ;##(x,I) : bool = contains?(I)(x)

    RealInf : DATATYPE WITH SUBTYPES Inf,nInf,RealN 
    BEGIN
      oo  : inf? : Inf
      ninf(get_inf:Inf) : ninf? : nInf
      open(get_real:real) : open? : RealN 
    END RealInf

    rx,ry : VAR RealInf

    ;-(i:Inf) : nInf = ninf(oo)

    ;[||](x,ry) : RealInt = 
      LET y = IF open?(ry) THEN get_real(ry) ELSIF ninf?(ry) THEN x-1 ELSE x+1 ENDIF IN
      mk_realint(x,y,TRUE,open?(ry),TRUE,FALSE)

    ;[||](rx,y) : RealInt = 
      LET x = IF open?(rx) THEN get_real(rx) ELSIF inf?(rx) THEN y+1 ELSE y-1 ENDIF IN
      mk_realint(x,y,open?(rx),TRUE,FALSE,TRUE)

    ;[||](rx,ry) : RealInt = 
      LET x = IF open?(rx) THEN get_real(rx) 
              ELSIF open?(ry) THEN 
                IF inf?(rx) THEN get_real(ry)+1
                ELSE get_real(ry)-1 
                ENDIF
              ELSE -1 ENDIF,
          y = IF open?(ry) THEN get_real(ry) 
              ELSIF open?(rx) THEN 
                IF ninf?(ry) THEN get_real(rx)-1
                ELSE get_real(rx)+1 
                ENDIF
              ELSE 1 ENDIF IN
      mk_realint(x,y,open?(rx),open?(ry),FALSE,FALSE)

    z : VAR real

    in_ninf_inf : LEMMA
      z ## [| -oo, oo |]

    in_ninf_open : LEMMA
      z ## [| -oo, open(y) |] IFF z < y

    in_open_inf : LEMMA
      z ## [| open(x), oo |] IFF z > x

    in_open_open : LEMMA
      z ## [| open(x), open(y) |] IFF x < z AND z < y

    in_ninf_close : LEMMA
      z ## [| -oo, y |] IFF z <= y

    in_close_inf : LEMMA
      z ## [| x, oo |] IFF z >= x

  END RealInt

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

  RealInf_ord_defaxiom: AXIOM
    RealInf_ord(oo) = 0 AND
     (FORALL (get_inf: Inf): RealInf_ord(ninf(get_inf)) = 1) AND
      (FORALL (get_real: real): RealInf_ord(open(get_real)) = 2);

  RealInf_oo_extensionality: AXIOM
    FORALL (inf?_var: (inf?), inf?_var2: (inf?)): inf?_var = inf?_var2;

  RealInf_ninf_extensionality: AXIOM
    FORALL (ninf?_var: (ninf?), ninf?_var2: (ninf?)):
      get_inf(ninf?_var) = get_inf(ninf?_var2) IMPLIES ninf?_var = ninf?_var2;

  RealInf_ninf_eta: AXIOM
    FORALL (ninf?_var: (ninf?)): ninf(get_inf(ninf?_var)) = ninf?_var;

  RealInf_open_extensionality: AXIOM
    FORALL (open?_var: (open?), open?_var2: (open?)):
      get_real(open?_var) = get_real(open?_var2) IMPLIES
       open?_var = open?_var2;

  RealInf_open_eta: AXIOM
    FORALL (open?_var: (open?)): open(get_real(open?_var)) = open?_var;

  RealInf_get_inf_ninf: AXIOM
    FORALL (ninf1_var: Inf): get_inf(ninf(ninf1_var)) = ninf1_var;

  RealInf_get_real_open: AXIOM
    FORALL (open1_var: real): get_real(open(open1_var)) = open1_var;

  RealInf_inclusive: AXIOM
    FORALL (RealInf_var: RealInf):
      inf?(RealInf_var) OR ninf?(RealInf_var) OR open?(RealInf_var);

  RealInf_induction: AXIOM
    FORALL (p: [RealInf -> boolean]):
      (p(oo) AND
        (FORALL (ninf1_var: Inf): p(ninf1_var) IMPLIES p(ninf(ninf1_var)))
         AND (FORALL (open1_var: real): p(open(open1_var))))
       IMPLIES (FORALL (RealInf_var: RealInf): p(RealInf_var));

  RealInf_well_founded: AXIOM strict_well_founded?[RealInf](<<);

  RealInf: TYPE

  Inf: TYPE = (inf?)

  nInf: TYPE = (ninf?)

  RealN: TYPE = (open?)

  inf?: [RealInf -> boolean]

  ninf?: [RealInf -> boolean]

  open?: [RealInf -> boolean]

  Inf(x: RealInf):  boolean = inf?(x);

  nInf(x: RealInf):  boolean = ninf?(x);

  RealN(x: RealInf):  boolean = open?(x);

  get_inf: [nInf -> Inf]

  get_real: [RealN -> real]

  ninf: [Inf -> (ninf?)]

  open: [real -> (open?)]

  RealInf_ord: [RealInf -> upto(2)]

  ord(x: RealInf): [RealInf -> upto(2)] =
      CASES x OF oo: 0, ninf(ninf1_var): 1, open(open1_var): 2 ENDCASES

  subterm(x: RealInf, y: RealInf):  boolean =
      x = y OR
       CASES y
         OF oo: FALSE,
            ninf(ninf1_var): subterm(x, ninf1_var),
            open(open1_var): FALSE
         ENDCASES;

  reduce_nat(inf?_fun: nat, ninf?_fun: [nat -> nat],
             open?_fun: [real -> nat]):
        [RealInf -> nat] =
      LAMBDA (RealInf_adtvar: RealInf):
        LET red: [RealInf -> nat] =
              reduce_nat(inf?_fun, ninf?_fun, open?_fun)
          IN
          CASES RealInf_adtvar
            OF oo: inf?_fun,
               ninf(ninf1_var): ninf?_fun(red(ninf1_var)),
               open(open1_var): open?_fun(open1_var)
            ENDCASES;

  REDUCE_nat(inf?_fun: [RealInf -> nat], ninf?_fun: [[nat, RealInf] -> nat],
             open?_fun: [[real, RealInf] -> nat]):
        [RealInf -> nat] =
      LAMBDA (RealInf_adtvar: RealInf):
        LET red: [RealInf -> nat] =
              REDUCE_nat(inf?_fun, ninf?_fun, open?_fun)
          IN
          CASES RealInf_adtvar
            OF oo: inf?_fun(RealInf_adtvar),
               ninf(ninf1_var): ninf?_fun(red(ninf1_var), RealInf_adtvar),
               open(open1_var): open?_fun(open1_var, RealInf_adtvar)
            ENDCASES;

  reduce_ordinal(inf?_fun: ordinal, ninf?_fun: [ordinal -> ordinal],
                 open?_fun: [real -> ordinal]):
        [RealInf -> ordinal] =
      LAMBDA (RealInf_adtvar: RealInf):
        LET red: [RealInf -> ordinal] =
              reduce_ordinal(inf?_fun, ninf?_fun, open?_fun)
          IN
          CASES RealInf_adtvar
            OF oo: inf?_fun,
               ninf(ninf1_var): ninf?_fun(red(ninf1_var)),
               open(open1_var): open?_fun(open1_var)
            ENDCASES;

  REDUCE_ordinal(inf?_fun: [RealInf -> ordinal],
                 ninf?_fun: [[ordinal, RealInf] -> ordinal],
                 open?_fun: [[real, RealInf] -> ordinal]):
        [RealInf -> ordinal] =
      LAMBDA (RealInf_adtvar: RealInf):
        LET red: [RealInf -> ordinal] =
              REDUCE_ordinal(inf?_fun, ninf?_fun, open?_fun)
          IN
          CASES RealInf_adtvar
            OF oo: inf?_fun(RealInf_adtvar),
               ninf(ninf1_var): ninf?_fun(red(ninf1_var), RealInf_adtvar),
               open(open1_var): open?_fun(open1_var, RealInf_adtvar)
            ENDCASES;

  oo: (inf?)

  <<:  (strict_well_founded?[RealInf]) =
      LAMBDA (x, y: RealInf):
        CASES y
          OF oo: FALSE,
             ninf(ninf1_var): x = ninf1_var OR x << ninf1_var,
             open(open1_var): FALSE
          ENDCASES;


body:
  %------------------------------------------------------------------------------
  % connected_set
  % All type of intervals are connected sets
  %------------------------------------------------------------------------------

  connected_set : THEORY
  BEGIN

     x,y : VAR real
                    
     Connected : TYPE = 
       {s:set[real] | FORALL (a,b:(s)),(c:real): a <= c AND c <= b IMPLIES s(c)}

     ConnectedGt(x)     : TYPE = {s:Connected | FORALL (z:(s)): z > x}

     ConnectedGe(x)     : TYPE = {s:Connected | FORALL (z:(s)): z >= x}

     ConnectedLt(x)     : TYPE = {s:Connected | FORALL (z:(s)): z < x}

     ConnectedLe(x)     : TYPE = {s:Connected | FORALL (z:(s)): z <= x}

     ConnectedGtLt(x,y) : TYPE = {s:Connected | FORALL (z:(s)): x < z AND z < y}

     ConnectedGtLe(x,y) : TYPE = {s:Connected | FORALL (z:(s)): x < z AND z <= y}

     ConnectedGeLt(x,y) : TYPE = {s:Connected | FORALL (z:(s)): x <= z AND z < y}

     ConnectedGeLe(x,y): TYPE = {s:Connected | FORALL (z:(s)): x <= z AND z <= y}

     % (x,...)
     OpenInf(x) : ConnectedGt(x) = {z:real | z > x}

     % [x,...)
     CloseInf(x) : ConnectedGe(x) = {z:real | z >= x}

     % (...,x)
     InfOpen(x) : ConnectedLt(x) = {z:real | z < x}

     % (...,x]
     InfClose(x) : ConnectedLe(x) = {z:real | z <= x}

     % (x,y)
     OpenOpen(x,y) : ConnectedGtLt(x,y) = {z:real | x < z AND z < y}

     % (x,y]
     OpenClose(x,y) : ConnectedGtLe(x,y) = {z:real | x < z AND z <= y}

     % [x,y)
     CloseOpen(x,y) : ConnectedGeLt(x,y) = {z:real | x <= z AND z < y}

     % [x,y]
     CloseClose(x,y) : ConnectedGeLe(x,y) = {z:real | x <= z AND z <= y}

  END connected_set

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

  % Subtype TCC generated (at line 31, column 33) for  {z: real | z > x}
      % expected type  ConnectedGt(x)
  OpenInf_TCC1: OBLIGATION
    FORALL (x: real):
      (FORALL (a, b: ({z: real | z > x})), (c: real):
         a <= c AND c <= b IMPLIES c > x)
       AND (FORALL (z_1: ({z: real | z > x})): z_1 > x);

  % Subtype TCC generated (at line 34, column 34) for  {z: real | z >= x}
      % expected type  ConnectedGe(x)
  CloseInf_TCC1: OBLIGATION
    FORALL (x: real):
      (FORALL (a, b: ({z: real | z >= x})), (c: real):
         a <= c AND c <= b IMPLIES c >= x)
       AND (FORALL (z_1: ({z: real | z >= x})): z_1 >= x);

  % Subtype TCC generated (at line 37, column 33) for  {z: real | z < x}
      % expected type  ConnectedLt(x)
  InfOpen_TCC1: OBLIGATION
    FORALL (x: real):
      (FORALL (a, b: ({z: real | z < x})), (c: real):
         a <= c AND c <= b IMPLIES c < x)
       AND (FORALL (z_1: ({z: real | z < x})): z_1 < x);

  % Subtype TCC generated (at line 40, column 34) for  {z: real | z <= x}
      % expected type  ConnectedLe(x)
  InfClose_TCC1: OBLIGATION
    FORALL (x: real):
      (FORALL (a, b: ({z: real | z <= x})), (c: real):
         a <= c AND c <= b IMPLIES c <= x)
       AND (FORALL (z_1: ({z: real | z <= x})): z_1 <= x);

  % Subtype TCC generated (at line 43, column 40) for
      % {z: real | x < z AND z < y}
      % expected type  ConnectedGtLt(x, y)
  OpenOpen_TCC1: OBLIGATION
    FORALL (x: real, y: real):
      (FORALL (a, b: ({z: real | x < z AND z < y})), (c: real):
         a <= c AND c <= b IMPLIES x < c AND c < y)
       AND (FORALL (z_1: ({z: real | x < z AND z < y})): x < z_1 AND z_1 < y);

  % Subtype TCC generated (at line 46, column 41) for
      % {z: real | x < z AND z <= y}
      % expected type  ConnectedGtLe(x, y)
  OpenClose_TCC1: OBLIGATION
    FORALL (x: real, y: real):
      (FORALL (a, b: ({z: real | x < z AND z <= y})), (c: real):
         a <= c AND c <= b IMPLIES x < c AND c <= y)
       AND
       (FORALL (z_1: ({z: real | x < z AND z <= y})): x < z_1 AND z_1 <= y);

  % Subtype TCC generated (at line 49, column 41) for
      % {z: real | x <= z AND z < y}
      % expected type  ConnectedGeLt(x, y)
  CloseOpen_TCC1: OBLIGATION
    FORALL (x: real, y: real):
      (FORALL (a, b: ({z: real | x <= z AND z < y})), (c: real):
         a <= c AND c <= b IMPLIES x <= c AND c < y)
       AND
       (FORALL (z_1: ({z: real | x <= z AND z < y})): x <= z_1 AND z_1 < y);

  % Subtype TCC generated (at line 52, column 42) for
      % {z: real | x <= z AND z <= y}
      % expected type  ConnectedGeLe(x, y)
  CloseClose_TCC1: OBLIGATION
    FORALL (x: real, y: real):
      (FORALL (a, b: ({z: real | x <= z AND z <= y})), (c: real):
         a <= c AND c <= b IMPLIES x <= c AND c <= y)
       AND
       (FORALL (z_1: ({z: real | x <= z AND z <= y})): x <= z_1 AND z_1 <= y);


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 -> real] 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,low2       : VAR T_low
    high,high2      : VAR T_high 
    l,h,n,m,i : VAR T
    rng, nn   : VAR nat
    pn        : VAR posnat
    z         : VAR int
    a,x       : VAR real
    nzr       : VAR nzreal

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

     product(low, high, F): RECURSIVE real
        = 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_eq_0    : THEOREM product(low,high,F) = 0 IMPLIES  
                                    (EXISTS (n: subrange(low,high)): F(n) = 0)


    product_eq_zero    : THEOREM product(low,high,F) = 0 IFF  
                                    (EXISTS (n: subrange(low,high)): F(n) = 0)

    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_nz      : 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_prod2     : THEOREM low=low2 AND high=high2 IMPLIES
    		      	       product(low, high, F) * product(low2, high2, G)
                               = product(low, high, (LAMBDA i: F(i) * G(i)))

    product_cross   : THEOREM (FORALL (i:T): 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 -> real] = 
       (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_1          : THEOREM (FORALL (n: subrange(low,high)): F(n) = 1)
                                  IMPLIES product(low,high,F) = 1


  %   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
   
    Fnnr: VAR function[T -> nnreal]
    Fpr: VAR function[T -> posreal]
    Fnat: VAR function[T -> nat]
    Fposnat: VAR function[T -> posnat]

    prod_nnr: JUDGEMENT product(low,high,Fnnr) HAS_TYPE nnreal

    prod_pr: JUDGEMENT product(low,high,Fpr) HAS_TYPE posreal

    prod_nat: JUDGEMENT product(low,high,Fnat) HAS_TYPE nat

    prod_posnat: JUDGEMENT product(low,high,Fposnat) HAS_TYPE posnat

  %   product_eq_1        : THEOREM product(low,high,Fnat) = 1 IMPLIES  
  %                                   (FORALL (n: subrange(low,high)): Fnat(n) = 1)

  % ------------- Tail recursive version

    IMPORTING structures@for_iterate[real]

    product_it(low, high, F): real =
      for(low,high,1,LAMBDA(i:subrange(low,high),a:real):F(i)*a)

    product_it_product : LEMMA
      product_it(low,high,F) = product(low,high,F)

  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 59, 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 59, 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 59, 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 65, 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 66, 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 66, 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 70, 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 70, 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 85, 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 85, 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 88, 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 88, 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 91, 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 92, 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 95, 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: nzreal):
      high >= low IMPLIES nzr /= 0 OR (high - low + 1) >= 0;

  % Subtype TCC generated (at line 101, column 34) for  (high - low + 1)
      % expected type  {i: int | a /= 0 OR i >= 0}
  product_scal_TCC1: OBLIGATION
    FORALL (a: real, 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 69) for  n
      % expected type  T
  product_eq_0_TCC1: OBLIGATION
    FORALL (F: [T -> real], high: T_high, low: T_low):
      product(low, high, F) = 0 IMPLIES
       (FORALL (n: subrange(low, high)): T_pred(n));

  % Subtype TCC generated (at line 114, column 69) for  n
      % expected type  T
  product_eq_zero_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, n: subrange(low, high)): T_pred(n);

  % Subtype TCC generated (at line 127, 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 127, 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 128, 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 131, 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 131, 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);

  % Subtype TCC generated (at line 147, column 93) for  G(i)
      % expected type  nznum
  product_cross_TCC1: OBLIGATION
    FORALL (G: [T -> real]):
      (FORALL (i: T): G(i) /= 0) IMPLIES (FORALL (i1): G(i1) /= 0);

  % Judgement subtype TCC generated (at line 196, column 22) for
      % product(low, high, Fnnr)
      % expected type  nnreal
  prod_nnr: OBLIGATION
    FORALL (Fnnr, high, low): product(low, high, Fnnr) >= 0;

  % Judgement subtype TCC generated (at line 198, column 21) for
      % product(low, high, Fpr)
      % expected type  posreal
  prod_pr: OBLIGATION FORALL (Fpr, high, low): product(low, high, Fpr) > 0;

  % Judgement subtype TCC generated (at line 200, column 22) for
      % product(low, high, Fnat)
      % expected type  nat
  prod_nat: OBLIGATION
    FORALL (Fnat, high, low):
      rational_pred(product(low, high, Fnat)) AND
       integer_pred(product(low, high, Fnat)) AND
        product(low, high, Fnat) >= 0;

  % Judgement subtype TCC generated (at line 202, column 25) for
      % product(low, high, Fposnat)
      % expected type  posnat
  prod_posnat: OBLIGATION
    FORALL (Fposnat, high, low): product(low, high, Fposnat) > 0;


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


  % --------- 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)

    product_reverse  : THEOREM low<=high IMPLIES
    		   product(low, high, F) = 
  		   product(low, high, LAMBDA (j:nat): IF high+low-j<0 THEN 0
  		   		      	     	      ELSE F(high+low-j) ENDIF)


  % ---- 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 61, 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 61, 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 66, column 33) for  high + low - j
      % expected type  nat
  product_reverse_TCC1: OBLIGATION
    FORALL (high: int, low: nat):
      low <= high IMPLIES
       (FORALL (j: nat): NOT high + low - j < 0 IMPLIES high + low - j >= 0);

  % Subtype TCC generated (at line 73, 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_fseq_posnat: THEORY
  %-------------------------------------------------------------------------------
  %
  %  products over finite sequences of posnats
  %
  %  Author: Rick Butler    NASA Langley
  %
  %  NOTE: Later we may derive this theory from product_fseq
  %
  %-------------------------------------------------------------------------------
  BEGIN

     

     IMPORTING structures@fseqs[posnat], product_nat

     unk: VAR fsq[posnat]
     fs,fs1,fs2: VAR fseq    
     n,m: VAR nat

     F: VAR [nat -> posnat]

     product_nat_nat: JUDGEMENT product(m,n,F) HAS_TYPE posnat

     product(fs): posnat = IF length(fs) = 0 THEN 1
                           ELSE product(0,length(fs)-1,fs`seq)
                           ENDIF

     len0: LEMMA length(fs) = 0 IMPLIES product(fs) = 1

     l1,l2: VAR nat

     product_fseq_shift: LEMMA  product(l1, l1 + l2 - 1,
                                   LAMBDA (n: nat): IF n < l1 THEN unk`seq(n)
                                                    ELSE fs`seq(n - l1)  ENDIF)
                           = product(0, l2 - 1, fs`seq)


     product_fseq_concat: LEMMA product(fs1 o fs2) = product(fs1) * product(fs2)


     product_fseq_empty_seq: LEMMA product(empty_seq) = 1

     product_fseq_split: LEMMA length(fs) > 1 IMPLIES
                              product(fs) = product(fs ^ (0, length(fs) - 2)) * 
                                             seq(fs)(length(fs) - 1) 

     product_fseq_ge: LEMMA FORALL (n: below(length(fs))): product(fs) >= seq(fs)(n)


     nn: VAR posnat
     product_fseq_concat1:  LEMMA nn * product(fs)  = product(fs o fseq1(nn))

     product_fseq1:  LEMMA product(fseq1(nn)) = nn

  END product_fseq_posnat

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

  % Subtype TCC generated (at line 23, column 40) for  n
      % expected type  T_high[nat]
  product_nat_nat_TCC1: OBLIGATION
    FORALL (n): n >= 0 OR (EXISTS (j: nat): n <= j);

  % Subtype TCC generated (at line 26, column 40) for  length(fs) - 1
      % expected type  T_high[nat]
  product_TCC1: OBLIGATION
    FORALL (fs: fseq[posnat]):
      NOT length(fs) = 0 IMPLIES
       length(fs) - 1 >= 0 OR (EXISTS (j: nat): length(fs) - 1 <= j);

  % Subtype TCC generated (at line 33, column 42) for  l1 + l2 - 1
      % expected type  T_high[nat]
  product_fseq_shift_TCC1: OBLIGATION
    FORALL (l1, l2: nat):
      l1 + l2 - 1 >= 0 OR (EXISTS (j: nat): l1 + l2 - 1 <= j);

  % Subtype TCC generated (at line 35, column 62) for  n - l1
      % expected type  nat
  product_fseq_shift_TCC2: OBLIGATION
    FORALL (l1, n: nat): NOT n < l1 IMPLIES n - l1 >= 0;

  % Subtype TCC generated (at line 36, column 38) for  l2 - 1
      % expected type  T_high[nat]
  product_fseq_shift_TCC3: OBLIGATION
    FORALL (l2: nat): l2 - 1 >= 0 OR (EXISTS (j: nat): l2 - 1 <= j);

  % Subtype TCC generated (at line 45, column 59) for  length(fs) - 2
      % expected type  nat
  product_fseq_split_TCC1: OBLIGATION
    FORALL (fs: fseq[posnat]): length(fs) > 1 IMPLIES length(fs) - 2 >= 0;

  % Subtype TCC generated (at line 46, column 51) for  length(fs) - 1
      % expected type  nat
  product_fseq_split_TCC2: OBLIGATION
    FORALL (fs: fseq[posnat]): length(fs) > 1 IMPLIES length(fs) - 1 >= 0;


body:
  product_fseq[T: TYPE+ FROM real]: THEORY
  %-------------------------------------------------------------------------------
  %
  %     products over finite sequences of reals
  %
  %     Author: Rick Butler    NASA Langley
  %
  %-------------------------------------------------------------------------------
  BEGIN

     

     IMPORTING structures@fseqs[T], product_nat

     unk: VAR fsq[T]
     fs,fs1,fs2: VAR fseq    

     product(fs): real = IF length(fs) = 0 THEN 1
                         ELSE product(0,length(fs)-1,fs`seq)
                         ENDIF

     n,m: VAR nat

     len0: LEMMA length(fs) = 0 IMPLIES product(fs) = 1

     l1,l2: VAR nat

     product_fseq_shift: LEMMA  product(l1, l1 + l2 - 1,
                                   LAMBDA (n: nat): IF n < l1 THEN unk`seq(n)
                                                    ELSE fs`seq(n - l1)  ENDIF)
                           = product(0, l2 - 1, fs`seq)


     product_fseq_concat: LEMMA product(fs1 o fs2) = product(fs1) * product(fs2)


     product_fseq_empty_seq: LEMMA product(empty_seq) = 1

     product_fseq_split: LEMMA length(fs) > 1 IMPLIES
                              product(fs) = product(fs ^ (0, length(fs) - 2)) * 
                                             seq(fs)(length(fs) - 1) 

     x: VAR T
     product_fseq1:  LEMMA product(fseq1(x)) = x

  END product_fseq

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

  % Subtype TCC generated (at line 19, column 38) for  length(fs) - 1
      % expected type  T_high[nat]
  product_TCC1: OBLIGATION
    FORALL (fs: fseq[T]):
      NOT length(fs) = 0 IMPLIES
       length(fs) - 1 >= 0 OR (EXISTS (j: nat): length(fs) - 1 <= j);

  % Subtype TCC generated (at line 28, column 42) for  l1 + l2 - 1
      % expected type  T_high[nat]
  product_fseq_shift_TCC1: OBLIGATION
    FORALL (l1, l2: nat):
      l1 + l2 - 1 >= 0 OR (EXISTS (j: nat): l1 + l2 - 1 <= j);

  % Subtype TCC generated (at line 30, column 62) for  n - l1
      % expected type  nat
  product_fseq_shift_TCC2: OBLIGATION
    FORALL (l1, n: nat): NOT n < l1 IMPLIES n - l1 >= 0;

  % Subtype TCC generated (at line 31, column 38) for  l2 - 1
      % expected type  T_high[nat]
  product_fseq_shift_TCC3: OBLIGATION
    FORALL (l2: nat): l2 - 1 >= 0 OR (EXISTS (j: nat): l2 - 1 <= j);

  % Subtype TCC generated (at line 40, column 59) for  length(fs) - 2
      % expected type  nat
  product_fseq_split_TCC1: OBLIGATION
    FORALL (fs: fseq[T]): length(fs) > 1 IMPLIES length(fs) - 2 >= 0;

  % Subtype TCC generated (at line 41, column 51) for  length(fs) - 1
      % expected type  nat
  product_fseq_split_TCC2: OBLIGATION
    FORALL (fs: fseq[T]): length(fs) > 1 IMPLIES length(fs) - 1 >= 0;


body:
  product_seq_scaf: THEORY
  BEGIN


     IMPORTING finite_sequences[posnat]

     fs: VAR finite_sequence

     product_rec(fs: finite_sequence, i: below(length(fs)) ): RECURSIVE posnat = 
                   IF i = 0 THEN seq(fs)(0)
                   ELSE seq(fs)(i) * product_rec(fs,i-1)
                   ENDIF MEASURE i

     fs1,fs2: VAR finite_sequence
     n,m: VAR nat

     product_rec_mult: LEMMA n < length(fs1 o fs2) IMPLIES
                     product_rec(fs1 o fs2,n) = 
                            IF n < length(fs1) THEN
                               product_rec(fs1,n)
                            ELSIF length(fs1) = 0 THEN
                               product_rec(fs2,n)
                            ELSE
                               product_rec(fs1,length(fs1)-1) 
                               * product_rec(fs2,n-length(fs1))
                            ENDIF

     product_rec_caret: LEMMA n < length(fs) AND m < length(fs) 
                                 AND n <= m IMPLIES product_rec(fs, n) =
                                 product_rec(fs ^ (0, m), n)

  END product_seq_scaf

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

  % Subtype TCC generated (at line 10, column 39) for  0
      % expected type  below[fs`length]
  product_rec_TCC1: OBLIGATION
    FORALL (fs: finite_sequence[posnat], i: below(length(fs))):
      i = 0 IMPLIES 0 < fs`length;

  % Subtype TCC generated (at line 11, column 50) for  i - 1
      % expected type  below(length(fs))
  product_rec_TCC2: OBLIGATION
    FORALL (fs: finite_sequence[posnat], i: below(length(fs))):
      NOT i = 0 IMPLIES i - 1 >= 0 AND i - 1 < length(fs);

  % Termination TCC generated (at line 11, column 35) for
      % product_rec(fs, i - 1)
  product_rec_TCC3: OBLIGATION
    FORALL (fs: finite_sequence[posnat], i: below(length(fs))):
      NOT i = 0 IMPLIES i - 1 < i;

  % Subtype TCC generated (at line 22, column 45) for  n
      % expected type  below(length(fs2))
  product_rec_mult_TCC1: OBLIGATION
    FORALL (fs1, fs2: finite_sequence[posnat], n: nat):
      n < length(fs1 o fs2) AND NOT n < length(fs1) AND length(fs1) = 0
       IMPLIES n < length(fs2);

  % Subtype TCC generated (at line 24, column 45) for  length(fs1) - 1
      % expected type  below(length(fs1))
  product_rec_mult_TCC2: OBLIGATION
    FORALL (fs1, fs2: finite_sequence[posnat], n: nat):
      n < length(fs1 o fs2) AND NOT n < length(fs1) AND NOT length(fs1) = 0
       IMPLIES length(fs1) - 1 >= 0 AND length(fs1) - 1 < length(fs1);

  % Subtype TCC generated (at line 25, column 47) for  n - length(fs1)
      % expected type  below(length(fs2))
  product_rec_mult_TCC3: OBLIGATION
    FORALL (fs1, fs2: finite_sequence[posnat], n: nat):
      n < length(fs1 o fs2) AND NOT n < length(fs1) AND NOT length(fs1) = 0
       IMPLIES n - length(fs1) >= 0 AND n - length(fs1) < length(fs2);

  % Subtype TCC generated (at line 30, column 56) for  n
      % expected type  below(length(fs ^ (0, m)))
  product_rec_caret_TCC1: OBLIGATION
    FORALL (fs: finite_sequence[posnat], m, n: nat):
      n <= m AND m < length(fs) AND n < length(fs) IMPLIES
       n < length(^[posnat](fs, (0, m)));


body:
  product_seq: THEORY
  %------------------------------------------------------------------------------
  % 
  %  Obsolete theory for computing a product over a finite sequence
  %  See new product theories and product_fseq in structures library
  %
  %  Author: Rick Butler NASA Langley
  %
  %------------------------------------------------------------------------------
  BEGIN


     IMPORTING finite_sequences[posnat],
               product_seq_scaf

     fs: VAR finite_sequence

     product(fs): posnat = IF length(fs) = 0 THEN 1
                           ELSE product_rec(fs,length(fs)-1)
                           ENDIF

     fs1,fs2: VAR finite_sequence
     n,m: VAR nat

     len0: LEMMA length(fs) = 0 IMPLIES product(fs) = 1

     product_mult: LEMMA product(fs1 o fs2) = product(fs1) * product(fs2)


     product_empty_seq: LEMMA product(empty_seq) = 1

     product_split: LEMMA length(fs) > 1 IMPLIES
                              product(fs) = product(fs ^ (0, length(fs) - 2)) * 
                                             seq(fs)(length(fs) - 1) 

     product_ge: LEMMA FORALL (n: below(length(fs))): product(fs) >= seq(fs)(n)

     gen_seq1(n: posnat): finite_sequence[posnat] =
                                 (# length := 1,
                                    seq := (LAMBDA (ii: below(1)): n) #)


     nn: VAR posnat
     product_concat1:  LEMMA nn * product(fs)  = product(fs o gen_seq1(nn))

  %   IMPORTING product_nat

  %   product_def: LEMMA product(fs) = product(0,length(fs)-1,fs`seq)

  END product_seq

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

  % Subtype TCC generated (at line 19, column 45) for  length(fs) - 1
      % expected type  below(length(fs))
  product_TCC1: OBLIGATION
    FORALL (fs: finite_sequence[posnat]):
      NOT length(fs) = 0 IMPLIES
       length(fs) - 1 >= 0 AND length(fs) - 1 < length(fs);

  % Subtype TCC generated (at line 33, column 59) for  length(fs) - 2
      % expected type  nat
  product_split_TCC1: OBLIGATION
    FORALL (fs: finite_sequence[posnat]):
      length(fs) > 1 IMPLIES length(fs) - 2 >= 0;

  % Subtype TCC generated (at line 34, column 51) for  length(fs) - 1
      % expected type  below[fs`length]
  product_split_TCC2: OBLIGATION
    FORALL (fs: finite_sequence[posnat]):
      length(fs) > 1 IMPLIES
       length(fs) - 1 >= 0 AND length(fs) - 1 < fs`length;


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


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


  % --------- 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_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 -> real]


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


  % --------- 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:
  intervals_real[T: TYPE FROM real]: THEORY
  BEGIN

     AUTO_REWRITE+ member

     x,y: VAR T
     S,S1,S2: VAR set[T]
     
     r: VAR posreal

     open_intv(a:T,b:{x:T|a<x})(x)  : MACRO bool = a <  x AND x <  b
     closed_intv(a:T,b:{x:T|a<=x})(x): MACRO bool = a <= x AND x <= b

     open_interval(a:T,b:{x:T|a<x}): TYPE = (open_intv(a,b))
     closed_interval(a:T,b:{x:T|a<=x}): TYPE = (closed_intv(a,b))

     Open_interval(a,b:T): TYPE = {x: T | (a <= b IMPLIES (a < x AND x < b)) 
                                        AND (b < a  IMPLIES (b < x AND x < a))}

     Closed_interval(a,b:T): TYPE = {x: T | (a <= b IMPLIES (a <= x AND x <= b)) 
                                        AND (b < a  IMPLIES (b <= x AND x <= a))}


     above_intv(a:T)(x) : MACRO bool = x > a
     below_intv(a:T)(x) : MACRO bool = x < a

     a,b: VAR T


  END intervals_real


body:
  sq: THEORY
  BEGIN

    a,b,d: VAR real
    nna,nnb,nnc : VAR nonneg_real   
    nz          : VAR nzreal 
    n           : VAR nat               

    sq(a): nonneg_real = a*a

    sq_nz_pos         : JUDGEMENT sq(nz) HAS_TYPE posreal 

    sq_rew            : LEMMA a*a = sq(a) 

    sq_expt2          : LEMMA sq(a) = a^2 

    sq_neg            : LEMMA sq(-a) = sq(a)
        
    sq_pos            : LEMMA sq(a) >= 0
        
    sq_plus_pos       : LEMMA sq(a)+sq(b) >= 0
        
    sq_times          : LEMMA sq(a*b) = sq(a) * sq(b)

    sq_plus           : LEMMA sq(a+b) = sq(a) + 2*a*b + sq(b)

    sq_minus          : LEMMA sq(a-b) = sq(a) - 2*a*b + sq(b)

    sq_neg_minus      : LEMMA sq(a-b) = sq(b-a)

    sq_abs            : LEMMA sq(abs(a)) = sq(a)

    sq_abs_neg        : LEMMA sq(abs(-a)) = sq(a)

    sq_0              : LEMMA sq(0) = 0

    sq_1              : LEMMA sq(1) = 1

    sq_eq_0           : LEMMA sq(a) = 0 IFF a = 0

    sq_gt_0           : LEMMA sq(a) > 0 IFF a /= 0      

    sq_div            : LEMMA d /= 0 => sq(a/d) = sq(a)/sq(d)

    sq_plus_eq_0      : LEMMA sq(a) + sq(b) = 0 <=> (a = 0 AND b = 0)

    AUTO_REWRITE-     sq_neg_minus   

  % -------------------- Inequalities --------------------

    sq_ge  : LEMMA sq(nna) >= sq(nnb) IFF nna >= nnb 

    sq_le  : LEMMA sq(nna) <= sq(nnb) IFF nna <= nnb 

    sq_gt  : LEMMA sq(nna) > sq(nnb)  IFF nna > nnb

    sq_lt  : LEMMA sq(nna) < sq(nnb)  IFF nna < nnb 

    sq_eq  : LEMMA sq(nna) = sq(nnb)  IFF nna = nnb 

    sq_neg_pos_le : LEMMA sq(a) <= sq(nnc) IFF (-nnc <= a AND a <= nnc)

    neg_pos_sq_le : LEMMA (-b <= a AND a <= b) IMPLIES sq(a) <= sq(b)
        
    sq_neg_pos_lt : LEMMA  sq(a) < sq(nnc) IFF (-nnc < a AND a < nnc) 

    neg_pos_sq_lt : LEMMA (-b < a AND a < b) IMPLIES sq(a) < sq(b)

    sq_le_abs     : LEMMA sq(a) <= sq(b) IFF abs(a) <= abs(b)
        
    sq_lt_abs     : LEMMA sq(a) < sq(b) IFF abs(a) < abs(b)

    sq_ge_abs     : LEMMA sq(a) >= sq(b) IFF abs(a) >= abs(b)
        
    sq_gt_abs     : LEMMA sq(a) > sq(b) IFF abs(a) > abs(b)

    sq_eq_abs     : LEMMA sq(a) = sq(b) IFF abs(a) = abs(b)

    sq_eq_rew     : LEMMA a = b IMPLIES sq(a) = sq(b)


    %   |\
    %   | \ C <= c
    % A |  \
    %   +----
    %    B 

    triangle_rectangle: LEMMA sq(a)+sq(b) <= sq(nnc) IMPLIES
                                -nnc <= a AND a <= nnc AND 
                                -nnc <= b AND b <= nnc   

    triangle_ineq_lt  : LEMMA sq(a) + sq(b) < sq(d) IMPLIES  
                                    abs(a) < abs(d) AND
                                    abs(b) < abs(d)   


    triangle_ineq_le  : LEMMA sq(a) + sq(b) <= sq(d) IMPLIES 
                                    abs(a) <= abs(d) AND
                                    abs(b) <= abs(d)   



    AUTO_REWRITE+ sq_0
    AUTO_REWRITE+ sq_1
    AUTO_REWRITE+ sq_abs
    AUTO_REWRITE+ sq_abs_neg 


  END sq

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

  % Subtype TCC generated (at line 9, column 23) for  a * a
      % expected type  nonneg_real
  sq_TCC1: OBLIGATION FORALL (a: real): a * a >= 0;

  % Judgement subtype TCC generated (at line 11, column 32) for  sq(nz)
      % expected type  posreal
  sq_nz_pos: OBLIGATION FORALL (nz): sq(nz) > 0;

  % Subtype TCC generated (at line 15, column 38) for  2
      % expected type  {i: int | a /= 0 OR i >= 0}
  sq_expt2_TCC1: OBLIGATION FORALL (a: real): a /= 0 OR 2 >= 0;

  % Subtype TCC generated (at line 43, column 54) for  sq(d)
      % expected type  nznum
  sq_div_TCC1: OBLIGATION FORALL (d: real): d /= 0 IMPLIES sq(d) /= 0;


body:
  sq_rew: THEORY
  BEGIN

    IMPORTING sq

  %  sq_rew            : LEMMA a*a = sq(a) 

    AUTO_REWRITE+ sq_neg            %  LEMMA sq(-a) = sq(a)
    AUTO_REWRITE+ sq_0              %  LEMMA sq(0) = 0
    AUTO_REWRITE+ sq_1              %  LEMMA sq(1) = 1
    AUTO_REWRITE+ sq_abs            %  LEMMA sq(abs(a)) = sq(a)
    AUTO_REWRITE+ sq_abs_neg        %  LEMMA sq(abs(-a)) = sq(a)

        
  %  sq_times          : LEMMA sq(a*b) = sq(a) * sq(b)
  %  sq_plus           : LEMMA sq(a+b) = sq(a) + 2*a*b + sq(b)
  %  sq_minus          : LEMMA sq(a-b) = sq(a) - 2*a*b + sq(b)
  %  sq_neg_minus      : LEMMA sq(a-b) = sq(b-a)
  %  sq_eq_0           : LEMMA sq(a) = 0 IFF a = 0
  %  sq_gt_0           : LEMMA sq(a) > 0 IFF a /= 0      
  %  sq_div            : LEMMA d /= 0 => sq(a/d) = sq(a)/sq(d)
  %  sq_plus_eq_0      : LEMMA sq(a) + sq(b) = 0 <=> (a = 0 AND b = 0)


  % -------------------- Inequalities --------------------

  %  sq_ge  : LEMMA sq(nna) >= sq(nnb) IFF nna >= nnb 
  %  sq_le  : LEMMA sq(nna) <= sq(nnb) IFF nna <= nnb 
  %  sq_gt  : LEMMA sq(nna) > sq(nnb)  IFF nna > nnb
  %  sq_lt  : LEMMA sq(nna) < sq(nnb)  IFF nna < nnb 
  %  sq_eq  : LEMMA sq(nna) = sq(nnb)  IFF nna = nnb 
    


  END sq_rew


body:
  sqrt_exists: THEORY
  %--------------------------------------------------------------------------------
  %
  %   This theory provides a non-constructive proof of the existence of the
  %   square root function.  The proof has been adapted from Rosenlicht's
  %   Introduction to Analysis.
  %
  %--------------------------------------------------------------------------------


  BEGIN
    
    e: VAR posreal
    x, y: VAR real
    nnx, nny: VAR nonneg_real
    i: var posnat
    
    epsilon_delta: LEMMA (FORALL e: abs(x - y) < e) => x = y

    expt_0       : LEMMA 0^i = 0

    lt1_expt_le  : LEMMA nnx < 1 => nnx^i <= nnx

    sqrt_exists  : LEMMA
                     EXISTS (x1: [nnx: nonneg_real -> {nny | nny*nny = nnx}]): TRUE

  END sqrt_exists

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

  % Subtype TCC generated (at line 22, column 38) for  i
      % expected type  {i: int | nnx /= 0 OR i >= 0}
  lt1_expt_le_TCC1: OBLIGATION
    FORALL (i: posnat, nnx: nonneg_real): nnx < 1 IMPLIES nnx /= 0 OR i >= 0;


body:
  %% Sign definition

  %% Created by Cesar Munoz
  %% Updated by Alfons Geser

  sign : THEORY
  BEGIN

    IMPORTING sq

    Sign : TYPE = {i:nzint|i=1 OR i=-1} 
    sign(x:real): Sign = IF x >= 0 THEN 1 ELSE -1 ENDIF

    eps,
    eps1,eps2 : VAR Sign
    x,y,z     : VAR real
    nnx       : VAR nnreal
    nx        : VAR negreal
    n         : VAR nat

    sign_mult_clos: JUDGEMENT *(eps1,eps2) HAS_TYPE Sign

    sign_div_clos : JUDGEMENT  /(eps1,eps2) HAS_TYPE Sign

    sign_neg_clos : JUDGEMENT  -(eps1) HAS_TYPE Sign

    sign_sq_clos  : JUDGEMENT   sq(eps1) HAS_TYPE Sign

    sign_id       : LEMMA sign(eps) = eps

    sign_pos      : LEMMA sign(x)*x >= 0

    sign_eq_1     : LEMMA sign(nnx) = 1
   
    sign_eq_neg1  : LEMMA sign(nx) = -1

    sign_nat      : LEMMA sign(n) = 1

    sign_abs      : LEMMA abs(x) = sign(x)*x

    sign_nneg     : LEMMA sign(x)*x >= 0

    square_eps    : LEMMA eps*eps = 1

    sq_eps        : LEMMA sq(eps) = 1

    sq_eq_sign    : LEMMA sq(x) = sq(y)  IFF (EXISTS eps: x = eps*y)
    
    sq_sign       : LEMMA sq(sign(x)) = 1

    sign_sign     : LEMMA sign(x)*sign(x) = 1

    sign_times_abs: LEMMA sign(x)*abs(x) = x

    abs_sign      : LEMMA eps*x >= 0 IMPLIES eps*x = abs(x)

    abs_pos       : LEMMA abs(x) > 0 IFF x /= 0

    sign_neg      : LEMMA x /= 0 IMPLIES  sign(-x) = -sign(x)

    sign_minus    : LEMMA x /= y IMPLIES  -sign(x-y) = sign(y-x)

    sign_mult     : LEMMA x /= 0 and y/=0 IMPLIES  sign(x*y) = sign(x)*sign(y)

    sign_div      : LEMMA y /= 0 AND x /= 0 IMPLIES sign(x/y) = sign(x)*sign(y)

    sign_mult_pos : LEMMA x > 0 IMPLIES sign(x*y) = sign(y)

    sign_div_pos1 : LEMMA x > 0 AND y /= 0 IMPLIES sign(x/y) = sign(y)

    sign_div_pos2 : LEMMA y > 0 IMPLIES sign(x/y) = sign(x)

    sign_mult_neg : LEMMA x < 0 IMPLIES sign(x*y) = sign(-y)

    sign_div_neg1 : LEMMA x < 0 AND y /= 0 IMPLIES sign(x/y) = -sign(y)

    sign_div_neg2 : LEMMA y < 0 IMPLIES sign(x/y) = sign(-x)

    sign_div_mult : LEMMA sign(x)/sign(y) = sign(x)*sign(y)

    sign_and_abs  : LEMMA sign(x) = sign(y) AND abs(x) = abs(y) IFF x = y

    sign_le : LEMMA
       x <= y IMPLIES sign(x) <= sign(y)

    sign_ge : LEMMA
       x >= y IMPLIES sign(x) >= sign(y)

    sign_dichotomy : LEMMA
       sign(x)=sign(y) OR sign(x)=-sign(y)

    AUTO_REWRITE+ sign_nat

    sign_ext(x): {sig:real|(sig=-1 OR sig=1 OR sig=0) AND sig*x=abs(x)} =
      IF x<0 THEN -1
      ELSIF x>0 THEN 1
      ELSE 0 ENDIF

    sign_ext_mult: LEMMA FORALL (x,y:real): sign_ext(x*y) = sign_ext(x)*sign_ext(y)

  END sign

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

  % Judgement subtype TCC generated (at line 21, column 28) for  eps1 * eps2
      % expected type  Sign
  sign_mult_clos: OBLIGATION
    FORALL (eps1, eps2): eps1 * eps2 = 1 OR eps1 * eps2 = -1;

  % Judgement subtype TCC generated (at line 23, column 29) for  eps1 / eps2
      % expected type  Sign
  sign_div_clos: OBLIGATION
    FORALL (eps1, eps2):
      integer_pred(eps1 / eps2) AND
       eps1 / eps2 /= 0 AND (eps1 / eps2 = 1 OR eps1 / eps2 = -1);

  % Judgement subtype TCC generated (at line 25, column 29) for  -eps1
      % expected type  Sign
  sign_neg_clos: OBLIGATION FORALL (eps1): -eps1 = 1 OR -eps1 = -1;

  % Judgement subtype TCC generated (at line 27, column 30) for  sq(eps1)
      % expected type  Sign
  sign_sq_clos: OBLIGATION
    FORALL (eps1):
      rational_pred(sq(eps1)) AND
       integer_pred(sq(eps1)) AND
        sq(eps1) /= 0 AND (sq(eps1) = 1 OR sq(eps1) = -1);

  % Subtype TCC generated (at line 71, column 45) for  y
      % expected type  nznum
  sign_div_pos2_TCC1: OBLIGATION FORALL (y: real): y > 0 IMPLIES y /= 0;

  % Subtype TCC generated (at line 77, column 45) for  y
      % expected type  nznum
  sign_div_neg2_TCC1: OBLIGATION FORALL (y: real): y < 0 IMPLIES y /= 0;

  % Subtype TCC generated (at line 95, column 16) for  -1
      % expected type  {sig: real |
                     %          (sig = -1 OR sig = 1 OR sig = 0) AND
                     %           sig * x = abs(x)}
  sign_ext_TCC1: OBLIGATION FORALL (x: real): x < 0 IMPLIES -1 * x = abs(x);

  % Subtype TCC generated (at line 96, column 19) for  1
      % expected type  {sig: real |
                     %          (sig = -1 OR sig = 1 OR sig = 0) AND
                     %           sig * x = abs(x)}
  sign_ext_TCC2: OBLIGATION
    FORALL (x: real): x > 0 AND NOT x < 0 IMPLIES 1 * x = abs(x);

  % Subtype TCC generated (at line 97, column 9) for  0
      % expected type  {sig: real |
                     %          (sig = -1 OR sig = 1 OR sig = 0) AND
                     %           sig * x = abs(x)}
  sign_ext_TCC3: OBLIGATION
    FORALL (x: real): NOT x > 0 AND NOT x < 0 IMPLIES 0 * x = abs(x);


body:
  sqrt: THEORY
  %------------------------------------------------------------------------
  %
  %  Square root of non-negative real
  %
  %  Supercedes older version: sqrt_ax
  %
  %  Authors:  Rick Butler             NASA
  %            Cesar Munoz             NIA
  %------------------------------------------------------------------------
  BEGIN

    IMPORTING sq,sign,                      % sq(a): nonneg_real = a*a
              sqrt_exists

     nnx, nny, nnz: VAR nonneg_real
     a,x,y,z,xx: VAR real

    sqrt(nnx): {nnz : nnreal | nnz*nnz = nnx}

    sqrt_pos            : JUDGEMENT sqrt(px: posreal) HAS_TYPE posreal

  % -------------------- Special Arguments --------------------

    sqrt_0              : LEMMA  sqrt(0) = 0
    sqrt_1              : LEMMA  sqrt(1) = 1
    sqrt_eq_0           : LEMMA  sqrt(nnx) = 0 IMPLIES nnx = 0
    sqrt_eq_1           : LEMMA  sqrt(nnx) = 1 IMPLIES nnx = 1

  % -------------------- Basic Properties --------------------

    sqrt_lem            : LEMMA  sqrt(nny) = nnz IFF nnz * nnz = nny
                                 
    sqrt_def            : LEMMA  sqrt(nnx) * sqrt(nnx) = nnx

    sqrt_square         : LEMMA  sqrt(nnx * nnx) = nnx

    sqrt_sq             : LEMMA  x >= 0 IMPLIES sqrt(sq(x)) = x

    sqrt_sq_neg         : LEMMA  x < 0 IMPLIES sqrt(sq(x)) = -x

    sqrt_sq_abs         : LEMMA  sqrt(sq(x)) = abs(x)

    sqrt_sq_sign        : LEMMA  sqrt(sq(x)) = sign(x)*x

    sq_sqrt             : LEMMA  x >= 0 IMPLIES sq(sqrt(x))=x

    sqrt_times          : LEMMA  sqrt(nny * nnz) = sqrt(nny) * sqrt(nnz)

    sqrt_div            : LEMMA  nnz /= 0 IMPLIES 
                                     sqrt(nny / nnz) = sqrt(nny) / sqrt(nnz)

    abs_sqrt            : LEMMA abs(sqrt(nnx)) = sqrt(nnx)

    sqrt_scal           : LEMMA abs(a)*sqrt(nnx) = sqrt(sq(a)*nnx)


  % --------------------- Inequalities --------------------
                                 
    sqrt_lt             : LEMMA  sqrt(nny) < sqrt(nnz) IFF nny < nnz 

    sqrt_le             : LEMMA  sqrt(nny) <= sqrt(nnz) IFF nny <= nnz 

    sqrt_gt             : LEMMA  sqrt(nny) > sqrt(nnz) IFF nny > nnz 

    sqrt_ge             : LEMMA  sqrt(nny) >= sqrt(nnz) IFF nny >= nnz 

    sqrt_eq             : LEMMA  sqrt(nny) = sqrt(nnz) IFF nny = nnz  

    sqrt_less           : LEMMA  nnx > 1 IMPLIES sqrt(nnx) < nnx

    sqrt_more           : LEMMA  nnx > 0 AND nnx < 1 IMPLIES sqrt(nnx) > nnx


    sqrt_lt_0           : LEMMA  nnx < 0 IFF sqrt(nnx) < 0

    sqrt_le_0           : LEMMA  nnx <= 0 IFF sqrt(nnx) <= 0

    sqrt_gt_0           : LEMMA  nnx > 0 IFF sqrt(nnx) > 0

    sqrt_ge_0           : LEMMA  nnx >= 0 IFF sqrt(nnx) >= 0


    sqrt_lt1            : LEMMA  nnx < 1 IFF sqrt(nnx) < 1

    sqrt_le1            : LEMMA  nnx <= 1 IFF sqrt(nnx) <= 1

    sqrt_gt1            : LEMMA  nnx > 1 IFF sqrt(nnx) > 1

    sqrt_ge1            : LEMMA  nnx >= 1 IFF sqrt(nnx) >= 1




    sqrt_plus_le        : LEMMA  sqrt(nnx+nny) <= sqrt(nnx) + sqrt(nny)

    sqrt_cauchy         : LEMMA FORALL (a,b,c,d: real):
                             a*c + b*d <= sqrt(sq(a)+sq(b)) *  sqrt(sq(c)+sq(d))



    sqrt_4              : LEMMA  sqrt(4) = 2
    sqrt_9              : LEMMA  sqrt(9) = 3 
    sqrt_16             : LEMMA  sqrt(16) = 4
    sqrt_25             : LEMMA  sqrt(25) = 5

    AUTO_REWRITE+   sqrt_4
    AUTO_REWRITE+   sqrt_9
    AUTO_REWRITE+   sqrt_16
    AUTO_REWRITE+   sqrt_25

    AUTO_REWRITE+ sqrt_0
    AUTO_REWRITE+ sqrt_1
    AUTO_REWRITE+ sqrt_square
    AUTO_REWRITE+ sqrt_sq
    AUTO_REWRITE+ sqrt_sq_neg
    AUTO_REWRITE+ sq_sqrt


  END sqrt

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

  % Existence TCC generated (at line 19, column 2) for
      % sqrt(nnx): {nnz: nnreal | nnz * nnz = nnx}
  sqrt_TCC1: OBLIGATION
    EXISTS (x: [nnx: nonneg_real -> {nnz: nnreal | nnz * nnz = nnx}]): TRUE;

  % Judgement subtype TCC generated (at line 21, column 34) for  sqrt(px)
      % expected type  posreal
  sqrt_pos: OBLIGATION FORALL (px: posreal): sqrt(px) > 0;

  % Subtype TCC generated (at line 51, column 40) for  nny / nnz
      % expected type  nnx: nonneg_real
  sqrt_div_TCC1: OBLIGATION
    FORALL (nny, nnz: nonneg_real): nnz /= 0 IMPLIES nny / nnz >= 0;

  % Subtype TCC generated (at line 51, column 65) for  sqrt(nnz)
      % expected type  nznum
  sqrt_div_TCC2: OBLIGATION
    FORALL (nnz: nonneg_real): nnz /= 0 IMPLIES sqrt(nnz) /= 0;


body:
  sqrt_rew: THEORY
  %------------------------------------------------------------------------
  %
  %  Square root AUTO-REWRITE+ definitions to increase automation
  %
  %------------------------------------------------------------------------

  BEGIN

    IMPORTING sqrt, sq_rew

    nnx, nny, nnz, nna : VAR nonneg_real
    x,y,z,xx: VAR real


    AUTO_REWRITE+   sqrt_0         %  : LEMMA  sqrt(0) = 0
    AUTO_REWRITE+   sqrt_1         %  : LEMMA  sqrt(1) = 1

    AUTO_REWRITE+   sqrt_eq_0      %  : LEMMA  sqrt(nnx) = 0 IMPLIES nnx = 0
    AUTO_REWRITE+   sqrt_def       %  : LEMMA  sqrt(nnx) * sqrt(nnx) = nnx
    AUTO_REWRITE+   sqrt_square    %  : LEMMA  sqrt(nnx * nnx) = nnx

    AUTO_REWRITE+   sqrt_sq        %  : LEMMA  x >= 0 IMPLIES sqrt(sq(x)) = x
    AUTO_REWRITE+   sqrt_sq_neg    %  : LEMMA  x < 0 IMPLIES sqrt(sq(x)) = -x
    AUTO_REWRITE+   sqrt_sq_abs    %  : LEMMA  sqrt(sq(x)) = abs(x)

    sqrt_4              : LEMMA  sqrt(4) = 2
    sqrt_9              : LEMMA  sqrt(9) = 3 
    sqrt_16             : LEMMA  sqrt(16) = 4
    sqrt_25             : LEMMA  sqrt(25) = 5
    sqrt_36             : LEMMA  sqrt(36) = 6
    sqrt_49             : LEMMA  sqrt(49) = 7
    sqrt_64             : LEMMA  sqrt(64) = 8
    sqrt_81             : LEMMA  sqrt(81) = 9
    sqrt_100            : LEMMA  sqrt(100) = 10

    AUTO_REWRITE+   sqrt_4
    AUTO_REWRITE+   sqrt_9
    AUTO_REWRITE+   sqrt_16
    AUTO_REWRITE+   sqrt_25
    AUTO_REWRITE+   sqrt_36
    AUTO_REWRITE+   sqrt_49
    AUTO_REWRITE+   sqrt_64
    AUTO_REWRITE+   sqrt_81
    AUTO_REWRITE+   sqrt_100


    sqrt_factor_left  : LEMMA  sqrt(nna * nnx * nnx) = sqrt(nna) * nnx
    sqrt_factor_middle: LEMMA  sqrt(nnx * nna * nnx) = sqrt(nna) * nnx
    sqrt_factor_right : LEMMA  sqrt(nnx * nnx * nna) = sqrt(nna) * nnx

    AUTO_REWRITE+   sqrt_factor_left
    AUTO_REWRITE+   sqrt_factor_middle
    AUTO_REWRITE+   sqrt_factor_right


  %  sqrt_times_rev  : LEMMA  sqrt(nny) * sqrt(nnz) = sqrt(nny * nnz)  

  %  sqrt_div_rev    : LEMMA  nnz /= 0 IMPLIES 
  %                              sqrt(nny) / sqrt(nnz) = sqrt(nny / nnz) 

  %  AUTO_REWRITE+   sqrt_times_rev
  %  AUTO_REWRITE+   sqrt_div_rev

  END sqrt_rew


body:
  prelude_aux: THEORY
  BEGIN
     px: VAR posreal
     x,y: VAR real
     i: VAR nat

     floor_le    : LEMMA x <= y IMPLIES floor(x) <= floor(y)

     floor_lt    : LEMMA x < y IMPLIES floor(x) < floor(y) + 1

     floor_div_le: LEMMA y >= 1 IMPLIES floor(px/y) <= px

     floor_div_lt: LEMMA y > 1  IMPLIES floor(px/y) < px

     floor_le_floor: LEMMA y >= 1 IMPLIES floor(px/y) <= floor(px)

     floor_lt_floor_int: LEMMA i > 1 AND  x >= i IMPLIES
                             floor(x / i) < floor(x)

     %% this is a generalization of what is already in the prelude
     floor_small: LEMMA  abs(x) < abs(y) IMPLIES
                           floor(x/y) = IF x/y >= 0 THEN 0 ELSE -1 ENDIF




  END prelude_aux

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

  % Subtype TCC generated (at line 11, column 47) for  y
      % expected type  nznum
  floor_div_le_TCC1: OBLIGATION FORALL (y: real): y >= 1 IMPLIES y /= 0;

  % Subtype TCC generated (at line 13, column 47) for  y
      % expected type  nznum
  floor_div_lt_TCC1: OBLIGATION FORALL (y: real): y > 1 IMPLIES y /= 0;

  % Subtype TCC generated (at line 18, column 37) for  i
      % expected type  nznum
  floor_lt_floor_int_TCC1: OBLIGATION
    FORALL (i: nat, x: real): x >= i AND i > 1 IMPLIES i /= 0;

  % Subtype TCC generated (at line 22, column 33) for  y
      % expected type  nznum
  floor_small_TCC1: OBLIGATION
    FORALL (x, y: real): abs(x) < abs(y) IMPLIES y /= 0;


body:
  log_nat : THEORY
  %----------------------------------------------------------------------------
  %
  % Authors: Cesar Munoz (NIA)
  % This theory implements an algorithm to compute the natural part and the 
  % real part of a logarithm. This algorithm is analogous to the Euclidean 
  % division procedure.
  % Date: March 28 2005
  %
  %----------------------------------------------------------------------------
  BEGIN

    x,y,ya : VAR {x:real| x >= 1}
    na     : VAR nat
    p      : VAR above(1)

    IMPORTING prelude_aux

    log_nat(x,p): RECURSIVE [n:nat,{y | y<p AND x=p^n*y}] =
      if   x < p then (0,x)
      else let (n,y) = log_nat(x/p,p) in (n+1,y)
      endif
      MEASURE floor(x)

    log_nat_bounds : LEMMA
      let (n,y)=log_nat(x,p) in
      p^n <= x AND x < p^(n+1)

    log_nat_incr : LEMMA
      p*x <= y IMPLIES
      log_nat(x,p)`1 < log_nat(y,p)`1

    log_nat_itaux(x,p,na,(ya | x=p^na*ya)): RECURSIVE [n:nat,{y | y<p AND x=p^n*y}] = 
      if   ya < p then (na,ya)
      else log_nat_itaux(x,p,na+1,ya/p)
      endif
      MEASURE floor(ya)

    log_nat_it(x,p) :  [n:nat,{y | y <p AND x=p^n*y}] =
      log_nat_itaux(x,p,0,x)

    log_nat_id : LEMMA
      log_nat_it(x,p) = log_nat(x,p)

    least_pow_2_ge(xp:posreal): {k:int |
      xp<=2^k AND FORALL (i:int): i<k IMPLIES 2^i<xp} =
      IF xp>=1 THEN
        LET (n,y) = log_nat_it(xp,2) IN
          IF y=1 THEN n
  	ELSE n+1 ENDIF
      ELSIF xp>1/2 THEN 0
      ELSE LET n = log_nat_it(1/xp,2)`1 IN -n ENDIF

  END log_nat  

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

  % Subtype TCC generated (at line 19, column 50) for  n
      % expected type  {i: int | p /= 0 OR i >= 0}
  log_nat_TCC1: OBLIGATION
    FORALL (n: nat, p, y: {x: real | x >= 1}): y < p IMPLIES p /= 0 OR n >= 0;

  % Subtype TCC generated (at line 23, column 12) for  floor(x)
      % expected type  naturalnumber
  log_nat_TCC2: OBLIGATION FORALL (x: {x: real | x >= 1}): floor(x) >= 0;

  % Subtype TCC generated (at line 20, column 23) for  x
      % expected type  {y | y < p AND x = p ^ 0 * y}
  log_nat_TCC3: OBLIGATION
    FORALL (x: {x: real | x >= 1}, p: above(1)):
      x < p IMPLIES x < p AND x = p ^ 0 * x;

  % Subtype TCC generated (at line 21, column 44) for  y
      % expected type  {y | y < p AND x = (p ^ (1 + n)) * y}
  log_nat_TCC4: OBLIGATION
    FORALL (x: {x: real | x >= 1},
            v:
              [d1:
                 {z: [{x: real | x >= 1}, above(1)] |
                          floor(z`1) < floor(x)} ->
                 [n: nat, {y | y < d1`2 AND d1`1 = d1`2 ^ n * y}]],
            p: above(1)):
      NOT x < p IMPLIES
       (FORALL (n: nat, y: {y | y < p AND x / p = p ^ n * y}):
          y = v(x / p, p)`2 AND n = v(x / p, p)`1 IMPLIES
           y < p AND x = (p ^ (1 + n)) * y);

  % Subtype TCC generated (at line 21, column 29) for  x / p
      % expected type  {x: real | x >= 1}
  log_nat_TCC5: OBLIGATION
    FORALL (x: {x: real | x >= 1}, p: above(1)): NOT x < p IMPLIES x / p >= 1;

  % Termination TCC generated (at line 21, column 21) for  log_nat(x / p, p)
  log_nat_TCC6: OBLIGATION
    FORALL (x: {x: real | x >= 1}, p: above(1)):
      NOT x < p IMPLIES floor(x / p) < floor(x);

  % Subtype TCC generated (at line 27, column 6) for  n
      % expected type  {i: int | p /= 0 OR i >= 0}
  log_nat_bounds_TCC1: OBLIGATION
    FORALL (p: above(1), x: {x: real | x >= 1}, n: nat,
            y: {y | y < p AND x = p ^ n * y}):
      y = log_nat(x, p)`2 AND n = log_nat(x, p)`1 IMPLIES p /= 0 OR n >= 0;

  % Subtype TCC generated (at line 27, column 24) for  (n + 1)
      % expected type  {i: int | p /= 0 OR i >= 0}
  log_nat_bounds_TCC2: OBLIGATION
    FORALL (p: above(1), x: {x: real | x >= 1}, n: nat,
            y: {y | y < p AND x = p ^ n * y}):
      p ^ n <= x AND y = log_nat(x, p)`2 AND n = log_nat(x, p)`1 IMPLIES
       p /= 0 OR (n + 1) >= 0;

  % Subtype TCC generated (at line 33, column 33) for  na
      % expected type  {i: int | p /= 0 OR i >= 0}
  log_nat_itaux_TCC1: OBLIGATION
    FORALL (na, p, ya: {x: real | x >= 1}): p /= 0 OR na >= 0;

  % Subtype TCC generated (at line 37, column 12) for  floor(ya)
      % expected type  naturalnumber
  log_nat_itaux_TCC2: OBLIGATION
    FORALL (x: {x: real | x >= 1}, p: above(1), na: nat,
            (ya: {x: real | x >= 1} | x = p ^ na * ya)):
      floor(ya) >= 0;

  % Subtype TCC generated (at line 34, column 25) for  ya
      % expected type  {y | y < p AND x = p ^ na * y}
  log_nat_itaux_TCC3: OBLIGATION
    FORALL (x: {x: real | x >= 1}, p: above(1), na: nat,
            (ya: {x: real | x >= 1} | x = p ^ na * ya)):
      ya < p IMPLIES ya < p AND x = p ^ na * ya;

  % Subtype TCC generated (at line 35, column 32) for  ya / p
      % expected type  {ya | x = (p ^ (1 + na)) * ya}
  log_nat_itaux_TCC4: OBLIGATION
    FORALL (x: {x: real | x >= 1}, p: above(1), na: nat,
            (ya: {x: real | x >= 1} | x = p ^ na * ya)):
      NOT ya < p IMPLIES ya / p >= 1 AND x = (p ^ (1 + na)) * (ya / p);

  % Termination TCC generated (at line 35, column 9) for
      % log_nat_itaux(x, p, na + 1, ya / p)
  log_nat_itaux_TCC5: OBLIGATION
    FORALL (x: {x: real | x >= 1}, p: above(1), na: nat,
            (ya: {x: real | x >= 1} | x = p ^ na * ya)):
      NOT ya < p IMPLIES floor(ya / p) < floor(ya);

  % Subtype TCC generated (at line 40, column 24) for  x
      % expected type  {ya | x = p ^ 0 * ya}
  log_nat_it_TCC1: OBLIGATION
    FORALL (x: {x: real | x >= 1}, p: above(1)): x = p ^ 0 * x;

  % Subtype TCC generated (at line 49, column 20) for  n
      % expected type  {k: int |
                     %          xp <= 2 ^ k AND
                     %           (FORALL (i: int): i < k IMPLIES 2 ^ i < xp)}
  least_pow_2_ge_TCC1: OBLIGATION
    FORALL (xp: posreal):
      xp >= 1 IMPLIES
       (FORALL (n: nat, y: {y | y < 2 AND xp = 2 ^ n * y}):
          y = 1 AND y = log_nat_it(xp, 2)`2 AND n = log_nat_it(xp, 2)`1
           IMPLIES
           xp <= 2 ^ n AND (FORALL (i: int): i < n IMPLIES 2 ^ i < xp));

  % Subtype TCC generated (at line 50, column 6) for  n + 1
      % expected type  {k: int |
                     %          xp <= 2 ^ k AND
                     %           (FORALL (i: int): i < k IMPLIES 2 ^ i < xp)}
  least_pow_2_ge_TCC2: OBLIGATION
    FORALL (xp: posreal):
      xp >= 1 IMPLIES
       (FORALL (n: nat, y: {y | y < 2 AND xp = 2 ^ n * y}):
          NOT y = 1 AND y = log_nat_it(xp, 2)`2 AND n = log_nat_it(xp, 2)`1
           IMPLIES
           xp <= 2 ^ (n + 1) AND
            (FORALL (i: int): i < n + 1 IMPLIES 2 ^ i < xp));

  % Subtype TCC generated (at line 51, column 22) for  0
      % expected type  {k: int |
                     %          xp <= 2 ^ k AND
                     %           (FORALL (i: int): i < k IMPLIES 2 ^ i < xp)}
  least_pow_2_ge_TCC3: OBLIGATION
    FORALL (xp: posreal):
      xp > 1 / 2 AND NOT xp >= 1 IMPLIES
       xp <= 2 ^ 0 AND (FORALL (i: int): i < 0 IMPLIES 2 ^ i < xp);

  % Subtype TCC generated (at line 52, column 28) for  1 / xp
      % expected type  {x: real | x >= 1}
  least_pow_2_ge_TCC4: OBLIGATION
    FORALL (xp: posreal): NOT xp > 1 / 2 AND NOT xp >= 1 IMPLIES 1 / xp >= 1;

  % Subtype TCC generated (at line 52, column 41) for  -n
      % expected type  {k: int |
                     %          xp <= 2 ^ k AND
                     %           (FORALL (i: int): i < k IMPLIES 2 ^ i < xp)}
  least_pow_2_ge_TCC5: OBLIGATION
    FORALL (xp: posreal):
      NOT xp > 1 / 2 AND NOT xp >= 1 IMPLIES
       (FORALL (n: nat):
          n = log_nat_it(1 / xp, 2)`1 IMPLIES
           xp <= 2 ^ -n AND (FORALL (i: int): i < -n IMPLIES 2 ^ i < xp));


body:
  sqrt_approx : theory
  begin
  %-----------------------------------------------------------------------------
  %
  %  Includes sqrt_newton, sqrt_approx
  %
  %  This theory was originally developed by Michel Levy (LSR IMAG, France) after
  %  Exercise Page 66 N°8 of Reasoned Programming by Krysia Broda, 
  %  Susan Eisenbach, Hessam Koshnevisan, and Steve Vickers, 1994. Prentice Hall.
  %
  %  It was modified and integrated to sqrt_approx in the NASA PVS Library 
  %  by C. Munoz (NIA) on March 28 2005. The definition of sqrt_bisect was 
  %  moved to the Interval package.
  % 
  %-----------------------------------------------------------------------------

    IMPORTING sq,sqrt,log_nat

    x,y           : VAR nnreal  
    n             : VAR nat
    z             : VAR posreal
    eps,eps1,eps2 : VAR posreal 

    sq_sq_aux : lemma 
      sq((z+x/z)/2)-x = sq((sq(z)-x)/(2*z))

    sqrt_newton_aux(x,(y | x < sq(y)),eps) :  
      recursive {z | x < sq(z) AND sq(z)-x < eps} =
      if sq(y)-x < eps then y  
      else sqrt_newton_aux(x,((y+x/y)/2),eps) 
      endif
      measure if sq(y)-x < eps then 0 else 1+log_nat((sq(y)-x)/eps,4)`1 endif

    sqrt_newton_aux_NOT_increasing: LEMMA 
      EXISTS (x1,x2:nnreal,(y1:nnreal|x1<sq(y1)),(y2:nnreal|x2<sq(y2)),eps): 
        x1<x2 AND y1<y2 IMPLIES
          sqrt_newton_aux(x1,y1,eps) >= sqrt_newton_aux(x2,y2,eps)

    sqrt_newton(x,eps) : {z | x < sq(z) AND sq(z)-x < eps} = 
      sqrt_newton_aux(x,x+1,eps)

    sqrt_newton_is_NOT_increasing: LEMMA
      sqrt_newton(1.61,0.99) < sqrt_newton(1.6,0.99)

    sq_sqrt_newton         : LEMMA sq(sqrt_newton(x,eps)) > x

    sqrt_newton_gt         : LEMMA sqrt_newton(x,eps) > sqrt(x)
   
    sqrt_newton_lt         : LEMMA x /= 0 IMPLIES x/sqrt_newton(x,eps) < sqrt(x)
   
    sqrt_newton_le         : LEMMA x/sqrt_newton(x,eps) <= sqrt(x)

    sqrt_approx(x,n) : {z | abs(sq(z)-x) < 10^(-n)/2} =
      LET eps = 10^(-n),
          N = 2*10^n,
  	k = floor(x*N),
  	xx = k/N
      IN sqrt_newton(xx,10^(-n)/2)

    sqrt_approx_increasing: LEMMA x<=y IMPLIES sqrt_approx(x,n)<=sqrt_approx(y,n)

    sqrt_ub_old(x,n)    : posreal = sqrt_approx(x,2*n)+10^(-n)

    sqrt_lb_old(x,n)    : nnreal = max(sqrt_approx(x,2*n)-10^(-n),0)

    sqrt_old_bounds      : LEMMA
  	sqrt_lb_old(x,n) <= sqrt(x) AND
          sqrt(x) < sqrt_ub_old(x,n)

    sqrt_approx_fast(x,n) : {z | abs(sq(z)-x) < 10^(-n)/2} =
      IF x<=64 THEN LET sa = sqrt_approx(x,n) IN min(sa,8) ELSE
        LET twoexp = log_nat(x,4)`1,
            newx = x/(4^twoexp),
  	  exp2err = floor(twoexp/3)+1,
  	  newn = n + 2*exp2err
        IN LET sa = (2^twoexp)*min(sqrt_approx(newx,newn),2) IN max(sa,8)
      ENDIF

    sqrt_approx_fast_increasing: LEMMA 
        x<=y IMPLIES sqrt_approx_fast(x,n)<=sqrt_approx_fast(y,n)

    sqrt_ub(x,n)    : posreal = sqrt_approx_fast(x,2*n)+10^(-n)

    sqrt_lb(x,n)    : nnreal = max(sqrt_approx_fast(x,2*n)-10^(-n),0)

    sqrt_bounds      : LEMMA
  	sqrt_lb(x,n) <= sqrt(x) AND
          sqrt(x) < sqrt_ub(x,n)


  end sqrt_approx

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

  % Subtype TCC generated (at line 32, column 51) for  (sq(y) - x) / eps
      % expected type  {x: real | x >= 1}
  sqrt_newton_aux_TCC1: OBLIGATION
    FORALL (x: nnreal, (y: nnreal | x < sq(y)), eps: posreal):
      NOT sq(y) - x < eps IMPLIES (sq(y) - x) / eps >= 1;

  % Subtype TCC generated (at line 32, column 51) for
      % (sq(z1`2) - z1`1) / z1`3
      % expected type  {x: real | x >= 1}
  sqrt_newton_aux_TCC2: OBLIGATION
    FORALL (z1: [x: nnreal, {y | x < sq(y)}, posreal]):
      NOT sq(z1`2) - z1`1 < z1`3 IMPLIES (sq(z1`2) - z1`1) / z1`3 >= 1;

  % Subtype TCC generated (at line 29, column 26) for  y
      % expected type  {z | x < sq(z) AND sq(z) - x < eps}
  sqrt_newton_aux_TCC3: OBLIGATION
    FORALL (x: nnreal, (y: nnreal | x < sq(y)), eps: posreal):
      sq(y) - x < eps IMPLIES y > 0 AND x < sq(y) AND sq(y) - x < eps;

  % Subtype TCC generated (at line 30, column 33) for  y
      % expected type  nznum
  sqrt_newton_aux_TCC4: OBLIGATION
    FORALL (x: nnreal, (y: nnreal | x < sq(y)), eps: posreal):
      NOT sq(y) - x < eps IMPLIES y /= 0;

  % Subtype TCC generated (at line 30, column 28) for  ((y + x / y) / 2)
      % expected type  {y | x < sq(y)}
  sqrt_newton_aux_TCC5: OBLIGATION
    FORALL (x: nnreal, (y: nnreal | x < sq(y)), eps: posreal):
      NOT sq(y) - x < eps IMPLIES
       ((y + x / y) / 2) >= 0 AND x < sq(((y + x / y) / 2));

  % Termination TCC generated (at line 30, column 9) for
      % sqrt_newton_aux(x, ((y + x / y) / 2), eps)
  sqrt_newton_aux_TCC6: OBLIGATION
    FORALL (x: nnreal, (y: nnreal | x < sq(y)), eps: posreal):
      NOT sq(y) - x < eps IMPLIES
       IF sq(((y + x / y) / 2)) - x < eps THEN 0
       ELSE 1 + log_nat((sq(((y + x / y) / 2)) - x) / eps, 4)`1
       ENDIF
        <
        IF sq(y) - x < eps THEN 0
        ELSE 1 + log_nat((sq(y) - x) / eps, 4)`1
        ENDIF;

  % Subtype TCC generated (at line 40, column 22) for  x + 1
      % expected type  {y | x < sq(y)}
  sqrt_newton_TCC1: OBLIGATION FORALL (x: nnreal): x < sq(x + 1);

  % Subtype TCC generated (at line 58, column 19) for  xx
      % expected type  nnreal
  sqrt_approx_TCC1: OBLIGATION
    FORALL (x: nnreal, n: nat, eps: posrat):
      eps = 10 ^ (-n) IMPLIES
       (FORALL (N: posint):
          N = 2 * 10 ^ n IMPLIES
           (FORALL (k: {i | i <= x * N & x * N < 1 + i}):
              k = floor(x * N) IMPLIES
               (FORALL (xx: rat): xx = k / N IMPLIES xx >= 0)));

  % Subtype TCC generated (at line 58, column 7) for
      % sqrt_newton(xx, 10 ^ (-n) / 2)
      % expected type  {z | abs(sq(z) - x) < 10 ^ (-n) / 2}
  sqrt_approx_TCC2: OBLIGATION
    FORALL (x: nnreal, n: nat, eps: posrat):
      eps = 10 ^ (-n) IMPLIES
       (FORALL (N: posint):
          N = 2 * 10 ^ n IMPLIES
           (FORALL (k: {i | i <= x * N & x * N < 1 + i}):
              k = floor(x * N) IMPLIES
               (FORALL (xx: rat):
                  xx = k / N IMPLIES
                   abs(sq(sqrt_newton(xx, 10 ^ (-n) / 2)) - x) <
                    10 ^ (-n) / 2)));

  % Subtype TCC generated (at line 71, column 47) for  min(sa, 8)
      % expected type  {z | abs(sq(z) - x) < 10 ^ (-n) / 2}
  sqrt_approx_fast_TCC1: OBLIGATION
    FORALL (x: nnreal, n: nat):
      x <= 64 IMPLIES
       (FORALL (sa: {z | abs(sq(z) - x) < 10 ^ (-n) / 2}):
          sa = sqrt_approx(x, n) IMPLIES
           abs(sq(min(sa, 8)) - x) < 10 ^ (-n) / 2);

  % Subtype TCC generated (at line 72, column 27) for  x
      % expected type  {x: real | x >= 1}
  sqrt_approx_fast_TCC2: OBLIGATION
    FORALL (x: nnreal): NOT x <= 64 IMPLIES x >= 1;

  % Subtype TCC generated (at line 76, column 62) for  max(sa, 8)
      % expected type  {z | abs(sq(z) - x) < 10 ^ (-n) / 2}
  sqrt_approx_fast_TCC3: OBLIGATION
    FORALL (x: nnreal, n: nat):
      NOT x <= 64 IMPLIES
       (FORALL (twoexp: nat):
          twoexp = log_nat(x, 4)`1 IMPLIES
           (FORALL (newx: nnreal):
              newx = x / (4 ^ twoexp) IMPLIES
               (FORALL (exp2err: posint):
                  exp2err = floor(twoexp / 3) + 1 IMPLIES
                   (FORALL (newn: posint):
                      newn = n + 2 * exp2err IMPLIES
                       (FORALL (sa: posreal):
                          sa = (2 ^ twoexp) * min(sqrt_approx(newx, newn), 2)
                           IMPLIES
                           abs(sq(max(sa, 8)) - x) < 10 ^ (-n) / 2)))));


body:
  %% 3-valued sign

  %% Created by Cesar Munoz

  sign3 : THEORY
  BEGIN

    IMPORTING sign,sq

    Sign3 : TYPE = {i:int |i=1 OR i=-1 OR i=0} 

    sign3(x:real): Sign3 = IF x = 0 THEN 0
                           ELSIF x > 0 THEN 1
                           ELSE -1 ENDIF
    eps,
    eps1,eps2 : VAR Sign3
    epsnz     : VAR Sign 
    x,y,z     : VAR real

    sign3_mult_clos: JUDGEMENT *(eps1,eps2) HAS_TYPE Sign3

    sign3_div_clos : JUDGEMENT  /(eps,epsnz) HAS_TYPE Sign3

    sign3_neg_clos : JUDGEMENT  -(eps1) HAS_TYPE Sign3

    sign3_sq_clos  : JUDGEMENT   sq(eps1) HAS_TYPE Sign3

    sign3_sign     : LEMMA x /= 0 IMPLIES sign3(x)=sign(x)

    sign3_id       : LEMMA sign3(eps) = eps

    sign3_0        : LEMMA sign3(0) = 0

    sign3_eq_1     : LEMMA x > 0 IMPLIES sign3(x) = 1

    sign3_eq_neg1  : LEMMA x < 0 IMPLIES sign3(x) = -1

    sign3_pos      : LEMMA sign3(x)*x >= 0

    sign3_abs      : LEMMA abs(x) = sign3(x)*x

    sign3_nneg     : LEMMA sign3(x)*x >= 0

    square_eps     : LEMMA eps*eps <= 1

    sq_eps         : LEMMA sq(eps) <= 1

    sq_sign3       : LEMMA sq(sign3(x)) <= 1

    sign3_times_abs: LEMMA sign3(x)*abs(x) = x

    abs_sign3      : LEMMA eps*x > 0 IMPLIES eps*x = abs(x)

    sign3_neg      : LEMMA -sign3(x) = sign3(-x)

    sign3_minus    : LEMMA -sign3(x-y) = sign3(y-x)

    sign3_mult     : LEMMA  sign3(x*y) = sign3(x)*sign3(y)

    sign3_div      : LEMMA  y /= 0 IMPLIES sign3(x/y) = sign3(x)*sign3(y)

    sign3_mult_pos : LEMMA x > 0 IMPLIES sign3(x*y) = sign3(y)

    sign3_div_pos1 : LEMMA x > 0 AND y /= 0 IMPLIES sign3(x/y) = sign3(y)

    sign3_div_pos2 : LEMMA y > 0 IMPLIES sign3(x/y) = sign3(x)

    sign3_mult_neg : LEMMA x < 0 IMPLIES sign3(x*y) = -sign3(y)

    sign3_div_neg1 : LEMMA x < 0 AND y /= 0 IMPLIES sign3(x/y) = -sign3(y)

    sign3_div_neg2 : LEMMA y < 0 IMPLIES sign3(x/y) = -sign3(x)

    sign3_div_mult : LEMMA 
      y /= 0 IMPLIES sign3(x)/sign3(y) = sign3(x)*sign3(y)

    sign3_and_abs  : LEMMA sign3(x) = sign3(y) AND abs(x) = abs(y) IFF x = y

    sign3_le : LEMMA
      x <= y IMPLIES sign3(x) <= sign3(y)

    sign3_ge : LEMMA
      x >= y IMPLIES sign3(x) >= sign3(y)

    AUTO_REWRITE+ sign3_0

  END sign3

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

  % Judgement subtype TCC generated (at line 20, column 29) for  eps1 * eps2
      % expected type  Sign3
  sign3_mult_clos: OBLIGATION
    FORALL (eps1, eps2):
      eps1 * eps2 = 1 OR eps1 * eps2 = -1 OR eps1 * eps2 = 0;

  % Judgement subtype TCC generated (at line 22, column 30) for  eps / epsnz
      % expected type  Sign3
  sign3_div_clos: OBLIGATION
    FORALL (eps, epsnz):
      integer_pred(eps / epsnz) AND
       (eps / epsnz = 1 OR eps / epsnz = -1 OR eps / epsnz = 0);

  % Judgement subtype TCC generated (at line 24, column 30) for  -eps1
      % expected type  Sign3
  sign3_neg_clos: OBLIGATION
    FORALL (eps1): -eps1 = 1 OR -eps1 = -1 OR -eps1 = 0;

  % Judgement subtype TCC generated (at line 26, column 31) for  sq(eps1)
      % expected type  Sign3
  sign3_sq_clos: OBLIGATION
    FORALL (eps1):
      rational_pred(sq(eps1)) AND
       integer_pred(sq(eps1)) AND
        (sq(eps1) = 1 OR sq(eps1) = -1 OR sq(eps1) = 0);

  % Subtype TCC generated (at line 66, column 47) for  y
      % expected type  nznum
  sign3_div_pos2_TCC1: OBLIGATION FORALL (y: real): y > 0 IMPLIES y /= 0;

  % Subtype TCC generated (at line 72, column 47) for  y
      % expected type  nznum
  sign3_div_neg2_TCC1: OBLIGATION FORALL (y: real): y < 0 IMPLIES y /= 0;

  % Subtype TCC generated (at line 75, column 28) for  sign3(y)
      % expected type  nznum
  sign3_div_mult_TCC1: OBLIGATION
    FORALL (y: real): y /= 0 IMPLIES sign3(y) /= 0;


body:
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %  Properties of real numbers   %
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  real_facts : THEORY

    BEGIN

    S: VAR (nonempty?[real])

    bounded?_lem  : LEMMA bounded?(S) IFF
                            EXISTS (B: real): FORALL (x: (S)):  abs(x) <= B


    %----------------------------------------
    %  More properties of archimedean field 
    %----------------------------------------

    archimedean2 : THEOREM
  	FORALL (x : posreal) : EXISTS (a : posnat) : 1/a < x

    archimedean3 : THEOREM
  	FORALL (x : nonneg_real) :
  	   (FORALL (a : posnat) : x <= 1/a) implies x = 0


    %-------------------------------------------------
    %  Every real is between two successive integers
    %-------------------------------------------------

    nat_interval : LEMMA
  	FORALL (x : nonneg_real) : EXISTS (a : nat) : a <= x and x < a + 1

    int_interval : LEMMA
  	FORALL (x : real) : EXISTS (a : integer) : a <= x and x < a +1 


    %---------------------------------------
    %  Short cuts for lub and glb of sets
    %---------------------------------------

    U: VAR (bounded_above?)
    V: VAR (bounded_below?)
    a,b,x, y: VAR real
    epsilon: VAR posreal


    lub_is_bound: LEMMA FORALL (x: (U)):  x <= lub(U)

    lub_is_lub: LEMMA lub(U) <= y IFF FORALL (x: (U)): x <= y

    lub_closed_intv: LEMMA a < b IMPLIES lub({x | a <= x AND x <= b}) = b


    adherence_sup: LEMMA 
  	FORALL epsilon: EXISTS (x: (U)): lub(U) - epsilon < x


    glb_is_bound: LEMMA FORALL (x: (V)): glb(V) <= x

    glb_is_glb: LEMMA y <= glb(V) IFF FORALL (x: (V)): y <= x

    glb_closed_intv: LEMMA a < b IMPLIES glb({x | a <= x AND x <= b}) = a

    adherence_inf: LEMMA
  	FORALL epsilon: EXISTS (x: (V)): x < glb(V) + epsilon



    END real_facts

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

  % Subtype TCC generated (at line 52, column 43) for  {x | a <= x AND x <= b}
      % expected type  SA: (bounded_above?)
  lub_closed_intv_TCC1: OBLIGATION
    FORALL (a, b: real):
      a < b IMPLIES
       nonempty?[real]({x | a <= x AND x <= b}) AND
        bounded_above?({x | a <= x AND x <= b});

  % Subtype TCC generated (at line 63, column 43) for  {x | a <= x AND x <= b}
      % expected type  SB: (bounded_below?)
  glb_closed_intv_TCC1: OBLIGATION
    FORALL (a, b: real):
      a < b IMPLIES
       nonempty?[real]({x | a <= x AND x <= b}) AND
        bounded_below?({x | a <= x AND x <= b});


body:
  bound_defs[T: TYPE, S: TYPE FROM T]: THEORY
  %------------------------------------------------------------------------
  %
  %   The following definitions are very similar to the definitions in the 
  %   prelude theory orders.  There is an important distinctions. pe is defined
  %   as
  %
  %      pe: VAR pred[S]
  %
  %  rather than
  %
  %     pe: VAR {p: pred[T] | EXISTS (x: T): p(x)}
  %
  %  this prevents the proliferation of superfluous "extend"s
  %       
  %------------------------------------------------------------------------
  BEGIN

    < : VAR pred[[T, T]]

    pe: VAR pred[S]

    x,y: VAR T
    z: VAR S

    upper_bound(<)(x, pe): bool = FORALL (z: (pe)): z < x

    lower_bound(<)(x, pe): bool = FORALL (z: (pe)): x < z

    least_upper_bound(<)(x, pe): bool =
      upper_bound(<)(x, pe) AND
        (FORALL y: upper_bound(<)(y, pe) IMPLIES (x < y OR x = y))

    greatest_lower_bound(<)(x, pe): bool =
      lower_bound(<)(x, pe) AND
         (FORALL y: lower_bound(<)(y, pe) IMPLIES (y < x OR x = y))

  END bound_defs


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

    IMPORTING  bound_defs[real,T]

    real_complete2: LEMMA   % this could replace real_complete in prelude
      (FORALL (S: (nonempty?[T])):
        (EXISTS (y: real): upper_bound(<=)(y, S)) IMPLIES
          (EXISTS (x: real): least_upper_bound(<=)(x, S)))

    real_lower_complete2: LEMMA % this could replace real_complete in prelude
      (FORALL (S: (nonempty?[T])):
        (EXISTS (y : real): lower_bound(<=)(y, S)) IMPLIES 
          (EXISTS (x: real): greatest_lower_bound(<=)(x, S)))


  END reals_complete_more


body:
  bounded_reals [T: TYPE FROM real]: THEORY
  %------------------------------------------------------------------------
  %  Defines bounds and extrema for sets of reals or its subtypes
  %
  %     Adapted by Rick Butler from the "real_sets" theory that was
  %        developed by Bruno Dutertre 
  %
  %  This theory defines four functions:
  %
  %     sup: returns least upper bound of set with upper bound
  %     inf: returns greatest lower bound of set with lower bound
  %     max: returns maximal element of sets containing a maximum
  %     min: returns minimal element of sets containing a minimum
  %
  %  NOTE. None of these functions are interpreted.  Therefore, it is
  %  necessary to rewrite with the _def theorems or use TYPEPREDs.
  %  IT is usually easier to rewrite with the _def theoremsL
  %
  %     sup_def   : LEMMA sup(Su) = x IFF least_upper_bound(<=)(x, Su)
  %     inf_def   : LEMMA inf(Sl) = x IFF greatest_lower_bound(<=)(x, Sl)
  %     max_def   : LEMMA max(W) = t  IFF maximum?(t, W)
  %     min_def   : LEMMA min(X) = t  IFF minimum?(t, X)
  %
  %  This version uses revised prelude axioms in order to prevent the
  %  generation of superfluous "extend"s.  These are in prelude_aux.
  %
  %------------------------------------------------------------------------
    BEGIN

    IMPORTING reals_complete_more[T]
      
    n,x: VAR real
    t: VAR T
    
    E : VAR setof[T]
    S: VAR (nonempty?[T])

  % ------------- sup ---------------

    above_bounded(E): bool = (EXISTS n: upper_bound(<=)(n, E))

    sup_set: TYPE = { S | above_bounded(S) }

    Su: VAR sup_set
    sup_exists: LEMMA (EXISTS x: least_upper_bound(<=)(x, Su))

    sup(Su): {x | least_upper_bound(<=)(x, Su)}

    sup_def        : LEMMA sup(Su) = x IFF least_upper_bound(<=)(x, Su)

    in_set(x,S): bool = IF T_pred(x) THEN S(x) ELSE FALSE ENDIF

    max_set: TYPE = {Su: sup_set | in_set(sup(Su),Su)}

    W: VAR max_set
    max(W): T = sup(W)

    maximum?(t, S) : bool = S(t) AND upper_bound(<=)(t, S)

    max_def        : LEMMA max(W) = t IFF maximum?(t, W)

  % ------------- inf ---------------

    below_bounded(E): bool = (EXISTS n: lower_bound(<=)(n, E))

    inf_set: TYPE = { S | below_bounded(S) }
  	
    Sl: VAR inf_set
    inf_exists: LEMMA (EXISTS x: greatest_lower_bound(<=)(x, Sl))

    inf(Sl): {x | greatest_lower_bound(<=)(x, Sl)}

    inf_def        : LEMMA inf(Sl) = x IFF greatest_lower_bound(<=)(x, Sl)

    ext(Sl): set[real] = { x | IF T_pred(x) THEN Sl(x) ELSE FALSE ENDIF}

    min_set: TYPE = {Sl: inf_set | ext(Sl)(inf(Sl))}

    X: VAR min_set
    min(X): T = inf(X)

    minimum?(t, S) : bool = S(t) AND lower_bound(<=)(t, S)

    min_def        : LEMMA min(X) = t IFF minimum?(t, X)

  END bounded_reals

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

  % Existence TCC generated (at line 47, column 2) for
      % sup(Su): {x | least_upper_bound(<=)(x, Su)}
  sup_TCC1: OBLIGATION
    EXISTS (x1:
              [Su: sup_set -> {x | least_upper_bound[real, T](<=)(x, Su)}]):
      TRUE;

  % Subtype TCC generated (at line 56, column 14) for  sup(W)
      % expected type  T
  max_TCC1: OBLIGATION FORALL (W: max_set): T_pred(sup(W));

  % Existence TCC generated (at line 71, column 2) for
      % inf(Sl): {x | greatest_lower_bound(<=)(x, Sl)}
  inf_TCC1: OBLIGATION
    EXISTS (x1:
              [Sl: inf_set ->
                 {x | greatest_lower_bound[real, T](<=)(x, Sl)}]):
      TRUE;

  % Subtype TCC generated (at line 80, column 14) for  inf(X)
      % expected type  T
  min_TCC1: OBLIGATION FORALL (X: min_set): T_pred(inf(X));


body:
  real_sets[T: TYPE FROM real]: THEORY
  %------------------------------------------------------------------------
  %
  %   Adapted by Rick Butler from theory that was 
  %        developed by Bruno Dutertre
  %
  %   Fundamental definitions are in bounded_reals. 
  %
  %------------------------------------------------------------------------
  BEGIN

    IMPORTING bounded_reals[T]

    S,S1,S2: VAR (nonempty?[T])
    U,U1,U2: VAR sup_set   % { S | (EXISTS a : upper_bound?(<=)(a, S))}
    V,V1,V2: VAR inf_set   % { S | (EXISTS a : lower_bound?(<=)(a, S))}
    W,W1,W2: VAR max_set   % { S | (EXISTS c : S(c) AND upper_bound?(<=)(c, S)}
    X,X1,X2: VAR min_set   % { S | (EXISTS c : S(c) AND lower_bound?(<=)(c, S)}
    a, x: VAR real
    c: VAR T

    sup_lemma            : LEMMA least_upper_bound(<=)(sup(U), U)

      sup_is_bound       : COROLLARY (FORALL (y: (U)) : y <= sup(U))
      sup_is_bound2      : COROLLARY upper_bound(<=)(sup(U), U)	
      sup_is_sup         : COROLLARY upper_bound(<=)(x, U) IFF sup(U) <= x

    upper_bound_subset   : LEMMA subset?(S1, S2) AND upper_bound(<=)(a, S2) 
  	                         IMPLIES upper_bound(<=)(a, S1)

      subset_above_bounded : COROLLARY subset?(S, U) IMPLIES above_bounded(S)
      sup_of_subset        : COROLLARY subset?(U1, U2) IMPLIES sup(U1) <= sup(U2)

    adherence_sup        : THEOREM (FORALL (epsilon: posreal):
                                       (EXISTS (y: (U)) : sup(U) - epsilon < y))


    inf_lemma            : LEMMA   greatest_lower_bound(<=)(inf(V), V)

      inf_is_bound       : COROLLARY (FORALL (y: (V)) : inf(V) <= y)
      inf_is_bound2      : COROLLARY lower_bound(<=)(inf(V), V)
      inf_is_inf         : COROLLARY lower_bound(<=)(x, V) IFF x <= inf(V)

    lower_bound_subset   : LEMMA subset?(S1, S2) and lower_bound(<=)(a, S2) 
  	                          IMPLIES lower_bound(<=)(a, S1)

      subset_below_bounded : COROLLARY subset?(S, V) IMPLIES below_bounded(S)
      inf_of_subset        : COROLLARY subset?(V1, V2) IMPLIES inf(V2) <= inf(V1)

    adherence_inf        : THEOREM (FORALL (epsilon: posreal):
                                       (EXISTS (y: (V)) : y < inf(V) + epsilon))

  END real_sets


body:
  real_fun_preds [T : TYPE FROM real] : THEORY
  %----------------------------------------------------------------------%
  %  Defines several predicates over real-valued functions [T -> real]   %
  %
  %  These predicates now follow ? convention.
  %  Old names without ? are included as macros to maintain upwards-
  %  compatibility.
  %
  %----------------------------------------------------------------------%
  BEGIN

    f    : VAR [T -> real]
    x, y : VAR T
    a, z : VAR real
    E    : VAR setof[real]

    increasing?(f)        : bool = FORALL x, y : x <= y IMPLIES f(x) <= f(y)
    decreasing?(f)        : bool = FORALL x, y : x <= y IMPLIES f(y) <= f(x)
    strict_increasing?(f) : bool = FORALL x, y : x < y IMPLIES f(x) < f(y)
    strict_decreasing?(f) : bool = FORALL x, y : x < y IMPLIES f(y) < f(x)

    monotonic?(f): bool = increasing?(f) or decreasing?(f)

    constant?(f)          : bool = FORALL x, y : f(x) = f(y)

    is_maximum?(x, f)     : bool = FORALL y : f(y) <= f(x)
    is_minimum?(x, f)     : bool = FORALL y : f(x) <= f(y)

    bounded_above?(f)     : bool = EXISTS a: FORALL x: f(x) <= a
    bounded_below?(f)     : bool = EXISTS a: FORALL x: a <= f(x)
    bounded?(f)           : bool = bounded_above?(f) AND bounded_below?(f)

    bounded?_lem          : LEMMA bounded?(f) IFF
                                 EXISTS (B: nnreal): FORALL x: abs(f(x)) <= B



  % ------- The following are included to maintain upwards compatibility 
  % ------- with previous versions of libraries 

    increasing(f)         : MACRO bool = increasing?(f)
    decreasing(f)         : MACRO bool = decreasing?(f)
    strict_increasing(f)  : MACRO bool = strict_increasing?(f)
    strict_decreasing(f)  : MACRO bool = strict_decreasing?(f) 
    constant(f)           : MACRO bool = constant?(f)   
    is_maximum(x,f)       : MACRO bool = is_maximum?(x,f)
    is_minimum(x,f)       : MACRO bool = is_minimum?(x,f)


  END real_fun_preds


body:
  real_fun_ops  [ T : TYPE ] : THEORY
  %------------------------------------------%
  %  Operations on functions : [ T -> real]  %
  %------------------------------------------%
  BEGIN

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

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


    +(f1, f2) : [T -> real] = LAMBDA x : f1(x) + f2(x);
    -(f1)     : [T -> real] = LAMBDA x : -f1(x);
    *(f1, f2) : [T -> real] = LAMBDA x : f1(x) * f2(x);
    *(a, f1)  : [T -> real] = LAMBDA x : a * f1(x);
    -(f1, f2) : [T -> real] = LAMBDA x : f1(x) - f2(x);
    /(f1, f3) : [T -> real] = LAMBDA x : f1(x) / f3(x);
    /(a, f3)  : [T -> real] = LAMBDA x : a / f3(x);
    inv(f3)   : [T -> real] = 1 / f3;
    abs(f1)   : [T -> nonneg_real] = LAMBDA x : abs(f1(x));

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

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

    diff_function    : LEMMA f1 - f2 = f1 + (- f2)
    div_function     : LEMMA f1 / f3 = f1 * (1 /f3)
    scal_function    : LEMMA a * f1 = const_fun(a) * f1
    scaldiv_function : LEMMA a / f3 = const_fun(a) / f3
    negneg_function  : LEMMA - (- f1) = f1

  END real_fun_ops

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

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


body:
  real_fun_props [T : TYPE FROM real] : THEORY
  %----------------------------------------------------------------------%
  %  Defines several properties of functions [T -> real]                 %
  %  -> increasing/decreasing functions                                  %
  %  -> upper/lower bound                                                %
  %  -> maximum/minimum of a function                                    %
  %----------------------------------------------------------------------%
  BEGIN

    IMPORTING real_fun_ops, real_fun_preds

    f    : VAR [T -> real]
    x, y : VAR T
    a, z : VAR real
    
    %-------------------
    %  Easy properties
    %-------------------

    strict_incr_to_incr : LEMMA  strict_increasing?(f) IMPLIES increasing?(f)
    strict_decr_to_decr : LEMMA  strict_decreasing?(f) IMPLIES decreasing?(f)


    incr_neg       : LEMMA increasing?(- f) IFF decreasing?(f)
    decr_neg       : LEMMA decreasing?(- f) IFF increasing?(f)


    strict_incr_neg: LEMMA strict_increasing?(- f) IFF strict_decreasing?(f)
    strict_decr_neg: LEMMA strict_decreasing?(- f) IFF strict_increasing?(f)

    %-----------------------
    %  Constant functions
    %-----------------------

    constant_to_incr    : LEMMA  constant?(f) IMPLIES increasing?(f)
    constant_to_decr    : LEMMA  constant?(f) IMPLIES decreasing?(f)
    constant_neg        : LEMMA  constant?(- f) IFF constant?(f)

    %------------------------
    %  Relation to negative function
    %------------------------

    bounded_above_neg : LEMMA bounded_above?(- f) IFF bounded_below?(f)
    bounded_below_neg : LEMMA bounded_below?(- f) IFF bounded_above?(f)

    %------------------------
    %  Relation with bounds  
    %------------------------

    max_bounded : LEMMA is_maximum?(x, f) IMPLIES bounded_above?(f)
    min_bounded : LEMMA is_minimum?(x, f) IMPLIES bounded_below?(f)

    %----------------------------------
    %  Relation with negative functions
    %----------------------------------

    max_neg : LEMMA 	is_maximum?(x, - f) IFF is_minimum?(x, f)
    min_neg : LEMMA 	is_minimum?(x, - f) IFF is_maximum?(x, f)

    %--------------------------------------------------------
    %  Image of a function
    %   redefined from function_image to avoid conversions
    %--------------------------------------------------------

    E: VAR setof[real]

    Im(f)    : setof[real] = { z | EXISTS x : z = f(x) }
    Im(f, E) : setof[real] = { z | EXISTS x : E(x) AND z = f(x) }


  END real_fun_props


body:
  %------------------------------------------------------------------------------
  % Orders defined on functions [T->real]
  %
  %     Author: David Lester, Manchester University
  %
  %     Version 1.0            14/06/09  Initial Version
  %------------------------------------------------------------------------------
  real_fun_orders[T:TYPE]: THEORY

  BEGIN

    x:     VAR T
    f1,f2: VAR [T->real]
  ;
    <=(f1,f2): bool = FORALL x: f1(x) <= f2(x);
    <(f1,f2):  bool = FORALL x: f1(x) <  f2(x);
    >(f1,f2):  bool = FORALL x: f1(x) >  f2(x);
    >=(f1,f2): bool = FORALL x: f1(x) >= f2(x);

  END real_fun_orders


body:
  %------------------------------------------------------------------------------
  % Arithmetic Operations defined on functions [T->real]
  %
  %     Author: David Lester, Manchester University
  %
  %     Version 1.0            14/06/09  Initial Version
  %------------------------------------------------------------------------------
  real_fun_ops_aux[T:TYPE]: THEORY

  BEGIN

    IMPORTING real_fun_ops, sq

    f,f1,f2: VAR [T->real]
    f3:      VAR [T -> nzreal]
    F:       VAR sequence[[T->real]]
    x,y:     VAR T
    nnc:     VAR nnreal
    npc:     VAR npreal
    a,c:     VAR real
    n,i:     VAR nat

    sq(f):     [T->nnreal] = lambda x: sq(f(x))
    min(f1,f2):[T->real]   = lambda x: min(f1(x),f2(x))
    max(f1,f2):[T->real]   = lambda x: max(f1(x),f2(x))
    minus(f):  [T->nnreal] = lambda x: -min(f(x),0)
    plus(f):   [T->nnreal] = lambda x: max(f(x),0)

    maximum(F,n): RECURSIVE [T->real]
      = IF n = 0 THEN F(0) ELSE max(F(n),maximum(F,n-1)) ENDIF MEASURE n
    minimum(F,n): RECURSIVE [T->real]
      = IF n = 0 THEN F(0) ELSE min(F(n),minimum(F,n-1)) ENDIF MEASURE n

    plus_minus_def: LEMMA f = plus(f) - minus(f)
    max_plus_min:   LEMMA max(f1,f2)+min(f1,f2) = f1+f2
    max_minus_min:  LEMMA max(f1,f2)-min(f1,f2) = abs(f1-f2)
    max_def:        LEMMA max(f1,f2) = (1/2)*(f1+f2+abs(f1-f2))
    min_def:        LEMMA min(f1,f2) = (1/2)*(f1+f2-abs(f1-f2))
    prod_def:       LEMMA *(f1,f2)   = (1/4)*(sq(f1+f2)-sq(f1-f2))

    plus_plus:   LEMMA plus(plus(f))   = plus(f)
    plus_minus:  LEMMA plus(minus(f))  = minus(f)
    minus_plus:  LEMMA minus(plus(f))  = const_fun(0)
    minus_minus: LEMMA minus(minus(f)) = const_fun(0)

    plus_scal:  LEMMA plus(c*f)  = IF c>=0 THEN c*plus(f)  ELSE -c*minus(f) ENDIF
    minus_scal: LEMMA minus(c*f) = IF c>=0 THEN c*minus(f) ELSE -c*plus(f)  ENDIF

    maximum_def1: LEMMA i <= n => FORALL x: F(i)(x) <= maximum(F,n)(x)
    maximum_def2: LEMMA EXISTS i: i <= n AND maximum(F,n)(x) = F(i)(x)
    minimum_def1: LEMMA i <= n => FORALL x: minimum(F,n)(x) <= F(i)(x)
    minimum_def2: LEMMA EXISTS i: i <= n AND minimum(F,n)(x) = F(i)(x)

  END real_fun_ops_aux

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

  % Subtype TCC generated (at line 26, column 37) for  -min(f(x), 0)
      % expected type  nnreal
  minus_TCC1: OBLIGATION FORALL (f: [T -> real], x): -min(f(x), 0) >= 0;

  % Subtype TCC generated (at line 27, column 37) for  max(f(x), 0)
      % expected type  nnreal
  plus_TCC1: OBLIGATION FORALL (f: [T -> real], x): max(f(x), 0) >= 0;

  % Subtype TCC generated (at line 30, column 49) for  n - 1
      % expected type  nat
  maximum_TCC1: OBLIGATION FORALL (n: nat): NOT n = 0 IMPLIES n - 1 >= 0;

  % Termination TCC generated (at line 30, column 39) for  maximum(F, n - 1)
  maximum_TCC2: OBLIGATION FORALL (n: nat): NOT n = 0 IMPLIES n - 1 < n;


body:
  real_order_ep: THEORY

  BEGIN

    x,y:VAR real
    epsil:VAR posreal

    real_ord_ep(epsil)(x,y): bool =
      floor(abs(x)/epsil) < floor(abs(y)/epsil)

    real_ord_ep_well_founded: JUDGEMENT
      real_ord_ep(epsil) has_type (well_founded?[real])

    real_ord_ep_decreases_halves: LEMMA
      abs(x)>=epsil IMPLIES
      real_ord_ep(epsil)(x/2,x)

  END real_order_ep

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

  % Judgement subtype TCC generated (at line 12, column 4) for
      % real_ord_ep(epsil)
      % expected type  (well_founded?[real])
  real_ord_ep_well_founded: OBLIGATION
    FORALL (epsil): well_founded?[real](real_ord_ep(epsil));


body:
  real_orders : THEORY
  BEGIN

    rel    	  : VAR [[real,real]->bool]

    realorder?(rel) : bool = (rel = (<=)) OR (rel = (<)) OR (rel = (>=)) OR (rel = (>))
    RealOrder       : TYPE = (realorder?)
    relreal         : VAR RealOrder

    le_realorder    : JUDGEMENT <= HAS_TYPE RealOrder
    lt_realorder    : JUDGEMENT <  HAS_TYPE RealOrder
    ge_realorder    : JUDGEMENT >= HAS_TYPE RealOrder
    gt_realorder    : JUDGEMENT >  HAS_TYPE RealOrder

    neg_rel(relreal)(x,y:real): bool = 
      NOT relreal(x,y)

    neg_rel_le_gt : LEMMA
      neg_rel(<=) = >

    neg_rel_lt_ge : LEMMA
      neg_rel(<) = >=

    neg_rel_ge_lt : LEMMA
      neg_rel(>=) = <

    neg_rel_gt_le : LEMMA
      neg_rel(>) = <=

    neg_rel_order : JUDGEMENT
      neg_rel(relreal) HAS_TYPE RealOrder

    le_ne_lt : LEMMA
      NOT ((reals.<=) = (reals.<))

    le_ne_ge : LEMMA
      NOT ((reals.<=) = (reals.>=))

    le_ne_gt : LEMMA
      NOT ((reals.<=) = (reals.>))

    lt_ne_le : LEMMA
      NOT ((reals.<) = (reals.<=))

    lt_ne_ge : LEMMA
      NOT ((reals.<) = (reals.>=))

    lt_ne_gt : LEMMA
      NOT ((reals.<) = (reals.>))

    ge_ne_gt : LEMMA
      NOT ((reals.>=) = (reals.>))

    ge_ne_le : LEMMA
      NOT ((reals.>=) = (reals.<=))

    ge_ne_lt : LEMMA
      NOT ((reals.>=) = (reals.<))

    gt_ne_ge : LEMMA
      NOT ((reals.>) = (reals.>=))

    gt_ne_le : LEMMA
      NOT ((reals.>) = (reals.<=))

    gt_ne_lt : LEMMA
      NOT ((reals.>) = (reals.<))

  END real_orders

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

  % Judgement subtype TCC generated (at line 10, column 30) for  <=
      % expected type  RealOrder
  le_realorder: OBLIGATION realorder?(<=);

  % Judgement subtype TCC generated (at line 11, column 30) for  <
      % expected type  RealOrder
  lt_realorder: OBLIGATION realorder?(<);

  % Judgement subtype TCC generated (at line 12, column 30) for  >=
      % expected type  RealOrder
  ge_realorder: OBLIGATION realorder?(>=);

  % Judgement subtype TCC generated (at line 13, column 30) for  >
      % expected type  RealOrder
  gt_realorder: OBLIGATION realorder?(>);

  % Judgement subtype TCC generated (at line 31, column 4) for
      % neg_rel(relreal)
      % expected type  RealOrder
  neg_rel_order: OBLIGATION FORALL (relreal): realorder?(neg_rel(relreal));


body:
  %----------------------------------------------------------------------------
  %
  %  Authors: Cesar Munoz, Alfons Geser                   NASA ICASE
  %
  %  NOTE: 
  %        Introduced root(a,b,c,eps). x1 and x2 are defined as macros for
  %        backward compatibility.
  %        Predicate solvable has been eliminated.
  %        not_solvable_quadratic is a LEMMA rather than an AXIOM
  %        Definitions of x1 and x2 revised.
  %        bac renamed discr
  %        Consequences of canonical_sq added.
  %        Vieta's equations (lemma vieta1 and vieta2) added.
  %        x1_eq_x2 added.
  %        
  %----------------------------------------------------------------------------

  quadratic : THEORY
  BEGIN
    IMPORTING sqrt, sign

    a      : VAR nonzero_real
    aa,b,c : VAR real
    x      : VAR real
    eps    : VAR Sign
    k      : VAR nzreal

    canonical_sq : LEMMA
      a*sq(x) + b*x + c  = 
      a*sq(x + b/(2*a)) + (4*a*c - sq(b))/(4*a)

    discr(a,b,c) : real = sq(b) - 4*a*c

    discr_symm : LEMMA
      discr(a,b,c) = discr(-a,-b,-c)

    discr_scalar : LEMMA
      discr(k*a,k*b,k*c) = sq(k)*discr(a,b,c)

    a_gt_0_discr_gt_0 : LEMMA
      a > 0 AND a*sq(x) + b*x + c < 0 IMPLIES
      discr(a,b,c) > 0

    a_gt_0_discr_ge_0 : LEMMA
      a > 0 AND a*sq(x) + b*x + c <= 0 IMPLIES
      discr(a,b,c) >= 0

    a_lt_0_discr_gt_0 : LEMMA
      a < 0 AND a*sq(x) + b*x + c > 0 IMPLIES
      discr(a,b,c) > 0

    a_lt_0_discr_ge_0 : LEMMA
      a < 0 AND a*sq(x) + b*x + c >= 0 IMPLIES
      discr(a,b,c) >= 0

    discr_ge_0 : LEMMA
      a*sq(x) + b*x + c = 0 IMPLIES
      discr(a,b,c) >= 0

    root(a:nonzero_real,b:real,c:real|discr(a,b,c)>=0,eps:Sign):real =
      (-b + eps*sqrt(discr(a,b,c)))/(2*a)

    root_symm : LEMMA
      discr(a,b,c) >= 0 IMPLIES
        root(a,b,c,eps) = root(-a,-b,-c,-eps)

    root_scalar : LEMMA
      discr(a,b,c) >= 0 IMPLIES
        root(k*a,k*b,k*c,eps) = root(a,b,c,sign(k)*eps)

    x1(a:nonzero_real,b:real,c:real|discr(a,b,c)>=0) : MACRO real =
      root(a,b,c,1)

    x2(a:nonzero_real,b:real,c:real|discr(a,b,c)>=0) : MACRO real =
      root(a,b,c,-1)

    vieta1: LEMMA
      discr(a,b,c) >= 0 =>
      x1(a,b,c)+x2(a,b,c) = -b/a

    vieta_add: LEMMA
      discr(a,b,c) >= 0 =>
      root(a,b,c,eps)+root(a,b,c,-eps) = -b/a

    vieta2: LEMMA
      discr(a,b,c) >= 0 =>
      x1(a,b,c)*x2(a,b,c) = c/a

    vieta_mult: LEMMA
      discr(a,b,c) >= 0 =>
      root(a,b,c,eps)*root(a,b,c,-eps) = c/a

    root_neq_0 : LEMMA
      discr(a,b,c) >= 0 AND
      c /= 0 IMPLIES
      root(a,b,c,eps) /= 0

    root_eq_0 : LEMMA
      discr(a,b,c) >= 0 IMPLIES
        (c = 0 AND (b = 0 OR eps = sign(b)) IFF
         root(a,b,c,eps) = 0)

    c_eq_0 : LEMMA
     discr(a,b,c) >= 0 AND
     b = 0 AND
     a*c >= 0
     IMPLIES
      c = 0

    root_eq : LEMMA
      discr(a,b,c) >= 0 IMPLIES
      (discr(a,b,c) = 0 IFF x1(a,b,c) = x2(a,b,c))

    roots_eq_0 : LEMMA
      discr(a,b,c) >= 0 IMPLIES
        (b = 0 AND a*c >= 0 
        IFF
        root(a,b,c,-eps) = 0 AND root(a,b,c,eps) = 0)

    root_inv : LEMMA
      discr(a,b,c) >= 0 AND
      c /= 0 IMPLIES
      root(a,b,c,eps) = 1/root(c,b,a,-eps)

    root_le : LEMMA
      discr(a,b,c) >= 0 IMPLIES 
      root(a,b,c,-sign(a)) <= root(a,b,c,sign(a))

    root_lt : LEMMA
      discr(a,b,c) > 0 IMPLIES 
      root(a,b,c,-sign(a)) < root(a,b,c,sign(a))

    roots_le_ge_0 : LEMMA
     discr(a,b,c) >= 0 IMPLIES
     (a*c <= 0 AND
      (c=0 AND b=0 OR eps=sign(a))
      IFF
      root(a,b,c,-eps) <= 0 AND
      root(a,b,c,eps) >= 0)

    roots_lt_gt_0 : LEMMA
     discr(a,b,c) >= 0 IMPLIES
     (a*c < 0 AND eps=sign(a)
      IFF
      root(a,b,c,-eps) < 0 AND
      root(a,b,c,eps) > 0)

    sign_ab_roots_ge_0 : LEMMA
      discr(a,b,c) >= 0 AND
      a*c >= 0 
      IMPLIES
      -sign(a*b)*root(a,b,c,eps) >= 0

    roots_ge_0 : LEMMA
      discr(a,b,c) >= 0 
      IMPLIES
        (a*c >= 0 AND a*b <= 0 
         IFF
         root(a,b,c,-eps) >= 0 AND
         root(a,b,c,eps) >= 0)

    roots_le_0 : LEMMA
      discr(a,b,c) >= 0 IMPLIES
      (a*c >= 0 AND a*b >= 0 
       IFF
       root(a,b,c,-eps) <= 0 AND
       root(a,b,c,eps) <= 0)

    sign_ab_roots_gt_0 : LEMMA
      discr(a,b,c) >= 0 AND
      a*c > 0 
      IMPLIES
      -sign(a*b)*root(a,b,c,eps) > 0

    roots_gt_0 : LEMMA
      discr(a,b,c) >= 0 IMPLIES
      (a*c > 0 AND a*b <= 0 
       IFF
       root(a,b,c,-eps) > 0 AND
       root(a,b,c,eps) > 0)

    roots_lt_0 : LEMMA
      discr(a,b,c) >= 0 IMPLIES
      (a*c > 0 AND a*b >= 0 
       IFF
       root(a,b,c,-eps) < 0 AND
       root(a,b,c,eps) < 0)

    root_gt_0 : LEMMA
      discr(a,b,c) >= 0 IMPLIES
      ((a*c > 0 AND a*b <= 0) OR
       (a*c <= 0 AND eps=sign(a) AND (c /= 0 OR a*b < 0))
       IFF
       root(a,b,c,eps) > 0)

    root_ge_0 : LEMMA
      discr(a,b,c) >= 0 IMPLIES
      ((a*c >= 0 AND a*b <= 0) OR
       (a*c <= 0 AND eps = sign(a))
       IFF
       root(a,b,c,eps) >= 0)

    root_lt_0 : LEMMA
      discr(a,b,c) >= 0 IMPLIES
      ((a*c > 0 AND a*b >= 0) OR
       (a*c <= 0 AND eps=-sign(a) AND (c /= 0 OR a*b > 0))
       IFF
       root(a,b,c,eps) < 0)

    root_le_0 : LEMMA
      discr(a,b,c) >= 0 IMPLIES
      ((a*c >= 0 AND a*b >= 0) OR
       (a*c <= 0 AND eps = -sign(a))
       IFF
       root(a,b,c,eps) <= 0)

    quadratic_aux : LEMMA
      discr(a,b,c) >= 0 =>
      a*sq(x)+b*x+c = a*(x-x1(a,b,c))*(x-x2(a,b,c))

    quadratic_eq_0 : LEMMA
      (a*sq(x) + b*x + c = 0 IFF
        discr(a,b,c) >= 0 AND
        (x = x1(a,b,c) OR
         x = x2(a,b,c)))

    solvable_quadratic : LEMMA
      discr(a,b,c) >= 0 IFF
      EXISTS (x) : a*sq(x) + b*x + c = 0 

    not_solvable_quadratic : LEMMA     
      NOT discr(a,b,c) >= 0 =>
      ((FORALL(x) : a * sq(x) + b*x + c > 0) OR
       (FORALL(x) : a * sq(x) + b*x + c < 0))

    quadratic_le_0 : LEMMA
      a*sq(x) + b*x + c <= 0 IFF
      ((discr(a,b,c) >= 0 AND 
        ((a > 0 AND x2(a,b,c) <= x AND x <= x1(a,b,c)) OR
         (a < 0 AND (x <= x1(a,b,c) OR x2(a,b,c) <= x)))) OR
       (discr(a,b,c) < 0 AND c <= 0))

    quadratic_lt_0 : LEMMA
      a*sq(x) + b*x + c < 0 IFF
      ((discr(a,b,c) >= 0 AND   
        ((a > 0 AND  x2(a,b,c) < x AND x < x1(a,b,c)) OR
         (a < 0 AND ((x < x1(a,b,c) AND x < x2(a,b,c)) OR
                     (x1(a,b,c) < x AND x2(a,b,c) < x))))) OR
       (discr(a,b,c) < 0 AND c < 0))

    quadratic_ge_0 : LEMMA
      a*sq(x) + b*x + c >= 0 IFF
      ((discr(a,b,c) >= 0 AND 
        ((a < 0 AND x1(a,b,c) <= x AND x <= x2(a,b,c)) OR
         (a > 0 AND (x <= x2(a,b,c) OR x1(a,b,c) <= x)))) OR
       (discr(a,b,c) < 0 AND c >= 0))

    quadratic_gt_0 : LEMMA
      a*sq(x) + b*x + c > 0 IFF
      ((discr(a,b,c) >= 0 AND 
        ((a < 0 AND x1(a,b,c) < x AND x < x2(a,b,c)) OR
         (a > 0 AND (x < x2(a,b,c) OR x1(a,b,c) < x)))) OR
       (discr(a,b,c) < 0 AND c > 0))

  %% quadratic equations that may collapse to linear equations
  %% and the solutions of such equations

    solvable?(aa,b,c): bool =
      (aa = 0 AND b /= 0 OR aa /= 0 AND discr(aa,b,c) >= 0)

    solution(aa,b,(c | solvable?(aa,b,c)), eps: Sign): real =
      IF aa = 0 THEN -c/b ELSE root(aa,b,c,eps) ENDIF

    quadratic_eq_0_full: THEOREM
      aa*sq(x) + b*x + c = 0 IFF
        aa = 0 AND b = 0 AND c = 0 OR
        solvable?(aa,b,c) AND (x = solution(aa,b,c,-1) OR x = solution(aa,b,c,1))

  %% --- Some unexpanded forms ---
    quadratic(a,b,c: real)(x): real = a*sq(x) + b*x + c 

    complete_square : LEMMA
      quadratic(a,b,c)(x) = a * sq(x + b/(2*a)) + (4*a*c - sq(b))/(4*a)

    quad_eq_0 : THEOREM
      quadratic(a,b,c)(x) = 0 IFF
        discr(a,b,c) >= 0 AND EXISTS (eps): x = root(a,b,c,eps)

    quad_eq_0_full: THEOREM
      quadratic(aa,b,c)(x) = 0 IFF
        aa = 0 AND b = 0 AND c = 0 OR
        solvable?(aa,b,c) AND EXISTS (eps): x = solution(aa,b,c,eps) 

  END quadratic

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

  % Subtype TCC generated (at line 61, column 19) for  discr(a, b, c)
      % expected type  nnx: nonneg_real
  root_TCC1: OBLIGATION
    FORALL (a: nonzero_real, b: real, c: real | discr(a, b, c) >= 0,
            eps: Sign):
      discr(a, b, c) >= 0;

  % Subtype TCC generated (at line 65, column 35) for  -c
      % expected type  {c: real | discr(-a, -b, c) >= 0}
  root_symm_TCC1: OBLIGATION
    FORALL (a: nonzero_real, b, c: real):
      discr(a, b, c) >= 0 IMPLIES discr(-a, -b, -c) >= 0;

  % Subtype TCC generated (at line 69, column 19) for  k * c
      % expected type  {c: real | discr(k * a, k * b, c) >= 0}
  root_scalar_TCC1: OBLIGATION
    FORALL (a: nonzero_real, b, c: real, k: nzreal):
      discr(a, b, c) >= 0 IMPLIES discr(k * a, k * b, k * c) >= 0;

  % Subtype TCC generated (at line 123, column 33) for  a
      % expected type  {c_1: real | discr(c, b, c_1) >= 0}
  root_inv_TCC1: OBLIGATION
    FORALL (a: nonzero_real, b, c: real):
      c /= 0 AND discr(a, b, c) >= 0 IMPLIES discr(c, b, a) >= 0;

  % Subtype TCC generated (at line 123, column 24) for  root(c, b, a, -eps)
      % expected type  nznum
  root_inv_TCC2: OBLIGATION
    FORALL (a: nonzero_real, b, c: real, eps: Sign):
      c /= 0 AND discr(a, b, c) >= 0 IMPLIES root(c, b, a, -eps) /= 0;

  % Subtype TCC generated (at line 131, column 13) for  c
      % expected type  {c: real | discr(a, b, c) >= 0}
  root_lt_TCC1: OBLIGATION
    FORALL (a: nonzero_real, b, c: real):
      discr(a, b, c) > 0 IMPLIES discr(a, b, c) >= 0;

  % Subtype TCC generated (at line 272, column 22) for  b
      % expected type  nznum
  solution_TCC1: OBLIGATION
    FORALL (aa: real, b: real, (c: real | solvable?(aa, b, c)), eps: Sign):
      aa = 0 IMPLIES b /= 0;

  % Subtype TCC generated (at line 272, column 34) for  aa
      % expected type  nonzero_real
  solution_TCC2: OBLIGATION
    FORALL (aa: real, b: real, (c: real | solvable?(aa, b, c)), eps: Sign):
      NOT aa = 0 IMPLIES aa /= 0;

  % Subtype TCC generated (at line 272, column 39) for  c
      % expected type  {c: real | discr(aa, b, c) >= 0}
  solution_TCC3: OBLIGATION
    FORALL (aa: real, b: real, (c: real | solvable?(aa, b, c)), eps: Sign):
      NOT aa = 0 IMPLIES discr(aa, b, c) >= 0;


body:
  convex_functions: THEORY
  %------------------------------------------------------------------------------
  % In This Theory, We Define Convex And Stricly Convex Functions. We Prove
  %    That The Maximum Of Two Convex Functions Is Convex And That
  %    A Convex Function Has At Most One Minimum
  %
  %     Authors: Anthony Narkawicz,  NASA Langley
  %
  %     Version 1.0         9/23/2009  Initial Version
  %     Version 1.1	  10/21/2009
  %------------------------------------------------------------------------------
  BEGIN

     IMPORTING quadratic, real_fun_ops

     f,g: VAR [real -> real]
     A,B,C,v,w,x,y,z,t,b,c,d: VAR real
     k  : VAR nat
     a,H: VAR posreal
     aaa: VAR nnreal


     % Convex

     convex?(f): bool = FORALL (x,y,t): 0 <= t and t <= 1 IMPLIES 
     	       	    f(t*x + (1-t)*y) <= t*f(x) + (1-t)*f(y)

     % Basic Properties

     composition_of_convex: LEMMA (FORALL (x,y): x<=y IMPLIES g(x)<=g(y))
     			    AND convex?(f) AND convex?(g) IMPLIES convex?(g o f)

     max_of_convex: LEMMA convex?(f) AND convex?(g) IMPLIES 
     		  convex?((LAMBDA (z): max(f(z),g(z))))

     sum_of_convex: LEMMA convex?(f) AND convex?(g) IMPLIES convex?(f+g)

     scal_convex:	  LEMMA convex?(f) IMPLIES convex?(aaa*f)

     convex_function_right_lt: LEMMA convex?(f) AND A<C AND C<B
       IMPLIES f(B) >= ((B-A)/(C-A))*f(C) - ((B-C)/(C-A))*f(A)

     convex_function_left_lt: LEMMA convex?(f) AND A<C AND C<B
       IMPLIES f(A) >= ((B-A)/(B-C))*f(C) - ((C-A)/(B-C))*f(B)


     % The Following Theorem Can Help In Proofs Where Convexity Is Used
     % By Allowing The User To Escape The Construction Of A Specific t-value

     between_point_is_wtd_av: LEMMA FORALL (x,y,z: real): x<=z AND z<=y
     			    IMPLIES (EXISTS (t: real): 0<=t AND t<=1
  			    	    AND z = t*x + (1-t)*y)

     % Sometimes, it may be convenient to have the t as the coeff of x

     between_point_is_wtd_av2: LEMMA FORALL (x,y,z: real): x<=z AND z<=y
     			    IMPLIES (EXISTS (t: real): 0<=t AND t<=1
  			    	    AND z = (1-t)*x + t*y)

     % The Minima Of Convex Functions Have Certain Fun(ction) properties

     convex_const_on_connected_min: LEMMA convex?(f) AND x < y AND
     		(FORALL (z): x<=z AND z<=y IMPLIES f(x) = f(z))
  		IMPLIES
  		(FORALL (w): f(x) <= f(w))

     convex_min_is_connected: LEMMA convex?(f) AND x < y AND f(x) = f(y)
     			    AND (FORALL (z): f(x) <= f(z))
  			    IMPLIES
  			    (FORALL (w): x<=w AND w<=y IMPLIES f(w) = f(x))

  		   % Part B: Local Minima Of Convex Functions....

     loc_convex_min_is_connected: LEMMA convex?(f) AND A<=x AND x<y AND y<=B AND
     		f(x) = f(y) AND
     		(FORALL (w): x<=w AND w<=y IMPLIES f(x) <= f(w)) IMPLIES
  		(FORALL (w): x<=w AND w<=y IMPLIES f(w) = f(x))

     % Helpful results about convex functions

     convex_btw_pt_left_lt: LEMMA convex?(f) AND A<x AND x<=B AND f(A)<=c
     			     AND f(B)<c IMPLIES f(x) < c

     convex_btw_pt_right_lt: LEMMA convex?(f) AND A<=x AND x<B AND f(A)<c
     			     AND f(B)<=c IMPLIES f(x) < c

     convex_wtd_av_lt: LEMMA convex?(f) AND f(x)<c AND f(y) < c
        		     IMPLIES (FORALL (t): 0 <= t AND t <= 1 IMPLIES 
     	       	     f(t*x + (1-t)*y) < c)

     % If a convex function has x as its min, then it is increasing to the
     % right of x and decreasing to the left of x

     convex_increasing: LEMMA convex?(f) AND (FORALL (y): f(y)>=f(x))
     		      AND v>=x AND w>=v IMPLIES
  		      f(w)>=f(v)

     convex_decreasing: LEMMA convex?(f) AND (FORALL (y): f(y)>=f(x))
     		      AND w<=v AND v<=x IMPLIES
  		      f(w)>=f(v)




     % STRICTLY CONVEX FUNCTIONS

     strictly_convex?(f): bool = FORALL (x,y,t): 0 < t and t < 1 and x /= y IMPLIES 
     	       	    	f(t*x + (1-t)*y) < t*f(x) + (1-t)*f(y)

     strictly_convex_implies_convex: LEMMA strictly_convex?(f) IMPLIES convex?(f)

     strictly_convex_unique_min: LEMMA strictly_convex?(f) AND (FORALL (z):
     			       f(x) <= f(z) AND f(y) <= f(z)) IMPLIES
  			       x = y

     strictly_conv_uniq_intv_min: LEMMA strictly_convex?(f) AND 
     				(A <= x AND x <= B) AND
  				(A <= y AND y <= B) AND
  				(FORALL (z): (A <= z and z <= B) IMPLIES
  				 f(x) <= f(z) AND f(y) <= f(z))
  				IMPLIES
  				x = y


     % Basic Properties

     composition_of_strictly_convex: LEMMA (FORALL (x,y): x<=y IMPLIES g(x)<g(y))
     			    AND convex?(f) AND strictly_convex?(g) 
  			    IMPLIES strictly_convex?(g o f)

     max_of_strictly_convex: LEMMA strictly_convex?(f) AND
     			  	strictly_convex?(g) IMPLIES
  				strictly_convex?((LAMBDA (z): max(f(z),g(z))))

     sum_of_strictly_convex: LEMMA strictly_convex?(f) AND strictly_convex?(g) 
     			   IMPLIES strictly_convex?(f+g)

     scal_strictly_convex:  LEMMA strictly_convex?(f) IMPLIES strictly_convex?(a*f)

     % Helpful results about strictly convex functions

     strictly_convex_btw_pt_lt: LEMMA strictly_convex?(f) AND A<x AND x<B AND f(A)<=c
     			     AND f(B)<=c IMPLIES f(x) < c

     % Special Case: Quadratics

     quad_convex: LEMMA convex?(quadratic(aaa,b,c))

     quad_strictly_convex: LEMMA strictly_convex?(quadratic(a,b,c))

     abs_linear_convex: LEMMA convex?((LAMBDA (t): abs(x + t*y)-H))


     quad_linear_max_convex: LEMMA LET maxfun = (LAMBDA (t): max(quadratic(a,b,c)(t),
  							     abs(x + t*y)-H))
  			       IN convex?(maxfun)

     quad_linear_max_glob_min: LEMMA LET maxfun = (LAMBDA (t): max(quadratic(a,b,c)(t),
  							     abs(x + t*y)-H))
  			       IN y /= 0 AND maxfun(w) = 0 AND maxfun(v) = 0 AND
  			       	  (FORALL (z): 0 <= maxfun(z)) 
  				  IMPLIES
  				  v = w

     quad_linear_max_loc_min: LEMMA LET maxfun = (LAMBDA (t): max(quadratic(a,b,c)(t),
  							     abs(x + t*y)-H))
  			       IN y /= 0 AND 
  			       	  (A <= w AND w <= B) AND (A <= v AND v <= B) AND
  			       	  maxfun(w) = 0 AND maxfun(v) = 0 AND
  			       	  (FORALL (z): (A <= z AND z <= B) IMPLIES 0 <= maxfun(z)) 
  				  IMPLIES
  				  v = w

     % Special Case: Exponentials Of Convex Functions


     power_of_convex: LEMMA convex?(f) AND (FORALL (x): f(x)>=0)
     		IMPLIES convex?(LAMBDA (x): f(x)^k)

     power_of_strictly_convex: LEMMA strictly_convex?(f) AND (FORALL (x): f(x)>=0)
     		IMPLIES strictly_convex?(LAMBDA (x): f(x)^(k+1))




  END convex_functions

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

  % Subtype TCC generated (at line 41, column 29) for  (C - A)
      % expected type  nznum
  convex_function_right_lt_TCC1: OBLIGATION
    FORALL (A, B, C: real, f: [real -> real]):
      C < B AND A < C AND convex?(f) IMPLIES (C - A) /= 0;

  % Subtype TCC generated (at line 44, column 29) for  (B - C)
      % expected type  nznum
  convex_function_left_lt_TCC1: OBLIGATION
    FORALL (A, B, C: real, f: [real -> real]):
      C < B AND A < C AND convex?(f) IMPLIES (B - C) /= 0;

  % Subtype TCC generated (at line 178, column 38) for  k
      % expected type  {i: int | f(x) /= 0 OR i >= 0}
  power_of_convex_TCC1: OBLIGATION
    FORALL (f: [real -> real], k: nat):
      (FORALL (x): f(x) >= 0) AND convex?(f) IMPLIES
       (FORALL (x1: real): f(x1) /= 0 OR k >= 0);

  % Subtype TCC generated (at line 181, column 48) for  (k + 1)
      % expected type  {i: int | f(x) /= 0 OR i >= 0}
  power_of_strictly_convex_TCC1: OBLIGATION
    FORALL (f: [real -> real], k: nat):
      (FORALL (x): f(x) >= 0) AND strictly_convex?(f) IMPLIES
       (FORALL (x1: real): f(x1) /= 0 OR (k + 1) >= 0);


body:
  quad_minmax: THEORY
  %----------------------------------------------------------------------------
  %
  %  Minimums and Maximums of quadratic functions:
  %
  %        quadratic(a,b,c)(x): real = a*sq(x) + b*x + c 
  %
  %  This theory is derived from quadratic_minmax.  This theory has the same
  %  theorems but used a more convenient LET ... IN form that reduces the
  %  number of free variables.
  %
  %----------------------------------------------------------------------------
  BEGIN

    IMPORTING quadratic        %% quadratic_minmax deprecated

    a   : VAR nonzero_real
    b,c: VAR real
    x,y  : VAR real
    xl,xu,t: VAR real
    f: VAR [real -> real]
    epsil: VAR posreal


  % ---------- Following apply to both min and max cases -----------

    quad_minmaxpt_delta: LEMMA LET f = quadratic(a,b,c), m = -b/(2*a) IN
                                 f(m + t) = f(m - t)

    quad_minmaxpt_midpt: LEMMA LET f = quadratic(a,b,c), m = -b/(2*a) IN
  		               x /= y AND f(x) = f(y) IMPLIES m = (x + y)/2


  % ---- is_minimum? is also defined in real_fun_preds in analysis library

  %  is_minimum?(x:real, f: [real -> real]): bool = FORALL y : f(x) <= f(y)

    is_minimum?(x, f): bool = FORALL y : f(x) <= f(y)


    quad_min : LEMMA  LET f = quadratic(a,b,c),
                              minpt = -b/(2*a) IN
                            a > 0 IMPLIES
                               is_minimum?(minpt,f)

    quad_min_val : LEMMA LET f = quadratic(a,b,c),
                             minpt = -b/(2*a) IN
                              a > 0  
                                IMPLIES f(x) >= (4*a*c-sq(b))/(4*a)

    quad_min_mono_inc : LEMMA LET f = quadratic(a,b,c),
                                  minpt = -b/(2*a) IN
                               a > 0 IMPLIES 
                               x > y AND y >= minpt
                               IMPLIES 
                               f(x) > f(y)

    quad_min_mono_dec : LEMMA  LET f = quadratic(a,b,c),
                                   minpt = -b/(2*a) IN
                                a > 0 AND 
                                x < y AND y <= minpt 
                                IMPLIES 
                                   f(x) > f(y)  

    quad_min_eq_intv: LEMMA a > 0 AND 
                             quadratic(a,b,c)(xl) = quadratic(a,b,c)(xu) AND
                             xl < t AND t < xu
                                 IMPLIES 
                                    quadratic(a,b,c)(t) < quadratic(a,b,c)(xu)

    quad_min_eq_is_in: LEMMA a > 0 AND 
                             quadratic(a,b,c)(xl) = quadratic(a,b,c)(xu) AND
                             quadratic(a,b,c)(t) < quadratic(a,b,c)(xu) AND 
                             xl < xu
                                 IMPLIES 
                                   (xl < t AND t < xu)

    quad_loc_min_is_glob_min: LEMMA a > 0 AND (FORALL (y): (x-epsil < y AND
    			    	  y < x+epsil) IMPLIES 
  				  quadratic(a,b,c)(y) >= quadratic(a,b,c)(x))
  				  IMPLIES
  				  x = -b/(2*a)



  % ---- is_maximum? is also defined in real_fun_preds in analysis library

  %  is_maximum?(x:real, f: [real -> real]): bool = FORALL y : f(x) >= f(y)

    is_maximum?(x, f): bool = FORALL y : f(x) >= f(y)


    quad_max : LEMMA LET f = quadratic(a,b,c),
                         maxpt = -b/(2*a) IN 
                           a < 0                          
                             IMPLIES is_maximum?(maxpt,f)

    quad_max_val : LEMMA LET f = quadratic(a,b,c),
                             maxpt = -b/(2*a) IN 
                                a < 0 
                                  IMPLIES f(x) <= (4*a*c-sq(b))/(4*a)


    quad_max_mono_inc : LEMMA LET f = quadratic(a,b,c),
                                  maxpt = -b/(2*a) IN
                               a < 0 AND
                               x < y AND y <= maxpt 
                               IMPLIES 
                                   f(x) < f(y)

    quad_max_mono_dec : LEMMA LET f = quadratic(a,b,c),
                                  maxpt = -b/(2*a) IN
                                    a < 0 AND 
                                    x > y AND y >= maxpt
                                    IMPLIES 
                                        f(x) < f(y)

    quad_max_eq_intv: LEMMA a < 0 AND 
                             quadratic(a,b,c)(xl) = quadratic(a,b,c)(xu) AND
                             xl < t AND t < xu
                                 IMPLIES 
                                    quadratic(a,b,c)(t) > quadratic(a,b,c)(xu)

    quad_max_eq_is_in: LEMMA a < 0 AND 
                             quadratic(a,b,c)(xl) = quadratic(a,b,c)(xu) AND
                             quadratic(a,b,c)(t) > quadratic(a,b,c)(xu) AND 
                             xl < xu
                                 IMPLIES 
                                   (xl < t AND t < xu)

    quad_loc_max_is_glob_max: LEMMA a < 0 AND (FORALL (y): (x-epsil < y AND
    			    	y < x+epsil) IMPLIES 
  				quadratic(a,b,c)(y) <= quadratic(a,b,c)(x))
  				IMPLIES
  				x = -b/(2*a)

    quad_intv_max_at_endpoint: LEMMA a>0 AND xl<=xu IMPLIES
      (FORALL (t): xl<=t AND t<=xu IMPLIES quadratic(a,b,c)(t)<=quadratic(a,b,c)(xl))
      OR
      (FORALL (t): xl<=t AND t<=xu IMPLIES quadratic(a,b,c)(t)<=quadratic(a,b,c)(xu))

    quad_intv_increasing_from_min: LEMMA a > 0 AND abs(x-(-b/(2*a))) <= abs(y-(-b/(2*a)))
      IMPLIES quadratic(a,b,c)(x) <= quadratic(a,b,c)(y)

  END quad_minmax


body:
  % A better root when b is even
  quadratic_2b : THEORY
  BEGIN
    IMPORTING quadratic

    a   : VAR nzreal
    b,c : VAR real
    x   : VAR real
    eps : VAR Sign

    discr2b(a,b,c)  : real = sq(b) - a*c

    discr2b_discr : LEMMA
      discr2b(a,b,c) = discr(a,2*b,c)/4

    discr_discr2b : LEMMA
      discr(a,b,c) = 4*discr2b(a,b/2,c)

    discr2b_discr_eq_0 : LEMMA
      discr2b(a,b,c) = 0 IFF discr(a,2*b,c) = 0

    discr_discr2b_eq_0 : LEMMA
      discr(a,b,c) = 0 IFF discr2b(a,b/2,c) = 0

    discr2b_discr_ge_0 : LEMMA
      discr2b(a,b,c) >= 0 IFF discr(a,2*b,c) >= 0

    discr_discr2b_ge_0 : LEMMA
      discr(a,b,c) >= 0 IFF discr2b(a,b/2,c) >= 0

    discr2b_discr_gt_0 : LEMMA
      discr2b(a,b,c) > 0 IFF discr(a,2*b,c) > 0

    discr_discr2b_gt_0 : LEMMA
      discr(a,b,c) > 0 IFF discr2b(a,b/2,c) > 0

    root2b(a:nzreal,b:real,c:real|discr2b(a,b,c)>=0,eps:Sign):real =
      (-b + eps*sqrt(discr2b(a,b,c)))/a

    root2b_root : LEMMA
      discr2b(a,b,c) >= 0 IMPLIES
        root2b(a,b,c,eps) = root(a,2*b,c,eps)

    root_root2b : LEMMA
      discr(a,b,c) >= 0 IMPLIES
        root(a,b,c,eps) = root2b(a,b/2,c,eps)

    quad2b_eq_0 : THEOREM
      quadratic(a,2*b,c)(x) = 0 IFF
        discr2b(a,b,c) >= 0 AND
        EXISTS (eps): x = root2b(a,b,c,eps)

  END quadratic_2b

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

  % Subtype TCC generated (at line 38, column 19) for  discr2b(a, b, c)
      % expected type  nnx: nonneg_real
  root2b_TCC1: OBLIGATION
    FORALL (a: nzreal, b: real, c: real | discr2b(a, b, c) >= 0, eps: Sign):
      discr2b(a, b, c) >= 0;

  % Subtype TCC generated (at line 42, column 37) for  c
      % expected type  {c: real | discr(a, 2 * b, c) >= 0}
  root2b_root_TCC1: OBLIGATION
    FORALL (a: nzreal, b, c: real):
      discr2b(a, b, c) >= 0 IMPLIES discr(a, 2 * b, c) >= 0;

  % Subtype TCC generated (at line 46, column 37) for  c
      % expected type  {c: real | discr2b(a, b / 2, c) >= 0}
  root_root2b_TCC1: OBLIGATION
    FORALL (a: nzreal, b, c: real):
      discr(a, b, c) >= 0 IMPLIES discr2b(a, b / 2, c) >= 0;


body:
  sigma[T: TYPE FROM int]: THEORY
  %------------------------------------------------------------------------------
  % The summations theory introduces and defines properties of the sigma 
  % function that sums an arbitrary function F: [T -> real] over a range
  % from low to high
  %
  %  		          high
  %		          ----
  %  sigma(low, high, F) =  \     F(j)
  %		          /
  %		          ----
  %		         j = low
  %
  %  NOTE:
  %
  %     This is the generic theory.  It is usually preferable to use
  %     sigma_nat, sigma_int, sigma_below, etc.
  %
  %  MODIFICATIONS:
  %
  %    8/7/01   added sigma_zero, sigma_with 
  %
  %    3/24/06  generalized to allow index ranges to fall outside of
  %             domain of T when high < low.  This upgrade will break
  %             some old proofs, but will reduce TCC generation significantly
  %
  %    11/7/07  replace sigma with simpler definition.  Old definition available in
  %             old_sigma_*.pvs theories.  Also old definition is retained as
  %             sigma2.
  %  
  %  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,low1,low2       : VAR T_low
    high,high1,high2      : VAR T_high 
    l,h,n,m,i : VAR T
    rng, nn   : VAR nat
    pn        : VAR posnat
    z,z1,z2         : VAR int
    a,x,B     : VAR real

    T_pred_lem : LEMMA low <= z AND z <= high IMPLIES T_pred(z)

  % AUTO_REWRITE+ T_pred_lem  %% THIS DOES NOT HELP

  % T_pred_low : LEMMA low <= m IMPLIES T_pred(low)
  % T_pred_high: LEMMA m <= high IMPLIES T_pred(high)
  %  AUTO_REWRITE+ T_pred_low, T_pred_high  %% DOES NOT HELP

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

    % *** NEW *** Simpler Definition
    sigma(low, high, F): RECURSIVE real
        = IF low > high THEN 0
          ELSE  F(high) + sigma(low, high-1, F)
          ENDIF                            
     MEASURE (LAMBDA low, high, F: abs(high+1-low))

    % *** Old Definition ***  
    sigma2(low, high, F): RECURSIVE real
        = IF low > high THEN 0
          ELSIF high = low THEN F(low) 
          ELSE  F(high) + sigma2(low, high-1, F)
          ENDIF
     MEASURE (LAMBDA low, high, F: abs(high+1-low))

    % provides one unfolding analogous to old definition -- useful for upgrade
    sigma_rew : LEMMA sigma(low, high, F) = IF low > high THEN 0
                                            ELSIF high = low THEN F(low) 
                                            ELSE  F(high) + sigma(low, high-1, F)
                                            ENDIF

    sigma_rew2: LEMMA sigma(low, high, F) = sigma2(low, high, F)


    sigma_spl     : THEOREM T_pred(low + nn + rng) IMPLIES 
                             sigma(low, low+nn+rng, F) = 
                                sigma(low,low+nn,F) + sigma(low+nn+1,low+nn+rng,F)

    sigma_split   : THEOREM low - 1 <= z AND z <= high IMPLIES 
                              sigma(low, high, F) = 
                                       sigma(low, z, F) + sigma(z+1, high, F)


  % Both of the following are now covered by sigma_split

  %   sigma_split_l: THEOREM %T_pred(low-1) AND
  %                           low-1 <= m AND m < high IMPLIES 
  %                             sigma(low, high, F) = 
  %                                      sigma(low, m, F) + sigma(m+1, high, F)


  %   sigma_split_h: THEOREM low <= m AND m <= high AND T_pred(m+1) IMPLIES 
  %                             sigma(low, high, F) = 
  %                                      sigma(low, m, F) + sigma(m+1, high, F)


    sigma_diff    : THEOREM low - 1 <= z AND z <= high IMPLIES
                      sigma(low, high, F) - sigma(low, z, F) = sigma(z+1, high, F)

    sigma_diff_neg: THEOREM low - 1 <= z AND z <= high IMPLIES
                    sigma(low, z, F) - sigma(low, high, F) = - sigma(z+1, high, F)
   		 
    sigma_eq_arg  : THEOREM sigma(m, m, F) = F(m)

    sigma_first   : THEOREM high >= low IMPLIES 
                             sigma(low, high, F) = F(low) + sigma(low+1, high, F)

    sigma_last    : THEOREM high >= low IMPLIES 
                            sigma(low, high, F) = sigma(low, high-1, F) + F(high)

    sigma_middle : THEOREM high >= i AND i >= low IMPLIES
                            sigma(low, high, F) = sigma(low, i-1, F) + F(i) +
                                                  sigma(i+1, high, F) 

    sigma_const   : THEOREM sigma(low, high, (LAMBDA i: x)) = 
                             IF high >= low THEN (high-low+1) * x ELSE 0 ENDIF


    sigma_zero    : THEOREM sigma(low, high, (LAMBDA i: 0)) = 0
   		 
    sigma_scal    : THEOREM sigma(low, high, (LAMBDA i: a * F(i)))
                               = a * sigma(low, high, F)

    % Sometimes sigma_scal does not rewrite if the scalar is on the right, so the next lemma is needed

    sigma_scal_right    : THEOREM sigma(low, high, (LAMBDA i: F(i)*a))
                               = sigma(low, high, F)*a
  		 
    sigma_bound   : THEOREM low - 1 <= high AND
                           (FORALL i: i >= low AND i <= high IMPLIES F(i) <= B)
                              IMPLIES sigma(low, high, F) <= B*(high-low+1) %was abs(high-low+1)

    sigma_abs     : THEOREM abs(sigma(low, high, F)) <= 
                                sigma(low, high, LAMBDA (n: T): abs(F(n)))

    sigma_ge_0    : THEOREM (FORALL (n: subrange(low,high)): F(n) >= 0)
                                  IMPLIES sigma(low,high,F) >= 0

    sigma_gt_0    : THEOREM low <= high AND 
                            (FORALL (n: subrange(low,high)): F(n) > 0)
                                  IMPLIES sigma(low,high,F) > 0


    sigma_shift_T : THEOREM (FORALL (i:T): T_pred(i+z)) IMPLIES 
  			         sigma(low+z,high+z,F) = 
                                      sigma(low,high, (LAMBDA (i:T): F(i+z)))

    sigma_shift_T2 : THEOREM T_pred(low+z) AND T_pred(high+z) IMPLIES 
  			         sigma(low+z,high+z,F) = 
                   sigma(low,high, (LAMBDA (i:T): IF T_pred(i+z) THEN F(i+z)
                                                  ELSE 0 ENDIF))


  % ------------------ Summation Involving Two Functions ------------------

    sigma_sum     : THEOREM sigma(low, high, F) + sigma(low, high, G)
                               = sigma(low, high, (LAMBDA i: F(i) + G(i)))

    sigma_minus   : THEOREM sigma(low, high, F) - sigma(low, high, G)
                               = sigma(low, high, (LAMBDA i: F(i) - G(i)))

    sigma_abs_bnd  : THEOREM (FORALL (i: subrange(low,high)): abs(F(i)) <= G(i))
                         IMPLIES sigma(low, high, LAMBDA (n: T): abs(F(n))) <=
                                          sigma(low, high, G)

    restrict(F, low, high): function[T -> real] = 
       (LAMBDA i: IF i < low OR i > high THEN 0 ELSE F(i) ENDIF )

    sigma_restrict   : THEOREM l <= low AND h >= high IMPLIES	
                              sigma(low,high,F) = sigma(low,high,restrict(F,l,h))

    sigma_restrict_to: THEOREM sigma(low,high,F) = 
                                  sigma(low,high,restrict(F,low,high))

    sigma_restrict_eq: THEOREM restrict(F,low,high) = restrict(G,low,high) 
                                  IMPLIES sigma(low,high,F) = sigma(low,high,G)

    sigma_shift_fun_eq: THEOREM high1-low1 = high2-low2 AND
    		      	      (FORALL (i:subrange(0,high1-low1)): F(low1+i) = G(low2+i))
  			      IMPLIES
  			      sigma(low1,high1,F) = sigma(low2,high2,G)

    sigma_const_restrict_eq: LEMMA restrict(F,low,high) = restrict(G,low,high) 
                                  IMPLIES x*sigma(low,high,F) = x*sigma(low,high,G)

    sigma_restrict_eq_0: THEOREM (FORALL (i: subrange(low,high)): F(i) = 0)
    		       	       IMPLIES sigma(low,high,F) = 0

    sigma_triangle: LEMMA abs(sigma(low,high,F))<=sigma(low,high,LAMBDA (n:T):abs(F(n)))

    sigma_eq_one_arg : THEOREM low<=z AND z<=high AND
    		     	     (FORALL (i:subrange(low,z-1)):F(i)=0) AND
  			     (FORALL (i:subrange(z+1,high)):F(i)=0) IMPLIES
  			     sigma(low,high,F) = F(z)

    sigma_eq_one_arg2 : THEOREM low<=z AND z<=high AND
    		     	     (FORALL (i:subrange(low,high)):i/=z IMPLIES F(i)=0) IMPLIES
  			     sigma(low,high,F) = F(z)

    sigma_eq_two_args: THEOREM low<=z1 AND z1<=high AND
    		     	     low<=z2 AND z2<=high AND z1/=z2 AND
  			     (FORALL (i:subrange(low,high)): i/=z1 AND i/=z2 IMPLIES F(i)=0)
  			     IMPLIES sigma(low,high,F) = F(z1)+F(z2)

    sigma_const_restrict_eq_0: THEOREM (FORALL (i: subrange(low,high)): F(i) = 0)
    		       	       IMPLIES x*sigma(low,high,F) = 0


    sigma_eq         : THEOREM (FORALL (n: subrange(low,high)): F(n) = G(n))
                                  IMPLIES sigma(low,high,F) = sigma(low,high,G) 


    sigma_le         : THEOREM (FORALL (n: subrange(low,high)): F(n) <= G(n))
                                  IMPLIES sigma(low,high,F) <= sigma(low,high,G) 

    sigma_lt         : THEOREM low <= high AND
                               (FORALL (n: subrange(low,high)): F(n) < G(n))
                                  IMPLIES sigma(low,high,F) < sigma(low,high,G)

    sigma_ge         : THEOREM (FORALL (n: subrange(low,high)): F(n) >= G(n))
                                  IMPLIES sigma(low,high,F) >= sigma(low,high,G) 

    sigma_gt         : THEOREM low <= high AND
                               (FORALL (n: subrange(low,high)): F(n) > G(n))
                                  IMPLIES sigma(low,high,F) > sigma(low,high,G)

    sigma_with       : THEOREM low <= i AND i <= high AND
                               F = G WITH [i := a] IMPLIES
                            sigma(low, high,F) = sigma(low,high,G) - G(i) + a

    sigma_le_scal    : THEOREM low<=high AND
                        (FORALL (i): low<=i AND i<=high IMPLIES F(i)<=B/(high-low+1))
                        IMPLIES
  		      sigma(low,high,F)<=B

  				 		   	       



  % ------------------------ Special Arguments --------------------------------

    sigma_nonneg     : THEOREM (FORALL i: F(i) >= 0) 
                                   IMPLIES sigma(low, high, F) >= 0
   
    sigma_nonpos     : THEOREM (FORALL i: F(i) <= 0) 
                                   IMPLIES sigma(low, high, F) <= 0




    Fnnr: VAR function[T -> nonneg_real]
    Fnpr: VAR function[T -> nonpos_real]
    Fnat: VAR function[T -> nat]
    Fnpi: VAR function[T -> nonpos_int]
    Fposnat: VAR function[T -> posnat]
    Fposreal: VAR function[T -> posreal]

    sigma_Fnnr        : LEMMA FORALL (Fnnr, high, low): sigma(low, high, Fnnr) >= 0

    sigma_nnreal      : JUDGEMENT sigma(low,high,Fnnr) HAS_TYPE nnreal

    sigma_nonpos_real : JUDGEMENT sigma(low,high,Fnpr) HAS_TYPE nonpos_real

    sigma_nat         : JUDGEMENT sigma(low,high,Fnat) HAS_TYPE nat

    sigma_nonpos_int  : JUDGEMENT sigma(low,high,Fnpi) HAS_TYPE nonpos_int

    sigma_posnat      : LEMMA low <= high IMPLIES sigma(low,high,Fposnat) > 0

    sigma_posreal     : LEMMA low <= high IMPLIES sigma(low,high,Fposreal) > 0

    sigma_nonneg_eq_0 : THEOREM sigma(low,high,Fnnr) = 0 
                                AND low <= i AND i <= high IMPLIES Fnnr(i) = 0

    sigma_nn_ge_comps : THEOREM low <= i AND i <= high IMPLIES 
                                    sigma(low,high,Fnnr) >= Fnnr(i) 


  % ------------------- Iterative Summation (tail recursion) ------------

     sum_it_def(low, high, F,a): RECURSIVE real
        = IF low > high THEN a
          ELSE  sum_it_def(low+1,high,F,a+F(low))
          ENDIF
     MEASURE (LAMBDA low, high, F, a: abs(high+1-low))

     sum_it(low,high,F) : real = sum_it_def(low,high,F,0)

     sum_it_prop : LEMMA
       low - 1 <= i AND i <= high =>
       sum_it_def(i+1,high,F,sigma(low,i,F)) = sigma(low,high,F)

     sum_it_sigma: LEMMA sum_it(low,high,F) = sigma(low,high,F)

     sigma_it(low,high,F) : MACRO real = sum_it(low,high,F)

  % Note: We would have preferred to use the following definitions:
  %
  %   T_low?: MACRO set[int] = {i:int | EXISTS (j:T): j <= i}
  %   T_low  : TYPE = {i:int | T_low?(i)}
  %
  %   T_high?: MACRO set[int] = {i:int | EXISTS (j:T): i <= j}
  %   T_high : TYPE = {i:int | T_high?(i)}
  %
  % but could not find any judgements that would fire and prevent
  % spurious TCC generation.


  END sigma

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

  % Subtype TCC generated (at line 72, 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 83, column 16) for  high
      % expected type  T
  sigma_TCC1: OBLIGATION
    FORALL (low: T_low, high: T_high): NOT low > high IMPLIES T_pred(high);

  % Subtype TCC generated (at line 83, column 35) for  high - 1
      % expected type  T_high
  sigma_TCC2: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES
       T_pred(high - 1) OR (EXISTS (j: T): high - 1 <= j);

  % Termination TCC generated (at line 83, column 24) for
      % sigma(low, high - 1, F)
  sigma_TCC3: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES abs(high - 1 + 1 - low) < abs(high + 1 - low);

  % Subtype TCC generated (at line 90, column 32) for  low
      % expected type  T
  sigma2_TCC1: OBLIGATION
    FORALL (low: T_low, high: T_high):
      high = low AND NOT low > high IMPLIES T_pred(low);

  % Subtype TCC generated (at line 105, column 38) for  low + nn + rng
      % expected type  T_high
  sigma_spl_TCC1: OBLIGATION
    FORALL (low: T_low, nn, rng: nat):
      T_pred(low + nn + rng) IMPLIES
       T_pred(low + nn + rng) OR (EXISTS (j: T): low + nn + rng <= j);

  % Subtype TCC generated (at line 106, column 40) for  low + nn
      % expected type  T_high
  sigma_spl_TCC2: OBLIGATION
    FORALL (low: T_low, nn, rng: nat):
      T_pred(low + nn + rng) IMPLIES
       T_pred(low + nn) OR (EXISTS (j: T): low + nn <= j);

  % Subtype TCC generated (at line 106, column 58) for  low + nn + 1
      % expected type  T_low
  sigma_spl_TCC3: OBLIGATION
    FORALL (low: T_low, nn, rng: nat):
      T_pred(low + nn + rng) IMPLIES
       T_pred(low + nn + 1) OR (EXISTS (j: T): j <= low + nn + 1);

  % Subtype TCC generated (at line 110, column 48) for  z
      % expected type  T_high
  sigma_split_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      z <= high AND low - 1 <= z IMPLIES T_pred(z) OR (EXISTS (j: T): z <= j);

  % Subtype TCC generated (at line 110, column 62) for  z + 1
      % expected type  T_low
  sigma_split_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      z <= high AND low - 1 <= z IMPLIES
       T_pred(z + 1) OR (EXISTS (j: T): j <= z + 1);

  % Subtype TCC generated (at line 135, column 51) for  low
      % expected type  T
  sigma_first_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low): high >= low IMPLIES T_pred(low);

  % Subtype TCC generated (at line 135, column 64) for  low + 1
      % expected type  T_low
  sigma_first_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low):
      high >= low IMPLIES T_pred(low + 1) OR (EXISTS (j: T): j <= low + 1);

  % Subtype TCC generated (at line 138, column 59) for  high - 1
      % expected type  T_high
  sigma_last_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low):
      high >= low IMPLIES T_pred(high - 1) OR (EXISTS (j: T): high - 1 <= j);

  % Subtype TCC generated (at line 138, column 74) for  high
      % expected type  T
  sigma_last_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low): high >= low IMPLIES T_pred(high);

  % Subtype TCC generated (at line 141, column 59) for  i - 1
      % expected type  T_high
  sigma_middle_TCC1: OBLIGATION
    FORALL (high: T_high, i: T, low: T_low):
      i >= low AND high >= i IMPLIES
       T_pred(i - 1) OR (EXISTS (j: T): i - 1 <= j);

  % Subtype TCC generated (at line 142, column 54) for  i + 1
      % expected type  T_low
  sigma_middle_TCC2: OBLIGATION
    FORALL (high: T_high, i: T, low: T_low):
      i >= low AND high >= i IMPLIES
       T_pred(i + 1) OR (EXISTS (j: T): j <= i + 1);

  % Subtype TCC generated (at line 165, column 61) for  n
      % expected type  T
  sigma_ge_0_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, n: subrange(low, high)): T_pred(n);

  % Subtype TCC generated (at line 174, column 18) for  low + z
      % expected type  T_low
  sigma_shift_T_TCC1: OBLIGATION
    FORALL (low: T_low, z: int):
      (FORALL (i: T): T_pred(i + z)) IMPLIES
       T_pred(low + z) OR (EXISTS (j: T): j <= low + z);

  % Subtype TCC generated (at line 174, column 24) for  high + z
      % expected type  T_high
  sigma_shift_T_TCC2: OBLIGATION
    FORALL (high: T_high, z: int):
      (FORALL (i: T): T_pred(i + z)) IMPLIES
       T_pred(high + z) OR (EXISTS (j: T): high + z <= j);

  % Subtype TCC generated (at line 175, column 69) for  i + z
      % expected type  T
  sigma_shift_T_TCC3: OBLIGATION
    FORALL (z: int):
      (FORALL (i: T): T_pred(i + z)) IMPLIES (FORALL (i1: T): T_pred(i1 + z));

  % Subtype TCC generated (at line 178, column 18) for  low + z
      % expected type  T_low
  sigma_shift_T2_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      T_pred(high + z) AND T_pred(low + z) IMPLIES
       T_pred(low + z) OR (EXISTS (j: T): j <= low + z);

  % Subtype TCC generated (at line 178, column 24) for  high + z
      % expected type  T_high
  sigma_shift_T2_TCC2: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      T_pred(high + z) AND T_pred(low + z) IMPLIES
       T_pred(high + z) OR (EXISTS (j: T): high + z <= j);

  % Subtype TCC generated (at line 208, column 55) for  low1 + i
      % expected type  T
  sigma_shift_fun_eq_TCC1: OBLIGATION
    FORALL (high1, high2: T_high, low1, low2: T_low):
      high1 - low1 = high2 - low2 IMPLIES
       (FORALL (i: subrange(0, high1 - low1)): T_pred(low1 + i));

  % Subtype TCC generated (at line 208, column 67) for  low2 + i
      % expected type  T
  sigma_shift_fun_eq_TCC2: OBLIGATION
    FORALL (high1, high2: T_high, low1, low2: T_low):
      high1 - low1 = high2 - low2 IMPLIES
       (FORALL (i: subrange(0, high1 - low1)): T_pred(low2 + i));

  % Subtype TCC generated (at line 221, column 47) for  i
      % expected type  T
  sigma_eq_one_arg_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low, z: int):
      low <= z AND z <= high IMPLIES
       (FORALL (i: subrange(low, z - 1)): T_pred(i));

  % Subtype TCC generated (at line 222, column 41) for  i
      % expected type  T
  sigma_eq_one_arg_TCC2: OBLIGATION
    FORALL (F: [T -> real], high: T_high, low: T_low, z: int):
      (low <= z AND
        z <= high AND (FORALL (i: subrange(low, z - 1)): F(i) = 0))
       IMPLIES (FORALL (i1: subrange(1 + z, high)): T_pred(i1));

  % Subtype TCC generated (at line 223, column 30) for  z
      % expected type  T
  sigma_eq_one_arg_TCC3: OBLIGATION
    FORALL (F: [T -> real], high: T_high, low: T_low, z: int):
      (FORALL (i: subrange(1 + z, high)): F(i) = 0) AND
       (FORALL (i: subrange(low, z - 1)): F(i) = 0) AND
        z <= high AND low <= z
       IMPLIES T_pred(z);

  % Subtype TCC generated (at line 227, column 30) for  z
      % expected type  T
  sigma_eq_one_arg2_TCC1: OBLIGATION
    FORALL (F: [T -> real], high: T_high, low: T_low, z: int):
      (FORALL (i: subrange(low, high)): i /= z IMPLIES F(i) = 0) AND
       z <= high AND low <= z
       IMPLIES T_pred(z);

  % Subtype TCC generated (at line 232, column 38) for  z1
      % expected type  T
  sigma_eq_two_args_TCC1: OBLIGATION
    FORALL (F: [T -> real], high: T_high, low: T_low, z1, z2: int):
           FORALL (i: subrange(low, high)):
             i /= z1 AND i /= z2 IMPLIES F(i) = 0
       AND z1 /= z2 AND z2 <= high AND low <= z2 AND z1 <= high AND low <= z1
       IMPLIES T_pred(z1);

  % Subtype TCC generated (at line 232, column 44) for  z2
      % expected type  T
  sigma_eq_two_args_TCC2: OBLIGATION
    FORALL (F: [T -> real], high: T_high, low: T_low, z1, z2: int):
           FORALL (i: subrange(low, high)):
             i /= z1 AND i /= z2 IMPLIES F(i) = 0
       AND z1 /= z2 AND z2 <= high AND low <= z2 AND z1 <= high AND low <= z1
       IMPLIES T_pred(z2);

  % Subtype TCC generated (at line 261, column 71) for  (high - low + 1)
      % expected type  nznum
  sigma_le_scal_TCC1: OBLIGATION
    FORALL (high: T_high, low: T_low):
      low <= high IMPLIES
       (FORALL (i: T): low <= i AND i <= high IMPLIES (high - low + 1) /= 0);

  % Judgement subtype TCC generated (at line 289, column 32) for
      % sigma(low, high, Fnnr)
      % expected type  nnreal
  sigma_nnreal: OBLIGATION
    FORALL (Fnnr, high, low): sigma(low, high, Fnnr) >= 0;

  % Judgement subtype TCC generated (at line 291, column 32) for
      % sigma(low, high, Fnpr)
      % expected type  nonpos_real
  sigma_nonpos_real: OBLIGATION
    FORALL (Fnpr, high, low): sigma(low, high, Fnpr) <= 0;

  % Judgement subtype TCC generated (at line 293, column 32) for
      % sigma(low, high, Fnat)
      % expected type  nat
  sigma_nat: OBLIGATION
    FORALL (Fnat, high, low):
      rational_pred(sigma(low, high, Fnat)) AND
       integer_pred(sigma(low, high, Fnat)) AND sigma(low, high, Fnat) >= 0;

  % Judgement subtype TCC generated (at line 295, column 32) for
      % sigma(low, high, Fnpi)
      % expected type  nonpos_int
  sigma_nonpos_int: OBLIGATION
    FORALL (Fnpi, high, low):
      rational_pred(sigma(low, high, Fnpi)) AND
       integer_pred(sigma(low, high, Fnpi)) AND sigma(low, high, Fnpi) <= 0;

  % Subtype TCC generated (at line 312, column 25) for  low + 1
      % expected type  T_low
  sum_it_def_TCC1: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES T_pred(low + 1) OR (EXISTS (j: T): j <= low + 1);

  % Subtype TCC generated (at line 312, column 42) for  low
      % expected type  T
  sum_it_def_TCC2: OBLIGATION
    FORALL (low: T_low, high: T_high): NOT low > high IMPLIES T_pred(low);

  % Termination TCC generated (at line 312, column 14) for
      % sum_it_def(low + 1, high, F, a + F(low))
  sum_it_def_TCC3: OBLIGATION
    FORALL (low: T_low, high: T_high):
      NOT low > high IMPLIES abs(high + 1 - (low + 1)) < abs(high + 1 - low);

  % Subtype TCC generated (at line 320, column 16) for  i + 1
      % expected type  T_low
  sum_it_prop_TCC1: OBLIGATION
    FORALL (high: T_high, i: T, low: T_low):
      i <= high AND low - 1 <= i IMPLIES
       T_pred(i + 1) OR (EXISTS (j: T): j <= i + 1);


