# TheoryBodies

body:
  top: THEORY

  BEGIN

   IMPORTING real_order, 
             system_solvers,
             compute_sturm_tarski,
             sturmtarski, 
             poly_families, 
             tarski_query,
             tarski_query_matrix,
             poly_systems,
  	   strategies,
             examples

  END top


body:
  sturmtarski: THEORY
  BEGIN

  % The proof of the theorem for the tarski query should be easier than
  % for sturm's theorem, because one doesn't have to consider roots at the
  % endpoints. Eventually, the endpoints will be pm infinity. 

  IMPORTING reals@polynomials,reals@more_polynomial_props,reals@sign,
  	  Sturm@polynomial_division,Sturm@number_sign_changes,
            structures@more_list_props,ints@gcd,
    	  structures@sort_array,Sturm@gcd_coeff

    a,r,g : VAR [nat->real]
    p : VAR [nat->[nat->real]]
    n : VAR [nat->nat]
    d,i,j,k : VAR nat
    m: VAR posnat
    %m : VAR posnat
    x,y,c,b : VAR real
    rel: VAR [[real,real]->bool]
    babove,bbelow,bbelow2,babove2: VAR bool

    % k is the degree of g

    constructed_sturm_sequence?(p,n,g,k,m): bool =
      (FORALL (i:below(m)): p(i)(n(i))/=0) AND
      (FORALL (i,j:subrange(1,m-1)): i<j IMPLIES n(i)>n(j)) AND
      n(0)>0 AND
      p(1) = polynomial_prod(g,k,poly_deriv(p(0)),n(0)-1) AND n(1) = k+n(0)-1 AND
      n(m) = 0 AND p(m)(0) = 0 AND
      (FORALL (j:nat): j>1 AND j<=m IMPLIES LET pd = poly_divide(p(j-2),n(j-2))(p(j-1),n(j-1))(0) IN
      	   	    	    	 	   EXISTS (c:posreal): 
      	   	    	    	 	   polynomial(p(j),n(j)) = 
  					   polynomial(-c*pd`rem,pd`rdeg))
      AND m>=2 AND g(k)/=0


    constructed_sturm_seq_repeated_root: LEMMA 
      constructed_sturm_sequence?(p,n,g,k,m) IMPLIES
      FORALL (i:nat): i+1<=m AND
      polynomial(p(i),n(i))(x)=0 AND polynomial(p(i+1),n(i+1))(x)=0
      IMPLIES
      (FORALL (j:upto(m)): polynomial(p(j),n(j))(x) = 0)

    default_root_degree?(p,n,g,k,m,y)(d): bool =
      ((d=0 AND root_degree(p(0),n(0))(y)=0 AND polynomial(p(0),n(0))(y)/=0 AND
             polynomial(g,k)(y)/=0) OR
       (root_degree(p(0),n(0))(y)=d+1 AND root_degree(p(1),n(1))(y)=d AND
             polynomial(g,k)(y)/=0) OR
       (root_degree(p(0),n(0))(y)=d AND root_degree(p(1),n(1))(y)=d AND
        root_degree(g,k)(y)=1 AND polynomial(g,k)(y)=0) OR
       (root_degree(p(0),n(0))(y)=d AND root_degree(p(1),n(1))(y)>d AND
        root_degree(g,k)(y)>0 AND polynomial(g,k)(y)=0)) AND
      (FORALL (i:nat): i<m AND root_degree(p(i),n(i))(y)/=d IMPLIES
        ((i>0 IMPLIES root_degree(p(i-1),n(i-1))(y)=d) AND
         (i<m-1 IMPLIES root_degree(p(i+1),n(i+1))(y)=d))) AND
       root_degree(p(m-1),n(m-1))(y)=d


    constructed_sturm_seq_root_degrees: LEMMA
      constructed_sturm_sequence?(p,n,g,k,m) IMPLIES
      ((polynomial(g,k)(y)=0 AND 
        default_root_degree?(p,n,g,k,m,y)(root_degree(p(0),n(0))(y))) OR
      (polynomial(g,k)(y)/=0 AND
        default_root_degree?(p,n,g,k,m,y)(max(root_degree(p(0),n(0))(y)-1,0))))

    default_root_deg(p,n,g,k,m)(y): nat =
      IF polynomial(g,k)(y)=0 THEN root_degree(p(0),n(0))(y)
      ELSE max(root_degree(p(0),n(0))(y)-1,0) ENDIF

    default_root_deg_def: LEMMA
      constructed_sturm_sequence?(p,n,g,k,m) IMPLIES
      default_root_degree?(p,n,g,k,m,y)(default_root_deg(p,n,g,k,m)(y))

    constructed_sturm_seq_root_degree_lower_bound: LEMMA
      constructed_sturm_sequence?(p,n,g,k,m) IMPLIES
      FORALL (i): i<m IMPLIES root_degree(p(i),n(i))(y)>=default_root_deg(p,n,g,k,m)(y)

    sturm_sig(p,n,m)(x): nat = number_sign_changes(LAMBDA (i): polynomial(p(i),n(i))(x),m)`num

    sturm_tarski_basic_1: LEMMA FORALL (z:real):
      constructed_sturm_sequence?(p,n,g,k,m) AND
      (FORALL (j:below(m)): only_root_between?(p(j),n(j),x,y)(z)) AND
      polynomial(p(0),n(0))(z)=0 AND polynomial(g,k)(z)/=0 IMPLIES
      number_sign_changes(LAMBDA (i): polynomial(p(i),n(i))(x),1)`num -
      number_sign_changes(LAMBDA (i): polynomial(p(i),n(i))(y),1)`num =
      sign_ext(polynomial(g,k)(z))

    sturm_tarski_basic_2: LEMMA FORALL (z:real):
      LET nsc = (LAMBDA (xyz:real,k:nat):
        	       	   number_sign_changes(LAMBDA (i): 
        	       	   polynomial(p(i),n(i))(xyz),k)`num)
        IN root_degree(p(1),n(1))(z) = root_degree(p(0),n(0))(z) AND constructed_sturm_sequence?(p,n,g,k,m) AND
      (FORALL (j:below(m)): only_root_between?(p(j),n(j),x,y)(z))
           IMPLIES nsc(x,1)=nsc(y,1)

    sturm_tarski_basic_3: LEMMA FORALL (z:real):
      m>2 AND
      constructed_sturm_sequence?(p,n,g,k,m) AND
      (FORALL (j:below(m)): only_root_between?(p(j),n(j),x,y)(z)) AND
      (polynomial(g,k)(z)=0 OR polynomial(p(0),n(0))(z)/=0) IMPLIES
        LET nsc = (LAMBDA (xyz:real,k:nat):
        	       	   number_sign_changes(LAMBDA (i): 
        	       	   polynomial(p(i),n(i))(xyz),k)`num)
        IN (root_degree(p(2),n(2))(z) = root_degree(p(0),n(0))(z)
  	 			           IMPLIES nsc(x,2)=nsc(y,2))

    sturm_tarski_basic: LEMMA FORALL (z:real):
      constructed_sturm_sequence?(p,n,g,k,m) AND
      (FORALL (j:below(m)): only_root_between?(p(j),n(j),x,y)(z))
      IMPLIES
      number_sign_changes(LAMBDA (i): polynomial(p(i),n(i))(x),m-1)`num -
      number_sign_changes(LAMBDA (i): polynomial(p(i),n(i))(y),m-1)`num =
      (IF polynomial(p(0),n(0))(z)/=0 OR polynomial(g,k)(z)=0 THEN 0
      ELSIF polynomial(g,k)(z)>0 THEN 1 ELSE -1 ENDIF)

    constructed_sturm_roots_between_enum: LEMMA % THIS NEEDS TO BE FOR ALL P(i) NOT JUST P(0)
      x<y AND constructed_sturm_sequence?(p,n,g,k,m) IMPLIES
        EXISTS ((K:nat|K>=2),enum:[below(K)->real]):
          (FORALL (i,j:below(K)): i<j IMPLIES enum(i)<enum(j)) AND
    	enum(0)=x AND enum(K-1)=y AND
    	(FORALL (b:real,j:nat): j<=m-1 AND x<b AND b<=y AND polynomial(p(j),n(j))(b)=0 IMPLIES
    	  EXISTS (i:below(K)): b = enum(i))

    Sol(a:[nat->real],(m:nat|a(m)/=0),g:[nat->real],k:nat,
        rel:[[real,real]->bool],x,y:real,bbelow,babove:bool):
      finite_set[real] = {r:real | polynomial(a,m)(r)=0 AND rel(polynomial(g,k)(r),0) AND
      		       	       	 (bbelow IMPLIES x<=r) AND (babove IMPLIES r<=y)}

    Sol_union_top: LEMMA FORALL (z:real): x<=y AND y<=z AND a(m)/=0 IMPLIES
      union(Sol(a,m,g,k,rel,x,y,bbelow,babove),Sol(a,m,g,k,rel,y,z,bbelow2,babove2)) =
      Sol(a,m,g,k,rel,x,z,bbelow AND bbelow2,babove AND babove2)

    NSol(a:[nat->real],(m:nat|a(m)/=0),g:[nat->real],k:nat,
        rel:[[real,real]->bool],x,y:real,bbelow,babove:bool): {d:nat |
          EXISTS (enumsol:[below(d)->(Sol(a,m,g,k,rel,x,y,bbelow,babove))]):
  	  bijective?(enumsol)} = card(Sol(a,m,g,k,rel,x,y,bbelow,babove))

    NSol_union_top: LEMMA FORALL (z:real): x<=y AND y<=z AND a(m)/=0 AND
      polynomial(a,m)(y)/=0 IMPLIES
      NSol(a,m,g,k,rel,x,y,bbelow,True)+NSol(a,m,g,k,rel,y,z,True,babove) =
      NSol(a,m,g,k,rel,x,z,bbelow,babove)

    sturm_tarski: LEMMA
      x<y AND
      constructed_sturm_sequence?(p,n,g,k,m) AND
      (FORALL (j:nat): j<m IMPLIES (polynomial(p(j),n(j))(x)/=0 AND polynomial(p(j),n(j))(y)/=0))
      IMPLIES
        LET nsc = LAMBDA (xyz:real): number_sign_changes(LAMBDA (i): polynomial(p(i),n(i))(xyz),m-1),
        	  Nroots = nsc(x)`num-nsc(y)`num
        IN Nroots = NSol(p(0),n(0),g,k,>,x,y,true,true)-NSol(p(0),n(0),g,k,<,x,y,true,true)

    % Unbounded sets

    Sol(a:[nat->real],(m:nat|a(m)/=0),g:[nat->real],k:nat,
        rel:[[real,real]->bool]):
      finite_set[real] = {r:real | polynomial(a,m)(r)=0 AND rel(polynomial(g,k)(r),0)}

    NSol(a:[nat->real],(m:nat|a(m)/=0),g:[nat->real],k:nat,
        rel:[[real,real]->bool]): {d:nat |
          EXISTS (enumsol:[below(d)->(Sol(a,m,g,k,rel))]):
  	  bijective?(enumsol)} = card(Sol(a,m,g,k,rel))

    sturm_tarski_unbounded: LEMMA
      constructed_sturm_sequence?(p,n,g,k,m) IMPLIES
        LET nschigh = number_sign_changes(LAMBDA (i): p(i)(n(i)),m-1),
        	  nsclow  = number_sign_changes(LAMBDA (i): (IF even?(n(i)) THEN 1 ELSE -1 ENDIF)*p(i)(n(i)),m-1),
        	  Nroots  = nsclow`num-nschigh`num
        IN Nroots = NSol(p(0),n(0),g,k,>)-NSol(p(0),n(0),g,k,<)

    NSol_sq_gt: LEMMA a(m)/=0 IMPLIES
      NSol(a,m,polynomial_prod(g,k,g,k),2*k,>) =
      NSol(a,m,g,k,>) + NSol(a,m,g,k,<)

    NSol_sq_lt: LEMMA a(m)/=0 IMPLIES
      NSol(a,m,polynomial_prod(g,k,g,k),2*k,<) = 0

    % constructed_sturm_sequence_p2: LEMMA
    %   constructed_sturm_sequence?(p,n,g,k,m) AND
    %   k>0 AND (m>2 OR k/=1 OR 
    %     (NOT (k=1 AND EXISTS (r:real): root_degree(p(0),n(0))(r) = n(0) AND
    %     	          polynomial(g,1)(r)=0)))
    %   IMPLIES
    %   EXISTS (c:posreal):
    %   polynomial(p(2),n(2)) = polynomial(-c*p(0),n(0))

  END sturmtarski

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

  % Subtype TCC generated (at line 27, column 49) for  i
      % expected type  nat
  constructed_sturm_sequence?_TCC1: OBLIGATION
    FORALL (p: [nat -> [nat -> real]], n: [nat -> nat], m: posnat):
      (FORALL (i: below(m)): p(i)(n(i)) /= 0) IMPLIES
       (FORALL (i1, j: subrange(1, m - 1)): i1 < j IMPLIES i1 >= 0);

  % Subtype TCC generated (at line 27, column 54) for  j
      % expected type  nat
  constructed_sturm_sequence?_TCC2: OBLIGATION
    FORALL (p: [nat -> [nat -> real]], n: [nat -> nat], m: posnat):
      (FORALL (i: below(m)): p(i)(n(i)) /= 0) IMPLIES
       (FORALL (i1, j: subrange(1, m - 1)): i1 < j IMPLIES j >= 0);

  % Subtype TCC generated (at line 29, column 48) for  n(0) - 1
      % expected type  nat
  constructed_sturm_sequence?_TCC3: OBLIGATION
    FORALL (p: [nat -> [nat -> real]], n: [nat -> nat], m: posnat):
      (n(0) > 0 AND
        (FORALL (i, j: subrange(1, m - 1)): i < j IMPLIES n(i) > n(j)) AND
         (FORALL (i: below(m)): p(i)(n(i)) /= 0))
       IMPLIES n(0) - 1 >= 0;

  % Subtype TCC generated (at line 31, column 80) for  j - 1
      % expected type  nat
  constructed_sturm_sequence?_TCC4: OBLIGATION
    FORALL (p: [nat -> [nat -> real]], n: [nat -> nat], g: [nat -> real],
            k: nat, m: posnat):
      (     p(m)(0) = 0 AND n(m) = 0 AND n(1) = k + n(0) - 1
        AND p(1) = polynomial_prod(g, k, poly_deriv(p(0)), n(0) - 1)
        AND n(0) > 0
        AND FORALL (i, j: subrange(1, m - 1)): i < j IMPLIES n(i) > n(j)
        AND FORALL (i: below(m)): p(i)(n(i)) /= 0)
       IMPLIES (FORALL (j1: nat): j1 > 1 AND j1 <= m IMPLIES j1 - 1 >= 0);

  % Subtype TCC generated (at line 31, column 85) for  n(j - 1)
      % expected type  {m | p(j - 1)(m) /= 0}
  constructed_sturm_sequence?_TCC5: OBLIGATION
    FORALL (p: [nat -> [nat -> real]], n: [nat -> nat], g: [nat -> real],
            k: nat, m: posnat):
      (     p(m)(0) = 0 AND n(m) = 0 AND n(1) = k + n(0) - 1
        AND p(1) = polynomial_prod(g, k, poly_deriv(p(0)), n(0) - 1)
        AND n(0) > 0
        AND FORALL (i, j: subrange(1, m - 1)): i < j IMPLIES n(i) > n(j)
        AND FORALL (i: below(m)): p(i)(n(i)) /= 0)
       IMPLIES
       (FORALL (j1: nat):
          j1 > 1 AND j1 <= m IMPLIES p(j1 - 1)(n(j1 - 1)) /= 0);

  % Subtype TCC generated (at line 31, column 65) for  j - 2
      % expected type  nat
  constructed_sturm_sequence?_TCC6: OBLIGATION
    FORALL (p: [nat -> [nat -> real]], n: [nat -> nat], g: [nat -> real],
            k: nat, m: posnat):
      (     p(m)(0) = 0 AND n(m) = 0 AND n(1) = k + n(0) - 1
        AND p(1) = polynomial_prod(g, k, poly_deriv(p(0)), n(0) - 1)
        AND n(0) > 0
        AND FORALL (i, j: subrange(1, m - 1)): i < j IMPLIES n(i) > n(j)
        AND FORALL (i: below(m)): p(i)(n(i)) /= 0)
       IMPLIES (FORALL (j1: nat): j1 > 1 AND j1 <= m IMPLIES j1 - 2 >= 0);

  % Subtype TCC generated (at line 55, column 34) for  i - 1
      % expected type  nat
  default_root_degree?_TCC1: OBLIGATION
    FORALL (p: [nat -> [nat -> real]], n: [nat -> nat], g: [nat -> real],
            k: nat, m: posnat, y: real, d: nat):
      ((d = 0 AND
         root_degree(p(0), n(0))(y) = 0 AND
          polynomial(p(0), n(0))(y) /= 0 AND polynomial(g, k)(y) /= 0)
        OR
        (root_degree(p(0), n(0))(y) = d + 1 AND
          root_degree(p(1), n(1))(y) = d AND polynomial(g, k)(y) /= 0)
         OR
         (root_degree(p(0), n(0))(y) = d AND
           root_degree(p(1), n(1))(y) = d AND
            root_degree(g, k)(y) = 1 AND polynomial(g, k)(y) = 0)
          OR
          (root_degree(p(0), n(0))(y) = d AND
            root_degree(p(1), n(1))(y) > d AND
             root_degree(g, k)(y) > 0 AND polynomial(g, k)(y) = 0))
       IMPLIES
       (FORALL (i: nat):
          i > 0 AND i < m AND root_degree(p(i), n(i))(y) /= d IMPLIES
           i - 1 >= 0);

  % Subtype TCC generated (at line 57, column 19) for  m - 1
      % expected type  nat
  default_root_degree?_TCC2: OBLIGATION
    FORALL (p: [nat -> [nat -> real]], n: [nat -> nat], g: [nat -> real],
            k: nat, m: posnat, y: real, d: nat):
      (FORALL (i: nat):
         i < m AND root_degree(p(i), n(i))(y) /= d IMPLIES
          ((i > 0 IMPLIES root_degree(p(i - 1), n(i - 1))(y) = d) AND
            (i < m - 1 IMPLIES root_degree(p(i + 1), n(i + 1))(y) = d)))
       AND
       ((d = 0 AND
          root_degree(p(0), n(0))(y) = 0 AND
           polynomial(p(0), n(0))(y) /= 0 AND polynomial(g, k)(y) /= 0)
         OR
         (root_degree(p(0), n(0))(y) = d + 1 AND
           root_degree(p(1), n(1))(y) = d AND polynomial(g, k)(y) /= 0)
          OR
          (root_degree(p(0), n(0))(y) = d AND
            root_degree(p(1), n(1))(y) = d AND
             root_degree(g, k)(y) = 1 AND polynomial(g, k)(y) = 0)
           OR
           (root_degree(p(0), n(0))(y) = d AND
             root_degree(p(1), n(1))(y) > d AND
              root_degree(g, k)(y) > 0 AND polynomial(g, k)(y) = 0))
       IMPLIES m - 1 >= 0;

  % Subtype TCC generated (at line 65, column 40) for
      % max(root_degree(p(0), n(0))(y) - 1, 0)
      % expected type  nat
  constructed_sturm_seq_root_degrees_TCC1: OBLIGATION
    FORALL (g: [nat -> real], k: nat, m: posnat, n: [nat -> nat],
            p: [nat -> [nat -> real]], y: real):
      constructed_sturm_sequence?(p, n, g, k, m) AND
       NOT (polynomial(g, k)(y) = 0 AND
             default_root_degree?(p, n, g, k, m, y)
                                 (root_degree(p(0), n(0))(y)))
        AND polynomial(g, k)(y) /= 0
       IMPLIES max(root_degree(p(0), n(0))(y) - 1, 0) >= 0;

  % Subtype TCC generated (at line 69, column 9) for
      % max(root_degree(p(0), n(0))(y) - 1, 0)
      % expected type  nat
  default_root_deg_TCC1: OBLIGATION
    FORALL (p: [nat -> [nat -> real]], n: [nat -> nat], g: [nat -> real],
            k: nat, y: real):
      NOT polynomial(g, k)(y) = 0 IMPLIES
       max(root_degree(p(0), n(0))(y) - 1, 0) >= 0;

  % Subtype TCC generated (at line 112, column 61) for  m - 1
      % expected type  nat
  sturm_tarski_basic_TCC1: OBLIGATION
    FORALL (g: [nat -> real], k: nat, m: posnat, n: [nat -> nat],
            p: [nat -> [nat -> real]], x, y, z: real):
      (constructed_sturm_sequence?(p, n, g, k, m) AND
        (FORALL (j: below(m)): only_root_between?(p(j), n(j), x, y)(z)))
       IMPLIES m - 1 >= 0;

  % Subtype TCC generated (at line 121, column 8) for  0
      % expected type  below(K)
  constructed_sturm_roots_between_enum_TCC1: OBLIGATION
    FORALL (g: [nat -> real], k: nat, m: posnat, n: [nat -> nat],
            p: [nat -> [nat -> real]], x, y: real):
      constructed_sturm_sequence?(p, n, g, k, m) AND x < y IMPLIES
       (FORALL ((K: nat | K >= 2), enum: [below(K) -> real]):
          (FORALL (i, j: below(K)): i < j IMPLIES enum(i) < enum(j)) IMPLIES
           0 < K);

  % Subtype TCC generated (at line 121, column 22) for  K - 1
      % expected type  below(K)
  constructed_sturm_roots_between_enum_TCC2: OBLIGATION
    FORALL (g: [nat -> real], k: nat, m: posnat, n: [nat -> nat],
            p: [nat -> [nat -> real]], x, y: real):
      constructed_sturm_sequence?(p, n, g, k, m) AND x < y IMPLIES
       (FORALL ((K: nat | K >= 2), enum: [below(K) -> real]):
          enum(0) = x AND
           (FORALL (i, j: below(K)): i < j IMPLIES enum(i) < enum(j))
           IMPLIES K - 1 >= 0 AND K - 1 < K);

  % Subtype TCC generated (at line 127, column 23) for
      % {r: real |
      %    polynomial(a, m)(r) = 0 AND
      %     rel(polynomial(g, k)(r), 0) AND
      %      (bbelow IMPLIES x <= r) AND (babove IMPLIES r <= y)}
      % expected type  finite_set[real]
  Sol_TCC1: OBLIGATION
    FORALL (a: [nat -> real], (m: nat | a(m) /= 0), g: [nat -> real], k: nat,
            rel: [[real, real] -> bool], x, y: real, bbelow, babove: bool):
      is_finite[real]
          ({r: real |
              polynomial(a, m)(r) = 0 AND
               rel(polynomial(g, k)(r), 0) AND
                (bbelow IMPLIES x <= r) AND (babove IMPLIES r <= y)});

  % Subtype TCC generated (at line 137, column 26) for
      % card(Sol(a, m, g, k, rel, x, y, bbelow, babove))
      % expected type  {d: nat |
                     %          EXISTS (enumsol:
                     %                  [below(d) ->
                     %                   (Sol
                     %                    (a,
                     %                     m,
                     %                     g,
                     %                     k,
                     %                     rel,
                     %                     x,
                     %                     y,
                     %                     bbelow,
                     %                     babove))]):
                     %            bijective?(enumsol)}
  NSol_TCC1: OBLIGATION
    FORALL (a: [nat -> real], (m: nat | a(m) /= 0), g: [nat -> real], k: nat,
            rel: [[real, real] -> bool], x, y: real, bbelow, babove: bool):
      EXISTS (enumsol:
                [below(card[real]
                           (Sol(a, m, g, k, rel, x, y, bbelow, babove))) ->
                   (Sol(a, m, g, k, rel, x, y, bbelow, babove))]):
        bijective?
            [below(card(Sol(a, m, g, k, rel, x, y, bbelow, babove))),
             (Sol(a, m, g, k, rel, x, y, bbelow, babove))]
            (enumsol);

  % Subtype TCC generated (at line 149, column 94) for  m - 1
      % expected type  nat
  sturm_tarski_TCC1: OBLIGATION
    FORALL (g: [nat -> real], k: nat, m: posnat, n: [nat -> nat],
            p: [nat -> [nat -> real]], x, y: real):
      (FORALL (j: nat):
         j < m IMPLIES
          (polynomial(p(j), n(j))(x) /= 0 AND
            polynomial(p(j), n(j))(y) /= 0))
       AND constructed_sturm_sequence?(p, n, g, k, m) AND x < y
       IMPLIES m - 1 >= 0;

  % Subtype TCC generated (at line 151, column 28) for  n(0)
      % expected type  {m: nat | p(0)(m) /= 0}
  sturm_tarski_TCC2: OBLIGATION
    FORALL (g: [nat -> real], k: nat, m: posnat, n: [nat -> nat],
            p: [nat -> [nat -> real]], x, y: real):
      (FORALL (j: nat):
         j < m IMPLIES
          (polynomial(p(j), n(j))(x) /= 0 AND
            polynomial(p(j), n(j))(y) /= 0))
       AND constructed_sturm_sequence?(p, n, g, k, m) AND x < y
       IMPLIES
       (FORALL (nsc: [real -> NSC]):
          (nsc =
            (LAMBDA (xyz: real):
               number_sign_changes(LAMBDA (i): polynomial(p(i), n(i))(xyz),
                                   m - 1)))
           IMPLIES
           (FORALL (Nroots: int):
              Nroots = nsc(x)`num - nsc(y)`num IMPLIES p(0)(n(0)) /= 0));

  % Subtype TCC generated (at line 157, column 23) for
      % {r: real | polynomial(a, m)(r) = 0 AND rel(polynomial(g, k)(r), 0)}
      % expected type  finite_set[real]
  Sol_TCC2: OBLIGATION
    FORALL (a: [nat -> real], (m: nat | a(m) /= 0), g: [nat -> real], k: nat,
            rel: [[real, real] -> bool]):
      is_finite[real]
          ({r: real |
              polynomial(a, m)(r) = 0 AND rel(polynomial(g, k)(r), 0)});

  % Subtype TCC generated (at line 162, column 26) for
      % card(Sol(a, m, g, k, rel))
      % expected type  {d: nat |
                     %          EXISTS (enumsol:
                     %                  [below(d) ->
                     %                   (Sol(a, m, g, k, rel))]):
                     %            bijective?(enumsol)}
  NSol_TCC2: OBLIGATION
    FORALL (a: [nat -> real], (m: nat | a(m) /= 0), g: [nat -> real], k: nat,
            rel: [[real, real] -> bool]):
      EXISTS (enumsol:
                [below(card[real](Sol(a, m, g, k, rel))) ->
                   (Sol(a, m, g, k, rel))]):
        bijective?[below(card(Sol(a, m, g, k, rel))), (Sol(a, m, g, k, rel))]
            (enumsol);

  % Subtype TCC generated (at line 166, column 63) for  m - 1
      % expected type  nat
  sturm_tarski_unbounded_TCC1: OBLIGATION
    FORALL (g: [nat -> real], k: nat, m: posnat, n: [nat -> nat],
            p: [nat -> [nat -> real]]):
      constructed_sturm_sequence?(p, n, g, k, m) IMPLIES m - 1 >= 0;

  % Subtype TCC generated (at line 169, column 28) for  n(0)
      % expected type  {m: nat | p(0)(m) /= 0}
  sturm_tarski_unbounded_TCC2: OBLIGATION
    FORALL (g: [nat -> real], k: nat, m: posnat, n: [nat -> nat],
            p: [nat -> [nat -> real]]):
      constructed_sturm_sequence?(p, n, g, k, m) IMPLIES
       (FORALL (nschigh: NSC):
          nschigh = number_sign_changes(LAMBDA (i): p(i)(n(i)), m - 1)
           IMPLIES
           (FORALL (nsclow: NSC):
              nsclow =
               number_sign_changes(LAMBDA (i):
                                     (IF even?(n(i)) THEN 1 ELSE -1 ENDIF) *
                                      p(i)(n(i)),
                                   m - 1)
               IMPLIES
               (FORALL (Nroots: int):
                  Nroots = nsclow`num - nschigh`num IMPLIES
                   p(0)(n(0)) /= 0)));


body:
  compute_sturm_tarski: THEORY
  BEGIN

    IMPORTING sturmtarski,
  	    Sturm@remainder_sequence,
  	    Sturm@clear_denominators,
  	    reals@more_polynomial_props

    a,g,g1,g2 : VAR [nat->int]
    n : VAR posnat
    k,k1,k2 : VAR nat
    x,y,z: VAR real
    aq: VAR [nat->rat]
    gq: VAR [nat->rat]

    %%% Support Lemmas %%%

    der_prod(a,n,g,k)(i:nat): int =
      polynomial_prod(g,k,poly_deriv(a),n-1)(i)

    finite_bij_real_remove_one: LEMMA
      FORALL (m:nat,A:set[real],bij:[below(m)->(A)]):
        bijective?(bij) AND A(x) IMPLIES
         m-1>=0 AND EXISTS (bijec:[below(m-1)->{r:(A)|r/=x}]):
           bijective?(bijec)

    finite_bij_real_remove_two: LEMMA
      FORALL (m:nat,A:set[real],bij:[below(m)->(A)]):
        bijective?(bij) AND A(x) AND A(y) AND x/=y IMPLIES
         m-2>=0 AND EXISTS (bijec:[below(m-2)->{r:(A)|r/=x AND r/=y}]):
           bijective?(bijec)

    computed_sturm_spec: LEMMA a(n)/=0 AND g(k)/=0 AND
      (FORALL (i:nat): i>n IMPLIES a(i)=0) IMPLIES
      LET sl = remainder_seq(a,n,der_prod(a,n,g,k),n-1+k),
      	P: [nat->[nat->int]] = (LAMBDA (j:nat): IF j<length(sl) 
  	   		          THEN list2array[int](0)(nth(sl,length(sl)-1-j))
  	   		         ELSE (LAMBDA (i:nat): 0) ENDIF),
          N: [nat->nat] = (LAMBDA (j:nat): IF j<length(sl) 
  	                   THEN max(length(nth(sl,length(sl)-1-j))-1,0) ELSE 0 ENDIF),
  	M: nat = length(sl)-1
      IN  constructed_sturm_sequence?(P,N,g,k,M) AND P(0)=a AND N(0)=n

    Eq_computed_remainder?(a,(n|a(n)/=0),g,(k|g(k)/=0))(sl:list[list[int]]): bool =
      sl = remainder_seq((LAMBDA (i:nat): IF i<=n THEN a(i) ELSE 0 ENDIF),
             n,der_prod((LAMBDA (i:nat): IF i<=n THEN a(i) ELSE 0 ENDIF),n,g,k),n-1+k)

    % Standard but possibly unbounded interval %

    lower_bound,upper_bound: VAR bool

    % Formalizatin brings in complications with evaluating at infinity

    compute_TQ_param(a,(n|a(n)/=0),g,(k|g(k)/=0),
  		   sl:(Eq_computed_remainder?(a,n,g,k))): 
      int =
      LET P: [nat->[nat->int]] = (LAMBDA (j:nat): IF j<length(sl) 
  	                          THEN list2array[int](0)(nth(sl,length(sl)-1-j))
  	   		         ELSE (LAMBDA (i:nat): 0) ENDIF),
          N: [nat->nat] = (LAMBDA (j:nat): IF j<length(sl) 
  	                   THEN max(length(nth(sl,length(sl)-1-j))-1,0) ELSE 0 ENDIF),
  	M: nat     = length(sl)-1,
          nschighlow = LAMBDA (b:bool): IF b THEN 
  	  number_sign_changes(LAMBDA (i:nat): P(i)(N(i)),M-1)
  	  ELSE number_sign_changes(LAMBDA (i:nat): 
  	    (IF even?(N(i)) THEN 1 ELSE -1 ENDIF)*P(i)(N(i)),M-1) ENDIF,
        	Nroots     = nschighlow(FALSE)`num-nschighlow(TRUE)`num
      IN Nroots

    TQ(a,(n|a(n)/=0),g,(k|g(k)/=0)): int =
      LET newa = (LAMBDA (i:nat): IF i<=n THEN a(i) ELSE 0 ENDIF),
      	sl = remainder_seq(newa,n,
  	  der_prod(newa,n,g,k),n-1+k)
      IN compute_TQ_param(newa,n,g,k,sl)

    TQ_def: LEMMA
      a(n)/=0 AND g(k)/=0 IMPLIES
      TQ(a,n,g,k) = NSol(a,n,g,k,>)-NSol(a,n,g,k,<)

    TQ_eq_g: LEMMA a(n)/=0 AND g1(k)/=0 AND g2(k)/=0 AND
      (FORALL (i:upto(k)): g1(i)=g2(i))
      IMPLIES
      TQ(a,n,g1,k)=TQ(a,n,g2,k)

  END compute_sturm_tarski

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

  % Subtype TCC generated (at line 19, column 38) for  n - 1
      % expected type  nat
  der_prod_TCC1: OBLIGATION FORALL (n: posnat): n - 1 >= 0;

  % Subtype TCC generated (at line 19, column 4) for
      % polynomial_prod(g, k, poly_deriv(a), n - 1)(i)
      % expected type  int
  der_prod_TCC2: OBLIGATION
    FORALL (a: [nat -> int], n: posnat, g: [nat -> int], k: nat, i: nat):
      rational_pred(polynomial_prod(g, k, poly_deriv(a), n - 1)(i)) AND
       integer_pred(polynomial_prod(g, k, poly_deriv(a), n - 1)(i));

  % Subtype TCC generated (at line 35, column 49) for  n - 1 + k
      % expected type  {m | der_prod(a, n, g, k)(m) /= 0}
  computed_sturm_spec_TCC1: OBLIGATION
    FORALL (a, g: [nat -> int], k: nat, n: posnat):
      (FORALL (i: nat): i > n IMPLIES a(i) = 0) AND g(k) /= 0 AND a(n) /= 0
       IMPLIES n - 1 + k >= 0 AND der_prod(a, n, g, k)(n - 1 + k) /= 0;

  % Subtype TCC generated (at line 37, column 47) for  length(sl) - 1 - j
      % expected type  below[length[list[int]](sl)]
  computed_sturm_spec_TCC2: OBLIGATION
    FORALL (a, g: [nat -> int], k: nat, n: posnat):
      (FORALL (i: nat): i > n IMPLIES a(i) = 0) AND g(k) /= 0 AND a(n) /= 0
       IMPLIES
       (FORALL (sl:
                  {crem:
                     (is_neg_remainder_list?(a,
                                             n,
                                             der_prod(a, n, g, k),
                                             n - 1 + k)) |
                           length[list[int]](crem) > 1 AND
                            length[int](nth[list[int]](crem, 0)) = 0}):
          sl = remainder_seq(a, n, der_prod(a, n, g, k), n - 1 + k) IMPLIES
           (FORALL (j: nat):
              j < length(sl) IMPLIES
               length[list[int]](sl) - 1 - j >= 0 AND
                length[list[int]](sl) - 1 - j < length[list[int]](sl)));

  % Subtype TCC generated (at line 40, column 25) for
      % max(length(nth(sl, length(sl) - 1 - j)) - 1, 0)
      % expected type  nat
  computed_sturm_spec_TCC3: OBLIGATION
    FORALL (a, g: [nat -> int], k: nat, n: posnat):
      (FORALL (i: nat): i > n IMPLIES a(i) = 0) AND g(k) /= 0 AND a(n) /= 0
       IMPLIES
       (FORALL (sl:
                  {crem:
                     (is_neg_remainder_list?(a,
                                             n,
                                             der_prod(a, n, g, k),
                                             n - 1 + k)) |
                           length[list[int]](crem) > 1 AND
                            length[int](nth[list[int]](crem, 0)) = 0}):
          sl = remainder_seq(a, n, der_prod(a, n, g, k), n - 1 + k) IMPLIES
           (FORALL (P: [nat -> [nat -> int]]):
              (P =
                (LAMBDA (j: nat):
                   IF j < length(sl)
                     THEN list2array[int](0)(nth(sl, length(sl) - 1 - j))
                   ELSE (LAMBDA (i: nat): 0)
                   ENDIF))
               IMPLIES
               (FORALL (j1: nat):
                  j1 < length(sl) IMPLIES
                   max(length[int]
                           (nth[list[int]]
                                (sl, length[list[int]](sl) - 1 - j1))
                        - 1,
                       0)
                    >= 0)));

  % Subtype TCC generated (at line 41, column 10) for  length(sl) - 1
      % expected type  nat
  computed_sturm_spec_TCC4: OBLIGATION
    FORALL (a, g: [nat -> int], k: nat, n: posnat):
      (FORALL (i: nat): i > n IMPLIES a(i) = 0) AND g(k) /= 0 AND a(n) /= 0
       IMPLIES
       (FORALL (sl:
                  {crem:
                     (is_neg_remainder_list?(a,
                                             n,
                                             der_prod(a, n, g, k),
                                             n - 1 + k)) |
                           length[list[int]](crem) > 1 AND
                            length[int](nth[list[int]](crem, 0)) = 0}):
          sl = remainder_seq(a, n, der_prod(a, n, g, k), n - 1 + k) IMPLIES
           (FORALL (P: [nat -> [nat -> int]]):
              (P =
                (LAMBDA (j: nat):
                   IF j < length(sl)
                     THEN list2array[int](0)(nth(sl, length(sl) - 1 - j))
                   ELSE (LAMBDA (i: nat): 0)
                   ENDIF))
               IMPLIES
               (FORALL (N: [nat -> nat]):
                  (N =
                    (LAMBDA (j: nat):
                       IF j < length(sl)
                         THEN max(length(nth(sl, length(sl) - 1 - j)) - 1, 0)
                       ELSE 0
                       ENDIF))
                   IMPLIES length[list[int]](sl) - 1 >= 0)));

  % Subtype TCC generated (at line 42, column 44) for  M
      % expected type  posnat
  computed_sturm_spec_TCC5: OBLIGATION
    FORALL (a, g: [nat -> int], k: nat, n: posnat):
      (FORALL (i: nat): i > n IMPLIES a(i) = 0) AND g(k) /= 0 AND a(n) /= 0
       IMPLIES
       (FORALL (sl:
                  {crem:
                     (is_neg_remainder_list?(a,
                                             n,
                                             der_prod(a, n, g, k),
                                             n - 1 + k)) |
                           length[list[int]](crem) > 1 AND
                            length[int](nth[list[int]](crem, 0)) = 0}):
          sl = remainder_seq(a, n, der_prod(a, n, g, k), n - 1 + k) IMPLIES
           (FORALL (P: [nat -> [nat -> int]]):
              (P =
                (LAMBDA (j: nat):
                   IF j < length(sl)
                     THEN list2array[int](0)(nth(sl, length(sl) - 1 - j))
                   ELSE (LAMBDA (i: nat): 0)
                   ENDIF))
               IMPLIES
               (FORALL (N: [nat -> nat]):
                  (N =
                    (LAMBDA (j: nat):
                       IF j < length(sl)
                         THEN max(length(nth(sl, length(sl) - 1 - j)) - 1, 0)
                       ELSE 0
                       ENDIF))
                   IMPLIES
                   (FORALL (M: nat): M = length(sl) - 1 IMPLIES M > 0))));

  % Subtype TCC generated (at line 46, column 11) for  n
      % expected type  {n_1 | IF n_1 <= n THEN a(n_1) ELSE 0 ENDIF /= 0}
  Eq_computed_remainder?_TCC1: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0)):
      IF n <= n THEN a(n) ELSE 0 ENDIF /= 0;

  % Subtype TCC generated (at line 46, column 78) for  n - 1 + k
      % expected type  {m |
                     %          der_prod((LAMBDA
                     %                    (i: nat):
                     %                    IF i <= n THEN a(i) ELSE 0 ENDIF),
                     %                   n,
                     %                   g,
                     %                   k)
                     %                  (m)
                     %           /= 0}
  Eq_computed_remainder?_TCC2: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0)):
      n - 1 + k >= 0 AND
       der_prod(LAMBDA (i: nat): IF i <= n THEN a(i) ELSE 0 ENDIF, n, g, k)
               (n - 1 + k)
        /= 0;

  % Subtype TCC generated (at line 58, column 58) for  length(sl) - 1 - j
      % expected type  below[length[list[int]](sl)]
  compute_TQ_param_TCC1: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0), sl: (Eq_computed_remainder?(a, n, g, k)),
            j: nat):
      j < length(sl) IMPLIES
       length[list[int]](sl) - 1 - j >= 0 AND
        length[list[int]](sl) - 1 - j < length[list[int]](sl);

  % Subtype TCC generated (at line 61, column 25) for
      % max(length(nth(sl, length(sl) - 1 - j)) - 1, 0)
      % expected type  nat
  compute_TQ_param_TCC2: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0), sl: (Eq_computed_remainder?(a, n, g, k)),
            P: [nat -> [nat -> int]]):
      (P =
        (LAMBDA (j: nat):
           IF j < length(sl)
             THEN list2array[int](0)(nth(sl, length(sl) - 1 - j))
           ELSE (LAMBDA (i: nat): 0)
           ENDIF))
       IMPLIES
       (FORALL (j1: nat):
          j1 < length(sl) IMPLIES
           max(length[int]
                   (nth[list[int]](sl, length[list[int]](sl) - 1 - j1))
                - 1,
               0)
            >= 0);

  % Subtype TCC generated (at line 62, column 14) for  length(sl) - 1
      % expected type  nat
  compute_TQ_param_TCC3: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0), sl: (Eq_computed_remainder?(a, n, g, k)),
            P: [nat -> [nat -> int]]):
      (P =
        (LAMBDA (j: nat):
           IF j < length(sl)
             THEN list2array[int](0)(nth(sl, length(sl) - 1 - j))
           ELSE (LAMBDA (i: nat): 0)
           ENDIF))
       IMPLIES
       (FORALL (N: [nat -> nat]):
          (N =
            (LAMBDA (j: nat):
               IF j < length(sl)
                 THEN max(length(nth(sl, length(sl) - 1 - j)) - 1, 0)
               ELSE 0
               ENDIF))
           IMPLIES length[list[int]](sl) - 1 >= 0);

  % Subtype TCC generated (at line 64, column 50) for  M - 1
      % expected type  nat
  compute_TQ_param_TCC4: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0), sl: (Eq_computed_remainder?(a, n, g, k)),
            P: [nat -> [nat -> int]]):
      (P =
        (LAMBDA (j: nat):
           IF j < length(sl)
             THEN list2array[int](0)(nth(sl, length(sl) - 1 - j))
           ELSE (LAMBDA (i: nat): 0)
           ENDIF))
       IMPLIES
       (FORALL (N: [nat -> nat]):
          (N =
            (LAMBDA (j: nat):
               IF j < length(sl)
                 THEN max(length(nth(sl, length(sl) - 1 - j)) - 1, 0)
               ELSE 0
               ENDIF))
           IMPLIES
           (FORALL (M: nat):
              M = length(sl) - 1 IMPLIES
               (FORALL (b: bool): b IMPLIES M - 1 >= 0)));

  % Subtype TCC generated (at line 66, column 54) for  M - 1
      % expected type  nat
  compute_TQ_param_TCC5: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0), sl: (Eq_computed_remainder?(a, n, g, k)),
            P: [nat -> [nat -> int]]):
      (P =
        (LAMBDA (j: nat):
           IF j < length(sl)
             THEN list2array[int](0)(nth(sl, length(sl) - 1 - j))
           ELSE (LAMBDA (i: nat): 0)
           ENDIF))
       IMPLIES
       (FORALL (N: [nat -> nat]):
          (N =
            (LAMBDA (j: nat):
               IF j < length(sl)
                 THEN max(length(nth(sl, length(sl) - 1 - j)) - 1, 0)
               ELSE 0
               ENDIF))
           IMPLIES
           (FORALL (M: nat):
              M = length(sl) - 1 IMPLIES
               (FORALL (b: bool): NOT b IMPLIES M - 1 >= 0)));

  % Subtype TCC generated (at line 72, column 29) for  n
      % expected type  {n | newa(n) /= 0}
  TQ_TCC1: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0), newa: [nat -> int]):
      (newa = (LAMBDA (i: nat): IF i <= n THEN a(i) ELSE 0 ENDIF)) IMPLIES
       newa(n) /= 0;

  % Subtype TCC generated (at line 73, column 24) for  n - 1 + k
      % expected type  {m | der_prod(newa, n, g, k)(m) /= 0}
  TQ_TCC2: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0), newa: [nat -> int]):
      (newa = (LAMBDA (i: nat): IF i <= n THEN a(i) ELSE 0 ENDIF)) IMPLIES
       n - 1 + k >= 0 AND der_prod(newa, n, g, k)(n - 1 + k) /= 0;

  % Subtype TCC generated (at line 74, column 35) for  sl
      % expected type  (Eq_computed_remainder?(newa, n, g, k))
  TQ_TCC3: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0), newa: [nat -> int]):
      (newa = (LAMBDA (i: nat): IF i <= n THEN a(i) ELSE 0 ENDIF)) IMPLIES
       (FORALL (sl:
                  {crem:
                     (is_neg_remainder_list?(newa,
                                             n,
                                             der_prod(newa, n, g, k),
                                             n - 1 + k)) |
                           length[list[int]](crem) > 1 AND
                            length[int](nth[list[int]](crem, 0)) = 0}):
          sl = remainder_seq(newa, n, der_prod(newa, n, g, k), n - 1 + k)
           IMPLIES Eq_computed_remainder?(newa, n, g, k)(sl));


body:
  poly_families: THEORY
  BEGIN


  IMPORTING sturmtarski,compute_sturm_tarski,reals@base_repr

    a,r,g : VAR [nat->int]
    n : VAR posnat
    d,i,j,k : VAR nat
    m: VAR posnat
    %m : VAR posnat
    x,y,c,b : VAR real
    rel: VAR [[real,real]->bool]
    babove,bbelow,bbelow2,babove2: VAR bool

    poly1(i): nat = IF i=0 THEN 1 ELSE 0 ENDIF


    GF: VAR [nat->[nat->int]]
    KF: VAR [nat->nat] % degrees
    GP: VAR [nat->subrange(0,2)]
    RelF,RelF1,RelF2: VAR [nat->subrange(-1,1)]
    ll: VAR list[int]
    RelF6,TQRow: VAR [nat->subrange(0,5)]

    % Forgot powers of the GF's

    polynomial_prod_int: LEMMA
      rational_pred(polynomial_prod(a,d,g,k)(i)) AND integer_pred(polynomial_prod(a,d,g,k)(i)) 

    prod_polynomials(GF,KF,GP,k): RECURSIVE {a | 
      (FORALL (x): polynomial(a,sigma(0,k,KF*GP))(x) =
        product(0,k,LAMBDA (j): polynomial(GF(j),KF(j))(x)^GP(j))) AND
      ((FORALL (i): i<=k AND GP(i)/=0 IMPLIES GF(i)(KF(i))/=0) IMPLIES a(sigma(0,k,KF*GP))/=0) AND
      (FORALL (i): i>sigma(0,k,KF*GP) IMPLIES a(i)=0)}
      = LET  tpoly = (IF GP(k)=0 THEN poly1 ELSIF GP(k)=1 THEN 
        	   	       (LAMBDA (i:nat): IF i<=KF(k) THEN GF(k)(i) ELSE 0 ENDIF)
        	     	       ELSE polynomial_prod(GF(k),KF(k),GF(k),KF(k)) ENDIF),
  	   tdeg = IF GP(k)=0 THEN 0 ELSIF GP(k)=1 THEN KF(k) ELSE 2*KF(k) ENDIF,
  	   bpoly = (IF k = 0 THEN poly1 ELSE prod_polynomials(GF,KF,GP,k-1) ENDIF),
  	   bdeg = IF k = 0 THEN 0 ELSE sigma(0,k-1,KF*GP) ENDIF,
  	   anspoly = (IF k = 0 THEN tpoly 
  	   	      ELSIF GP(k)=0 THEN prod_polynomials(GF,KF,GP,k-1)
  		      ELSE polynomial_prod(bpoly,bdeg,tpoly,tdeg) ENDIF)
        IN anspoly
        MEASURE k

    prod_polynomials_list(GF,KF,GP,k): RECURSIVE {ll | 
      length(ll)-1=sigma(0,k,KF*GP) AND prod_polynomials(GF,KF,GP,k) = 
        (LAMBDA (i): IF i<length(ll) THEN nth(ll,i) ELSE 0 ENDIF)}
      = LET  tpolyinit = (IF GP(k)=0 THEN poly1 ELSIF GP(k)=1 THEN GF(k)
        	     	       ELSE polynomial_prod(GF(k),KF(k),GF(k),KF(k)) ENDIF),
  	   tdeg = IF GP(k)=0 THEN 0 ELSIF GP(k)=1 THEN KF(k) ELSE 2*KF(k) ENDIF,
  	   tpoly = array2list[int](tdeg+1)(tpolyinit),
  	   bpolyinit = (IF k = 0 THEN poly1 ELSE prod_polynomials(GF,KF,GP,k-1) ENDIF),
  	   bdeg = IF k = 0 THEN 0 ELSE sigma(0,k-1,KF*GP) ENDIF,
  	   bpoly = array2list[int](bdeg+1)(bpolyinit),
  	   anspoly = (IF k = 0 THEN tpoly 
  	   	      ELSIF GP(k)=0 THEN prod_polynomials_list(GF,KF,GP,k-1)
  		      ELSE array2list[int](tdeg+bdeg+1)(
  		        polynomial_prod(bpolyinit,bdeg,tpolyinit,tdeg)) ENDIF)
        IN anspoly
        MEASURE k

    TQ_fam(k,a,(n|a(n)/=0),GF,(KF|FORALL (i:upto(k)):GF(i)(KF(i))/=0),GP): int =
      LET ll = prod_polynomials_list(GF,KF,GP,k),
      	d  = length[int](ll)-1,
  	g  = (LAMBDA (i): IF i<=d THEN nth(ll,i) ELSE 0 ENDIF)
      IN  TQ(a,n,g,d)

    TQ_fam_def: LEMMA a(n)/=0 AND (FORALL (i:upto(k)):GF(i)(KF(i))/=0)
      IMPLIES TQ_fam(k,a,n,GF,KF,GP) = TQ(a,n,prod_polynomials(GF,KF,GP,k),sigma(0,k,KF*GP))

    Sol(k,a,(n|a(n)/=0),GF,KF,RelF):
      finite_set[real] = {r:real | polynomial(a,n)(r)=0 AND (FORALL (i): i<=k IMPLIES
      		       	       	 (IF RelF(i)=-1 THEN polynomial(GF(i),KF(i))(r)<0
  				  ELSIF RelF(i)=1 THEN polynomial(GF(i),KF(i))(r)>0
  				  ELSIF RelF(i)=0 THEN polynomial(GF(i),KF(i))(r)=0 ELSE TRUE ENDIF))}

    Sol_all(k,a,(n|a(n)/=0),GF,KF,RelF6):
      finite_set[real] = {r:real | polynomial(a,n)(r)=0 AND (FORALL (i): i<=k IMPLIES
      		       	       	 (IF RelF6(i)=0 THEN polynomial(GF(i),KF(i))(r)=0
  				  ELSIF RelF6(i)=1 THEN polynomial(GF(i),KF(i))(r)>0
  				  ELSIF RelF6(i)=2 THEN polynomial(GF(i),KF(i))(r)<0 
  				  ELSIF RelF6(i)=3 THEN polynomial(GF(i),KF(i))(r)/=0 
  				  ELSIF RelF6(i)=4 THEN polynomial(GF(i),KF(i))(r)>=0 
  				  ELSIF RelF6(i)=5 THEN polynomial(GF(i),KF(i))(r)<=0 ELSE TRUE ENDIF))}

    NSol(k,a,(n|a(n)/=0),GF,KF,RelF): nat =
      card(Sol(k,a,n,GF,KF,RelF))

    NSol_all(k,a,(n|a(n)/=0),GF,KF,RelF6): nat =
      card(Sol_all(k,a,n,GF,KF,RelF6))

    sign_prod(k,GP,RelF): subrange(-1,1) =
      product[nat](0,k,LAMBDA (i:nat): RelF(i)^GP(i))

    sign_prod_eq: LEMMA (FORALL (i:nat): i<=k IMPLIES RelF1(i)=RelF2(i))
      IMPLIES sign_prod(k,GP,RelF1)=sign_prod(k,GP,RelF2)

    sign_ext_pow: LEMMA sign_ext(x^k)=sign_ext(x)^k

    sign_ext_prod_polynomials: LEMMA
      LET RelFF = (LAMBDA (i:nat): sign_ext(polynomial(GF(i),KF(i))(x)))
      IN sign_ext(polynomial(prod_polynomials(GF,KF,GP,k),sigma(0,k,KF*GP))(x)) = sign_prod(k,GP,RelFF)
    
    % TQ_fam_rec: LEMMA k>0 AND a(n)/=0 AND 
    %   (FORALL (i):i<=k IMPLIES GF(i)(KF(i))/=0)
    %   IMPLIES
    %   TQ_fam(k,a,n,GF,KF,GP) =
    %     IF GP(k)=0 THEN TQ_fam(k-1,a,n,GF,KF,GP)
    %     ELSIF GP(k)=1 THEN NSol(a,n,prod_polynomials(GF,KF,GP,k),sigma(0,k-1,KF*GP),>) 

    atest(i): int = IF i<6 THEN i ELSIF i<=9 THEN i+4 ELSE 0 ENDIF
    ntest: posnat = 9
    GFtest(i)(j): int = IF i<j THEN 1+j ELSIF i+j<=6 THEN i*j ELSIF j<=7 THEN 2 ELSE 0 ENDIF
    KFtest(i): nat = 7
    GPtest(i): nat = IF i <=3 THEN 2 ELSIF i<=5 THEN 1 ELSE 0 ENDIF

    sig(ii:subrange(0,2)): subrange(-1,1) = IF ii=0 THEN 0 
        ELSIF ii=1 THEN 1
        ELSE -1
        ENDIF

    unsig(ii:subrange(-1,1)): subrange(0,2) = mod(ii,3)

    sig_unsig: LEMMA FORALL (ii:subrange(-1,1)): sig(unsig(ii)) = ii

    sig_seq(GP)(i:nat): subrange(-1,1) = sig(GP(i))

    unsig_seq(RelF)(i:nat): subrange(0,2) = unsig(RelF(i))

    sig_seq_unsig_seq: LEMMA
      sig_seq(unsig_seq(RelF)) = RelF

    base_3_seq(k,i)(p:nat): subrange(0,2) = (IF p<=k THEN base_n(3,i)(k-p) ELSE 0 ENDIF)

    base_6_seq(k,i)(p:nat): subrange(0,5) = (IF p<=k THEN base_n(6,i)(k-p) ELSE 0 ENDIF)

    sig_seq_base_3_onto: LEMMA FORALL (RelF,k): EXISTS (i:below(3^(k+1))):
      sig_seq(base_3_seq(k,i)) = (LAMBDA (i:nat): IF i<=k THEN RelF(i) ELSE 0 ENDIF)

    sig_seq_base_3_onto_2: LEMMA FORALL (RelF,k): EXISTS (i:below(3^(k+1))):
      sig_seq(base_n(3,i)) = (LAMBDA (i:nat): IF i<=k THEN RelF(i) ELSE 0 ENDIF)

    sig_seq_base_6_onto: LEMMA FORALL (RelF,k): EXISTS (i:below(6^(k+1))): (FORALL (j:nat): base_6_seq(k,i)(j)<=2) AND
      sig_seq(base_6_seq(k,i)) = (LAMBDA (i:nat): IF i<=k THEN RelF(i) ELSE 0 ENDIF)

    sig_seq_base_6_onto_2: LEMMA FORALL (RelF,k): EXISTS (i:below(6^(k+1))): (FORALL (j:nat): base_n(6,i)(j)<=2) AND
      sig_seq(base_n(6,i)) = (LAMBDA (i:nat): IF i<=k THEN RelF(i) ELSE 0 ENDIF)

    % Fix the 3^k issue!!!

    base_3_seq_unique: LEMMA FORALL (i,j): i<3^(k+1) AND j<3^(k+1) AND i/=j IMPLIES
      base_3_seq(k,i)/=base_3_seq(k,j)

    base_n_3_seq_unique: LEMMA FORALL (i,j): i<3^(k+1) AND j<3^(k+1) AND i/=j IMPLIES
      base_n(3,i)/=base_n(3,j)

    union_upto(k:nat,setseq:[nat->set[real]]): RECURSIVE {Aset:set[real]|
      FORALL (x): Aset(x) IFF EXISTS (i:upto(k)): setseq(i)(x)} =
      (IF k = 0 THEN setseq(0) ELSE union[real](union_upto(k-1,setseq),setseq(k)) ENDIF)
      MEASURE k

    union_upto_finite: LEMMA (FORALL (setseq:[nat->set[real]]):
      (FORALL (i:upto(k)): is_finite[real](setseq(i))) IMPLIES
      is_finite[real](union_upto(k,setseq)))

    real_set_disj_union_cards: LEMMA FORALL (setseq:[nat->set[real]]):
      (FORALL (i:nat): is_finite[real](setseq(i))) AND 
      is_finite[real](union_upto(k,setseq)) AND
      (FORALL (i,j:nat): i/=j IMPLIES disjoint?[real](setseq(i),setseq(j)))
      IMPLIES
      card[real](union_upto(k,setseq)) = sigma(0,k,LAMBDA (i): card[real](setseq(i)))

    mult_tarski_query_simple: LEMMA
      a(n)/=0 AND (FORALL (i:upto(k)):GF(i)(KF(i))/=0)
      IMPLIES
      TQ_fam(k,a,n,GF,KF,GP) =
      sigma(0,3^(k+1)-1,LAMBDA (i:nat):
        sign_prod(k,GP,sig_seq(base_n(3,i)))*
        NSol(k,a,n,GF,KF,sig_seq(base_n(3,i))))
      	  

   % splitting base 6 function

   split_index_fun_entry( F:[nat->[nat, nat]], i:nat): [nat->[nat, nat]] = 
         IF F(i)`1<3 THEN F
         ELSIF F(i)`1 = 3 THEN F WITH [i:=(1,2)] 
         ELSIF F(i)`1 = 4 THEN F WITH [i:=(0,1)]
         ELSE                  F WITH [i:=(0,2)]
         ENDIF

   split_index_fun(F:[nat->[nat, nat]], n:nat): RECURSIVE {G:[nat->[nat, nat]]|
     (FORALL (i:upto(n)): G(i) = split_index_fun_entry(F,i)(i)) AND
     (FORALL (i:above(n)): G(i) = F(i))} = 
        IF n = 0 THEN split_index_fun_entry(F, n) 
        ELSE split_index_fun(split_index_fun_entry(F,n), n-1)
        ENDIF
        MEASURE n

    % 99 here is arbitrary, only used as an indicator.
   fun_to_pairsfun(F:[nat->nat])(i:nat): [nat, nat] = (F(i), 99)

   base6_pairs(k:nat)(i:nat): [nat,nat] = fun_to_pairsfun(base_n(6,k))(i)

   split_base6(n:posnat, k:nat): [nat->[nat, nat]] = 
        split_index_fun(base6_pairs(k), n-1)

    % unproven, but should be very easy.
   splits_to_base3: LEMMA FORALL (n:posnat, k:nat, i:below(n)): 
       split_base6(n, k)(i) =   
           IF base_n(6,k)(i)<3 THEN (base_n(6,k)(i), 99)
  	 ELSIF base_n(6,k)(i) = 3  THEN (1,2)
   	 ELSIF base_n(6,k)(i) = 4  THEN (0,1)
  	 ELSE (0,2)
  	 ENDIF

    sign_prod_coeff6(k,GP,i): subrange(-1,1) =
      IF i>=6^(k+1) OR (EXISTS (p:upto(k)): base_n(6,i)(p)>=3) THEN 0
      ELSE sign_prod(k,GP,sig_seq(base_n(6,i))) ENDIF

    NSol_seq6(k,a,(n|a(n)/=0),GF,KF)(i): nat =
      IF i>=6^(k+1) OR (EXISTS (p:upto(k)): base_n(6,i)(p)>=3) THEN 0
      ELSE NSol(k,a,n,GF,KF,sig_seq(base_n(6,i))) ENDIF

    mult_tarski_query_simple_6_0_to_3: LEMMA
      a(n)/=0 AND (FORALL (i:upto(k)):GF(i)(KF(i))/=0)
      IMPLIES
      TQ_fam(k,a,n,GF,KF,GP) =
      sigma(0,6^(k+1)-1,LAMBDA (i:nat):
        sign_prod_coeff6(k,GP,i)*NSol_seq6(k,a,n,GF,KF)(i))

    sign_coeff6_zero_entry(k,TQRow,i,j): subrange(-1,1) =
      LET bij = base_n(6,i)(j) IN
        IF TQRow(j)=0 THEN (IF bij>=3 THEN 0 ELSE 1 ENDIF)
        ELSIF TQRow(j)=1 THEN (IF bij=1 THEN 1 ELSIF bij=2 THEN -1 ELSE 0 ENDIF)
        ELSIF TQRow(j)=2 THEN (IF 1<=bij AND bij<=2 THEN 1 ELSE 0 ENDIF)
        ELSIF TQRow(j)=3 THEN (IF 1<=bij AND bij<=2 THEN -1 ELSIF bij=3 THEN 1 ELSE 0 ENDIF)
        ELSIF TQRow(j)=4 THEN (IF bij<=1 THEN -1 ELSIF bij=4 THEN 1 ELSE 0 ENDIF)
        ELSIF TQRow(j)=5 THEN (IF bij=0 OR bij=2 THEN -1 ELSIF bij=5 THEN 1 ELSE 0 ENDIF)
        ELSE 0 ENDIF

    sign_coeff6_zero_entry_eq: LEMMA
      base_n(6,i)(j) = base_n(6,d)(j) IMPLIES
      sign_coeff6_zero_entry(k,TQRow,i,j) =
      sign_coeff6_zero_entry(k,TQRow,d,j)

    sign_coeff6_zero(k,TQRow,i): subrange(-1,1) =
      IF i>=6^(k+1) THEN 0
      ELSE product[nat](0,k,LAMBDA (j):sign_coeff6_zero_entry(k,TQRow,i,j)) ENDIF

    in6?(vk:[nat,nat,nat,nat,nat,nat],j): bool =
      (j=vk`1 OR j=vk`2 OR j=vk`3 OR j=vk`4 OR j=vk`5 OR j=vk`6)

    sigma_disjoinction_6: LEMMA
      FORALL (v:[nat->[nat,nat,nat,nat,nat,nat]]):
        (FORALL (j): j<=6^(k+1)-1 IMPLIES EXISTS (i): i<=6^k-1 AND in6?(v(i),j)) AND
        (FORALL (i): i<=6^k-1 IMPLIES
          (v(i)`1 < v(i)`2 AND v(i)`2 < v(i)`3 AND v(i)`3 < v(i)`4 
  	  AND v(i)`4 < v(i)`5 AND v(i)`5 < v(i)`6 AND v(i)`6<=6^(k+1)-1)) AND
        (FORALL (i,d,j): i<=6^k-1 AND d<=6^k-1 AND j<=6^(k+1)-1 AND in6?(v(i),j) AND in6?(v(d),j)
        	      IMPLIES i = d) AND
        (FORALL (i): i<=6^k-1 IMPLIES
          (g(v(i)`1)+g(v(i)`2)+g(v(i)`3)+g(v(i)`4)+g(v(i)`5)+g(v(i)`6)) = 0)
        IMPLIES sigma(0,6^(k+1)-1,g)=0

    mult_tarski_query_simple_6_above_2: LEMMA
      a(n)/=0 AND (FORALL (i:upto(k)):GF(i)(KF(i))/=0) AND
      (EXISTS (i:upto(k)): TQRow(i)>2)
      IMPLIES
      sigma(0,6^(k+1)-1,LAMBDA (i:nat):
        sign_coeff6_zero(k,TQRow,i)*NSol_all(k,a,n,GF,KF,base_n(6,i)))=0

    

  END poly_families

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

  % Subtype TCC generated (at line 32, column 38) for  k
      % expected type  T_high[nat]
  prod_polynomials_TCC1: OBLIGATION
    FORALL (k): k >= 0 OR (EXISTS (j: nat): k <= j);

  % Subtype TCC generated (at line 32, column 30) for  sigma(0, k, KF * GP)
      % expected type  nat
  prod_polynomials_TCC2: OBLIGATION
    FORALL (GP, KF, k):
      rational_pred(sigma[nat](0, k, *[nat](KF, GP))) AND
       integer_pred(sigma[nat](0, k, *[nat](KF, GP))) AND
        sigma[nat](0, k, *[nat](KF, GP)) >= 0;

  % Subtype TCC generated (at line 33, column 57) for  GP(j)
      % expected type  {i: int | polynomial(GF(j), KF(j))(x) /= 0 OR i >= 0}
  prod_polynomials_TCC3: OBLIGATION
    FORALL (GF, GP, KF, x: real, j: nat):
      polynomial(GF(j), KF(j))(x) /= 0 OR GP(j) >= 0;

  % Assuming TCC generated (at line 11, column 28) for  reals@product[nat]
      % generated from assumption product.connected_domain
  prod_polynomials_TCC4: OBLIGATION
    (FORALL (x, y: nat), (z: integer): x <= z AND z <= y IMPLIES z >= 0);

  % Subtype TCC generated (at line 40, column 64) for  k - 1
      % expected type  nat
  prod_polynomials_TCC5: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat, tpoly: [nat -> real]):
      tpoly =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1
          THEN LAMBDA (i: nat): IF i <= KF(k) THEN GF(k)(i) ELSE 0 ENDIF
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          NOT k = 0 AND
           tdeg =
            IF GP(k) = 0 THEN 0
            ELSIF GP(k) = 1 THEN KF(k)
            ELSE 2 * KF(k)
            ENDIF
           IMPLIES k - 1 >= 0);

  % Termination TCC generated (at line 40, column 38) for
      % prod_polynomials(GF, KF, GP, k - 1)
  prod_polynomials_TCC6: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat, tpoly: [nat -> real]):
      tpoly =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1
          THEN LAMBDA (i: nat): IF i <= KF(k) THEN GF(k)(i) ELSE 0 ENDIF
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          NOT k = 0 AND
           tdeg =
            IF GP(k) = 0 THEN 0
            ELSIF GP(k) = 1 THEN KF(k)
            ELSE 2 * KF(k)
            ENDIF
           IMPLIES k - 1 < k);

  % Subtype TCC generated (at line 44, column 35) for  bdeg
      % expected type  nat
  prod_polynomials_TCC7: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat,
            v:
              [d1:
                 {z:
                    [[nat -> [nat -> int]], [nat -> nat],
                     [nat -> subrange(0, 2)], nat] |
                          z`4 < k} ->
                 {a |
                          (FORALL (x):
                             polynomial(a, sigma(0, d1`4, d1`2 * d1`3))(x) =
                              product(0,
                                      d1`4,
                                      LAMBDA
                                      (j):
                                      polynomial(d1`1(j), d1`2(j))(x)
                                      ^
                                      d1`3(j)))
                           AND
                           ((FORALL (i):
                               i <= d1`4 AND d1`3(i) /= 0 IMPLIES
                                d1`1(i)(d1`2(i)) /= 0)
                             IMPLIES a(sigma(0, d1`4, d1`2 * d1`3)) /= 0)
                            AND
                            (FORALL (i):
                               i > sigma(0, d1`4, d1`2 * d1`3) IMPLIES
                                a(i) = 0)}],
            tpoly: [nat -> real]):
      tpoly =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1
          THEN LAMBDA (i: nat): IF i <= KF(k) THEN GF(k)(i) ELSE 0 ENDIF
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          tdeg =
           IF GP(k) = 0 THEN 0
           ELSIF GP(k) = 1 THEN KF(k)
           ELSE 2 * KF(k)
           ENDIF
           IMPLIES
           (FORALL (bpoly: [nat -> int]):
              bpoly = (IF k = 0 THEN poly1 ELSE v(GF, KF, GP, k - 1) ENDIF)
               IMPLIES
               (FORALL (bdeg: real):
                  NOT GP(k) = 0 AND
                   NOT k = 0 AND
                    bdeg =
                     IF k = 0 THEN 0 ELSE sigma(0, k - 1, KF * GP) ENDIF
                   IMPLIES
                   rational_pred(bdeg) AND
                    integer_pred(bdeg) AND bdeg >= 0)));

  % Subtype TCC generated (at line 45, column 9) for  anspoly
      % expected type  {a |
                     %          (FORALL (x):
                     %             polynomial(a, sigma(0, k, KF * GP))(x) =
                     %              product(0,
                     %                      k,
                     %                      LAMBDA
                     %                      (j):
                     %                      polynomial(GF(j), KF(j))(x)
                     %                      ^
                     %                      GP(j)))
                     %           AND
                     %           ((FORALL (i):
                     %               i <= k AND GP(i) /= 0 IMPLIES
                     %                GF(i)(KF(i)) /= 0)
                     %             IMPLIES a(sigma(0, k, KF * GP)) /= 0)
                     %            AND
                     %            (FORALL (i):
                     %               i > sigma(0, k, KF * GP) IMPLIES
                     %                a(i) = 0)}
  prod_polynomials_TCC8: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat,
            v:
              [d1:
                 {z:
                    [[nat -> [nat -> int]], [nat -> nat],
                     [nat -> subrange(0, 2)], nat] |
                          z`4 < k} ->
                 {a |
                          (FORALL (x):
                             polynomial(a, sigma(0, d1`4, d1`2 * d1`3))(x) =
                              product(0,
                                      d1`4,
                                      LAMBDA
                                      (j):
                                      polynomial(d1`1(j), d1`2(j))(x)
                                      ^
                                      d1`3(j)))
                           AND
                           ((FORALL (i):
                               i <= d1`4 AND d1`3(i) /= 0 IMPLIES
                                d1`1(i)(d1`2(i)) /= 0)
                             IMPLIES a(sigma(0, d1`4, d1`2 * d1`3)) /= 0)
                            AND
                            (FORALL (i):
                               i > sigma(0, d1`4, d1`2 * d1`3) IMPLIES
                                a(i) = 0)}],
            tpoly: [nat -> real]):
      tpoly =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1
          THEN LAMBDA (i: nat): IF i <= KF(k) THEN GF(k)(i) ELSE 0 ENDIF
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          tdeg =
           IF GP(k) = 0 THEN 0
           ELSIF GP(k) = 1 THEN KF(k)
           ELSE 2 * KF(k)
           ENDIF
           IMPLIES
           (FORALL (bpoly: [nat -> int]):
              bpoly = (IF k = 0 THEN poly1 ELSE v(GF, KF, GP, k - 1) ENDIF)
               IMPLIES
               (FORALL (bdeg: real):
                  bdeg = IF k = 0 THEN 0 ELSE sigma(0, k - 1, KF * GP) ENDIF
                   IMPLIES
                   (FORALL (anspoly: [nat -> real]):
                      anspoly =
                       (IF k = 0 THEN tpoly
                        ELSIF GP(k) = 0 THEN v(GF, KF, GP, k - 1)
                        ELSE polynomial_prod(bpoly, bdeg, tpoly, tdeg)
                        ENDIF)
                       IMPLIES
                       (FORALL (x1: nat):
                          rational_pred(anspoly(x1)) AND
                           integer_pred(anspoly(x1)))
                        AND
                        (FORALL (x):
                           polynomial(anspoly,
                                      sigma[nat](0, k, *[nat](KF, GP)))
                                     (x)
                            =
                            product[nat]
                                (0, k,
                                 LAMBDA (j):
                                   polynomial(GF(j), KF(j))(x) ^ GP(j)))
                         AND
                         ((FORALL (i):
                             i <= k AND GP(i) /= 0 IMPLIES GF(i)(KF(i)) /= 0)
                           IMPLIES
                           anspoly(sigma[nat](0, k, *[nat](KF, GP))) /= 0)
                          AND
                          (FORALL (i):
                             i > sigma[nat](0, k, *[nat](KF, GP)) IMPLIES
                              anspoly(i) = 0)))));

  % Subtype TCC generated (at line 54, column 36) for  tpolyinit
      % expected type  a: [nat -> int]
  prod_polynomials_list_TCC1: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat, tpolyinit: [nat -> real]):
      tpolyinit =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1 THEN GF(k)
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          tdeg =
           IF GP(k) = 0 THEN 0
           ELSIF GP(k) = 1 THEN KF(k)
           ELSE 2 * KF(k)
           ENDIF
           IMPLIES
           (FORALL (x1: nat):
              rational_pred(tpolyinit(x1)) AND integer_pred(tpolyinit(x1))));

  % Subtype TCC generated (at line 55, column 68) for  k - 1
      % expected type  nat
  prod_polynomials_list_TCC2: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat, tpolyinit: [nat -> real]):
      tpolyinit =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1 THEN GF(k)
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          tdeg =
           IF GP(k) = 0 THEN 0
           ELSIF GP(k) = 1 THEN KF(k)
           ELSE 2 * KF(k)
           ENDIF
           IMPLIES
           (FORALL (tpoly:
                      {l: listn[int](1 + tdeg) |
                               FORALL (i: below(1 + tdeg)):
                                 tpolyinit(i) = nth[int](l, i)}):
              NOT k = 0 AND tpoly = array2list[int](tdeg + 1)(tpolyinit)
               IMPLIES k - 1 >= 0));

  % Subtype TCC generated (at line 57, column 28) for  bdeg + 1
      % expected type  n: nat
  prod_polynomials_list_TCC3: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat, tpolyinit: [nat -> real]):
      tpolyinit =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1 THEN GF(k)
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          tdeg =
           IF GP(k) = 0 THEN 0
           ELSIF GP(k) = 1 THEN KF(k)
           ELSE 2 * KF(k)
           ENDIF
           IMPLIES
           (FORALL (tpoly:
                      {l: listn[int](1 + tdeg) |
                               FORALL (i: below(1 + tdeg)):
                                 tpolyinit(i) = nth[int](l, i)}):
              tpoly = array2list[int](tdeg + 1)(tpolyinit) IMPLIES
               (FORALL (bpolyinit: [nat -> int]):
                  bpolyinit =
                   (IF k = 0 THEN poly1
                    ELSE prod_polynomials(GF, KF, GP, k - 1)
                    ENDIF)
                   IMPLIES
                   (FORALL (bdeg: real):
                      bdeg =
                       IF k = 0 THEN 0 ELSE sigma(0, k - 1, KF * GP) ENDIF
                       IMPLIES
                       rational_pred(bdeg + 1) AND
                        integer_pred(bdeg + 1) AND bdeg + 1 >= 0))));

  % Termination TCC generated (at line 59, column 30) for
      % prod_polynomials_list(GF, KF, GP, k - 1)
  prod_polynomials_list_TCC4: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat, tpolyinit: [nat -> real]):
      tpolyinit =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1 THEN GF(k)
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          tdeg =
           IF GP(k) = 0 THEN 0
           ELSIF GP(k) = 1 THEN KF(k)
           ELSE 2 * KF(k)
           ENDIF
           IMPLIES
           (FORALL (tpoly:
                      {l: listn[int](1 + tdeg) |
                               FORALL (i: below(1 + tdeg)):
                                 tpolyinit(i) = nth[int](l, i)}):
              tpoly = array2list[int](tdeg + 1)(tpolyinit) IMPLIES
               (FORALL (bpolyinit: [nat -> int]):
                  bpolyinit =
                   (IF k = 0 THEN poly1
                    ELSE prod_polynomials(GF, KF, GP, k - 1)
                    ENDIF)
                   IMPLIES
                   (FORALL (bdeg: real):
                      bdeg =
                       IF k = 0 THEN 0 ELSE sigma(0, k - 1, KF * GP) ENDIF
                       IMPLIES
                       (FORALL (bpoly:
                                  {l: listn[int](1 + bdeg) |
                                           FORALL
                                           (i: below(1 + bdeg)):
                                           bpolyinit(i) = nth[int](l, i)}):
                          GP(k) = 0 AND
                           NOT k = 0 AND
                            bpoly = array2list[int](bdeg + 1)(bpolyinit)
                           IMPLIES k - 1 < k)))));

  % Subtype TCC generated (at line 61, column 36) for  bdeg
      % expected type  nat
  prod_polynomials_list_TCC5: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat, tpolyinit: [nat -> real]):
      tpolyinit =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1 THEN GF(k)
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          tdeg =
           IF GP(k) = 0 THEN 0
           ELSIF GP(k) = 1 THEN KF(k)
           ELSE 2 * KF(k)
           ENDIF
           IMPLIES
           (FORALL (tpoly:
                      {l: listn[int](1 + tdeg) |
                               FORALL (i: below(1 + tdeg)):
                                 tpolyinit(i) = nth[int](l, i)}):
              tpoly = array2list[int](tdeg + 1)(tpolyinit) IMPLIES
               (FORALL (bpolyinit: [nat -> int]):
                  bpolyinit =
                   (IF k = 0 THEN poly1
                    ELSE prod_polynomials(GF, KF, GP, k - 1)
                    ENDIF)
                   IMPLIES
                   (FORALL (bdeg: real):
                      bdeg =
                       IF k = 0 THEN 0 ELSE sigma(0, k - 1, KF * GP) ENDIF
                       IMPLIES
                       (FORALL (bpoly:
                                  {l: listn[int](1 + bdeg) |
                                           FORALL
                                           (i: below(1 + bdeg)):
                                           bpolyinit(i) = nth[int](l, i)}):
                          NOT GP(k) = 0 AND
                           NOT k = 0 AND
                            bpoly = array2list[int](bdeg + 1)(bpolyinit)
                           IMPLIES
                           rational_pred(bdeg) AND
                            integer_pred(bdeg) AND bdeg >= 0)))));

  % Subtype TCC generated (at line 61, column 10) for
      % polynomial_prod(bpolyinit, bdeg, tpolyinit, tdeg)
      % expected type  a: [nat -> int]
  prod_polynomials_list_TCC6: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat, tpolyinit: [nat -> real]):
      tpolyinit =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1 THEN GF(k)
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          tdeg =
           IF GP(k) = 0 THEN 0
           ELSIF GP(k) = 1 THEN KF(k)
           ELSE 2 * KF(k)
           ENDIF
           IMPLIES
           (FORALL (tpoly:
                      {l: listn[int](1 + tdeg) |
                               FORALL (i: below(1 + tdeg)):
                                 tpolyinit(i) = nth[int](l, i)}):
              tpoly = array2list[int](tdeg + 1)(tpolyinit) IMPLIES
               (FORALL (bpolyinit: [nat -> int]):
                  bpolyinit =
                   (IF k = 0 THEN poly1
                    ELSE prod_polynomials(GF, KF, GP, k - 1)
                    ENDIF)
                   IMPLIES
                   (FORALL (bdeg: real):
                      bdeg =
                       IF k = 0 THEN 0 ELSE sigma(0, k - 1, KF * GP) ENDIF
                       IMPLIES
                       (FORALL (bpoly:
                                  {l: listn[int](1 + bdeg) |
                                           FORALL
                                           (i: below(1 + bdeg)):
                                           bpolyinit(i) = nth[int](l, i)}):
                          NOT GP(k) = 0 AND
                           NOT k = 0 AND
                            bpoly = array2list[int](bdeg + 1)(bpolyinit)
                           IMPLIES
                           (FORALL (x1: nat):
                              rational_pred(polynomial_prod
                                            (bpolyinit, bdeg, tpolyinit, tdeg)
                                            (x1))
                               AND
                               integer_pred(polynomial_prod
                                            (bpolyinit, bdeg, tpolyinit, tdeg)
                                            (x1))))))));

  % Subtype TCC generated (at line 60, column 29) for  tdeg + bdeg + 1
      % expected type  n: nat
  prod_polynomials_list_TCC7: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat, tpolyinit: [nat -> real]):
      tpolyinit =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1 THEN GF(k)
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          tdeg =
           IF GP(k) = 0 THEN 0
           ELSIF GP(k) = 1 THEN KF(k)
           ELSE 2 * KF(k)
           ENDIF
           IMPLIES
           (FORALL (tpoly:
                      {l: listn[int](1 + tdeg) |
                               FORALL (i: below(1 + tdeg)):
                                 tpolyinit(i) = nth[int](l, i)}):
              tpoly = array2list[int](tdeg + 1)(tpolyinit) IMPLIES
               (FORALL (bpolyinit: [nat -> int]):
                  bpolyinit =
                   (IF k = 0 THEN poly1
                    ELSE prod_polynomials(GF, KF, GP, k - 1)
                    ENDIF)
                   IMPLIES
                   (FORALL (bdeg: real):
                      bdeg =
                       IF k = 0 THEN 0 ELSE sigma(0, k - 1, KF * GP) ENDIF
                       IMPLIES
                       (FORALL (bpoly:
                                  {l: listn[int](1 + bdeg) |
                                           FORALL
                                           (i: below(1 + bdeg)):
                                           bpolyinit(i) = nth[int](l, i)}):
                          NOT GP(k) = 0 AND
                           NOT k = 0 AND
                            bpoly = array2list[int](bdeg + 1)(bpolyinit)
                           IMPLIES
                           rational_pred(tdeg + bdeg + 1) AND
                            integer_pred(tdeg + bdeg + 1) AND
                             tdeg + bdeg + 1 >= 0)))));

  % Subtype TCC generated (at line 62, column 9) for  anspoly
      % expected type  {ll |
                     %          length(ll) - 1 = sigma(0, k, KF * GP) AND
                     %           prod_polynomials(GF, KF, GP, k) =
                     %            (LAMBDA (i):
                     %               IF i < length(ll) THEN nth(ll, i)
                     %               ELSE 0
                     %               ENDIF)}
  prod_polynomials_list_TCC8: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            GP: [nat -> subrange(0, 2)], k: nat,
            v:
              [d1:
                 {z:
                    [[nat -> [nat -> int]], [nat -> nat],
                     [nat -> subrange(0, 2)], nat] |
                          z`4 < k} ->
                 {ll |
                          length(ll) - 1 = sigma(0, d1`4, d1`2 * d1`3) AND
                           prod_polynomials(d1`1, d1`2, d1`3, d1`4) =
                            (LAMBDA (i):
                               IF i < length(ll) THEN nth(ll, i)
                               ELSE 0
                               ENDIF)}],
            tpolyinit: [nat -> real]):
      tpolyinit =
       (IF GP(k) = 0 THEN poly1
        ELSIF GP(k) = 1 THEN GF(k)
        ELSE polynomial_prod(GF(k), KF(k), GF(k), KF(k))
        ENDIF)
       IMPLIES
       (FORALL (tdeg: naturalnumber):
          tdeg =
           IF GP(k) = 0 THEN 0
           ELSIF GP(k) = 1 THEN KF(k)
           ELSE 2 * KF(k)
           ENDIF
           IMPLIES
           (FORALL (tpoly:
                      {l: listn[int](1 + tdeg) |
                               FORALL (i: below(1 + tdeg)):
                                 tpolyinit(i) = nth[int](l, i)}):
              tpoly = array2list[int](tdeg + 1)(tpolyinit) IMPLIES
               (FORALL (bpolyinit: [nat -> int]):
                  bpolyinit =
                   (IF k = 0 THEN poly1
                    ELSE prod_polynomials(GF, KF, GP, k - 1)
                    ENDIF)
                   IMPLIES
                   (FORALL (bdeg: real):
                      bdeg =
                       IF k = 0 THEN 0 ELSE sigma(0, k - 1, KF * GP) ENDIF
                       IMPLIES
                       (FORALL (bpoly:
                                  {l: listn[int](1 + bdeg) |
                                           FORALL
                                           (i: below(1 + bdeg)):
                                           bpolyinit(i) = nth[int](l, i)}):
                          bpoly = array2list[int](bdeg + 1)(bpolyinit)
                           IMPLIES
                           (FORALL (anspoly: list[int]):
                              anspoly =
                               (IF k = 0 THEN tpoly
                                ELSIF GP(k) = 0 THEN v(GF, KF, GP, k - 1)
                                ELSE array2list[int]
                                         (tdeg + bdeg + 1)
                                         (polynomial_prod
                                          (bpolyinit, bdeg, tpolyinit, tdeg))
                                ENDIF)
                               IMPLIES
                               length[int](anspoly) - 1 =
                                sigma[nat](0, k, *[nat](KF, GP))
                                AND
                                prod_polynomials(GF, KF, GP, k) =
                                 (LAMBDA (i):
                                    IF i < length[int](anspoly)
                                      THEN nth[int](anspoly, i)
                                    ELSE 0
                                    ENDIF)))))));

  % Subtype TCC generated (at line 68, column 39) for  i
      % expected type  below[length(ll)]
  TQ_fam_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]],
            (KF: [nat -> nat] | FORALL (i: upto(k)): GF(i)(KF(i)) /= 0),
            GP: [nat -> subrange(0, 2)],
            ll:
              {ll |
                       length[int](ll) - 1 = sigma[nat](0, k, *[nat](KF, GP))
                        AND
                        prod_polynomials(GF, KF, GP, k) =
                         (LAMBDA (i):
                            IF i < length[int](ll) THEN nth[int](ll, i)
                            ELSE 0
                            ENDIF)}):
      ll = prod_polynomials_list(GF, KF, GP, k) IMPLIES
       (FORALL (d: int):
          d = length[int](ll) - 1 IMPLIES
           (FORALL (i: nat): i <= d IMPLIES i < length[int](ll)));

  % Subtype TCC generated (at line 69, column 17) for  d
      % expected type  {k | g(k) /= 0}
  TQ_fam_TCC2: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]],
            (KF: [nat -> nat] | FORALL (i: upto(k)): GF(i)(KF(i)) /= 0),
            GP: [nat -> subrange(0, 2)],
            ll:
              {ll |
                       length[int](ll) - 1 = sigma[nat](0, k, *[nat](KF, GP))
                        AND
                        prod_polynomials(GF, KF, GP, k) =
                         (LAMBDA (i):
                            IF i < length[int](ll) THEN nth[int](ll, i)
                            ELSE 0
                            ENDIF)}):
      ll = prod_polynomials_list(GF, KF, GP, k) IMPLIES
       (FORALL (d: int):
          d = length[int](ll) - 1 IMPLIES
           (FORALL (g: [nat -> int]):
              (g = (LAMBDA (i): IF i <= d THEN nth(ll, i) ELSE 0 ENDIF))
               IMPLIES d >= 0 AND g(d) /= 0));

  % Subtype TCC generated (at line 72, column 73) for  sigma(0, k, KF * GP)
      % expected type  {k_1 | prod_polynomials(GF, KF, GP, k)(k_1) /= 0}
  TQ_fam_def_TCC1: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], GP: [nat -> subrange(0, 2)],
            KF: [nat -> nat], a: [nat -> int], k: nat, n: posnat):
      (FORALL (i: upto(k)): GF(i)(KF(i)) /= 0) AND a(n) /= 0 IMPLIES
       rational_pred(sigma[nat](0, k, *[nat](KF, GP))) AND
        integer_pred(sigma[nat](0, k, *[nat](KF, GP))) AND
         sigma[nat](0, k, *[nat](KF, GP)) >= 0 AND
          prod_polynomials(GF, KF, GP, k)(sigma[nat](0, k, *[nat](KF, GP)))
           /= 0;

  % Subtype TCC generated (at line 75, column 23) for
      % {r: real |
      %    polynomial(a, n)(r) = 0 AND
      %     (FORALL (i):
      %        i <= k IMPLIES
      %         (IF RelF(i) = -1 THEN polynomial(GF(i), KF(i))(r) < 0
      %          ELSIF RelF(i) = 1 THEN polynomial(GF(i), KF(i))(r) > 0
      %          ELSIF RelF(i) = 0 THEN polynomial(GF(i), KF(i))(r) = 0
      %          ELSE TRUE
      %          ENDIF))}
      % expected type  finite_set[real]
  Sol_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]], KF: [nat -> nat],
            RelF: [nat -> subrange(-1, 1)]):
      is_finite[real]
          ({r: real |
              polynomial(a, n)(r) = 0 AND
               (FORALL (i):
                  i <= k IMPLIES
                   (IF RelF(i) = -1 THEN polynomial(GF(i), KF(i))(r) < 0
                    ELSIF RelF(i) = 1 THEN polynomial(GF(i), KF(i))(r) > 0
                    ELSIF RelF(i) = 0 THEN polynomial(GF(i), KF(i))(r) = 0
                    ELSE TRUE
                    ENDIF))});

  % Subtype TCC generated (at line 81, column 23) for
      % {r: real |
      %    polynomial(a, n)(r) = 0 AND
      %     (FORALL (i):
      %        i <= k IMPLIES
      %         (IF RelF6(i) = 0 THEN polynomial(GF(i), KF(i))(r) = 0
      %          ELSIF RelF6(i) = 1 THEN polynomial(GF(i), KF(i))(r) > 0
      %          ELSIF RelF6(i) = 2 THEN polynomial(GF(i), KF(i))(r) < 0
      %          ELSIF RelF6(i) = 3 THEN polynomial(GF(i), KF(i))(r) /= 0
      %          ELSIF RelF6(i) = 4 THEN polynomial(GF(i), KF(i))(r) >= 0
      %          ELSIF RelF6(i) = 5 THEN polynomial(GF(i), KF(i))(r) <= 0
      %          ELSE TRUE
      %          ENDIF))}
      % expected type  finite_set[real]
  Sol_all_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]], KF: [nat -> nat],
            RelF6: [nat -> subrange(0, 5)]):
      is_finite[real]
          ({r: real |
              polynomial(a, n)(r) = 0 AND
               (FORALL (i):
                  i <= k IMPLIES
                   (IF RelF6(i) = 0 THEN polynomial(GF(i), KF(i))(r) = 0
                    ELSIF RelF6(i) = 1 THEN polynomial(GF(i), KF(i))(r) > 0
                    ELSIF RelF6(i) = 2 THEN polynomial(GF(i), KF(i))(r) < 0
                    ELSIF RelF6(i) = 3 THEN polynomial(GF(i), KF(i))(r) /= 0
                    ELSIF RelF6(i) = 4 THEN polynomial(GF(i), KF(i))(r) >= 0
                    ELSIF RelF6(i) = 5 THEN polynomial(GF(i), KF(i))(r) <= 0
                    ELSE TRUE
                    ENDIF))});

  % Subtype TCC generated (at line 96, column 45) for  GP(i)
      % expected type  {i_1: int | RelF(i) /= 0 OR i_1 >= 0}
  sign_prod_TCC1: OBLIGATION
    FORALL (GP: [nat -> subrange(0, 2)], RelF: [nat -> subrange(-1, 1)],
            i: nat):
      RelF(i) /= 0 OR GP(i) >= 0;

  % Subtype TCC generated (at line 96, column 4) for
      % product[nat](0, k, LAMBDA (i: nat): RelF(i) ^ GP(i))
      % expected type  subrange(-1, 1)
  sign_prod_TCC2: OBLIGATION
    FORALL (k: nat, GP: [nat -> subrange(0, 2)],
            RelF: [nat -> subrange(-1, 1)]):
      rational_pred(product[nat](0, k, LAMBDA (i: nat): RelF(i) ^ GP(i))) AND
       integer_pred(product[nat](0, k, LAMBDA (i: nat): RelF(i) ^ GP(i))) AND
        -1 <= product[nat](0, k, LAMBDA (i: nat): RelF(i) ^ GP(i)) AND
         product[nat](0, k, LAMBDA (i: nat): RelF(i) ^ GP(i)) <= 1;

  % Subtype TCC generated (at line 101, column 33) for  k
      % expected type  {i: int | x /= 0 OR i >= 0}
  sign_ext_pow_TCC1: OBLIGATION FORALL (k: nat, x: real): x /= 0 OR k >= 0;

  % Subtype TCC generated (at line 101, column 48) for  k
      % expected type  {i: int | sign_ext(x) /= 0 OR i >= 0}
  sign_ext_pow_TCC2: OBLIGATION
    FORALL (k: nat, x: real): sign_ext(x) /= 0 OR k >= 0;

  % Subtype TCC generated (at line 105, column 95) for  RelFF
      % expected type  [nat -> subrange(-1, 1)]
  sign_ext_prod_polynomials_TCC1: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat], x: real,
            RelFF:
              [i: nat ->
                 {sig: real |
                          (sig = -1 OR sig = 1 OR sig = 0) AND
                           sig * polynomial(GF(i), KF(i))(x) =
                            abs(polynomial(GF(i), KF(i))(x))}]):
      (RelFF = (LAMBDA (i: nat): sign_ext(polynomial(GF(i), KF(i))(x))))
       IMPLIES
       (FORALL (x1: nat):
          rational_pred(RelFF(x1)) AND
           integer_pred(RelFF(x1)) AND -1 <= RelFF(x1) AND RelFF(x1) <= 1);

  % Subtype TCC generated (at line 125, column 44) for  mod(ii, 3)
      % expected type  subrange(0, 2)
  unsig_TCC1: OBLIGATION
    FORALL (ii: subrange(-1, 1)): 0 <= mod(ii, 3) AND mod(ii, 3) <= 2;

  % Subtype TCC generated (at line 136, column 68) for  k - p
      % expected type  nat
  base_3_seq_TCC1: OBLIGATION
    FORALL (k: nat, p: nat): p <= k IMPLIES k - p >= 0;

  % Subtype TCC generated (at line 136, column 56) for  base_n(3, i)(k - p)
      % expected type  subrange(0, 2)
  base_3_seq_TCC2: OBLIGATION
    FORALL (k: nat, i: nat, p: nat):
      p <= k IMPLIES 0 <= base_n(3, i)(k - p) AND base_n(3, i)(k - p) <= 2;

  % Subtype TCC generated (at line 138, column 56) for  base_n(6, i)(k - p)
      % expected type  subrange(0, 5)
  base_6_seq_TCC1: OBLIGATION
    FORALL (k: nat, i: nat, p: nat):
      p <= k IMPLIES 0 <= base_n(6, i)(k - p) AND base_n(6, i)(k - p) <= 5;

  % Subtype TCC generated (at line 144, column 12) for  base_n(3, i)
      % expected type  [nat -> subrange(0, 2)]
  sig_seq_base_3_onto_2_TCC1: OBLIGATION
    FORALL (RelF: [nat -> subrange(-1, 1)], k: nat, i: below(3 ^ (k + 1))):
      FORALL (x1: nat): 0 <= base_n(3, i)(x1) AND base_n(3, i)(x1) <= 2;

  % Subtype TCC generated (at line 147, column 12) for  base_6_seq(k, i)
      % expected type  [nat -> subrange(0, 2)]
  sig_seq_base_6_onto_TCC1: OBLIGATION
    FORALL (RelF: [nat -> subrange(-1, 1)], k: nat, i: below(6 ^ (k + 1))):
      (FORALL (j: nat): base_6_seq(k, i)(j) <= 2) IMPLIES
       (FORALL (x1: nat):
          0 <= base_6_seq(k, i)(x1) AND base_6_seq(k, i)(x1) <= 2);

  % Subtype TCC generated (at line 150, column 12) for  base_n(6, i)
      % expected type  [nat -> subrange(0, 2)]
  sig_seq_base_6_onto_2_TCC1: OBLIGATION
    FORALL (RelF: [nat -> subrange(-1, 1)], k: nat, i: below(6 ^ (k + 1))):
      (FORALL (j: nat): base_n(6, i)(j) <= 2) IMPLIES
       (FORALL (x1: nat): 0 <= base_n(6, i)(x1) AND base_n(6, i)(x1) <= 2);

  % Subtype TCC generated (at line 162, column 19) for  setseq(0)
      % expected type  {Aset: set[real] |
                     %          FORALL (x):
                     %            Aset(x) IFF
                     %             (EXISTS (i: upto(k)): setseq(i)(x))}
  union_upto_TCC1: OBLIGATION
    FORALL (k: nat, setseq: [nat -> set[real]]):
      k = 0 IMPLIES
       (FORALL (x): setseq(0)(x) IFF (EXISTS (i: upto(k)): setseq(i)(x)));

  % Subtype TCC generated (at line 162, column 57) for  k - 1
      % expected type  nat
  union_upto_TCC2: OBLIGATION FORALL (k: nat): NOT k = 0 IMPLIES k - 1 >= 0;

  % Termination TCC generated (at line 162, column 46) for
      % union_upto(k - 1, setseq)
  union_upto_TCC3: OBLIGATION FORALL (k: nat): NOT k = 0 IMPLIES k - 1 < k;

  % Subtype TCC generated (at line 162, column 34) for
      % union[real](union_upto(k - 1, setseq), setseq(k))
      % expected type  {Aset: set[real] |
                     %          FORALL (x):
                     %            Aset(x) IFF
                     %             (EXISTS (i: upto(k)): setseq(i)(x))}
  union_upto_TCC4: OBLIGATION
    FORALL (k: nat, setseq: [nat -> set[real]]):
      NOT k = 0 IMPLIES
       (FORALL (x,
                v:
                  [d1: {z: [nat, [nat -> set[real]]] | z`1 < k} ->
                     {Aset: set[real] |
                              FORALL (x):
                                Aset(x) IFF
                                 (EXISTS (i: upto(d1`1)): d1`2(i)(x))}]):
          union[real](v(k - 1, setseq), setseq(k))(x) IFF
           (EXISTS (i: upto(k)): setseq(i)(x)));

  % Subtype TCC generated (at line 174, column 72) for  setseq(i)
      % expected type  S: finite_set[real]
  real_set_disj_union_cards_TCC1: OBLIGATION
    FORALL (k: nat, setseq: [nat -> set[real]]):
      (FORALL (i: nat): is_finite[real](setseq(i))) AND
       is_finite[real](union_upto(k, setseq)) AND
        (FORALL (i, j: nat):
           i /= j IMPLIES disjoint?[real](setseq(i), setseq(j)))
       IMPLIES (FORALL (i1: nat): is_finite[real](setseq(i1)));

  % Subtype TCC generated (at line 180, column 12) for  3 ^ (k + 1) - 1
      % expected type  T_high[nat]
  mult_tarski_query_simple_TCC1: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat], a: [nat -> int],
            k: nat, n: posnat):
      (FORALL (i: upto(k)): GF(i)(KF(i)) /= 0) AND a(n) /= 0 IMPLIES
       3 ^ (k + 1) - 1 >= 0 OR (EXISTS (j: nat): 3 ^ (k + 1) - 1 <= j);

  % Subtype TCC generated (at line 181, column 29) for  base_n(3, i)
      % expected type  [nat -> subrange(0, 2)]
  mult_tarski_query_simple_TCC2: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat], a: [nat -> int],
            k: nat, n: posnat):
      (FORALL (i: upto(k)): GF(i)(KF(i)) /= 0) AND a(n) /= 0 IMPLIES
       (FORALL (i1: nat):
          FORALL (x1: nat):
            0 <= base_n(3, i1)(x1) AND base_n(3, i1)(x1) <= 2);

  % Subtype TCC generated (at line 197, column 20) for
      % split_index_fun_entry(F, n)
      % expected type  {G: [nat -> [nat, nat]] |
                     %          (FORALL (i: upto(n)):
                     %             G(i) = split_index_fun_entry(F, i)(i))
                     %           AND (FORALL (i: above(n)): G(i) = F(i))}
  split_index_fun_TCC1: OBLIGATION
    FORALL (F: [nat -> [nat, nat]], n: nat):
      n = 0 IMPLIES
       (FORALL (i: upto(n)):
          split_index_fun_entry(F, n)(i) = split_index_fun_entry(F, i)(i))
        AND (FORALL (i: above(n)): split_index_fun_entry(F, n)(i) = F(i));

  % Subtype TCC generated (at line 198, column 11) for
      % split_index_fun(split_index_fun_entry(F, n), n - 1)
      % expected type  {G: [nat -> [nat, nat]] |
                     %          (FORALL (i: upto(n)):
                     %             G(i) = split_index_fun_entry(F, i)(i))
                     %           AND (FORALL (i: above(n)): G(i) = F(i))}
  split_index_fun_TCC2: OBLIGATION
    FORALL (F: [nat -> [nat, nat]], n: nat,
            v:
              [d1: {z: [[nat -> [nat, nat]], nat] | z`2 < n} ->
                 {G: [nat -> [nat, nat]] |
                          (FORALL (i: upto(d1`2)):
                             G(i) = split_index_fun_entry(d1`1, i)(i))
                           AND (FORALL (i: above(d1`2)): G(i) = d1`1(i))}]):
      NOT n = 0 IMPLIES
       (FORALL (i: upto(n)):
          v(split_index_fun_entry(F, n), n - 1)(i) =
           split_index_fun_entry(F, i)(i))
        AND
        (FORALL (i: above(n)):
           v(split_index_fun_entry(F, n), n - 1)(i) = F(i));

  % Subtype TCC generated (at line 208, column 38) for  n - 1
      % expected type  nat
  split_base6_TCC1: OBLIGATION FORALL (n: posnat): n - 1 >= 0;

  % Subtype TCC generated (at line 221, column 32) for  base_n(6, i)
      % expected type  [nat -> subrange(0, 2)]
  sign_prod_coeff6_TCC1: OBLIGATION
    FORALL (k: nat, GP: [nat -> subrange(0, 2)], i: nat):
      NOT i >= 6 ^ (k + 1) AND
       NOT (EXISTS (p: upto(k)): base_n(6, i)(p) >= 3)
       IMPLIES
       (FORALL (x1: nat): 0 <= base_n(6, i)(x1) AND base_n(6, i)(x1) <= 2);

  % Subtype TCC generated (at line 225, column 34) for  base_n(6, i)
      % expected type  [nat -> subrange(0, 2)]
  NSol_seq6_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0), i: nat):
      NOT i >= 6 ^ (k + 1) AND
       NOT (EXISTS (p: upto(k)): base_n(6, i)(p) >= 3)
       IMPLIES
       (FORALL (x1: nat): 0 <= base_n(6, i)(x1) AND base_n(6, i)(x1) <= 2);

  % Subtype TCC generated (at line 231, column 12) for  6 ^ (k + 1) - 1
      % expected type  T_high[nat]
  mult_tarski_query_simple_6_0_to_3_TCC1: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat], a: [nat -> int],
            k: nat, n: posnat):
      (FORALL (i: upto(k)): GF(i)(KF(i)) /= 0) AND a(n) /= 0 IMPLIES
       6 ^ (k + 1) - 1 >= 0 OR (EXISTS (j: nat): 6 ^ (k + 1) - 1 <= j);

  % Subtype TCC generated (at line 251, column 9) for
      % product[nat](0, k, LAMBDA (j): sign_coeff6_zero_entry(k, TQRow, i, j))
      % expected type  subrange(-1, 1)
  sign_coeff6_zero_TCC1: OBLIGATION
    FORALL (k: nat, TQRow: [nat -> subrange(0, 5)], i: nat):
      NOT i >= 6 ^ (k + 1) IMPLIES
       rational_pred(product[nat]
                         (0, k,
                          LAMBDA (j):
                            sign_coeff6_zero_entry(k, TQRow, i, j)))
        AND
        integer_pred(product[nat]
                         (0, k,
                          LAMBDA (j):
                            sign_coeff6_zero_entry(k, TQRow, i, j)))
         AND
         -1 <=
          product[nat]
              (0, k, LAMBDA (j): sign_coeff6_zero_entry(k, TQRow, i, j))
          AND
          product[nat]
              (0, k, LAMBDA (j): sign_coeff6_zero_entry(k, TQRow, i, j))
           <= 1;

  % Subtype TCC generated (at line 266, column 22) for  6 ^ (k + 1) - 1
      % expected type  T_high[nat]
  sigma_disjoinction_6_TCC1: OBLIGATION
    FORALL (g: [nat -> int], k: nat,
            v: [nat -> [nat, nat, nat, nat, nat, nat]]):
      ((FORALL (j):
          j <= 6 ^ (k + 1) - 1 IMPLIES
           (EXISTS (i): i <= 6 ^ k - 1 AND in6?(v(i), j)))
        AND
        (FORALL (i):
           i <= 6 ^ k - 1 IMPLIES
            (     v(i)`1 < v(i)`2 AND v(i)`2 < v(i)`3 AND v(i)`3 < v(i)`4
              AND v(i)`4 < v(i)`5 AND v(i)`5 < v(i)`6
              AND v(i)`6 <= 6 ^ (k + 1) - 1))
         AND
         (FORALL (i, d, j):
                 i <= 6 ^ k - 1 AND d <= 6 ^ k - 1 AND j <= 6 ^ (k + 1) - 1
             AND in6?(v(i), j) AND in6?(v(d), j)
             IMPLIES i = d)
          AND
          (FORALL (i):
             i <= 6 ^ k - 1 IMPLIES
              (g(v(i)`1) + g(v(i)`2) + g(v(i)`3) + g(v(i)`4) + g(v(i)`5) +
                g(v(i)`6))
               = 0))
       IMPLIES
       6 ^ (k + 1) - 1 >= 0 OR (EXISTS (j: nat): 6 ^ (k + 1) - 1 <= j);

  % Subtype TCC generated (at line 273, column 55) for  base_n(6, i)
      % expected type  [nat -> subrange(0, 5)]
  mult_tarski_query_simple_6_above_2_TCC1: OBLIGATION
    FORALL (GF: [nat -> [nat -> int]], KF: [nat -> nat],
            TQRow: [nat -> subrange(0, 5)], a: [nat -> int], k: nat,
            n: posnat):
      (EXISTS (i: upto(k)): TQRow(i) > 2) AND
       (FORALL (i: upto(k)): GF(i)(KF(i)) /= 0) AND a(n) /= 0
       IMPLIES
       (FORALL (i1: nat):
          FORALL (x1: nat):
            0 <= base_n(6, i1)(x1) AND base_n(6, i1)(x1) <= 5);


body:
  tarski_query: THEORY
  BEGIN


  IMPORTING poly_families, reals@product_nat,
            matrices@tensor_product, matrices@matrices,
  	  matrices@query_coeff

    a,r,g : VAR [nat->int]
    n : VAR posnat
    d,i,j,k : VAR nat
    m: VAR posnat
    x,y,c,b : VAR real
    rel: VAR [[real,real]->bool]
    babove,bbelow,bbelow2,babove2: VAR bool

    % k is the degree of g

    NSol_squared_gt: LEMMA a(n)/=0 IMPLIES
      NSol(a,n,polynomial_prod(g,k,g,k),2*k,>) =
      NSol(a,n,g,k,/=)

    NSol_squared_lt: LEMMA a(n)/=0 IMPLIES
      NSol(a,n,polynomial_prod(g,k,g,k),2*k,<) = 0

    NSol_poly1_lt: LEMMA a(n)/=0 IMPLIES
      NSol(a,n,poly1,0,<)=0

    A3: {M: PosFullMatrix | rows(M)=3 AND columns(M)=3} =
      (: (: 1, 0, -1 :), (: 0, 1/2, 1/2 :), (: 0, -1/2, 1/2 :) :)

    A3_inv: {M: PosFullMatrix | rows(M)=3 AND columns(M)=3 AND det(M)/=0 AND inverse(M)=A3} =
      (: (: 1,1,1 :), (: 0,1,-1 :), (: 0,1,1 :) :)

    TQ_vect3(a,(n|a(n)/=0),g,(k|g(k)/=0)): {v: PosFullMatrix | rows(v)=3 AND columns(v)=1} =
      (: (: TQ(a,n,poly1,0) :),(: TQ(a,n,g,k) :), (: TQ(a,n,polynomial_prod(g,k,g,k),2*k) :) :)

    NSol_vect3(a,(n|a(n)/=0),g,(k|g(k)/=0)): {v: PosFullMatrix | rows(v)=3 AND columns(v)=1} =
      (: (: NSol(a,n,g,k,=) :),(: NSol(a,n,g,k,>) :), (: NSol(a,n,g,k,<) :) :)

    tarski_query_system_basic_3: LEMMA a(n)/=0 AND g(k)/=0 IMPLIES
      A3*TQ_vect3(a,n,g,k) = NSol_vect3(a,n,g,k)

    A6: {M: PosFullMatrix | rows(M)=6 AND columns(M)=3} =
      (: (: 1, 0, -1 :), 
         (: 0, 1/2, 1/2 :),	
         (: 0, -1/2, 1/2 :),
         (: 0,0,1 :), 
         (: 1,1/2,-1/2 :), 
         (: 1,-1/2,-1/2 :) :)

    NSol_vect6(a,(n|a(n)/=0),g,(k|g(k)/=0)): {v: PosFullMatrix | rows(v)=6 AND columns(v)=1} =
      (: (: NSol(a,n,g,k,=) :),(: NSol(a,n,g,k,>) :), (: NSol(a,n,g,k,<) :),
         (: NSol(a,n,g,k,/=) :),(: NSol(a,n,g,k,>=) :), (: NSol(a,n,g,k,<=) :) :)

    tarski_query_system_basic_6: LEMMA a(n)/=0 AND g(k)/=0 IMPLIES
      A6*TQ_vect3(a,n,g,k) = NSol_vect6(a,n,g,k)

  END tarski_query

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

  % Subtype TCC generated (at line 30, column 7) for  (: 1, 0, -1 :)
      % expected type  list[real]
  A3_TCC1: OBLIGATION
    every[number]
        (LAMBDA (x: number): number_field_pred(x) AND real_pred(x))
        ((: 1, 0, -1 :));

  % Subtype TCC generated (at line 30, column 23) for
      % (: (: 0, 1 / 2, 1 / 2 :), (: 0, -1 / 2, 1 / 2 :) :)
      % expected type  list[list[real]]
  A3_TCC2: OBLIGATION
    every[list[number]]
        (LAMBDA (x: list[number]):
           every[number]
               (LAMBDA (x: number): number_field_pred(x) AND real_pred(x))(x))
        ((: (: 0, 1 / 2, 1 / 2 :), (: 0, -1 / 2, 1 / 2 :) :));

  % Subtype TCC generated (at line 30, column 4) for
      % (: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :), (: 0, -1 / 2, 1 / 2 :) :)
      % expected type  {M: PosFullMatrix | rows(M) = 3 AND columns(M) = 3}
  A3_TCC3: OBLIGATION
         null?[list[real]]
             ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                 (: 0, -1 / 2, 1 / 2 :) :))
          OR
          (FORALL (i,
                   j:
                     below(length[list[real]]
                               ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                                   (: 0, -1 / 2, 1 / 2 :) :)))):
             length[real]
                 (nth[list[real]]
                      ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                          (: 0, -1 / 2, 1 / 2 :) :),
                       i))
              =
              length[real]
                  (nth[list[real]]
                       ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                           (: 0, -1 / 2, 1 / 2 :) :),
                        j)))
     AND rows((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                 (: 0, -1 / 2, 1 / 2 :) :))
          > 0
     AND columns((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                    (: 0, -1 / 2, 1 / 2 :) :))
          > 0
     AND rows((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                 (: 0, -1 / 2, 1 / 2 :) :))
          = 3
     AND columns((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                    (: 0, -1 / 2, 1 / 2 :) :))
          = 3;

  % Subtype TCC generated (at line 32, column 83) for  M
      % expected type  SQ: {SQ | det(SQ) /= 0 OR invertible?(SQ)}
  A3_inv_TCC1: OBLIGATION
    FORALL (M: PosFullMatrix):
      det(M) /= 0 AND columns(M) = 3 AND rows(M) = 3 IMPLIES
       rows(M) = columns(M) AND (det(M) /= 0 OR invertible?(M));

  % Subtype TCC generated (at line 33, column 7) for  (: 1, 1, 1 :)
      % expected type  list[real]
  A3_inv_TCC2: OBLIGATION
    every[number]
        (LAMBDA (x: number): number_field_pred(x) AND real_pred(x))
        ((: 1, 1, 1 :));

  % Subtype TCC generated (at line 33, column 20) for
      % (: (: 0, 1, -1 :), (: 0, 1, 1 :) :)
      % expected type  list[list[real]]
  A3_inv_TCC3: OBLIGATION
    every[list[number]]
        (LAMBDA (x: list[number]):
           every[number]
               (LAMBDA (x: number): number_field_pred(x) AND real_pred(x))(x))
        ((: (: 0, 1, -1 :), (: 0, 1, 1 :) :));

  % Subtype TCC generated (at line 33, column 4) for
      % (: (: 1, 1, 1 :), (: 0, 1, -1 :), (: 0, 1, 1 :) :)
      % expected type  {M: PosFullMatrix |
                     %          rows(M) = 3 AND
                     %           columns(M) = 3 AND
                     %            det(M) /= 0 AND inverse(M) = A3}
  A3_inv_TCC4: OBLIGATION
         null?[list[real]]
             ((: (: 1, 1, 1 :), (: 0, 1, -1 :), (: 0, 1, 1 :) :))
          OR
          (FORALL (i,
                   j:
                     below(length[list[real]]
                               ((: (: 1, 1, 1 :), (: 0, 1, -1 :),
                                   (: 0, 1, 1 :) :)))):
             length[real]
                 (nth[list[real]]
                      ((: (: 1, 1, 1 :), (: 0, 1, -1 :), (: 0, 1, 1 :) :),
                       i))
              =
              length[real]
                  (nth[list[real]]
                       ((: (: 1, 1, 1 :), (: 0, 1, -1 :), (: 0, 1, 1 :) :),
                        j)))
     AND rows((: (: 1, 1, 1 :), (: 0, 1, -1 :), (: 0, 1, 1 :) :)) > 0
     AND columns((: (: 1, 1, 1 :), (: 0, 1, -1 :), (: 0, 1, 1 :) :)) > 0
     AND rows((: (: 1, 1, 1 :), (: 0, 1, -1 :), (: 0, 1, 1 :) :)) = 3
     AND columns((: (: 1, 1, 1 :), (: 0, 1, -1 :), (: 0, 1, 1 :) :)) = 3
     AND det((: (: 1, 1, 1 :), (: 0, 1, -1 :), (: 0, 1, 1 :) :)) /= 0
     AND inverse((: (: 1, 1, 1 :), (: 0, 1, -1 :), (: 0, 1, 1 :) :)) = A3;

  % Subtype TCC generated (at line 36, column 23) for  0
      % expected type  {k | poly1(k) /= 0}
  TQ_vect3_TCC1: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0)):
      poly1(0) /= 0;

  % Subtype TCC generated (at line 36, column 58) for
      % polynomial_prod(g, k, g, k)
      % expected type  [nat -> int]
  TQ_vect3_TCC2: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0)):
      FORALL (x1: nat):
        rational_pred(polynomial_prod(g, k, g, k)(x1)) AND
         integer_pred(polynomial_prod(g, k, g, k)(x1));

  % Subtype TCC generated (at line 36, column 83) for  2 * k
      % expected type  {k_1 | polynomial_prod(g, k, g, k)(k_1) /= 0}
  TQ_vect3_TCC3: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0)):
      polynomial_prod(g, k, g, k)(2 * k) /= 0;

  % Subtype TCC generated (at line 36, column 4) for
      % (: (: TQ(a, n, poly1, 0) :), (: TQ(a, n, g, k) :),
      %    (: TQ(a, n, polynomial_prod(g, k, g, k), 2 * k) :) :)
      % expected type  {v: PosFullMatrix | rows(v) = 3 AND columns(v) = 1}
  TQ_vect3_TCC4: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0)):
           null?[list[real]]
               ((: (: TQ(a, n, poly1, 0) :), (: TQ(a, n, g, k) :),
                   (: TQ(a, n, polynomial_prod(g, k, g, k), 2 * k) :) :))
            OR
            (FORALL (i,
                     j:
                       below(length[list[real]]
                                 ((: (: TQ(a, n, poly1, 0) :),
                                     (: TQ(a, n, g, k) :),
                                     (: TQ
                                        (a,
                                         n,
                                         polynomial_prod(g, k, g, k),
                                         2 * k) :) :)))):
               length[real]
                   (nth[list[real]]
                        ((: (: TQ(a, n, poly1, 0) :), (: TQ(a, n, g, k) :),
                            (: TQ(a, n, polynomial_prod(g, k, g, k),
                                  2 * k) :) :),
                         i))
                =
                length[real]
                    (nth[list[real]]
                         ((: (: TQ(a, n, poly1, 0) :), (: TQ(a, n, g, k) :),
                             (: TQ(a, n, polynomial_prod(g, k, g, k),
                                   2 * k) :) :),
                          j)))
       AND rows((: (: TQ(a, n, poly1, 0) :), (: TQ(a, n, g, k) :),
                   (: TQ(a, n, polynomial_prod(g, k, g, k), 2 * k) :) :))
            > 0
       AND columns((: (: TQ(a, n, poly1, 0) :), (: TQ(a, n, g, k) :),
                      (: TQ(a, n, polynomial_prod(g, k, g, k), 2 * k) :) :))
            > 0
       AND rows((: (: TQ(a, n, poly1, 0) :), (: TQ(a, n, g, k) :),
                   (: TQ(a, n, polynomial_prod(g, k, g, k), 2 * k) :) :))
            = 3
       AND columns((: (: TQ(a, n, poly1, 0) :), (: TQ(a, n, g, k) :),
                      (: TQ(a, n, polynomial_prod(g, k, g, k), 2 * k) :) :))
            = 1;

  % Subtype TCC generated (at line 39, column 4) for
      % (: (: NSol(a, n, g, k,
      %            restrict[[number, number], [real, real], boolean](=)) :),
      %    (: NSol(a, n, g, k, >) :), (: NSol(a, n, g, k, <) :) :)
      % expected type  {v: PosFullMatrix | rows(v) = 3 AND columns(v) = 1}
  NSol_vect3_TCC1: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0)):
           null?[list[real]]
               ((: (: NSol(a, n, g, k,
                           restrict[[number, number], [real, real], boolean]
                               (=)) :),
                   (: NSol(a, n, g, k, >) :), (: NSol(a, n, g, k, <) :) :))
            OR
            (FORALL (i,
                     j:
                       below(length[list[real]]
                                 ((: (: NSol
                                        (a,
                                         n,
                                         g,
                                         k,
                                         restrict
                                         [[number, number],
                                          [real, real],
                                          boolean]
                                         (=)) :),
                                     (: NSol(a, n, g, k, >) :),
                                     (: NSol(a, n, g, k, <) :) :)))):
               length[real]
                   (nth[list[real]]
                        ((: (: NSol(a, n, g, k,
                                    restrict
                                        [[number, number],
                                         [real, real],
                                         boolean]
                                        (=)) :),
                            (: NSol(a, n, g, k, >) :),
                            (: NSol(a, n, g, k, <) :) :),
                         i))
                =
                length[real]
                    (nth[list[real]]
                         ((: (: NSol(a, n, g, k,
                                     restrict
                                         [[number, number],
                                          [real, real],
                                          boolean]
                                         (=)) :),
                             (: NSol(a, n, g, k, >) :),
                             (: NSol(a, n, g, k, <) :) :),
                          j)))
       AND rows((: (: NSol(a, n, g, k,
                           restrict[[number, number], [real, real], boolean]
                               (=)) :),
                   (: NSol(a, n, g, k, >) :), (: NSol(a, n, g, k, <) :) :))
            > 0
       AND columns((: (: NSol(a, n, g, k,
                              restrict
                                  [[number, number], [real, real], boolean]
                                  (=)) :),
                      (: NSol(a, n, g, k, >) :),
                      (: NSol(a, n, g, k, <) :) :))
            > 0
       AND rows((: (: NSol(a, n, g, k,
                           restrict[[number, number], [real, real], boolean]
                               (=)) :),
                   (: NSol(a, n, g, k, >) :), (: NSol(a, n, g, k, <) :) :))
            = 3
       AND columns((: (: NSol(a, n, g, k,
                              restrict
                                  [[number, number], [real, real], boolean]
                                  (=)) :),
                      (: NSol(a, n, g, k, >) :),
                      (: NSol(a, n, g, k, <) :) :))
            = 1;

  % Subtype TCC generated (at line 46, column 7) for
      % (: (: 0, 1 / 2, 1 / 2 :), (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
      %    (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :)
      % expected type  list[list[real]]
  A6_TCC1: OBLIGATION
    every[list[number]]
        (LAMBDA (x: list[number]):
           every[number]
               (LAMBDA (x: number): number_field_pred(x) AND real_pred(x))(x))
        ((: (: 0, 1 / 2, 1 / 2 :), (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
            (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :));

  % Subtype TCC generated (at line 45, column 4) for
      % (: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :), (: 0, -1 / 2, 1 / 2 :),
      %    (: 0, 0, 1 :), (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :)
      % expected type  {M: PosFullMatrix | rows(M) = 6 AND columns(M) = 3}
  A6_TCC2: OBLIGATION
         null?[list[real]]
             ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                 (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                 (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :))
          OR
          (FORALL (i,
                   j:
                     below(length[list[real]]
                               ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                                   (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                                   (: 1, 1 / 2, -1 / 2 :),
                                   (: 1, -1 / 2, -1 / 2 :) :)))):
             length[real]
                 (nth[list[real]]
                      ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                          (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                          (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :),
                       i))
              =
              length[real]
                  (nth[list[real]]
                       ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                           (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                           (: 1, 1 / 2, -1 / 2 :),
                           (: 1, -1 / 2, -1 / 2 :) :),
                        j)))
     AND rows((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                 (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                 (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :))
          > 0
     AND columns((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                    (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                    (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :))
          > 0
     AND rows((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                 (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                 (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :))
          = 6
     AND columns((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                    (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                    (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :))
          = 3;

  % Subtype TCC generated (at line 53, column 4) for
      % (: (: NSol(a, n, g, k,
      %            restrict[[number, number], [real, real], boolean](=)) :),
      %    (: NSol(a, n, g, k, >) :), (: NSol(a, n, g, k, <) :),
      %    (: NSol(a, n, g, k,
      %            restrict[[number, number], [real, real], boolean](/=)) :),
      %    (: NSol(a, n, g, k, >=) :), (: NSol(a, n, g, k, <=) :) :)
      % expected type  {v: PosFullMatrix | rows(v) = 6 AND columns(v) = 1}
  NSol_vect6_TCC1: OBLIGATION
    FORALL (a: [nat -> int], (n: posnat | a(n) /= 0), g: [nat -> int],
            (k: nat | g(k) /= 0)):
           null?[list[real]]
               ((: (: NSol(a, n, g, k,
                           restrict[[number, number], [real, real], boolean]
                               (=)) :),
                   (: NSol(a, n, g, k, >) :), (: NSol(a, n, g, k, <) :),
                   (: NSol(a, n, g, k,
                           restrict[[number, number], [real, real], boolean]
                               (/=)) :),
                   (: NSol(a, n, g, k, >=) :), (: NSol(a, n, g, k, <=) :) :))
            OR
            (FORALL (i,
                     j:
                       below(length[list[real]]
                                 ((: (: NSol
                                        (a,
                                         n,
                                         g,
                                         k,
                                         restrict
                                         [[number, number],
                                          [real, real],
                                          boolean]
                                         (=)) :),
                                     (: NSol(a, n, g, k, >) :),
                                     (: NSol(a, n, g, k, <) :),
                                     (: NSol
                                        (a,
                                         n,
                                         g,
                                         k,
                                         restrict
                                         [[number, number],
                                          [real, real],
                                          boolean]
                                         (/=)) :),
                                     (: NSol(a, n, g, k, >=) :),
                                     (: NSol(a, n, g, k, <=) :) :)))):
               length[real]
                   (nth[list[real]]
                        ((: (: NSol(a, n, g, k,
                                    restrict
                                        [[number, number],
                                         [real, real],
                                         boolean]
                                        (=)) :),
                            (: NSol(a, n, g, k, >) :),
                            (: NSol(a, n, g, k, <) :),
                            (: NSol(a, n, g, k,
                                    restrict
                                        [[number, number],
                                         [real, real],
                                         boolean]
                                        (/=)) :),
                            (: NSol(a, n, g, k, >=) :),
                            (: NSol(a, n, g, k, <=) :) :),
                         i))
                =
                length[real]
                    (nth[list[real]]
                         ((: (: NSol(a, n, g, k,
                                     restrict
                                         [[number, number],
                                          [real, real],
                                          boolean]
                                         (=)) :),
                             (: NSol(a, n, g, k, >) :),
                             (: NSol(a, n, g, k, <) :),
                             (: NSol(a, n, g, k,
                                     restrict
                                         [[number, number],
                                          [real, real],
                                          boolean]
                                         (/=)) :),
                             (: NSol(a, n, g, k, >=) :),
                             (: NSol(a, n, g, k, <=) :) :),
                          j)))
       AND rows((: (: NSol(a, n, g, k,
                           restrict[[number, number], [real, real], boolean]
                               (=)) :),
                   (: NSol(a, n, g, k, >) :), (: NSol(a, n, g, k, <) :),
                   (: NSol(a, n, g, k,
                           restrict[[number, number], [real, real], boolean]
                               (/=)) :),
                   (: NSol(a, n, g, k, >=) :), (: NSol(a, n, g, k, <=) :) :))
            > 0
       AND columns((: (: NSol(a, n, g, k,
                              restrict
                                  [[number, number], [real, real], boolean]
                                  (=)) :),
                      (: NSol(a, n, g, k, >) :), (: NSol(a, n, g, k, <) :),
                      (: NSol(a, n, g, k,
                              restrict
                                  [[number, number], [real, real], boolean]
                                  (/=)) :),
                      (: NSol(a, n, g, k, >=) :),
                      (: NSol(a, n, g, k, <=) :) :))
            > 0
       AND rows((: (: NSol(a, n, g, k,
                           restrict[[number, number], [real, real], boolean]
                               (=)) :),
                   (: NSol(a, n, g, k, >) :), (: NSol(a, n, g, k, <) :),
                   (: NSol(a, n, g, k,
                           restrict[[number, number], [real, real], boolean]
                               (/=)) :),
                   (: NSol(a, n, g, k, >=) :), (: NSol(a, n, g, k, <=) :) :))
            = 6
       AND columns((: (: NSol(a, n, g, k,
                              restrict
                                  [[number, number], [real, real], boolean]
                                  (=)) :),
                      (: NSol(a, n, g, k, >) :), (: NSol(a, n, g, k, <) :),
                      (: NSol(a, n, g, k,
                              restrict
                                  [[number, number], [real, real], boolean]
                                  (/=)) :),
                      (: NSol(a, n, g, k, >=) :),
                      (: NSol(a, n, g, k, <=) :) :))
            = 1;


body:
  tarski_query_matrix: THEORY
  BEGIN


  IMPORTING tarski_query

    a,r,g : VAR [nat->int]
    n : VAR posnat
    d,i,j,k : VAR nat
    m: VAR posnat
    %m : VAR posnat
    x,y,c,b : VAR real
    rel: VAR [[real,real]->bool]
    babove,bbelow,bbelow2,babove2: VAR bool
    p : VAR nat


    GF: VAR [nat->[nat->int]]
    KF: VAR [nat->nat] % degrees
    GP: VAR [nat->subrange(0,2)]
    RelF,RelF1,RelF2: VAR [nat->subrange(-1,1)]
    ll: VAR list[int]

    TQ_vect3k(k,a,(n|a(n)/=0),GF,(KF|FORALL (i:upto(k)):GF(i)(KF(i))/=0)): {v: PosFullMatrix | rows(v)=3^(k+1) AND columns(v)=1} =
      LET GPFun = (LAMBDA (i,j): base_n(3,i)),
      	eij = (LAMBDA (i,j): IF i>=3^(k+1) OR j>=1 THEN 0 ELSE TQ_fam(k,a,n,GF,KF,GPFun(i,j)) ENDIF)
      IN form_matrix(eij,3^(k+1),1)

    TQ_vect6k(k,a,(n|a(n)/=0),GF,(KF|FORALL (i:upto(k)):GF(i)(KF(i))/=0)): {v: PosFullMatrix | rows(v)=6^(k+1) AND columns(v)=1} =
      LET GPFun = (LAMBDA (i,j): base_n(6,i)),
      	eij = (LAMBDA (i,j): IF i>=6^(k+1) OR j>=1 OR (EXISTS (p:upto(k)): GPFun(i,j)(p)>2) THEN 0 ELSE TQ_fam(k,a,n,GF,KF,GPFun(i,j)) ENDIF)
      IN form_matrix(eij,6^(k+1),1)

    NSol_vect3k(k,a,(n|a(n)/=0),GF,(KF|FORALL (i:upto(k)):GF(i)(KF(i))/=0)): {v: PosFullMatrix | rows(v)=3^(k+1) AND columns(v)=1} =
      LET eij = (LAMBDA (i,j): IF i>=3^(k+1) OR j>=1 THEN 0 ELSE NSol(k,a,n,GF,KF,sig_seq(base_n(3,i))) ENDIF)
      IN form_matrix(eij,3^(k+1),1)

    NSol_vect6k(k,a,(n|a(n)/=0),GF,(KF|FORALL (i:upto(k)):GF(i)(KF(i))/=0)): {v: PosFullMatrix | rows(v)=6^(k+1) AND columns(v)=1} =
      LET eij = (LAMBDA (i,j): IF i>=6^(k+1) OR j>=1 THEN 0 ELSE NSol_all(k,a,n,GF,KF,base_n(6,i)) ENDIF)
      IN form_matrix(eij,6^(k+1),1)

    A66_inv: {M: PosFullMatrix | rows(M)=6 AND columns(M)=6} =
      (: (: 1,   1,   1, 0, 0, 0 :), 
        	       	     (: 0,   1,  -1, 0, 0, 0 :), 
  		     (: 0,   1,   1, 0, 0, 0 :), 
  		     (: 0,  -1,  -1, 1, 0, 0 :), 
  		     (:-1,  -1,   0, 0, 1, 0 :), 
  		     (:-1,   0,  -1, 0, 0, 1 :) :)

    A66: {M: PosFullMatrix | rows(M)=6 AND columns(M)=6 AND M = inverse(A66_inv)} = 
     (: (: 1, 0, -1, 0, 0, 0 :), (: 0, 1/2, 1/2, 0, 0, 0 :),
     (: 0, -1/2, 1/2, 0, 0, 0 :), (: 0, 0, 1, 1, 0, 0 :),
     (: 1, 1/2, -1/2, 0, 1, 0 :), (: 1, -1/2, -1/2, 0, 0, 1 :) :)

    multi_sturm_tarski_6by6: LEMMA a(n)/=0 AND 
      (FORALL (i:upto(k)):GF(i)(KF(i))/=0)
      IMPLIES
      TQ_vect6k(k,a,n,GF,	KF) = tensor_power_alt(A66_inv,k+1)*
      NSol_vect6k(k,a,n,GF,KF)

    multi_sturm_tarski_NSol: LEMMA a(n)/=0 AND 
      (FORALL (i:upto(k)):GF(i)(KF(i))/=0)
      IMPLIES
      NSol_vect6k(k,a,n,GF,KF) = tensor_power_alt(A66,k+1)*
      TQ_vect6k(k,a,n,GF,	KF)

    A63: {M: PosFullMatrix | rows(M)=6 AND columns(M)=3} = 
     (: (: 1, 0, -1  :), (: 0, 1/2, 1/2  :),
     (: 0, -1/2, 1/2  :), (: 0, 0, 1 :),
     (: 1, 1/2, -1/2 :), (: 1, -1/2, -1/2 :) :)

    A63_def: LEMMA FORALL (i:upto(5),j:upto(2)):
      entry(A63)(i,j) = entry(A66)(i,j)

    multi_sturm_tarski_NSol63: LEMMA a(n)/=0 AND 
      (FORALL (i:upto(k)):GF(i)(KF(i))/=0)
      IMPLIES
      NSol_vect6k(k,a,n,GF,KF) = tensor_power_alt(A63,k+1)*
      TQ_vect3k(k,a,n,GF,	KF)





  END tarski_query_matrix

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

  % Subtype TCC generated (at line 26, column 79) for  GPFun(i, j)
      % expected type  [nat -> subrange(0, 2)]
  TQ_vect3k_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]],
            (KF: [nat -> nat] | FORALL (i: upto(k)): GF(i)(KF(i)) /= 0),
            GPFun: [[nat, nat] -> [nat -> nat]]):
      GPFun = (LAMBDA (i, j): base_n(3, i)) IMPLIES
       (FORALL (i1: nat, j1: nat):
          NOT i1 >= 3 ^ (k + 1) AND NOT j1 >= 1 IMPLIES
           (FORALL (x1: nat):
              0 <= GPFun(i1, j1)(x1) AND GPFun(i1, j1)(x1) <= 2));

  % Subtype TCC generated (at line 27, column 7) for
      % form_matrix(eij, 3 ^ (k + 1), 1)
      % expected type  {v: PosFullMatrix |
                     %          rows(v) = 3 ^ (1 + k) AND columns(v) = 1}
  TQ_vect3k_TCC2: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]],
            (KF: [nat -> nat] | FORALL (i: upto(k)): GF(i)(KF(i)) /= 0),
            GPFun: [[nat, nat] -> [nat -> nat]]):
      GPFun = (LAMBDA (i, j): base_n(3, i)) IMPLIES
       (FORALL (eij: [[nat, nat] -> int]):
          (eij =
            (LAMBDA (i, j):
               IF i >= 3 ^ (k + 1) OR j >= 1 THEN 0
               ELSE TQ_fam(k, a, n, GF, KF, GPFun(i, j))
               ENDIF))
           IMPLIES
           (rows(form_matrix(eij, 3 ^ (k + 1), 1)) = 3 ^ (1 + k) AND
             columns(form_matrix(eij, 3 ^ (k + 1), 1)) = 1)
            AND
            rows(form_matrix(eij, 3 ^ (k + 1), 1)) > 0 AND
             columns(form_matrix(eij, 3 ^ (k + 1), 1)) > 0);

  % Subtype TCC generated (at line 31, column 120) for  GPFun(i, j)
      % expected type  [nat -> subrange(0, 2)]
  TQ_vect6k_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]],
            (KF: [nat -> nat] | FORALL (i: upto(k)): GF(i)(KF(i)) /= 0),
            GPFun: [[nat, nat] -> [nat -> nat]]):
      GPFun = (LAMBDA (i, j): base_n(6, i)) IMPLIES
       (FORALL (i1: nat, j1: nat):
          NOT i1 >= 6 ^ (k + 1) AND
           NOT j1 >= 1 AND NOT (EXISTS (p: upto(k)): GPFun(i1, j1)(p) > 2)
           IMPLIES
           (FORALL (x1: nat):
              0 <= GPFun(i1, j1)(x1) AND GPFun(i1, j1)(x1) <= 2));

  % Subtype TCC generated (at line 32, column 7) for
      % form_matrix(eij, 6 ^ (k + 1), 1)
      % expected type  {v: PosFullMatrix |
                     %          rows(v) = 6 ^ (1 + k) AND columns(v) = 1}
  TQ_vect6k_TCC2: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]],
            (KF: [nat -> nat] | FORALL (i: upto(k)): GF(i)(KF(i)) /= 0),
            GPFun: [[nat, nat] -> [nat -> nat]]):
      GPFun = (LAMBDA (i, j): base_n(6, i)) IMPLIES
       (FORALL (eij: [[nat, nat] -> int]):
          (eij =
            (LAMBDA (i, j):
               IF i >= 6 ^ (k + 1) OR
                   j >= 1 OR (EXISTS (p: upto(k)): GPFun(i, j)(p) > 2)
                 THEN 0
               ELSE TQ_fam(k, a, n, GF, KF, GPFun(i, j))
               ENDIF))
           IMPLIES
           (rows(form_matrix(eij, 6 ^ (k + 1), 1)) = 6 ^ (1 + k) AND
             columns(form_matrix(eij, 6 ^ (k + 1), 1)) = 1)
            AND
            rows(form_matrix(eij, 6 ^ (k + 1), 1)) > 0 AND
             columns(form_matrix(eij, 6 ^ (k + 1), 1)) > 0);

  % Subtype TCC generated (at line 35, column 88) for  base_n(3, i)
      % expected type  [nat -> subrange(0, 2)]
  NSol_vect3k_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]],
            (KF: [nat -> nat] | FORALL (i: upto(k)): GF(i)(KF(i)) /= 0),
            i: nat, j: nat):
      NOT i >= 3 ^ (k + 1) AND NOT j >= 1 IMPLIES
       (FORALL (x1: nat): 0 <= base_n(3, i)(x1) AND base_n(3, i)(x1) <= 2);

  % Subtype TCC generated (at line 36, column 7) for
      % form_matrix(eij, 3 ^ (k + 1), 1)
      % expected type  {v: PosFullMatrix |
                     %          rows(v) = 3 ^ (1 + k) AND columns(v) = 1}
  NSol_vect3k_TCC2: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]],
            (KF: [nat -> nat] | FORALL (i: upto(k)): GF(i)(KF(i)) /= 0),
            eij: [[nat, nat] -> naturalnumber]):
      (eij =
        (LAMBDA (i, j):
           IF i >= 3 ^ (k + 1) OR j >= 1 THEN 0
           ELSE NSol(k, a, n, GF, KF, sig_seq(base_n(3, i)))
           ENDIF))
       IMPLIES
       (rows(form_matrix(eij, 3 ^ (k + 1), 1)) = 3 ^ (1 + k) AND
         columns(form_matrix(eij, 3 ^ (k + 1), 1)) = 1)
        AND
        rows(form_matrix(eij, 3 ^ (k + 1), 1)) > 0 AND
         columns(form_matrix(eij, 3 ^ (k + 1), 1)) > 0;

  % Subtype TCC generated (at line 39, column 84) for  base_n(6, i)
      % expected type  [nat -> subrange(0, 5)]
  NSol_vect6k_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]],
            (KF: [nat -> nat] | FORALL (i: upto(k)): GF(i)(KF(i)) /= 0),
            i: nat, j: nat):
      NOT i >= 6 ^ (k + 1) AND NOT j >= 1 IMPLIES
       (FORALL (x1: nat): 0 <= base_n(6, i)(x1) AND base_n(6, i)(x1) <= 5);

  % Subtype TCC generated (at line 40, column 7) for
      % form_matrix(eij, 6 ^ (k + 1), 1)
      % expected type  {v: PosFullMatrix |
                     %          rows(v) = 6 ^ (1 + k) AND columns(v) = 1}
  NSol_vect6k_TCC2: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (n: posnat | a(n) /= 0),
            GF: [nat -> [nat -> int]],
            (KF: [nat -> nat] | FORALL (i: upto(k)): GF(i)(KF(i)) /= 0),
            eij: [[nat, nat] -> naturalnumber]):
      (eij =
        (LAMBDA (i, j):
           IF i >= 6 ^ (k + 1) OR j >= 1 THEN 0
           ELSE NSol_all(k, a, n, GF, KF, base_n(6, i))
           ENDIF))
       IMPLIES
       (rows(form_matrix(eij, 6 ^ (k + 1), 1)) = 6 ^ (1 + k) AND
         columns(form_matrix(eij, 6 ^ (k + 1), 1)) = 1)
        AND
        rows(form_matrix(eij, 6 ^ (k + 1), 1)) > 0 AND
         columns(form_matrix(eij, 6 ^ (k + 1), 1)) > 0;

  % Subtype TCC generated (at line 43, column 7) for  (: 1, 1, 1, 0, 0, 0 :)
      % expected type  list[real]
  A66_inv_TCC1: OBLIGATION
    every[number]
        (LAMBDA (x: number): number_field_pred(x) AND real_pred(x))
        ((: 1, 1, 1, 0, 0, 0 :));

  % Subtype TCC generated (at line 44, column 20) for
      % (: (: 0, 1, -1, 0, 0, 0 :), (: 0, 1, 1, 0, 0, 0 :),
      %    (: 0, -1, -1, 1, 0, 0 :), (: -1, -1, 0, 0, 1, 0 :),
      %    (: -1, 0, -1, 0, 0, 1 :) :)
      % expected type  list[list[real]]
  A66_inv_TCC2: OBLIGATION
    every[list[number]]
        (LAMBDA (x: list[number]):
           every[number]
               (LAMBDA (x: number): number_field_pred(x) AND real_pred(x))(x))
        ((: (: 0, 1, -1, 0, 0, 0 :), (: 0, 1, 1, 0, 0, 0 :),
            (: 0, -1, -1, 1, 0, 0 :), (: -1, -1, 0, 0, 1, 0 :),
            (: -1, 0, -1, 0, 0, 1 :) :));

  % Subtype TCC generated (at line 43, column 4) for
      % (: (: 1, 1, 1, 0, 0, 0 :), (: 0, 1, -1, 0, 0, 0 :),
      %    (: 0, 1, 1, 0, 0, 0 :), (: 0, -1, -1, 1, 0, 0 :),
      %    (: -1, -1, 0, 0, 1, 0 :), (: -1, 0, -1, 0, 0, 1 :) :)
      % expected type  {M: PosFullMatrix | rows(M) = 6 AND columns(M) = 6}
  A66_inv_TCC3: OBLIGATION
         null?[list[real]]
             ((: (: 1, 1, 1, 0, 0, 0 :), (: 0, 1, -1, 0, 0, 0 :),
                 (: 0, 1, 1, 0, 0, 0 :), (: 0, -1, -1, 1, 0, 0 :),
                 (: -1, -1, 0, 0, 1, 0 :), (: -1, 0, -1, 0, 0, 1 :) :))
          OR
          (FORALL (i,
                   j:
                     below(length[list[real]]
                               ((: (: 1, 1, 1, 0, 0, 0 :),
                                   (: 0, 1, -1, 0, 0, 0 :),
                                   (: 0, 1, 1, 0, 0, 0 :),
                                   (: 0, -1, -1, 1, 0, 0 :),
                                   (: -1, -1, 0, 0, 1, 0 :),
                                   (: -1, 0, -1, 0, 0, 1 :) :)))):
             length[real]
                 (nth[list[real]]
                      ((: (: 1, 1, 1, 0, 0, 0 :), (: 0, 1, -1, 0, 0, 0 :),
                          (: 0, 1, 1, 0, 0, 0 :), (: 0, -1, -1, 1, 0, 0 :),
                          (: -1, -1, 0, 0, 1, 0 :),
                          (: -1, 0, -1, 0, 0, 1 :) :),
                       i))
              =
              length[real]
                  (nth[list[real]]
                       ((: (: 1, 1, 1, 0, 0, 0 :), (: 0, 1, -1, 0, 0, 0 :),
                           (: 0, 1, 1, 0, 0, 0 :), (: 0, -1, -1, 1, 0, 0 :),
                           (: -1, -1, 0, 0, 1, 0 :),
                           (: -1, 0, -1, 0, 0, 1 :) :),
                        j)))
     AND rows((: (: 1, 1, 1, 0, 0, 0 :), (: 0, 1, -1, 0, 0, 0 :),
                 (: 0, 1, 1, 0, 0, 0 :), (: 0, -1, -1, 1, 0, 0 :),
                 (: -1, -1, 0, 0, 1, 0 :), (: -1, 0, -1, 0, 0, 1 :) :))
          > 0
     AND columns((: (: 1, 1, 1, 0, 0, 0 :), (: 0, 1, -1, 0, 0, 0 :),
                    (: 0, 1, 1, 0, 0, 0 :), (: 0, -1, -1, 1, 0, 0 :),
                    (: -1, -1, 0, 0, 1, 0 :), (: -1, 0, -1, 0, 0, 1 :) :))
          > 0
     AND rows((: (: 1, 1, 1, 0, 0, 0 :), (: 0, 1, -1, 0, 0, 0 :),
                 (: 0, 1, 1, 0, 0, 0 :), (: 0, -1, -1, 1, 0, 0 :),
                 (: -1, -1, 0, 0, 1, 0 :), (: -1, 0, -1, 0, 0, 1 :) :))
          = 6
     AND columns((: (: 1, 1, 1, 0, 0, 0 :), (: 0, 1, -1, 0, 0, 0 :),
                    (: 0, 1, 1, 0, 0, 0 :), (: 0, -1, -1, 1, 0, 0 :),
                    (: -1, -1, 0, 0, 1, 0 :), (: -1, 0, -1, 0, 0, 1 :) :))
          = 6;

  % Subtype TCC generated (at line 50, column 70) for  A66_inv
      % expected type  SQ: {SQ | det(SQ) /= 0 OR invertible?(SQ)}
  A66_TCC1: OBLIGATION
    FORALL (M: PosFullMatrix):
      columns(M) = 6 AND rows(M) = 6 IMPLIES
       rows(A66_inv) = columns(A66_inv) AND
        (det(A66_inv) /= 0 OR invertible?(A66_inv));

  % Subtype TCC generated (at line 51, column 6) for  (: 1, 0, -1, 0, 0, 0 :)
      % expected type  list[real]
  A66_TCC2: OBLIGATION
    every[number]
        (LAMBDA (x: number): number_field_pred(x) AND real_pred(x))
        ((: 1, 0, -1, 0, 0, 0 :));

  % Subtype TCC generated (at line 51, column 31) for
      % (: (: 0, 1 / 2, 1 / 2, 0, 0, 0 :), (: 0, -1 / 2, 1 / 2, 0, 0, 0 :),
      %    (: 0, 0, 1, 1, 0, 0 :), (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
      %    (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :)
      % expected type  list[list[real]]
  A66_TCC3: OBLIGATION
    every[list[number]]
        (LAMBDA (x: list[number]):
           every[number]
               (LAMBDA (x: number): number_field_pred(x) AND real_pred(x))(x))
        ((: (: 0, 1 / 2, 1 / 2, 0, 0, 0 :), (: 0, -1 / 2, 1 / 2, 0, 0, 0 :),
            (: 0, 0, 1, 1, 0, 0 :), (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
            (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :));

  % Subtype TCC generated (at line 51, column 3) for
      % (: (: 1, 0, -1, 0, 0, 0 :), (: 0, 1 / 2, 1 / 2, 0, 0, 0 :),
      %    (: 0, -1 / 2, 1 / 2, 0, 0, 0 :), (: 0, 0, 1, 1, 0, 0 :),
      %    (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
      %    (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :)
      % expected type  {M: PosFullMatrix |
                     %          rows(M) = 6 AND
                     %           columns(M) = 6 AND M = inverse(A66_inv)}
  A66_TCC4: OBLIGATION
         null?[list[real]]
             ((: (: 1, 0, -1, 0, 0, 0 :), (: 0, 1 / 2, 1 / 2, 0, 0, 0 :),
                 (: 0, -1 / 2, 1 / 2, 0, 0, 0 :), (: 0, 0, 1, 1, 0, 0 :),
                 (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
                 (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :))
          OR
          (FORALL (i,
                   j:
                     below(length[list[real]]
                               ((: (: 1, 0, -1, 0, 0, 0 :),
                                   (: 0, 1 / 2, 1 / 2, 0, 0, 0 :),
                                   (: 0, -1 / 2, 1 / 2, 0, 0, 0 :),
                                   (: 0, 0, 1, 1, 0, 0 :),
                                   (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
                                   (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :)))):
             length[real]
                 (nth[list[real]]
                      ((: (: 1, 0, -1, 0, 0, 0 :),
                          (: 0, 1 / 2, 1 / 2, 0, 0, 0 :),
                          (: 0, -1 / 2, 1 / 2, 0, 0, 0 :),
                          (: 0, 0, 1, 1, 0, 0 :),
                          (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
                          (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :),
                       i))
              =
              length[real]
                  (nth[list[real]]
                       ((: (: 1, 0, -1, 0, 0, 0 :),
                           (: 0, 1 / 2, 1 / 2, 0, 0, 0 :),
                           (: 0, -1 / 2, 1 / 2, 0, 0, 0 :),
                           (: 0, 0, 1, 1, 0, 0 :),
                           (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
                           (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :),
                        j)))
     AND rows((: (: 1, 0, -1, 0, 0, 0 :), (: 0, 1 / 2, 1 / 2, 0, 0, 0 :),
                 (: 0, -1 / 2, 1 / 2, 0, 0, 0 :), (: 0, 0, 1, 1, 0, 0 :),
                 (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
                 (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :))
          > 0
     AND columns((: (: 1, 0, -1, 0, 0, 0 :), (: 0, 1 / 2, 1 / 2, 0, 0, 0 :),
                    (: 0, -1 / 2, 1 / 2, 0, 0, 0 :), (: 0, 0, 1, 1, 0, 0 :),
                    (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
                    (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :))
          > 0
     AND rows((: (: 1, 0, -1, 0, 0, 0 :), (: 0, 1 / 2, 1 / 2, 0, 0, 0 :),
                 (: 0, -1 / 2, 1 / 2, 0, 0, 0 :), (: 0, 0, 1, 1, 0, 0 :),
                 (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
                 (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :))
          = 6
     AND columns((: (: 1, 0, -1, 0, 0, 0 :), (: 0, 1 / 2, 1 / 2, 0, 0, 0 :),
                    (: 0, -1 / 2, 1 / 2, 0, 0, 0 :), (: 0, 0, 1, 1, 0, 0 :),
                    (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
                    (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :))
          = 6
     AND (: (: 1, 0, -1, 0, 0, 0 :), (: 0, 1 / 2, 1 / 2, 0, 0, 0 :),
            (: 0, -1 / 2, 1 / 2, 0, 0, 0 :), (: 0, 0, 1, 1, 0, 0 :),
            (: 1, 1 / 2, -1 / 2, 0, 1, 0 :),
            (: 1, -1 / 2, -1 / 2, 0, 0, 1 :) :)
          = inverse(A66_inv);

  % Subtype TCC generated (at line 68, column 6) for  (: 1, 0, -1 :)
      % expected type  list[real]
  A63_TCC1: OBLIGATION
    every[number]
        (LAMBDA (x: number): number_field_pred(x) AND real_pred(x))
        ((: 1, 0, -1 :));

  % Subtype TCC generated (at line 68, column 23) for
      % (: (: 0, 1 / 2, 1 / 2 :), (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
      %    (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :)
      % expected type  list[list[real]]
  A63_TCC2: OBLIGATION
    every[list[number]]
        (LAMBDA (x: list[number]):
           every[number]
               (LAMBDA (x: number): number_field_pred(x) AND real_pred(x))(x))
        ((: (: 0, 1 / 2, 1 / 2 :), (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
            (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :));

  % Subtype TCC generated (at line 68, column 3) for
      % (: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :), (: 0, -1 / 2, 1 / 2 :),
      %    (: 0, 0, 1 :), (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :)
      % expected type  {M: PosFullMatrix | rows(M) = 6 AND columns(M) = 3}
  A63_TCC3: OBLIGATION
         null?[list[real]]
             ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                 (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                 (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :))
          OR
          (FORALL (i,
                   j:
                     below(length[list[real]]
                               ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                                   (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                                   (: 1, 1 / 2, -1 / 2 :),
                                   (: 1, -1 / 2, -1 / 2 :) :)))):
             length[real]
                 (nth[list[real]]
                      ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                          (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                          (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :),
                       i))
              =
              length[real]
                  (nth[list[real]]
                       ((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                           (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                           (: 1, 1 / 2, -1 / 2 :),
                           (: 1, -1 / 2, -1 / 2 :) :),
                        j)))
     AND rows((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                 (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                 (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :))
          > 0
     AND columns((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                    (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                    (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :))
          > 0
     AND rows((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                 (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                 (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :))
          = 6
     AND columns((: (: 1, 0, -1 :), (: 0, 1 / 2, 1 / 2 :),
                    (: 0, -1 / 2, 1 / 2 :), (: 0, 0, 1 :),
                    (: 1, 1 / 2, -1 / 2 :), (: 1, -1 / 2, -1 / 2 :) :))
          = 3;


body:
  poly_systems: THEORY
  BEGIN

  % Systems of Polynomials 

  IMPORTING reals@polynomials,reals@more_polynomial_props,reals@sign,reals@real_orders,
  	  structures@sort_array,tarski_query_matrix

    a,r,g : VAR [nat->int]
    p : VAR [nat->[nat->int]]
    relseq: VAR [nat->RealOrder]
    n : VAR [nat->nat]
    d,i,j,k : VAR nat
    m: VAR posnat
    %m : VAR posnat
    x,y,c,b : VAR real
    babove,bbelow,bbelow2,babove2: VAR bool
    RelF6,TQRow: VAR [nat->subrange(0,5)]

    system_roots_enum: LEMMA 
      (FORALL (i):i<=k IMPLIES p(i)(n(i))/=0) IMPLIES
        EXISTS (K:nat,enum:[below(K)->real]):
          (FORALL (i,j:below(K)): i<j IMPLIES enum(i)<enum(j)) AND
  	(FORALL (i:below(K)): EXISTS (j): j<=k AND polynomial(p(j),n(j))(enum(i))=0) AND
    	(FORALL (b,j): j<=k AND polynomial(p(j),n(j))(b)=0 IMPLIES
    	  EXISTS (i:below(K)): b = enum(i))

    strict_poly_system_solvable: LEMMA (FORALL (i):i<=k IMPLIES p(i)(n(i))/=0) IMPLIES
      ((EXISTS (x): FORALL (i): i<=k IMPLIES polynomial(p(i),n(i))(x)>0)
      IFF
      ((FORALL (i): i<=k IMPLIES p(i)(n(i))>0) OR
       (FORALL (i): i<=k IMPLIES (IF odd?(n(i)) THEN -1 ELSE 1 ENDIF)*p(i)(n(i))>0) OR
       (EXISTS (x): (LET Q = prod_polynomials(p,n,(LAMBDA (i:nat): 1),k),Qdeg = sigma(0,k,n) IN
           Qdeg>0 AND polynomial(poly_deriv(Q),Qdeg-1)(x)=0) AND FORALL (i): i<=k 
  	 				IMPLIES polynomial(p(i),n(i))(x)>0)))

    % The following function computes the number of solutions to poly(a,m)(x)=0 
    % AND poly(p(i),n(i))(x)>0 for i<=k. Another version will be formed below.


    A63_tensor_power_mat_row(m)(RelF6): RECURSIVE {M:PosFullMatrix|rows(M)=1 AND columns(M)=3^m} =
      IF m = 1 THEN vect2matrix(row(A63)(RelF6(0)))
      ELSE tensor_prod(A63_tensor_power_mat_row(m-1)((LAMBDA (d): RelF6(d+1))),
              vect2matrix(row(A63)(RelF6(0))))
      ENDIF MEASURE m

    A63_tensor_power_mat_row_def: LEMMA 
      LET ii = base_n_to_nat(6,RelF6,k) IN
        A63_tensor_power_mat_row(1+k)(RelF6) =
        vect2matrix(row(tensor_power_alt(A63,1+k))(ii))

    sturm_tarski_solver_slow_basic(k,a,(m|a(m)/=0),p,
                  (n|FORALL (i:upto(k)):p(i)(n(i))/=0),RelF6):
      {r:real | r = NSol_all(k,a,m,p,n,RelF6) AND rational_pred(r) AND integer_pred(r)} =
          super_dot(row(A63_tensor_power_mat_row(k+1)(RelF6))(0),col(TQ_vect3k(k,a,m,p,n))(0))





  END poly_systems

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

  % Subtype TCC generated (at line 33, column 86) for  k
      % expected type  T_high[nat]
  strict_poly_system_solvable_TCC1: OBLIGATION
    FORALL (k: nat, n: [nat -> nat], p: [nat -> [nat -> int]]):
      (FORALL (i): i <= k IMPLIES p(i)(n(i)) /= 0) AND
       NOT (FORALL (i): i <= k IMPLIES p(i)(n(i)) > 0) AND
        NOT (FORALL (i):
               i <= k IMPLIES
                (IF odd?(n(i)) THEN -1 ELSE 1 ENDIF) * p(i)(n(i)) > 0)
       IMPLIES
       (FORALL (Q:
                  {a |
                           (FORALL (x):
                              polynomial(a,
                                         sigma[nat]
                                         (0,
                                          k,
                                          *[nat](n, (LAMBDA (i: nat): 1))))
                                        (x)
                               =
                               product[nat]
                                   (0, k,
                                    LAMBDA (j):
                                      polynomial(p(j), n(j))(x) ^ 1))
                            AND
                            ((FORALL (i_1: nat):
                                i_1 <= k IMPLIES p(i_1)(n(i_1)) /= 0)
                              IMPLIES
                              a(sigma[nat]
                                    (0, k, *[nat](n, (LAMBDA (i: nat): 1))))
                               /= 0)
                             AND
                             (FORALL (i_1: nat):
                                i_1 >
                                 sigma[nat]
                                     (0, k, *[nat](n, (LAMBDA (i: nat): 1)))
                                 IMPLIES a(i_1) = 0)}):
          Q = prod_polynomials(p, n, (LAMBDA (i: nat): 1), k) IMPLIES
           k >= 0 OR (EXISTS (j: nat): k <= j));

  % Subtype TCC generated (at line 34, column 45) for  Qdeg - 1
      % expected type  nat
  strict_poly_system_solvable_TCC2: OBLIGATION
    FORALL (k: nat, n: [nat -> nat], p: [nat -> [nat -> int]]):
      (FORALL (i): i <= k IMPLIES p(i)(n(i)) /= 0) AND
       NOT (FORALL (i): i <= k IMPLIES p(i)(n(i)) > 0) AND
        NOT (FORALL (i):
               i <= k IMPLIES
                (IF odd?(n(i)) THEN -1 ELSE 1 ENDIF) * p(i)(n(i)) > 0)
       IMPLIES
       (FORALL (Q:
                  {a |
                           (FORALL (x):
                              polynomial(a,
                                         sigma[nat]
                                         (0,
                                          k,
                                          *[nat](n, (LAMBDA (i: nat): 1))))
                                        (x)
                               =
                               product[nat]
                                   (0, k,
                                    LAMBDA (j):
                                      polynomial(p(j), n(j))(x) ^ 1))
                            AND
                            ((FORALL (i_1: nat):
                                i_1 <= k IMPLIES p(i_1)(n(i_1)) /= 0)
                              IMPLIES
                              a(sigma[nat]
                                    (0, k, *[nat](n, (LAMBDA (i: nat): 1))))
                               /= 0)
                             AND
                             (FORALL (i_1: nat):
                                i_1 >
                                 sigma[nat]
                                     (0, k, *[nat](n, (LAMBDA (i: nat): 1)))
                                 IMPLIES a(i_1) = 0)}):
          Q = prod_polynomials(p, n, (LAMBDA (i: nat): 1), k) IMPLIES
           (FORALL (Qdeg: nat):
              Qdeg > 0 AND Qdeg = sigma(0, k, n) IMPLIES Qdeg - 1 >= 0));

  % Subtype TCC generated (at line 42, column 30) for  row(A63)(RelF6(0))
      % expected type  v: {v | length(v) > 0}
  A63_tensor_power_mat_row_TCC1: OBLIGATION
    FORALL (m: posnat, RelF6: [nat -> subrange(0, 5)]):
      m = 1 IMPLIES length[real](row(A63)(RelF6(0))) > 0;

  % Subtype TCC generated (at line 42, column 18) for
      % vect2matrix(row(A63)(RelF6(0)))
      % expected type  {M: PosFullMatrix | rows(M) = 1 AND columns(M) = 3 ^ m}
  A63_tensor_power_mat_row_TCC2: OBLIGATION
    FORALL (m: posnat, RelF6: [nat -> subrange(0, 5)]):
      m = 1 IMPLIES
       rows(vect2matrix(row(A63)(RelF6(0)))) = 1 AND
        columns(vect2matrix(row(A63)(RelF6(0)))) = 3 ^ m;

  % Subtype TCC generated (at line 43, column 46) for  m - 1
      % expected type  m: posnat
  A63_tensor_power_mat_row_TCC3: OBLIGATION
    FORALL (m: posnat, RelF6: [nat -> subrange(0, 5)]):
      NOT m = 1 IMPLIES m - 1 >= 0 AND m - 1 > 0;

  % Termination TCC generated (at line 43, column 21) for
      % A63_tensor_power_mat_row(m - 1)
  A63_tensor_power_mat_row_TCC4: OBLIGATION
    FORALL (m: posnat, RelF6: [nat -> subrange(0, 5)]):
      NOT m = 1 IMPLIES m - 1 < m;

  % Subtype TCC generated (at line 44, column 24) for  row(A63)(RelF6(0))
      % expected type  v: {v | length(v) > 0}
  A63_tensor_power_mat_row_TCC5: OBLIGATION
    FORALL (m: posnat, RelF6: [nat -> subrange(0, 5)]):
      NOT m = 1 IMPLIES length[real](row(A63)(RelF6(0))) > 0;

  % Subtype TCC generated (at line 43, column 9) for
      % tensor_prod(A63_tensor_power_mat_row(m - 1)
      %                                     ((LAMBDA (d): RelF6(d + 1))),
      %             vect2matrix(row(A63)(RelF6(0))))
      % expected type  {M: PosFullMatrix | rows(M) = 1 AND columns(M) = 3 ^ m}
  A63_tensor_power_mat_row_TCC6: OBLIGATION
    FORALL (m: posnat,
            v:
              [m1: {z: posnat | z < m} ->
                 [[nat -> subrange(0, 5)] ->
                    {M: PosFullMatrix |
                             rows(M) = 1 AND columns(M) = 3 ^ m1}]],
            RelF6: [nat -> subrange(0, 5)]):
      NOT m = 1 IMPLIES
       rows(tensor_prod(v(m - 1)(LAMBDA (d): RelF6(d + 1)),
                        vect2matrix(row(A63)(RelF6(0)))))
        = 1
        AND
        columns(tensor_prod(v(m - 1)(LAMBDA (d): RelF6(d + 1)),
                            vect2matrix(row(A63)(RelF6(0)))))
         = 3 ^ m;

  % Subtype TCC generated (at line 50, column 18) for
      % row(tensor_power_alt(A63, 1 + k))(ii)
      % expected type  v: {v | length(v) > 0}
  A63_tensor_power_mat_row_def_TCC1: OBLIGATION
    FORALL (RelF6: [nat -> subrange(0, 5)], k, ii: nat):
      ii = base_n_to_nat(6, RelF6, k) IMPLIES
       length[real](row(tensor_power_alt(A63, 1 + k))(ii)) > 0;

  % Subtype TCC generated (at line 55, column 8) for
      % super_dot(row(A63_tensor_power_mat_row(k + 1)(RelF6))(0),
      %           col(TQ_vect3k(k, a, m, p, n))(0))
      % expected type  {r: real |
                     %          r = NSol_all(k, a, m, p, n, RelF6) AND
                     %           rational_pred(r) AND integer_pred(r)}
  sturm_tarski_solver_slow_basic_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (m: posnat | a(m) /= 0),
            p: [nat -> [nat -> int]],
            (n: [nat -> nat] | FORALL (i: upto(k)): p(i)(n(i)) /= 0),
            RelF6: [nat -> subrange(0, 5)]):
      super_dot(row(A63_tensor_power_mat_row(k + 1)(RelF6))(0),
                col(TQ_vect3k(k, a, m, p, n))(0))
       = NSol_all(k, a, m, p, n, RelF6)
       AND
       rational_pred(super_dot(row(A63_tensor_power_mat_row(k + 1)(RelF6))
                                  (0),
                               col(TQ_vect3k(k, a, m, p, n))(0)))
        AND
        integer_pred(super_dot(row(A63_tensor_power_mat_row(k + 1)(RelF6))
                                  (0),
                               col(TQ_vect3k(k, a, m, p, n))(0)));


body:
  system_solvers : THEORY

    BEGIN

  % different versions of algorithms to compute the number of solutions to a system


   IMPORTING poly_systems, matrices@query_coeff

    a,r,g : VAR [nat->int]
    p : VAR [nat->[nat->int]]
    relseq: VAR [nat->RealOrder]
    n : VAR [nat->nat]
    d,i,j,k : VAR nat
    m: VAR posnat
    %m : VAR posnat
    x,y,c,b : VAR real
    babove,bbelow,bbelow2,babove2: VAR bool
    RelF6,TQRow: VAR [nat->subrange(0,5)]


  %    ORIGINAL ALGORITHM ---- Others should use this signature.  
  %
  %    starm_tarski_solver_slow_basic(k,a,(m|a(m)/=0),p,
  %                (n|FORALL (i:upto(k)):p(i)(n(i))/=0),RelF6):
  %     {r:real | r = NSol_all(k,a,m,p,n,RelF6) AND rational_pred(r) AND integer_pred(r)} =
  %      LET ii = base_n_to_nat(6,RelF6,k) IN
  %        dot(row(tensor_power_alt(A63,k+1))(ii),col(TQ_vect3k(k,a,m,p,n))(0))
    

  % sturm_tarski_tail_generic(k,a,(m|a(m)/=0),p,
  %                 (n|FORALL (i:upto(k)):p(i)(n(i))/=0),RelF6, 
  % 		(F:{ff:[[nat->below(3)]->real]|FORALL (j:below(3^(k+1))): ff(base_n(3,j)) = entry(tensor_power_alt(A63,k+1))(base_n_to_nat(6, RelF6, k),j)}), 
  % 		(G:{ff:[[nat->below(3)]->real]|FORALL (j:below(3^(k+1))): ff(base_n(3,j)) = TQ_fam(k,a,m, p ,n,base_n(3, j))})   ):
  %      {r:real | r = NSol_all(k,a,m,p,n,RelF6) AND rational_pred(r) AND integer_pred(r)} = 
  %        dot_tail_sum2(k+1, F, G, 0, 0, base_n(3, 0))


  % % testing the generic solver...

  % F1(RelF6, k)(f:[nat->below(3)]): real = entry(tensor_power_alt(A63,k+1))(base_n_to_nat(6, RelF6, k),base_n_to_nat(3,f,k)) 
  % G1(k,a,(m|a(m)/=0),p, (n|FORALL (i:upto(k)):p(i)(n(i))/=0))(f:[nat->below(3)]): real = TQ_fam(k,a,m, p ,n,f)

  % sturm_tarski_generic_test(k,a,(m|a(m)/=0),p,
  %                 (n|FORALL (i:upto(k)):p(i)(n(i))/=0),RelF6):
  %      {r:real | r = NSol_all(k,a,m,p,n,RelF6) AND rational_pred(r) AND integer_pred(r)} = 
  %          sturm_tarski_tail_generic(k,a,m,p,n,RelF6, F1(RelF6, k), G1(k,a,m,p,n))

  rows_fun(RelF6, k)(j:upto(k)):  {V: Vector| V = row(A63)(RelF6(j)) AND length(V)=3} = row(A63)( RelF6(j))
       
  entry_fun(k, (RowF:[upto(k)->{V:Vector|length(V) = 3}]))((L:listn[below(3)](k+1))): 
           real = product[nat](0, k, LAMBDA(i:nat): IF i<=k THEN nth(RowF(i), nth(L, i)) ELSE 1 ENDIF)    

  entry_is: LEMMA FORALL (RelF6, k, (i:below(3^(k+1))) ):
         entry_fun(k, rows_fun(RelF6, k))(base_list(3, i, k+1)) = 
         entry(tensor_power_alt(A63, k+1))(base_n_to_nat(6, RelF6, k), i)

  TQlist_fun(k,a,(m|a(m)/=0),p, (n|FORALL (i:upto(k)):p(i)(n(i))/=0))(L:listn[below(3)](k+1)): real = TQ_fam(k,a,m, p ,n,list2array[below(3)](0)(L))

  TQlist_lem: LEMMA FORALL (k,a,(m|a(m)/=0),p, (n|FORALL (i:upto(k)):p(i)(n(i))/=0), j:below(3^(k+1))):
      TQlist_fun(k,a,m,p,n)(base_list(3,j,k+1)) = TQ_fam(k,a,m,p,n,base_n(3, j))

  sturm_tarski_faster(k,a,(m|a(m)/=0),p,
                  (n|FORALL (i:upto(k)):p(i)(n(i))/=0),RelF6):
       {r:real | r = NSol_all(k,a,m,p,n,RelF6) AND rational_pred(r) AND integer_pred(r)} =
       LET EntFun  = entry_fun(k, rows_fun(RelF6, k)) IN 
       IF k=0 THEN   sturm_tarski_solver_slow_basic(k,a,m,p,n,RelF6) 
       ELSE dot_tail_sum2plus(k+1, EntFun, TQlist_fun(k,a,m,p,n), 0, 0, base_list(3, 0, k+1))
       ENDIF
        


   T1(n:posnat, i, j:nat): real = entry(tensor_power_alt(A63, n))(i,j)

   T2(M:PosFullMatrix, i, j:nat): real = entry(M)(i,j)
    
   Test1(n:posnat, j:nat): RECURSIVE real = 
     if j=0 THEN T1(n, j, j) 
     ELSE LET ent = T1(n, j, j) in
     	Test1(n, j-1)
     ENDIF
     MEASURE j

   Test2recurse(M:PosFullMatrix, j:nat): RECURSIVE real= 
    IF j=0 THEN T2(M, j, j)
    ELSE LET ent  = T2(M, j, j) IN	
         Test2recurse(M, j-1)
    ENDIF		       
    MEASURE j


   Test2(n: posnat,  j:nat): real = 
      LET M = (tensor_power_alt(A63, n)) IN
      Test2recurse(M, j)




    END system_solvers

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

  % Subtype TCC generated (at line 49, column 86) for  row(A63)(RelF6(j))
      % expected type  {V: Vector | V = row(A63)(RelF6(j)) AND length(V) = 3}
  rows_fun_TCC1: OBLIGATION
    FORALL (RelF6: [nat -> subrange(0, 5)], k: nat, j: upto(k)):
      length[real](row(A63)(RelF6(j))) = 3;

  % Subtype TCC generated (at line 52, column 32) for  k
      % expected type  T_high[nat]
  entry_fun_TCC1: OBLIGATION
    FORALL (k: nat, (RowF: [upto(k) -> {V: Vector | length[real](V) = 3}]),
            (L: listn[below(3)](k + 1))):
      k >= 0 OR (EXISTS (j: nat): k <= j);

  % Subtype TCC generated (at line 52, column 83) for  i
      % expected type  below[length[below(3)](L)]
  entry_fun_TCC2: OBLIGATION
    FORALL (k: nat, (RowF: [upto(k) -> {V: Vector | length[real](V) = 3}]),
            (L: listn[below(3)](k + 1)), i: nat):
      i <= k IMPLIES i < length[below(3)](L);

  % Subtype TCC generated (at line 52, column 76) for  nth(L, i)
      % expected type  below[length[real](RowF(i))]
  entry_fun_TCC3: OBLIGATION
    FORALL (k: nat, (RowF: [upto(k) -> {V: Vector | length[real](V) = 3}]),
            (L: listn[below(3)](k + 1)), i: nat):
      i <= k IMPLIES nth[below(3)](L, i) < length[real](RowF(i));

  % Existence TCC generated (at line 58, column 119) for  list2array[below(3)]
  TQlist_fun_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (m: posnat | a(m) /= 0),
            p: [nat -> [nat -> int]],
            (n: [nat -> nat] | FORALL (i: upto(k)): p(i)(n(i)) /= 0),
            L: listn[below(3)](k + 1)):
      EXISTS (x: below(3)): TRUE;

  % Subtype TCC generated (at line 58, column 119) for
      % list2array[below(3)](0)(L)
      % expected type  [nat -> subrange(0, 2)]
  TQlist_fun_TCC2: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (m: posnat | a(m) /= 0),
            p: [nat -> [nat -> int]],
            (n: [nat -> nat] | FORALL (i: upto(k)): p(i)(n(i)) /= 0),
            L: listn[below(3)](k + 1)):
      FORALL (x1: nat):
        0 <= list2array[below(3)](0)(L)(x1) AND
         list2array[below(3)](0)(L)(x1) <= 2;

  % Subtype TCC generated (at line 61, column 65) for  base_n(3, j)
      % expected type  [nat -> subrange(0, 2)]
  TQlist_lem_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (m: posnat | a(m) /= 0),
            p: [nat -> [nat -> int]],
            (n: [nat -> nat] | FORALL (i: upto(k)): p(i)(n(i)) /= 0),
            j: below(3 ^ (k + 1))):
      FORALL (x1: nat): 0 <= base_n(3, j)(x1) AND base_n(3, j)(x1) <= 2;

  % Subtype TCC generated (at line 68, column 28) for  k + 1
      % expected type  {x: nat | x > 1}
  sturm_tarski_faster_TCC1: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (m: posnat | a(m) /= 0),
            p: [nat -> [nat -> int]],
            (n: [nat -> nat] | FORALL (i: upto(k)): p(i)(n(i)) /= 0),
            RelF6: [nat -> subrange(0, 5)],
            EntFun: [listn[below(3)](1 + k) -> real]):
      NOT k = 0 AND EntFun = entry_fun(k, rows_fun(RelF6, k)) IMPLIES
       k + 1 > 1;

  % Subtype TCC generated (at line 68, column 67) for  0
      % expected type  upto(3 ^ (1 + k))
  sturm_tarski_faster_TCC2: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (m: posnat | a(m) /= 0),
            p: [nat -> [nat -> int]],
            (n: [nat -> nat] | FORALL (i: upto(k)): p(i)(n(i)) /= 0),
            RelF6: [nat -> subrange(0, 5)],
            EntFun: [listn[below(3)](1 + k) -> real]):
      NOT k = 0 AND EntFun = entry_fun(k, rows_fun(RelF6, k)) IMPLIES
       0 <= 3 ^ (1 + k);

  % Subtype TCC generated (at line 68, column 70) for  base_list(3, 0, k + 1)
      % expected type  {ll: list[below(3)] | ll = base_list(3, 0, 1 + k)}
  sturm_tarski_faster_TCC3: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (m: posnat | a(m) /= 0),
            p: [nat -> [nat -> int]],
            (n: [nat -> nat] | FORALL (i: upto(k)): p(i)(n(i)) /= 0),
            RelF6: [nat -> subrange(0, 5)],
            EntFun: [listn[below(3)](1 + k) -> real]):
      NOT k = 0 AND EntFun = entry_fun(k, rows_fun(RelF6, k)) IMPLIES
       base_list(3, 0, k + 1) = base_list(3, 0, 1 + k);

  % Subtype TCC generated (at line 68, column 10) for
      % dot_tail_sum2plus(k + 1, EntFun, TQlist_fun(k, a, m, p, n), 0, 0,
      %                   base_list(3, 0, k + 1))
      % expected type  {r: real |
                     %          r = NSol_all(k, a, m, p, n, RelF6) AND
                     %           rational_pred(r) AND integer_pred(r)}
  sturm_tarski_faster_TCC4: OBLIGATION
    FORALL (k: nat, a: [nat -> int], (m: posnat | a(m) /= 0),
            p: [nat -> [nat -> int]],
            (n: [nat -> nat] | FORALL (i: upto(k)): p(i)(n(i)) /= 0),
            RelF6: [nat -> subrange(0, 5)],
            EntFun: [listn[below(3)](1 + k) -> real]):
      NOT k = 0 AND EntFun = entry_fun(k, rows_fun(RelF6, k)) IMPLIES
       dot_tail_sum2plus(k + 1, EntFun, TQlist_fun(k, a, m, p, n), 0, 0,
                         base_list(3, 0, k + 1))
        = NSol_all(k, a, m, p, n, RelF6)
        AND
        rational_pred(dot_tail_sum2plus(k + 1,
                                        EntFun,
                                        TQlist_fun(k, a, m, p, n),
                                        0,
                                        0,
                                        base_list(3, 0, k + 1)))
         AND
         integer_pred(dot_tail_sum2plus(k + 1,
                                        EntFun,
                                        TQlist_fun(k, a, m, p, n),
                                        0,
                                        0,
                                        base_list(3, 0, k + 1)));

  % Subtype TCC generated (at line 80, column 13) for  j - 1
      % expected type  nat
  Test1_TCC1: OBLIGATION
    FORALL (n: posnat, j: nat):
      NOT j = 0 IMPLIES
       (FORALL (ent: real): ent = T1(n, j, j) IMPLIES j - 1 >= 0);

  % Termination TCC generated (at line 80, column 4) for  Test1(n, j - 1)
  Test1_TCC2: OBLIGATION
    FORALL (n: posnat, j: nat):
      NOT j = 0 IMPLIES
       (FORALL (ent: real): ent = T1(n, j, j) IMPLIES j - 1 < j);

  % Subtype TCC generated (at line 87, column 23) for  j - 1
      % expected type  nat
  Test2recurse_TCC1: OBLIGATION
    FORALL (M: PosFullMatrix, j: nat):
      NOT j = 0 IMPLIES
       (FORALL (ent: real): ent = T2(M, j, j) IMPLIES j - 1 >= 0);

  % Termination TCC generated (at line 87, column 7) for
      % Test2recurse(M, j - 1)
  Test2recurse_TCC2: OBLIGATION
    FORALL (M: PosFullMatrix, j: nat):
      NOT j = 0 IMPLIES
       (FORALL (ent: real): ent = T2(M, j, j) IMPLIES j - 1 < j);


body:
  poly_system_strategy: THEORY
  BEGIN

  % Systems of Polynomials 

  IMPORTING poly_systems,system_solvers

    a,r,g : VAR [nat->int]
    p : VAR [nat->[nat->int]]
    relseq: VAR [nat->RealOrder]
    n : VAR [nat->nat]
    d,i,j,k : VAR nat
    m: VAR posnat
    %m : VAR posnat
    x,y,c,b : VAR real
    babove,bbelow,bbelow2,babove2: VAR bool
    RelF6,TQRow: VAR [nat->subrange(0,5)]



    % Next is a function that takes a system, possibly involving only inequalities and not equalities,
    % and converts it to a system(s) with at least one equality.

    strictify(RelF6)(i): subrange(0,5) = IF RelF6(i)=4 THEN 1 ELSIF RelF6(i)=5 THEN 2 ELSE RelF6(i) ENDIF

    first_eq(RelF6,k): RECURSIVE {i | (i>k IMPLIES FORALL (j:upto(k)): RelF6(j)>0) AND
    		     	       	    (i<=k IMPLIES RelF6(i)=0 AND FORALL (j): j<i IMPLIES RelF6(j)>0)} =
      IF k=0 THEN (IF RelF6(0)=0 THEN 0 ELSE 1 ENDIF)
      ELSE LET last = first_eq(RelF6,k-1) IN
             IF last>k-1 THEN (IF RelF6(k)=0 THEN k ELSE k+1 ENDIF)
  	   ELSE last ENDIF
      ENDIF MEASURE k

    prod_nonstrict(k,p,(n|FORALL (j:upto(k)): p(j)(n(j))/=0),RelF6): list[int] =
      prod_polynomials_list(LAMBDA (i): IF RelF6(i)>=4 THEN p(i) ELSE (LAMBDA (j:nat): 1) ENDIF,
      			  LAMBDA (i): IF RelF6(i)>=4 THEN n(i) ELSE 0 ENDIF,(LAMBDA (i): 1),k)

    rel5(i:subrange(0,5))(r1,r2:real): bool =
      (IF i=0 THEN r1=r2 ELSIF i=1 THEN r1>r2
  	ELSIF i=2 THEN r1<r2 ELSIF i=3 THEN r1/=r2 
  	ELSIF i=4 THEN r1>=r2 ELSIF i=5 THEN r1<=r2 ELSE TRUE ENDIF)

    solvable_at?(k,p,(n|FORALL (j:upto(k)): p(j)(n(j))/=0),RelF6)(x): bool =
     FORALL (i:upto(k)): 
        rel5(RelF6(i))(polynomial(p(i),n(i))(x),0)


    solvable?(k,p,(n|FORALL (j:upto(k)): p(j)(n(j))/=0),RelF6): bool =
      EXISTS (x): solvable_at?(k,p,n,RelF6)(x)

    greatify_poly(i:subrange(0,5),a): [nat->int] =
      IF i=2 OR i=5 THEN (-1)*a ELSE a ENDIF

    greatify_poly_rel(p,RelF6)(i): [nat->int] =
      greatify_poly(RelF6(i),p(i))

    greatify_rel(RelF6)(i): {pz:subrange(0,5)|pz/=2 AND pz/=5} =
      IF RelF6(i)=2 THEN 1 ELSIF RelF6(i)=5 THEN 4 ELSE RelF6(i) ENDIF

    greatify_def: LEMMA (FORALL (j:upto(k)): p(j)(n(j))/=0) IMPLIES
      (solvable?(k,p,n,RelF6) IFF
      solvable?(k,greatify_poly_rel(p,RelF6),n,greatify_rel(RelF6)))


    compute_solvable_single(i:subrange(0,5),a,(d|a(d)/=0)): bool = 
     IF d=0 THEN rel5(i)(a(0),0)
     ELSIF d=1 THEN TRUE
     ELSIF i=3 THEN TRUE
     ELSE LET iseq = sturm_tarski_faster(1,a,d,LAMBDA (k):LAMBDA (j):1,
  	       	   LAMBDA (k):0,LAMBDA (j):1)/=0
  	IN IF i=0 THEN iseq
  	   ELSIF i/=1 AND i/=2 AND iseq THEN TRUE
  	   ELSE LET newa = IF rel5(i)(1,0) THEN a ELSE (-1)*a ENDIF
  	   	IN 
  		  newa(d)>0 OR (odd?(d) AND newa(d)<0) OR
  		  sturm_tarski_faster(1,poly_deriv(a),d-1,LAMBDA (j): newa,
                      LAMBDA (j): d,greatify_rel(LAMBDA (j): i))/=0
             ENDIF
      ENDIF


    compute_solvable_single_def: LEMMA a(d)/=0 IMPLIES FORALL (i:subrange(0,5)):
      (EXISTS (x): rel5(i)(polynomial(a,d)(x),0)) IFF
      compute_solvable_single(i,a,d)

    poly_deriv_integer: LEMMA
      rational_pred(poly_deriv(a)(d)) AND
      integer_pred(poly_deriv(a)(d))


    compute_solvable(k,p,(n|FORALL (j:upto(k)): p(j)(n(j))/=0 AND n(j)>0),RelF6): bool =
      LET newp=greatify_poly_rel(p,RelF6),
  	newRel=greatify_rel(RelF6)
      IN
      IF k=0 THEN compute_solvable_single(RelF6(0),p(0),n(0))
      ELSIF (EXISTS (i:upto(k)): newRel(i)=0) THEN
        LET fe = first_eq(newRel,k) IN 
          sturm_tarski_faster(k-1,newp(fe),n(fe),
    	        (LAMBDA (i): IF i<fe THEN newp(i) ELSE newp(i+1) ENDIF),
                  (LAMBDA (i): IF i<fe THEN n(i) ELSE n(i+1) ENDIF),
    		(LAMBDA (i): IF i<fe THEN newRel(i) ELSE newRel(i+1) ENDIF))/=0
      ELSE
        LET Qprodlist = prod_polynomials_list(newp,n,LAMBDA i: 1,k),
  	  Qdeg = length(Qprodlist)-1,
  	  Qprod = (LAMBDA (i): IF i<length(Qprodlist) THEN nth(Qprodlist,i) ELSE 0 ENDIF)
        IN 
          (Qdeg>0 AND sturm_tarski_faster(k,Qprod,Qdeg,newp,n,newRel)/=0)
  	OR
  	(Qdeg>=2  AND
  	  ((FORALL (j:upto(k)): rel5(newRel(j))(newp(j)(n(j)),0)) OR
  	  (FORALL (j:upto(k)): (odd?(n(j)) IMPLIES rel5(newRel(j))(-newp(j)(n(j)),0)) AND
  	  	  	       (even?(n(j)) IMPLIES rel5(newRel(j))(newp(j)(n(j)),0))) OR
  	  sturm_tarski_faster(k,poly_deriv(Qprod),Qdeg-1,newp,n,newRel)/=0))
      ENDIF

    compute_solvable_def: LEMMA
      (FORALL (j:upto(k)): p(j)(n(j))/=0 AND n(j)>0) IMPLIES
      ((EXISTS (x:real): FORALL (j:upto(k)): rel5(RelF6(j))(polynomial(p(j),n(j))(x),0)) IFF
       compute_solvable(k,p,n,RelF6))

    poly_system_list(k,p,(n|FORALL (j:upto(k)): p(j)(n(j))/=0 AND n(j)>0)): {lli : list[list[int]] |
      length[list[int]](lli) = k+1 AND (FORALL (i:upto(k)): length[int](nth[list[int]](lli,i)) = n(i)+1) AND
      (FORALL (j:upto(k),i:upto(n(j))): nth[int](nth[list[int]](lli,j),i)=p(j)(i))} =
        array2list[list[int]](k+1)(LAMBDA (j:nat): array2list[int](n(j)+1)(p(j)))

    pq: VAR [nat->[nat->rat]]

    tarski(k,pq,(n|FORALL (j:upto(k)): pq(j)(n(j))/=0 AND n(j)>0),RelF6): bool =
      LET pi = (LAMBDA (j): rat_poly_to_int(pq(j),n(j))),
      	pl = poly_system_list(k,pi,n),
  	p = (LAMBDA (i): LAMBDA (j): IF i<=k AND j<=n(i) THEN nth[int](nth[list[int]](pl,i),j) ELSE 0 ENDIF)
      IN compute_solvable(k,p,n,RelF6)

    tarski_def: LEMMA
      (FORALL (j:upto(k)): pq(j)(n(j))/=0 AND n(j)>0) IMPLIES
      ((EXISTS (x:real): FORALL (j:upto(k)): rel5(RelF6(j))(polynomial(pq(j),n(j))(x),0)) IFF
       tarski(k,pq,n,RelF6))



  END poly_system_strategy

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

  % Subtype TCC generated (at line 28, column 36) for  0
      % expected type  {i |
                     %          (i > k IMPLIES
                     %            (FORALL (j: upto(k)): RelF6(j) > 0))
                     %           AND
                     %           (i <= k IMPLIES
                     %             RelF6(i) = 0 AND
                     %              (FORALL (j): j < i IMPLIES RelF6(j) > 0))}
  first_eq_TCC1: OBLIGATION
    FORALL (RelF6: [nat -> subrange(0, 5)], k: nat):
      RelF6(0) = 0 AND k = 0 IMPLIES
       (0 > k IMPLIES (FORALL (j: upto(k)): RelF6(j) > 0)) AND
        (0 <= k IMPLIES
          RelF6(0) = 0 AND (FORALL (j): j < 0 IMPLIES RelF6(j) > 0));

  % Subtype TCC generated (at line 28, column 43) for  1
      % expected type  {i |
                     %          (i > k IMPLIES
                     %            (FORALL (j: upto(k)): RelF6(j) > 0))
                     %           AND
                     %           (i <= k IMPLIES
                     %             RelF6(i) = 0 AND
                     %              (FORALL (j): j < i IMPLIES RelF6(j) > 0))}
  first_eq_TCC2: OBLIGATION
    FORALL (RelF6: [nat -> subrange(0, 5)], k: nat):
      NOT RelF6(0) = 0 AND k = 0 IMPLIES
       (1 > k IMPLIES (FORALL (j: upto(k)): RelF6(j) > 0)) AND
        (1 <= k IMPLIES
          RelF6(1) = 0 AND (FORALL (j): j < 1 IMPLIES RelF6(j) > 0));

  % Subtype TCC generated (at line 30, column 48) for  k
      % expected type  {i |
                     %          (i > k IMPLIES
                     %            (FORALL (j: upto(k)): RelF6(j) > 0))
                     %           AND
                     %           (i <= k IMPLIES
                     %             RelF6(i) = 0 AND
                     %              (FORALL (j): j < i IMPLIES RelF6(j) > 0))}
  first_eq_TCC3: OBLIGATION
    FORALL (RelF6: [nat -> subrange(0, 5)], k: nat,
            v:
              [d1: {z: [[nat -> subrange(0, 5)], nat] | z`2 < k} ->
                 {i |
                          (i > d1`2 IMPLIES
                            (FORALL (j: upto(d1`2)): d1`1(j) > 0))
                           AND
                           (i <= d1`2 IMPLIES
                             d1`1(i) = 0 AND
                              (FORALL (j): j < i IMPLIES d1`1(j) > 0))}]):
      NOT k = 0 IMPLIES
       (FORALL (last:
                  {i |
                           (i > k - 1 IMPLIES
                             (FORALL (j: upto(k - 1)): RelF6(j) > 0))
                            AND
                            (i <= k - 1 IMPLIES
                              RelF6(i) = 0 AND
                               (FORALL (j): j < i IMPLIES RelF6(j) > 0))}):
          RelF6(k) = 0 AND last > k - 1 AND last = v(RelF6, k - 1) IMPLIES
           (k > k IMPLIES (FORALL (j: upto(k)): RelF6(j) > 0)) AND
            (k <= k IMPLIES
              RelF6(k) = 0 AND (FORALL (j): j < k IMPLIES RelF6(j) > 0)));

  % Subtype TCC generated (at line 30, column 55) for  k + 1
      % expected type  {i |
                     %          (i > k IMPLIES
                     %            (FORALL (j: upto(k)): RelF6(j) > 0))
                     %           AND
                     %           (i <= k IMPLIES
                     %             RelF6(i) = 0 AND
                     %              (FORALL (j): j < i IMPLIES RelF6(j) > 0))}
  first_eq_TCC4: OBLIGATION
    FORALL (RelF6: [nat -> subrange(0, 5)], k: nat,
            v:
              [d1: {z: [[nat -> subrange(0, 5)], nat] | z`2 < k} ->
                 {i |
                          (i > d1`2 IMPLIES
                            (FORALL (j: upto(d1`2)): d1`1(j) > 0))
                           AND
                           (i <= d1`2 IMPLIES
                             d1`1(i) = 0 AND
                              (FORALL (j): j < i IMPLIES d1`1(j) > 0))}]):
      NOT k = 0 IMPLIES
       (FORALL (last:
                  {i |
                           (i > k - 1 IMPLIES
                             (FORALL (j: upto(k - 1)): RelF6(j) > 0))
                            AND
                            (i <= k - 1 IMPLIES
                              RelF6(i) = 0 AND
                               (FORALL (j): j < i IMPLIES RelF6(j) > 0))}):
          NOT RelF6(k) = 0 AND last > k - 1 AND last = v(RelF6, k - 1)
           IMPLIES
           (k + 1 > k IMPLIES (FORALL (j: upto(k)): RelF6(j) > 0)) AND
            (k + 1 <= k IMPLIES
              RelF6(k + 1) = 0 AND
               (FORALL (j): j < k + 1 IMPLIES RelF6(j) > 0)));

  % Subtype TCC generated (at line 31, column 9) for  last
      % expected type  {i |
                     %          (i > k IMPLIES
                     %            (FORALL (j: upto(k)): RelF6(j) > 0))
                     %           AND
                     %           (i <= k IMPLIES
                     %             RelF6(i) = 0 AND
                     %              (FORALL (j): j < i IMPLIES RelF6(j) > 0))}
  first_eq_TCC5: OBLIGATION
    FORALL (RelF6: [nat -> subrange(0, 5)], k: nat,
            v:
              [d1: {z: [[nat -> subrange(0, 5)], nat] | z`2 < k} ->
                 {i |
                          (i > d1`2 IMPLIES
                            (FORALL (j: upto(d1`2)): d1`1(j) > 0))
                           AND
                           (i <= d1`2 IMPLIES
                             d1`1(i) = 0 AND
                              (FORALL (j): j < i IMPLIES d1`1(j) > 0))}]):
      NOT k = 0 IMPLIES
       (FORALL (last:
                  {i |
                           (i > k - 1 IMPLIES
                             (FORALL (j: upto(k - 1)): RelF6(j) > 0))
                            AND
                            (i <= k - 1 IMPLIES
                              RelF6(i) = 0 AND
                               (FORALL (j): j < i IMPLIES RelF6(j) > 0))}):
          NOT last > k - 1 AND last = v(RelF6, k - 1) IMPLIES
           (last > k IMPLIES (FORALL (j: upto(k)): RelF6(j) > 0)) AND
            (last <= k IMPLIES
              RelF6(last) = 0 AND
               (FORALL (j): j < last IMPLIES RelF6(j) > 0)));

  % Subtype TCC generated (at line 29, column 35) for  k - 1
      % expected type  nat
  first_eq_TCC6: OBLIGATION
    FORALL (RelF6: [nat -> subrange(0, 5)], k: nat):
      NOT k = 0 IMPLIES k - 1 >= 0;

  % Termination TCC generated (at line 29, column 20) for
      % first_eq(RelF6, k - 1)
  first_eq_TCC7: OBLIGATION
    FORALL (RelF6: [nat -> subrange(0, 5)], k: nat):
      NOT k = 0 IMPLIES k - 1 < k;

  % Subtype TCC generated (at line 52, column 23) for  (-1) * a
      % expected type  [nat -> int]
  greatify_poly_TCC1: OBLIGATION
    FORALL (i: subrange(0, 5), a: [nat -> int]):
      i = 2 OR i = 5 IMPLIES
       (FORALL (x1: nat):
          rational_pred((*[nat]((-1), a))(x1)) AND
           integer_pred((*[nat]((-1), a))(x1)));

  % Subtype TCC generated (at line 58, column 54) for  RelF6(i)
      % expected type  {pz: subrange(0, 5) | pz /= 2 AND pz /= 5}
  greatify_rel_TCC1: OBLIGATION
    FORALL (RelF6: [nat -> subrange(0, 5)], i: nat):
      NOT RelF6(i) = 5 AND NOT RelF6(i) = 2 IMPLIES
       RelF6(i) /= 2 AND RelF6(i) /= 5;

  % Subtype TCC generated (at line 62, column 43) for  n
      % expected type  {n |
                     %          FORALL (j: upto(k)):
                     %            greatify_poly_rel(p, RelF6)(j)(n(j)) /= 0}
  greatify_def_TCC1: OBLIGATION
    FORALL (RelF6: [nat -> subrange(0, 5)], k: nat, n: [nat -> nat],
            p: [nat -> [nat -> int]]):
      (FORALL (j: upto(k)): p(j)(n(j)) /= 0) IMPLIES
       (FORALL (j: upto(k)): greatify_poly_rel(p, RelF6)(j)(n(j)) /= 0);

  % Subtype TCC generated (at line 69, column 43) for  d
      % expected type  {m | a(m) /= 0}
  compute_solvable_single_TCC1: OBLIGATION
    FORALL (i: subrange(0, 5), a: [nat -> int], (d: nat | a(d) /= 0)):
      NOT i = 3 AND NOT d = 1 AND NOT d = 0 IMPLIES d > 0 AND a(d) /= 0;

  % Subtype TCC generated (at line 76, column 26) for  poly_deriv(a)
      % expected type  [nat -> int]
  compute_solvable_single_TCC2: OBLIGATION
    FORALL (i: subrange(0, 5), a: [nat -> int], (d: nat | a(d) /= 0)):
      NOT i = 3 AND NOT d = 1 AND NOT d = 0 IMPLIES
       (FORALL (iseq: boolean):
          NOT (i /= 1 AND i /= 2 AND iseq) AND
           NOT i = 0 AND
            iseq =
             (sturm_tarski_faster(1, a, d, LAMBDA (k): LAMBDA (j): 1,
                                  LAMBDA (k): 0, LAMBDA (j): 1)
               /= 0)
           IMPLIES
           (FORALL (newa: [nat -> real]):
              NOT (odd?(d) AND newa(d) < 0) AND
               NOT newa(d) > 0 AND
                newa = IF rel5(i)(1, 0) THEN a ELSE (-1) * a ENDIF
               IMPLIES
               (FORALL (x1: nat):
                  rational_pred(poly_deriv(a)(x1)) AND
                   integer_pred(poly_deriv(a)(x1)))));

  % Subtype TCC generated (at line 76, column 40) for  d - 1
      % expected type  {m | poly_deriv(a)(m) /= 0}
  compute_solvable_single_TCC3: OBLIGATION
    FORALL (i: subrange(0, 5), a: [nat -> int], (d: nat | a(d) /= 0)):
      NOT i = 3 AND NOT d = 1 AND NOT d = 0 IMPLIES
       (FORALL (iseq: boolean):
          NOT (i /= 1 AND i /= 2 AND iseq) AND
           NOT i = 0 AND
            iseq =
             (sturm_tarski_faster(1, a, d, LAMBDA (k): LAMBDA (j): 1,
                                  LAMBDA (k): 0, LAMBDA (j): 1)
               /= 0)
           IMPLIES
           (FORALL (newa: [nat -> real]):
              NOT (odd?(d) AND newa(d) < 0) AND
               NOT newa(d) > 0 AND
                newa = IF rel5(i)(1, 0) THEN a ELSE (-1) * a ENDIF
               IMPLIES
               d - 1 >= 0 AND d - 1 > 0 AND poly_deriv(a)(d - 1) /= 0));

  % Subtype TCC generated (at line 76, column 56) for  newa
      % expected type  [nat -> int]
  compute_solvable_single_TCC4: OBLIGATION
    FORALL (i: subrange(0, 5), a: [nat -> int], (d: nat | a(d) /= 0)):
      NOT i = 3 AND NOT d = 1 AND NOT d = 0 IMPLIES
       (FORALL (iseq: boolean):
          NOT (i /= 1 AND i /= 2 AND iseq) AND
           NOT i = 0 AND
            iseq =
             (sturm_tarski_faster(1, a, d, LAMBDA (k): LAMBDA (j): 1,
                                  LAMBDA (k): 0, LAMBDA (j): 1)
               /= 0)
           IMPLIES
           (FORALL (newa: [nat -> real]):
              NOT (odd?(d) AND newa(d) < 0) AND
               NOT newa(d) > 0 AND
                newa = IF rel5(i)(1, 0) THEN a ELSE (-1) * a ENDIF
               IMPLIES
               (FORALL (x1: nat):
                  rational_pred(newa(x1)) AND integer_pred(newa(x1)))));

  % Subtype TCC generated (at line 77, column 20) for  LAMBDA (j): d
      % expected type  {n | FORALL (i: upto(1)): newa(n(i)) /= 0}
  compute_solvable_single_TCC5: OBLIGATION
    FORALL (i: subrange(0, 5), a: [nat -> int], (d: nat | a(d) /= 0)):
      NOT i = 3 AND NOT d = 1 AND NOT d = 0 IMPLIES
       (FORALL (iseq: boolean):
          NOT (i /= 1 AND i /= 2 AND iseq) AND
           NOT i = 0 AND
            iseq =
             (sturm_tarski_faster(1, a, d, LAMBDA (k): LAMBDA (j): 1,
                                  LAMBDA (k): 0, LAMBDA (j): 1)
               /= 0)
           IMPLIES
           (FORALL (newa: [nat -> real]):
              NOT (odd?(d) AND newa(d) < 0) AND
               NOT newa(d) > 0 AND
                newa = IF rel5(i)(1, 0) THEN a ELSE (-1) * a ENDIF
               IMPLIES (FORALL (i: upto(1)): newa(d) /= 0)));

  % Subtype TCC generated (at line 95, column 54) for  n(0)
      % expected type  {d | p(0)(d) /= 0}
  compute_solvable_TCC1: OBLIGATION
    FORALL (k: nat, p: [nat -> [nat -> int]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)], newp: [nat -> [nat -> int]]):
      newp = greatify_poly_rel(p, RelF6) IMPLIES
       (FORALL (newRel: [nat -> {pz: subrange(0, 5) | pz /= 2 AND pz /= 5}]):
          k = 0 AND newRel = greatify_rel(RelF6) IMPLIES p(0)(n(0)) /= 0);

  % Subtype TCC generated (at line 98, column 41) for  n(fe)
      % expected type  {m | newp(fe)(m) /= 0}
  compute_solvable_TCC2: OBLIGATION
    FORALL (k: nat, p: [nat -> [nat -> int]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)], newp: [nat -> [nat -> int]]):
      newp = greatify_poly_rel(p, RelF6) IMPLIES
       (FORALL (newRel: [nat -> {pz: subrange(0, 5) | pz /= 2 AND pz /= 5}]):
          (EXISTS (i: upto(k)): newRel(i) = 0) AND
           NOT k = 0 AND newRel = greatify_rel(RelF6)
           IMPLIES
           (FORALL (fe:
                      {i |
                               (i > k IMPLIES
                                 (FORALL (j: upto(k)): newRel(j) > 0))
                                AND
                                (i <= k IMPLIES
                                  newRel(i) = 0 AND
                                   (FORALL (j):
                                      j < i IMPLIES newRel(j) > 0))}):
              fe = first_eq(newRel, k) IMPLIES
               n(fe) > 0 AND newp(fe)(n(fe)) /= 0));

  % Subtype TCC generated (at line 100, column 17) for
      % (LAMBDA (i): IF i < fe THEN n(i) ELSE n(i + 1) ENDIF)
      % expected type  {n |
                     %          FORALL (i_1: upto(k - 1)):
                     %            NOT IF i_1 < fe
                     %                THEN newp(i_1)(n(i_1))
                     %                ELSE newp(1 + i_1)(n(i_1))
                     %                ENDIF
                     %                =
                     %                0}
  compute_solvable_TCC3: OBLIGATION
    FORALL (k: nat, p: [nat -> [nat -> int]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)], newp: [nat -> [nat -> int]]):
      newp = greatify_poly_rel(p, RelF6) IMPLIES
       (FORALL (newRel: [nat -> {pz: subrange(0, 5) | pz /= 2 AND pz /= 5}]):
          (EXISTS (i: upto(k)): newRel(i) = 0) AND
           NOT k = 0 AND newRel = greatify_rel(RelF6)
           IMPLIES
           (FORALL (fe:
                      {i |
                               (i > k IMPLIES
                                 (FORALL (j: upto(k)): newRel(j) > 0))
                                AND
                                (i <= k IMPLIES
                                  newRel(i) = 0 AND
                                   (FORALL (j):
                                      j < i IMPLIES newRel(j) > 0))}):
              fe = first_eq(newRel, k) IMPLIES
               (FORALL (i_1: upto(k - 1)):
                  NOT IF i_1 < fe
                        THEN newp(i_1)
                                 (IF i_1 < fe THEN n(i_1)
                                  ELSE n(i_1 + 1)
                                  ENDIF)
                      ELSE newp(1 + i_1)
                               (IF i_1 < fe THEN n(i_1)
                                ELSE n(i_1 + 1)
                                ENDIF)
                      ENDIF
                       = 0)));

  % Subtype TCC generated (at line 107, column 48) for  Qdeg
      % expected type  {m | Qprod(m) /= 0}
  compute_solvable_TCC4: OBLIGATION
    FORALL (k: nat, p: [nat -> [nat -> int]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)], newp: [nat -> [nat -> int]]):
      newp = greatify_poly_rel(p, RelF6) IMPLIES
       (FORALL (newRel: [nat -> {pz: subrange(0, 5) | pz /= 2 AND pz /= 5}]):
          NOT (EXISTS (i: upto(k)): newRel(i) = 0) AND
           NOT k = 0 AND newRel = greatify_rel(RelF6)
           IMPLIES
           (FORALL (Qprodlist:
                      {ll |
                               length[int](ll) - 1 =
                                sigma[nat](0, k, *[nat](n, LAMBDA i: 1))
                                AND
                                prod_polynomials(newp, n, LAMBDA i: 1, k) =
                                 (LAMBDA (i):
                                    IF i < length[int](ll)
                                      THEN nth[int](ll, i)
                                    ELSE 0
                                    ENDIF)}):
              Qprodlist = prod_polynomials_list(newp, n, LAMBDA i: 1, k)
               IMPLIES
               (FORALL (Qdeg: int):
                  Qdeg = length(Qprodlist) - 1 IMPLIES
                   (FORALL (Qprod: [nat -> int]):
                      (Qdeg > 0 AND
                        Qprod =
                         (LAMBDA (i):
                            IF i < length(Qprodlist) THEN nth(Qprodlist, i)
                            ELSE 0
                            ENDIF))
                       IMPLIES Qdeg >= 0 AND Qprod(Qdeg) /= 0))));

  % Subtype TCC generated (at line 107, column 58) for  n
      % expected type  {n | FORALL (i: upto(k)): newp(i)(n(i)) /= 0}
  compute_solvable_TCC5: OBLIGATION
    FORALL (k: nat, p: [nat -> [nat -> int]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)], newp: [nat -> [nat -> int]]):
      newp = greatify_poly_rel(p, RelF6) IMPLIES
       (FORALL (newRel: [nat -> {pz: subrange(0, 5) | pz /= 2 AND pz /= 5}]):
          NOT (EXISTS (i: upto(k)): newRel(i) = 0) AND
           NOT k = 0 AND newRel = greatify_rel(RelF6)
           IMPLIES
           (FORALL (Qprodlist:
                      {ll |
                               length[int](ll) - 1 =
                                sigma[nat](0, k, *[nat](n, LAMBDA i: 1))
                                AND
                                prod_polynomials(newp, n, LAMBDA i: 1, k) =
                                 (LAMBDA (i):
                                    IF i < length[int](ll)
                                      THEN nth[int](ll, i)
                                    ELSE 0
                                    ENDIF)}):
              Qprodlist = prod_polynomials_list(newp, n, LAMBDA i: 1, k)
               IMPLIES
               (FORALL (Qdeg: int):
                  Qdeg = length(Qprodlist) - 1 IMPLIES
                   (FORALL (Qprod: [nat -> int]):
                      (Qdeg > 0 AND
                        Qprod =
                         (LAMBDA (i):
                            IF i < length(Qprodlist) THEN nth(Qprodlist, i)
                            ELSE 0
                            ENDIF))
                       IMPLIES (FORALL (i: upto(k)): newp(i)(n(i)) /= 0)))));

  % Subtype TCC generated (at line 113, column 25) for  poly_deriv(Qprod)
      % expected type  [nat -> int]
  compute_solvable_TCC6: OBLIGATION
    FORALL (k: nat, p: [nat -> [nat -> int]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)], newp: [nat -> [nat -> int]]):
      newp = greatify_poly_rel(p, RelF6) IMPLIES
       (FORALL (newRel: [nat -> {pz: subrange(0, 5) | pz /= 2 AND pz /= 5}]):
          NOT (EXISTS (i: upto(k)): newRel(i) = 0) AND
           NOT k = 0 AND newRel = greatify_rel(RelF6)
           IMPLIES
           (FORALL (Qprodlist:
                      {ll |
                               length[int](ll) - 1 =
                                sigma[nat](0, k, *[nat](n, LAMBDA i: 1))
                                AND
                                prod_polynomials(newp, n, LAMBDA i: 1, k) =
                                 (LAMBDA (i):
                                    IF i < length[int](ll)
                                      THEN nth[int](ll, i)
                                    ELSE 0
                                    ENDIF)}):
              Qprodlist = prod_polynomials_list(newp, n, LAMBDA i: 1, k)
               IMPLIES
               (FORALL (Qdeg: int):
                  Qdeg = length(Qprodlist) - 1 IMPLIES
                   (FORALL (Qprod: [nat -> int]):
                      (     NOT (FORALL (j: upto(k)):
                                   (odd?(n(j)) IMPLIES
                                     rel5(newRel(j))(-newp(j)(n(j)), 0))
                                    AND
                                    (even?(n(j)) IMPLIES
                                      rel5(newRel(j))(newp(j)(n(j)), 0)))
                        AND NOT (FORALL (j: upto(k)):
                                   rel5(newRel(j))(newp(j)(n(j)), 0))
                        AND Qdeg >= 2
                        AND NOT (Qdeg > 0 AND
                                  sturm_tarski_faster(k,
                                                      Qprod,
                                                      Qdeg,
                                                      newp,
                                                      n,
                                                      newRel)
                                   /= 0)
                        AND Qprod =
                             (LAMBDA (i):
                                IF i < length(Qprodlist)
                                  THEN nth(Qprodlist, i)
                                ELSE 0
                                ENDIF))
                       IMPLIES
                       (FORALL (x1: nat):
                          rational_pred(poly_deriv(Qprod)(x1)) AND
                           integer_pred(poly_deriv(Qprod)(x1)))))));

  % Subtype TCC generated (at line 113, column 43) for  Qdeg - 1
      % expected type  {m | poly_deriv(Qprod)(m) /= 0}
  compute_solvable_TCC7: OBLIGATION
    FORALL (k: nat, p: [nat -> [nat -> int]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)], newp: [nat -> [nat -> int]]):
      newp = greatify_poly_rel(p, RelF6) IMPLIES
       (FORALL (newRel: [nat -> {pz: subrange(0, 5) | pz /= 2 AND pz /= 5}]):
          NOT (EXISTS (i: upto(k)): newRel(i) = 0) AND
           NOT k = 0 AND newRel = greatify_rel(RelF6)
           IMPLIES
           (FORALL (Qprodlist:
                      {ll |
                               length[int](ll) - 1 =
                                sigma[nat](0, k, *[nat](n, LAMBDA i: 1))
                                AND
                                prod_polynomials(newp, n, LAMBDA i: 1, k) =
                                 (LAMBDA (i):
                                    IF i < length[int](ll)
                                      THEN nth[int](ll, i)
                                    ELSE 0
                                    ENDIF)}):
              Qprodlist = prod_polynomials_list(newp, n, LAMBDA i: 1, k)
               IMPLIES
               (FORALL (Qdeg: int):
                  Qdeg = length(Qprodlist) - 1 IMPLIES
                   (FORALL (Qprod: [nat -> int]):
                      (     NOT (FORALL (j: upto(k)):
                                   (odd?(n(j)) IMPLIES
                                     rel5(newRel(j))(-newp(j)(n(j)), 0))
                                    AND
                                    (even?(n(j)) IMPLIES
                                      rel5(newRel(j))(newp(j)(n(j)), 0)))
                        AND NOT (FORALL (j: upto(k)):
                                   rel5(newRel(j))(newp(j)(n(j)), 0))
                        AND Qdeg >= 2
                        AND NOT (Qdeg > 0 AND
                                  sturm_tarski_faster(k,
                                                      Qprod,
                                                      Qdeg,
                                                      newp,
                                                      n,
                                                      newRel)
                                   /= 0)
                        AND Qprod =
                             (LAMBDA (i):
                                IF i < length(Qprodlist)
                                  THEN nth(Qprodlist, i)
                                ELSE 0
                                ENDIF))
                       IMPLIES
                       Qdeg - 1 >= 0 AND
                        Qdeg - 1 > 0 AND poly_deriv(Qprod)(Qdeg - 1) /= 0))));

  % Subtype TCC generated (at line 113, column 55) for  n
      % expected type  {n | FORALL (i: upto(k)): newp(i)(n(i)) /= 0}
  compute_solvable_TCC8: OBLIGATION
    FORALL (k: nat, p: [nat -> [nat -> int]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)], newp: [nat -> [nat -> int]]):
      newp = greatify_poly_rel(p, RelF6) IMPLIES
       (FORALL (newRel: [nat -> {pz: subrange(0, 5) | pz /= 2 AND pz /= 5}]):
          NOT (EXISTS (i: upto(k)): newRel(i) = 0) AND
           NOT k = 0 AND newRel = greatify_rel(RelF6)
           IMPLIES
           (FORALL (Qprodlist:
                      {ll |
                               length[int](ll) - 1 =
                                sigma[nat](0, k, *[nat](n, LAMBDA i: 1))
                                AND
                                prod_polynomials(newp, n, LAMBDA i: 1, k) =
                                 (LAMBDA (i):
                                    IF i < length[int](ll)
                                      THEN nth[int](ll, i)
                                    ELSE 0
                                    ENDIF)}):
              Qprodlist = prod_polynomials_list(newp, n, LAMBDA i: 1, k)
               IMPLIES
               (FORALL (Qdeg: int):
                  Qdeg = length(Qprodlist) - 1 IMPLIES
                   (FORALL (Qprod: [nat -> int]):
                      (     NOT (FORALL (j: upto(k)):
                                   (odd?(n(j)) IMPLIES
                                     rel5(newRel(j))(-newp(j)(n(j)), 0))
                                    AND
                                    (even?(n(j)) IMPLIES
                                      rel5(newRel(j))(newp(j)(n(j)), 0)))
                        AND NOT (FORALL (j: upto(k)):
                                   rel5(newRel(j))(newp(j)(n(j)), 0))
                        AND Qdeg >= 2
                        AND NOT (Qdeg > 0 AND
                                  sturm_tarski_faster(k,
                                                      Qprod,
                                                      Qdeg,
                                                      newp,
                                                      n,
                                                      newRel)
                                   /= 0)
                        AND Qprod =
                             (LAMBDA (i):
                                IF i < length(Qprodlist)
                                  THEN nth(Qprodlist, i)
                                ELSE 0
                                ENDIF))
                       IMPLIES (FORALL (i: upto(k)): newp(i)(n(i)) /= 0)))));

  % Subtype TCC generated (at line 122, column 89) for  i
      % expected type  below[length(lli)]
  poly_system_list_TCC1: OBLIGATION
    FORALL (k, lli: list[list[int]]):
      length[list[int]](lli) = k + 1 IMPLIES
       (FORALL (i: upto(k)): i < length[list[int]](lli));

  % Subtype TCC generated (at line 123, column 69) for  i
      % expected type  below[length[int](nth[list[int]](lli, j))]
  poly_system_list_TCC2: OBLIGATION
    FORALL (k, p,
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0),
            lli: list[list[int]]):
      (FORALL (i: upto(k)): length[int](nth[list[int]](lli, i)) = n(i) + 1)
       AND length[list[int]](lli) = k + 1
       IMPLIES
       (FORALL (j: upto(k), i1: upto(n(j))):
          i1 < length[int](nth[list[int]](lli, j)));

  % Subtype TCC generated (at line 124, column 6) for
      % array2list[list[int]]
      %     (k + 1)(LAMBDA (j: nat): array2list[int](n(j) + 1)(p(j)))
      % expected type  {lli: list[list[int]] |
                     %          length[list[int]](lli) = 1 + k AND
                     %           (FORALL (i: upto(k)):
                     %              length[int](nth[list[int]](lli, i)) =
                     %               1 + n(i))
                     %            AND
                     %            (FORALL (j: upto(k), i: upto(n(j))):
                     %               nth[int](nth[list[int]](lli, j), i) =
                     %                p(j)(i))}
  poly_system_list_TCC3: OBLIGATION
    FORALL (k: nat, p: [nat -> [nat -> int]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0)):
      length[list[int]]
          (array2list[list[int]]
               (k + 1)(LAMBDA (j: nat): array2list[int](n(j) + 1)(p(j))))
       = 1 + k
       AND
       (FORALL (i: upto(k)):
          length[int]
              (nth[list[int]]
                   (array2list[list[int]]
                        (k + 1)
                        (LAMBDA (j: nat): array2list[int](n(j) + 1)(p(j))),
                    i))
           = 1 + n(i))
        AND
        (FORALL (j_1: upto(k), i: upto(n(j_1))):
           nth[int]
               (nth[list[int]]
                    (array2list[list[int]]
                         (k + 1)
                         (LAMBDA (j: nat): array2list[int](n(j) + 1)(p(j))),
                     j_1),
                i)
            = p(j_1)(i));

  % Subtype TCC generated (at line 130, column 32) for  n
      % expected type  {n_1 |
                     %          FORALL (j: upto(k)):
                     %            pi(j)(n_1(j)) /= 0 AND n_1(j) > 0}
  tarski_TCC1: OBLIGATION
    FORALL (k: nat, pq: [nat -> [nat -> rat]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): pq(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)],
            pi:
              [j: nat ->
                 {ai: [nat -> int] |
                          EXISTS (cp: posrat):
                            FORALL (j_1: upto(n(j))):
                              ai(j_1) = cp * pq(j)(j_1)}]):
      (pi = (LAMBDA (j): rat_poly_to_int(pq(j), n(j)))) IMPLIES
       (FORALL (j: upto(k)): pi(j)(n(j)) /= 0 AND n(j) > 0);

  % Subtype TCC generated (at line 131, column 82) for  i
      % expected type  below[length(pl)]
  tarski_TCC2: OBLIGATION
    FORALL (k: nat, pq: [nat -> [nat -> rat]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): pq(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)],
            pi:
              [j: nat ->
                 {ai: [nat -> int] |
                          EXISTS (cp: posrat):
                            FORALL (j_1: upto(n(j))):
                              ai(j_1) = cp * pq(j)(j_1)}]):
      (pi = (LAMBDA (j): rat_poly_to_int(pq(j), n(j)))) IMPLIES
       (FORALL (pl:
                  {lli: list[list[int]] |
                           length[list[int]](lli) = 1 + k AND
                            (FORALL (i: upto(k)):
                               length[int](nth[list[int]](lli, i)) =
                                1 + n(i))
                             AND
                             (FORALL (j: upto(k), i: upto(n(j))):
                                nth[int](nth[list[int]](lli, j), i) =
                                 pi(j)(i))}):
          pl = poly_system_list(k, pi, n) IMPLIES
           (FORALL (i: nat, j1: nat):
              i <= k AND j1 <= n(i) IMPLIES i < length[list[int]](pl)));

  % Subtype TCC generated (at line 131, column 85) for  j
      % expected type  below[length[int](nth[list[int]](pl, i))]
  tarski_TCC3: OBLIGATION
    FORALL (k: nat, pq: [nat -> [nat -> rat]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): pq(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)],
            pi:
              [j: nat ->
                 {ai: [nat -> int] |
                          EXISTS (cp: posrat):
                            FORALL (j_1: upto(n(j))):
                              ai(j_1) = cp * pq(j)(j_1)}]):
      (pi = (LAMBDA (j): rat_poly_to_int(pq(j), n(j)))) IMPLIES
       (FORALL (pl:
                  {lli: list[list[int]] |
                           length[list[int]](lli) = 1 + k AND
                            (FORALL (i: upto(k)):
                               length[int](nth[list[int]](lli, i)) =
                                1 + n(i))
                             AND
                             (FORALL (j: upto(k), i: upto(n(j))):
                                nth[int](nth[list[int]](lli, j), i) =
                                 pi(j)(i))}):
          pl = poly_system_list(k, pi, n) IMPLIES
           (FORALL (i: nat, j1: nat):
              i <= k AND j1 <= n(i) IMPLIES
               j1 < length[int](nth[list[int]](pl, i))));

  % Subtype TCC generated (at line 132, column 28) for  n
      % expected type  {n | FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0}
  tarski_TCC4: OBLIGATION
    FORALL (k: nat, pq: [nat -> [nat -> rat]],
            (n: [nat -> nat]
                 | FORALL (j: upto(k)): pq(j)(n(j)) /= 0 AND n(j) > 0),
            RelF6: [nat -> subrange(0, 5)],
            pi:
              [j: nat ->
                 {ai: [nat -> int] |
                          EXISTS (cp: posrat):
                            FORALL (j_1: upto(n(j))):
                              ai(j_1) = cp * pq(j)(j_1)}]):
      (pi = (LAMBDA (j): rat_poly_to_int(pq(j), n(j)))) IMPLIES
       (FORALL (pl:
                  {lli: list[list[int]] |
                           length[list[int]](lli) = 1 + k AND
                            (FORALL (i: upto(k)):
                               length[int](nth[list[int]](lli, i)) =
                                1 + n(i))
                             AND
                             (FORALL (j: upto(k), i: upto(n(j))):
                                nth[int](nth[list[int]](lli, j), i) =
                                 pi(j)(i))}):
          pl = poly_system_list(k, pi, n) IMPLIES
           (FORALL (p: [nat -> [nat -> int]]):
              (p =
                (LAMBDA (i):
                   LAMBDA (j):
                     IF i <= k AND j <= n(i)
                       THEN nth[int](nth[list[int]](pl, i), j)
                     ELSE 0
                     ENDIF))
               IMPLIES (FORALL (j: upto(k)): p(j)(n(j)) /= 0 AND n(j) > 0)));


body:
  strategies : THEORY
  BEGIN

    IMPORTING poly_system_strategy,
              Sturm@strategies
    
    %% This constant is used by the strategies to check if all the required theories 
    %% have been imported in the current context

    TarskiStrategy__ : Unit 

  END strategies


body:
  examples: THEORY
  BEGIN

    IMPORTING strategies

    example_fall : LEMMA
      FORALL (x:real): x^3 < 0 OR x*x*x > 0 OR x^2 = 0
  %|- example_fall : PROOF
  %|- (tarski)
  %|- QED

    example_ex : LEMMA
      EXISTS (x:real) : x^3 = x AND x^2 = x
  %|- example_ex : PROOF
  %|- (tarski)
  %|- QED

    example_1: LEMMA
      FORALL(y,x,z:real): (x-2)^2*(-x+4)>0 AND x^2*(x-3)^2>=0 AND x-1>=0 AND -(x-3)^2+1>0
      IMPLIES
      -(x-11/12)^3*(x-41/10)^3>=0 
  %|- example_1 : PROOF
  %|- (tarski)
  %|- QED

    example_2: LEMMA
      FORALL (x:real): x>=-9 AND x<10 AND x^4>0 IMPLIES x^12>0
  %|- example_2 : PROOF
  %|- (tarski)
  %|- QED

    example_3: LEMMA
      EXISTS (x:real): 
        (x-2)^2*(-x+4)>0 AND x^2*(x-3)^2>=0 AND x-1>=0 AND -(x-3)^2+1>0 AND
       -(x-11/12)^3*(x-41/10)^3<1/10
  %|- example_3 : PROOF
  %|- (tarski)
  %|- QED

    example_4 : LEMMA
      EXISTS (x:real):
        x^5 - x - 1 = 0
        AND 
        x^12 + 425/23*x^11 - 228/23*x^10 - 2*x^8 
        - 896/23*x^7 - 394/23*x^6 + 456/23*x^5 + x^4 
        + 471/23*x^3 + 645/23*x^2 - 31/23*x - 228/23= 0 
        AND x^3 + 22*x^2 -31 >=0 
        AND x^22 -234/567*x^20 -419*x^10+ 1948>0
  %|- example_4 : PROOF
  %|- (tarski)
  %|- QED

   example_5 : LEMMA
     FORALL (x:real): x^2 >= 1 IMPLIES abs(x) >= 1
  %|- example_5 : PROOF
  %|- (tarski)
  %|- QED

  END examples

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

  % Subtype TCC generated (at line 7, column 23) for  3
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_fall_TCC1: OBLIGATION FORALL (x: real): x /= 0 OR 3 >= 0;

  % Subtype TCC generated (at line 7, column 47) for  2
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_fall_TCC2: OBLIGATION
    FORALL (x: real):
      NOT x * x * x > 0 AND NOT x ^ 3 < 0 IMPLIES x /= 0 OR 2 >= 0;

  % Subtype TCC generated (at line 13, column 36) for  2
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_ex_TCC1: OBLIGATION
    FORALL (x: real): x ^ 3 = x IMPLIES x /= 0 OR 2 >= 0;

  % Subtype TCC generated (at line 19, column 30) for  2
      % expected type  {i: int | (x - 2) /= 0 OR i >= 0}
  example_1_TCC1: OBLIGATION FORALL (x: real): (x - 2) /= 0 OR 2 >= 0;

  % Subtype TCC generated (at line 19, column 47) for  2
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_1_TCC2: OBLIGATION
    FORALL (x: real): (x - 2) ^ 2 * (-x + 4) > 0 IMPLIES x /= 0 OR 2 >= 0;

  % Subtype TCC generated (at line 19, column 55) for  2
      % expected type  {i: int | (x - 3) /= 0 OR i >= 0}
  example_1_TCC3: OBLIGATION
    FORALL (x: real):
      (x - 2) ^ 2 * (-x + 4) > 0 IMPLIES (x - 3) /= 0 OR 2 >= 0;

  % Subtype TCC generated (at line 21, column 15) for  3
      % expected type  {i: int | NOT (x - 11/12) = 0 OR i >= 0}
  example_1_TCC4: OBLIGATION
    FORALL (x: real):
      (x - 2) ^ 2 * (-x + 4) > 0 AND
       x ^ 2 * (x - 3) ^ 2 >= 0 AND x - 1 >= 0 AND -(x - 3) ^ 2 + 1 > 0
       IMPLIES NOT (x - 11/12) = 0 OR 3 >= 0;

  % Subtype TCC generated (at line 21, column 27) for  3
      % expected type  {i: int | NOT (x - 41/10) = 0 OR i >= 0}
  example_1_TCC5: OBLIGATION
    FORALL (x: real):
      (x - 2) ^ 2 * (-x + 4) > 0 AND
       x ^ 2 * (x - 3) ^ 2 >= 0 AND x - 1 >= 0 AND -(x - 3) ^ 2 + 1 > 0
       IMPLIES NOT (x - 41/10) = 0 OR 3 >= 0;

  % Subtype TCC generated (at line 27, column 42) for  4
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_2_TCC1: OBLIGATION
    FORALL (x: real): x < 10 AND x >= -9 IMPLIES x /= 0 OR 4 >= 0;

  % Subtype TCC generated (at line 27, column 56) for  12
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_2_TCC2: OBLIGATION
    FORALL (x: real):
      x >= -9 AND x < 10 AND x ^ 4 > 0 IMPLIES x /= 0 OR 12 >= 0;

  % Subtype TCC generated (at line 42, column 8) for  5
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_4_TCC1: OBLIGATION FORALL (x: real): x /= 0 OR 5 >= 0;

  % Subtype TCC generated (at line 44, column 8) for  12
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_4_TCC2: OBLIGATION
    FORALL (x: real): x ^ 5 - x - 1 = 0 IMPLIES x /= 0 OR 12 >= 0;

  % Subtype TCC generated (at line 44, column 22) for  11
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_4_TCC3: OBLIGATION
    FORALL (x: real): x ^ 5 - x - 1 = 0 IMPLIES x /= 0 OR 11 >= 0;

  % Subtype TCC generated (at line 44, column 36) for  10
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_4_TCC4: OBLIGATION
    FORALL (x: real): x ^ 5 - x - 1 = 0 IMPLIES x /= 0 OR 10 >= 0;

  % Subtype TCC generated (at line 44, column 45) for  8
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_4_TCC5: OBLIGATION
    FORALL (x: real): x ^ 5 - x - 1 = 0 IMPLIES x /= 0 OR 8 >= 0;

  % Subtype TCC generated (at line 45, column 17) for  7
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_4_TCC6: OBLIGATION
    FORALL (x: real): x ^ 5 - x - 1 = 0 IMPLIES x /= 0 OR 7 >= 0;

  % Subtype TCC generated (at line 45, column 30) for  6
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_4_TCC7: OBLIGATION
    FORALL (x: real): x ^ 5 - x - 1 = 0 IMPLIES x /= 0 OR 6 >= 0;

  % Subtype TCC generated (at line 45, column 49) for  4
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_4_TCC8: OBLIGATION
    FORALL (x: real): x ^ 5 - x - 1 = 0 IMPLIES x /= 0 OR 4 >= 0;

  % Subtype TCC generated (at line 46, column 30) for  2
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_4_TCC9: OBLIGATION
    FORALL (x: real): x ^ 5 - x - 1 = 0 IMPLIES x /= 0 OR 2 >= 0;

  % Subtype TCC generated (at line 48, column 12) for  22
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_4_TCC10: OBLIGATION
    FORALL (x: real):
      x ^ 3 + 22 * x ^ 2 - 31 >= 0 AND
       x ^ 12 + 425 / 23 * x ^ 11 - 228 / 23 * x ^ 10 - 2 * x ^ 8 -
        896 / 23 * x ^ 7
        - 394 / 23 * x ^ 6
        + 456 / 23 * x ^ 5
        + x ^ 4
        + 471 / 23 * x ^ 3
        + 645 / 23 * x ^ 2
        - 31 / 23 * x
        - 228 / 23
        = 0
        AND x ^ 5 - x - 1 = 0
       IMPLIES x /= 0 OR 22 >= 0;

  % Subtype TCC generated (at line 48, column 26) for  20
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_4_TCC11: OBLIGATION
    FORALL (x: real):
      x ^ 3 + 22 * x ^ 2 - 31 >= 0 AND
       x ^ 12 + 425 / 23 * x ^ 11 - 228 / 23 * x ^ 10 - 2 * x ^ 8 -
        896 / 23 * x ^ 7
        - 394 / 23 * x ^ 6
        + 456 / 23 * x ^ 5
        + x ^ 4
        + 471 / 23 * x ^ 3
        + 645 / 23 * x ^ 2
        - 31 / 23 * x
        - 228 / 23
        = 0
        AND x ^ 5 - x - 1 = 0
       IMPLIES x /= 0 OR 20 >= 0;

  % Subtype TCC generated (at line 54, column 22) for  2
      % expected type  {i: int | x /= 0 OR i >= 0}
  example_5_TCC1: OBLIGATION FORALL (x: real): x /= 0 OR 2 >= 0;


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

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:
  %------------------------------------------------------------------------------
  % Mathematical Structures (algebra)
  %
  % Group-, Ring-, and Field-like Mathematical Structures.
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler,  NASA Langley
  %             
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %     Version 1.3          10/18/04   Added a bunch of AUTO-REWRITE+s
  %     Version 1.4           8/27/07   Added theory cyclic_groups
  %     Version 1.5          12/14/07   Lagrange proof improved, cosets
  %                                     factor_groups
  %     Version 1.6          12/20/07   Consolidated finite_* theories into
  %                                     main theories -- no need for parent type
  %                                     to be finite. Can construct finite
  %                                     groups from infinite domains, renamed 
  %                                     inverse -> inv for slow typers
  %
  %------------------------------------------------------------------------------

  top: THEORY

  BEGIN

     IMPORTING top_group,
               %---------------------
               groupoid,              
               commutative_groupoid,  
               semigroup,             
               commutative_semigroup, 
               monad,                 
               monoid,                
               cyclic_monoid,
               cyclic_group,
               group,   
               subgroups,          
               lagrange,
               abelian_group,      
               symmetric_groups,
               group_test,

               finite_cyclic_groups,
               infinite_cyclic_groups,
               factor_groups,          %% RWB experimental
               A_group,       
               homomorphisms, 
               cayleys,       
               zn,                   

               top_field,
               %---------------------------
               ring,                      % semigroup[T,*]
               commutative_ring,          % commutative_semigroup[T,*]
               ring_nz_closed,            % semigroup[T,*], semigroup[nz_T,*]
               ring_with_one,             % monoid[T,*,one]
               commutative_ring_with_one, % commutative_monoid[T,*,one]
               integral_domain,           % commutative_semigroup[T,*]
                                          % commutative_semigroup[nz_T,*]
               division_ring,             % monoid[T,*,one], group[nz_T,*,one]
               field                      % commutative_monoid[T,*,one]
                                          % abelian_group[nz_T,*,one]
  END top


body:
  %------------------------------------------------------------------------------
  % Extras for operator_def file
  %
  %     Author: David Lester, Manchester University & NIA
  %
  %     Version 1.0            5/5/04   DRL
  %------------------------------------------------------------------------------

  operator_defs_more[T: TYPE]: THEORY

    BEGIN
    o,*:   VAR [T,T->T]
    x,y,z: VAR T

    closed_operator?(o)     : bool = (FORALL x,y:   member(x o y, fullset[T]))
    right_distributive?(*,o): bool = (FORALL x,y,z: x*(y o z) = (x*y) o (x*z))
    left_distributive?(*,o) : bool = (FORALL x,y,z: (x o y)*z = (x*z) o (y*z))

    commutative_over?(S:set[T])(*) : bool
       = (FORALL x,y:   member(x,S) AND member(y,S) IMPLIES x*y = y*x)
    associative_over?(S:set[T])(*) : bool
       = (FORALL x,y,z: member(x,S) AND member(y,S) AND member(z,S) IMPLIES
                                                           (x*y)*z = x*(y*z))

    END operator_defs_more


body:
  %------------------------------------------------------------------------------
  % Groupoids definition file
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  groupoid_def[T:Type,*:[T,T->T]]: THEORY

  BEGIN

    S: VAR set[T]

    star_closed?(S): bool           = (FORALL (x,y:(S)): member(x*y,S))

    groupoid?(S): MACRO bool        = star_closed?(S)
    finite_groupoid?(S): bool       = groupoid?(S) AND is_finite(S)
    commutative_groupoid?(S): bool  = groupoid?(S) AND commutative?[(S)](*)
    finite_commutative_groupoid?(S): bool
                                    = finite_groupoid?(S) AND
                                      commutative?[(S)](*)

  END groupoid_def

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

  % Subtype TCC generated (at line 22, column 71) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  commutative_groupoid?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      star_closed?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));

  % Subtype TCC generated (at line 25, column 54) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  finite_commutative_groupoid?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      finite_groupoid?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));


body:
  %------------------------------------------------------------------------------
  % Groupoids
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  groupoid[T:Type+,*:[T,T->T]]: THEORY

  BEGIN

     IMPORTING groupoid_def[T,*]

     fullset_is_groupoid: LEMMA groupoid?(fullset[T])

     groupoid: NONEMPTY_TYPE = (groupoid?) CONTAINING fullset[T]

     G: VAR groupoid

     closed         : LEMMA FORALL (x,y:(G)): member(x*y,G)

     star_closed    : LEMMA FORALL (x,y:(G)): G(x*y)

     groupoid_is_set: JUDGEMENT groupoid SUBTYPE_OF set[T]


  END groupoid

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

  % Subtype TCC generated (at line 20, column 52) for  fullset[T]
      % expected type  groupoid
  groupoid_TCC1: OBLIGATION star_closed?[T, *](fullset[T]);


body:
  %------------------------------------------------------------------------------
  % Semigroups definition file
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  semigroup_def[T:Type,*:[T,T->T]]: THEORY

  BEGIN

      IMPORTING groupoid_def[T,*]

      S: VAR set[T]

      semigroup?(S): MACRO bool              = groupoid?(S) AND
                                               associative?[(S)](*)
      finite_semigroup?(S): bool             = semigroup?(S) AND is_finite(S)
      commutative_semigroup?(S): bool        = semigroup?(S) AND
                                               commutative?[(S)](*)
      finite_commutative_semigroup?(S): bool = finite_semigroup?(S) AND
                                               commutative?[(S)](*)

  END semigroup_def

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

  % Subtype TCC generated (at line 21, column 63) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  semigroup?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      star_closed?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));

  % Subtype TCC generated (at line 26, column 63) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  finite_commutative_semigroup?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      finite_semigroup?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));


body:
  %------------------------------------------------------------------------------
  % Semigroups
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  semigroup[T:Type+,*:[T,T->T]]: THEORY

  BEGIN

     ASSUMING IMPORTING semigroup_def[T,*]

         fullset_is_semigroup: ASSUMPTION semigroup?(fullset[T])

     ENDASSUMING

     IMPORTING semigroup_def, groupoid[T,*]

     semigroup: TYPE+ = (semigroup?) CONTAINING fullset[T]

     x,y,z: VAR T

     associative:           LEMMA (x * y) * z = x * (y * z)

     semigroup_is_groupoid: JUDGEMENT semigroup SUBTYPE_OF groupoid


  END semigroup

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

  % Subtype TCC generated (at line 24, column 46) for  fullset[T]
      % expected type  semigroup
  semigroup_TCC1: OBLIGATION
    star_closed?[T, *](fullset[T]) AND
     associative?[(fullset[T])]
         (restrict[[T, T], [(fullset[T]), (fullset[T])], T](*));


body:
  %------------------------------------------------------------------------------
  % Monads definition file
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  monad_def[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN

    IMPORTING groupoid_def[T,*]

    S: VAR set[T]

    monad?(S): bool                    = groupoid?(S) AND
                                         member(one,S) AND
                                         identity?[(S)](*)(one)
    finite_monad?(S): bool             = monad?(S) AND is_finite(S)
    commutative_monad?(S): bool        = monad?(S) AND commutative?[(S)](*)
    finite_commutative_monad?(S): bool = finite_monad?(S) AND
                                         commutative?[(S)](*)

  END monad_def

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

  % Subtype TCC generated (at line 22, column 57) for  one
      % expected type  (S)
  monad?_TCC1: OBLIGATION
    FORALL (S: set[T]): member(one, S) AND star_closed?(S) IMPLIES S(one);

  % Subtype TCC generated (at line 22, column 54) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  monad?_TCC2: OBLIGATION
    FORALL (S: set[T]):
      member(one, S) AND star_closed?(S) IMPLIES
       (FORALL (x1: [(S), (S)]): S(*(x1)));

  % Subtype TCC generated (at line 24, column 71) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  commutative_monad?_TCC1: OBLIGATION
    FORALL (S: set[T]): monad?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));

  % Subtype TCC generated (at line 26, column 57) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  finite_commutative_monad?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      finite_monad?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));


body:
  %------------------------------------------------------------------------------
  % Monads
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  monad[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN

     ASSUMING IMPORTING monad_def[T,*,one]

         fullset_is_monad: ASSUMPTION monad?(fullset[T])

     ENDASSUMING

     IMPORTING monad_def[T,*,one], groupoid[T,*]

     monad: TYPE+ = (monad?) CONTAINING fullset[T]

     M:   VAR monad
     x,y: VAR T

     one_member:            LEMMA member(one,M)
     one_in    :            LEMMA M(one)
     left_identity:         LEMMA one * x = x
     right_identity:        LEMMA x * one = x
     unique_left_identity:  LEMMA (FORALL (x:(M)): y*x = x) IFF y = one
     unique_right_identity: LEMMA (FORALL (x:(M)): x*y = x) IFF y = one

     one_is_monad:          LEMMA monad?(singleton[T](one))

     trivial_monad: monad = singleton(one)

     monad_is_groupoid: JUDGEMENT monad SUBTYPE_OF groupoid

     AUTO_REWRITE+ one_member
     AUTO_REWRITE+ one_in
     AUTO_REWRITE+ left_identity
     AUTO_REWRITE+ right_identity
     AUTO_REWRITE+  member
     AUTO_REWRITE+  one_is_monad

     sing_one_finite_monad: LEMMA finite_monad?(singleton[T](one))

     finite_monad: TYPE+ = (finite_monad?) 
     commutative_monad: TYPE+ = (commutative_monad?) 
     finite_commutative_monad: TYPE+ = (finite_commutative_monad?)

     F: VAR finite_monad

     order(F):posnat  = card(F)

     order_is_1: LEMMA order(F) = 1 IMPLIES F = singleton[T](one)

     finite_monad_is_monad: JUDGEMENT finite_monad SUBTYPE_OF monad

     commutative_monad_is_monad:    JUDGEMENT commutative_monad SUBTYPE_OF monad

     finite_commutative_monad_is_commutative_monad:
        JUDGEMENT finite_commutative_monad SUBTYPE_OF commutative_monad

     finite_commutative_monad_is_finite_monad:
        JUDGEMENT finite_commutative_monad SUBTYPE_OF finite_monad

  END monad

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

  % Subtype TCC generated (at line 24, column 38) for  fullset[T]
      % expected type  monad
  monad_TCC1: OBLIGATION monad?[T, *, one](fullset[T]);

  % Subtype TCC generated (at line 38, column 26) for  singleton(one)
      % expected type  monad
  trivial_monad_TCC1: OBLIGATION monad?[T, *, one](singleton[T](one));

  % Judgement subtype TCC generated (at line 40, column 32) for  x
      % expected type  groupoid[T, *]
  monad_is_groupoid: OBLIGATION FORALL (x: monad): star_closed?[T, *](x);

  % Existence TCC generated (at line 51, column 3) for
      % finite_monad: TYPE+ = (finite_monad?)
  finite_monad_TCC1: OBLIGATION
    EXISTS (x: {x: set[T] | finite_monad?[T, *, one](x)}): TRUE;

  % Existence TCC generated (at line 52, column 3) for
      % commutative_monad: TYPE+ = (commutative_monad?)
  commutative_monad_TCC1: OBLIGATION
    EXISTS (x: {x: set[T] | commutative_monad?[T, *, one](x)}): TRUE;

  % Existence TCC generated (at line 53, column 3) for
      % finite_commutative_monad: TYPE+ = (finite_commutative_monad?)
  finite_commutative_monad_TCC1: OBLIGATION
    EXISTS (x: {x: set[T] | finite_commutative_monad?[T, *, one](x)}): TRUE;

  % Subtype TCC generated (at line 57, column 27) for  F
      % expected type  S: finite_set[T]
  order_TCC1: OBLIGATION FORALL (F: finite_monad): is_finite[T](F);

  % Subtype TCC generated (at line 57, column 22) for  card(F)
      % expected type  posnat
  order_TCC2: OBLIGATION FORALL (F: finite_monad): card[T](F) > 0;

  % Judgement subtype TCC generated (at line 61, column 36) for  x
      % expected type  monad
  finite_monad_is_monad: OBLIGATION
    FORALL (x: finite_monad): monad?[T, *, one](x);

  % Judgement subtype TCC generated (at line 63, column 44) for  x
      % expected type  monad
  commutative_monad_is_monad: OBLIGATION
    FORALL (x: commutative_monad): monad?[T, *, one](x);

  % Judgement subtype TCC generated (at line 66, column 16) for  x
      % expected type  commutative_monad
  finite_commutative_monad_is_commutative_monad: OBLIGATION
    FORALL (x: finite_commutative_monad): commutative_monad?[T, *, one](x);

  % Judgement subtype TCC generated (at line 69, column 16) for  x
      % expected type  finite_monad
  finite_commutative_monad_is_finite_monad: OBLIGATION
    FORALL (x: finite_commutative_monad): finite_monad?[T, *, one](x);


body:
  %------------------------------------------------------------------------------
  % Monoids definition file
  %
  %     Author: Rick Butler,  NASA Langley
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  monoid_def[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN

     IMPORTING monad_def[T,*,one]

     S: VAR set[T]
     a: VAR T
     n,m: VAR nat

     power(a,n):RECURSIVE T = IF n=0 THEN one ELSE a*power(a,n-1) ENDIF MEASURE n


     generated_set(a):set[T] = {t: T | EXISTS n: t = power(a,n)}

     generated_set_lem   : LEMMA generated_set(a)(power(a,n))

     monoid?(S): bool                    = monad?(S)  AND associative?[(S)](*)
     finite_monoid?(S): bool             = monoid?(S) AND is_finite(S)
     commutative_monoid?(S): bool        = monoid?(S) AND commutative?[(S)](*)
     finite_commutative_monoid?(S): bool = finite_monoid?(S) AND
                                           commutative?[(S)](*)

     infinite_order?(a):bool = (FORALL (n:posnat): power(a,n) /= one)
     finite_order?(a)  :bool = NOT infinite_order?(a)

  END monoid_def

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

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

  % Termination TCC generated (at line 22, column 51) for  power(a, n - 1)
  power_TCC2: OBLIGATION FORALL (n: nat): NOT n = 0 IMPLIES n - 1 < n;

  % Subtype TCC generated (at line 29, column 74) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  monoid?_TCC1: OBLIGATION
    FORALL (S: set[T]): monad?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));

  % Subtype TCC generated (at line 31, column 74) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  commutative_monoid?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      monoid?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));

  % Subtype TCC generated (at line 33, column 59) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  finite_commutative_monoid?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      finite_monoid?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));


body:
  %------------------------------------------------------------------------------
  % Monoids
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  monoid[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN

     ASSUMING IMPORTING monoid_def[T,*,one], semigroup_def

         fullset_is_monoid: ASSUMPTION monoid?(fullset[T])

     ENDASSUMING

     IMPORTING monoid_def[T,*,one], monad[T,*,one], semigroup[T,*]

     monoid: TYPE+ = (monoid?) CONTAINING fullset[T]

     S:   VAR set[T]
     M:   VAR monoid
     a:   VAR T
     n,m: VAR nat

     monoid_is_monad:     JUDGEMENT monoid SUBTYPE_OF monad
     monoid_is_semigroup: JUDGEMENT monoid SUBTYPE_OF semigroup

     submonoid?(S,M): bool = subset?(S,M) AND monoid?(S)

     power_0:             LEMMA power(a,0)            = one
     power_1:             LEMMA power(a,1)            = a
     one_power:           LEMMA power(one,n)          = one
     power_def:           LEMMA power(a,n+1)          = power(a,n)*a
     power_mult:          LEMMA power(a,n)*power(a,m) = power(a,n+m)
     power_power:         LEMMA power(power(a,n),m)   = power(a,n*m)
     power_commutes:      LEMMA power(a,n)*power(a,m) = power(a,m)*power(a,n)
     power_member:        LEMMA member(a,M) IMPLIES member(power(a,n),M)

     one_is_monoid:       LEMMA monoid?(singleton[T](one))

     AUTO_REWRITE+ power_0
     AUTO_REWRITE+ power_1
     AUTO_REWRITE+ one_power
     AUTO_REWRITE+ one_is_monoid
   
     generated_is_submonoid: LEMMA member(a,M) IMPLIES
                                                  submonoid?(generated_set(a),M)


     generated_set_card_1: LEMMA member(a,M) AND 
                                 is_finite(generated_set(a)) AND
                                 card(generated_set(a)) = 1
                                   IMPLIES a = one AND
                                        generated_set(a) = singleton[T](one)

     finite_monoid: TYPE+ = (finite_monoid?) 

     F: VAR finite_monoid

     finite_monoid_is_monoid: JUDGEMENT finite_monoid SUBTYPE_OF monoid
     finite_monoid_is_finite_monad:
                            JUDGEMENT finite_monoid SUBTYPE_OF finite_monad

     finite_submonoids: LEMMA submonoid?(S,M) IMPLIES finite_monoid?(F)

     commutative_monoid: TYPE+ = (commutative_monoid?)

     commutative_monoid_is_monoid: JUDGEMENT commutative_monoid SUBTYPE_OF monoid
     commutative_monoid_is_commutative_monad:
                    JUDGEMENT commutative_monoid SUBTYPE_OF commutative_monad

     H: VAR commutative_monoid
     commutative_submonoids: LEMMA submonoid?(S,H) IMPLIES commutative_monoid?(S)


  END monoid

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

  % Assuming TCC generated (at line 22, column 34) for  monad[T, *, one]
      % generated from assumption monad.fullset_is_monad
  IMP_monad_TCC1: OBLIGATION monad?[T, *, one](fullset[T]);

  % Assuming TCC generated (at line 22, column 50) for  semigroup[T, *]
      % generated from assumption semigroup.fullset_is_semigroup
  IMP_semigroup_TCC1: OBLIGATION
    star_closed?[T, *](fullset[T]) AND
     associative?[(fullset[T])]
         (restrict[[T, T], [(fullset[T]), (fullset[T])], T](*));

  % Subtype TCC generated (at line 24, column 40) for  fullset[T]
      % expected type  monoid
  monoid_TCC1: OBLIGATION monoid?[T, *, one](fullset[T]);

  % Judgement subtype TCC generated (at line 31, column 34) for  x
      % expected type  monad[T, *, one]
  monoid_is_monad: OBLIGATION FORALL (x: monoid): monad?[T, *, one](x);

  % Judgement subtype TCC generated (at line 32, column 34) for  x
      % expected type  semigroup[T, *]
  monoid_is_semigroup: OBLIGATION
    FORALL (x: monoid):
      star_closed?[T, *](x) AND
       associative?[(x)](restrict[[T, T], [(x), (x)], T](*));

  % Existence TCC generated (at line 62, column 3) for
      % finite_monoid: TYPE+ = (finite_monoid?)
  finite_monoid_TCC1: OBLIGATION
    EXISTS (x: {x: set[T] | finite_monoid?[T, *, one](x)}): TRUE;

  % Judgement subtype TCC generated (at line 66, column 38) for  x
      % expected type  monoid
  finite_monoid_is_monoid: OBLIGATION
    FORALL (x: finite_monoid): monoid?[T, *, one](x);

  % Judgement subtype TCC generated (at line 68, column 36) for  x
      % expected type  finite_monad[T, *, one]
  finite_monoid_is_finite_monad: OBLIGATION
    FORALL (x: finite_monoid): finite_monad?[T, *, one](x);

  % Existence TCC generated (at line 72, column 3) for
      % commutative_monoid: TYPE+ = (commutative_monoid?)
  commutative_monoid_TCC1: OBLIGATION
    EXISTS (x: {x: set[T] | commutative_monoid?[T, *, one](x)}): TRUE;

  % Judgement subtype TCC generated (at line 74, column 43) for  x
      % expected type  monoid
  commutative_monoid_is_monoid: OBLIGATION
    FORALL (x: commutative_monoid): monoid?[T, *, one](x);

  % Judgement subtype TCC generated (at line 76, column 28) for  x
      % expected type  commutative_monad[T, *, one]
  commutative_monoid_is_commutative_monad: OBLIGATION
    FORALL (x: commutative_monoid): commutative_monad?[T, *, one](x);


body:
  %------------------------------------------------------------------------------
  % Groups definition file
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  group_def[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN

     IMPORTING monoid_def[T,*,one]

     S: VAR set[T]

     inv_exists?(S): bool
                        = FORALL (x:(S)): EXISTS (y:(S)): x*y = one AND y*x = one

     group?(S): bool                = monoid?(S) AND inv_exists?(S)
     finite_group?(S): bool         = group?(S) AND is_finite(S)
     abelian_group?(S): bool        = group?(S) AND commutative?[(S)](*)
     finite_abelian_group?(S): bool = finite_group?(S) AND commutative?[(S)](*)

     subgroup?(S:set[T],G:(group?)): bool = subset?(S,G) AND group?(S)

     finite_group_surj: LEMMA group?(S) AND
                              (EXISTS (N: nat), (f: [below[N] -> (S)]): surjective?(f)) 
                           IMPLIES finite_group?(S)

  END group_def

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

  % Subtype TCC generated (at line 25, column 68) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  abelian_group?_TCC1: OBLIGATION
    FORALL (S: set[T]): group?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));

  % Subtype TCC generated (at line 26, column 75) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  finite_abelian_group?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      finite_group?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));


body:
  %------------------------------------------------------------------------------
  % Groups
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %             
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %     Version 1.3           12/5/07   Added a*H notation for cosets and
  %                                     changed cosets so that they are over parent
  %                                     type T rather thatn(G).
  %------------------------------------------------------------------------------

  group[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN
  %------------------------------------------------------------------------
  %  The imported type T with * and "one" must be a group.
  %  From this foundation other groups are created.  These are just subgroups of the
  %  underlying imported type.  I have wrestled with the question of whether it
  %  would be preferable to weaken the importing assumptions so as to allow
  %
  %     G: VAR group[real,*,1]
  %
  %  rather than requiring
  %
  %     G: VAR group[nzreal,*,1]
  %
  %  The advantage of the former is that it is more general and there is already sufficient
  %  mechanism to handle this.  But the advantage of the latter is that lemmas such as
  %  inv_left and cancel_right (see below) do not have to have constraining predicates, e.g.
  %
  %     G: VAR group
  %     inv_left: LEMMA G(x) IMPLIES inv(G)(x) * x = one 
  %
  %  where
  %  
  %     inv(G)(x: (G)): {y: (G) | x*y = one AND y*x = one}
  %
  %------------------------------------------------------------------------
     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING

     IMPORTING group_def[T,*,one], monoid[T,*,one]

     group: TYPE+ = (group?) CONTAINING fullset[T]

     subgroup(G: group): TYPE = {H: group | subgroup?(H,G)}
  	
     group_is_monoid: JUDGEMENT group SUBTYPE_OF monoid


     finite_group: TYPE+ = (finite_group?) 

     finite_group_is_group: JUDGEMENT finite_group SUBTYPE_OF group
     finite_group_is_finite_monoid:
                            JUDGEMENT finite_group SUBTYPE_OF finite_monoid

     finite_subgroups: LEMMA FORALL (S:set[T], H: finite_group): subgroup?(S,H) IMPLIES
                                                                 finite_group?(S)

     one_is_group    : LEMMA group?(singleton[T](one))
     AUTO_REWRITE+     one_is_group
     one_finite_group: LEMMA finite_group?(singleton[T](one))
     AUTO_REWRITE+     one_finite_group

     one_group: finite_group = singleton[T](one)

     group_card_gt_0: LEMMA FORALL (G: finite_group): card(G) > 0

     S,R:       VAR set[T]
     H,G:       VAR group
     a,b,x,y,z: VAR T
     m:         VAR nat
     i,j:       VAR int

     inv_exists: LEMMA EXISTS y: x*y = one AND y*x = one

     inv(x): {y | x*y = one AND y*x = one}
     inverse(x): MACRO {y | x*y = one AND y*x = one} = inv(x)

  %  ---- The following hold because the fullset[T] is constrained to be a group by the
  %       assuming clause

     inv_left            : LEMMA inv(x) * x = one 
     inv_right           : LEMMA x * inv(x) = one 
     cancel_right        : LEMMA x*z = y*z IFF x = y
     cancel_left         : LEMMA z*x = z*y IFF x = y
     inv_inv             : LEMMA inv(inv(x)) = x 
     cancel_right_inv    : LEMMA x*inv(z) = y*inv(z) IFF x = y
     cancel_left_inv     : LEMMA z*inv(x) = z*inv(y) IFF x = y
     inv_one             : LEMMA inv(one) = one
     inv_star            : LEMMA inv(x*y) = inv(y)*inv(x)
     unique_inv          : LEMMA x*y = one AND y*x = one IFF y = inv(x)
     inv_member          : LEMMA member(inv(x),G) IFF member(x,G)
     inv_in              : LEMMA FORALL (a:(G)): G(inv(a))
     divby               : LEMMA x = y * z IFF inv(y)*x = z

     product_in          : LEMMA G(a) AND G(b) IMPLIES G(a*b)

     AUTO_REWRITE+  inv_left
     AUTO_REWRITE+  inv_right
     AUTO_REWRITE+  inv_inv
     AUTO_REWRITE+  inv_one
     AUTO_REWRITE+  inv_in
     AUTO_REWRITE+  member


     inv_closed?(S): bool = (FORALL (x:(S)): member(inv(x),S))

     one_is_subgroup:   LEMMA subgroup?(one_group,G)

     group_is_subgroup: LEMMA subgroup?(G,G)

     subgroup_is_group: LEMMA subgroup?(S,G) IMPLIES group?(S)


  % Herstein Lemma 2.4.1 (Characterization of any subgroup)

     subgroup_def: LEMMA subgroup?(S,G) IFF
       (nonempty?(S) AND subset?(S,G) AND star_closed?(S) AND inv_closed?(S))


     inv_power:       LEMMA inv(power(a,m))   = power(inv(a),m)
     power_inv_right: LEMMA power(a,m) * power(inv(a),m) = one
     power_inv_left:  LEMMA power(inv(a),m) * power(a,m) = one

     ; % needed for syntax purposes!

     ^(a,i): T = IF i < 0 THEN power(inv(a),-i) ELSE power(a,i) ENDIF

     expt_0:             LEMMA a^0                = one
     expt_1:             LEMMA a^1                = a
     expt_m1:            LEMMA a^(-1)             = inv(a)
     one_expt:           LEMMA one^i              = one
     expt_neg:           LEMMA a^(-i)             = inv(a)^i
     inv_expt:           LEMMA inv(a^i)           = inv(a)^i
     expt_def1:          LEMMA a^(i+1)            = a^i*a
     expt_def2:          LEMMA a^(i+1)            = a*a^i
     expt_mult:          LEMMA a^i*a^j            = a^(i+j)
     expt_div :          LEMMA a^i*inv(a)^j       = a^(i-j)
     expt_expt:          LEMMA (a^i)^j            = a^(i*j)
     expt_commutes:      LEMMA a^i*a^j            = a^j*a^i
     expt_inv_right:     LEMMA a^i * inv(a)^i = one
     expt_inv_left:      LEMMA inv(a)^i * a^i = one
     expt_member:        LEMMA member(a,G) IMPLIES member(a^i,G)

  %   AUTO_REWRITE+  expt_0
  %   AUTO_REWRITE+  expt_1
  %   AUTO_REWRITE+  one_expt

     generated_by(a):group = {t: T | EXISTS (i: int): t = a^i}

     cyclic?(G): boolean = EXISTS (a:(G)): G = generated_by(a)

     generated_by_lem     : LEMMA generated_by(a)(a^i)

     generated_is_subgroup: LEMMA member(a,G) IMPLIES
                                                subgroup?(generated_by(a),G)

     generated_by_is_finite: LEMMA S = generated_by(a) AND 
                                   (EXISTS (k: posnat): a^k = one)
                                IMPLIES finite_group?(S)


  % ----- Center of a Group

     center(G): {s: set[T] | subset?(s,G)} = { s: (G) | FORALL (x:(G)): x*s = s*x}

     center_def     : LEMMA center(G)(x) IFF G(x) AND FORALL (y:(G)): y*x = x*y

     center_subgroup: LEMMA subgroup?(center(G),G)

  %  ---- Some Easy to Remember versions of Lemmas

     one_left:         LEMMA one * x = x
     one_right:        LEMMA x * one = x
     assoc:            LEMMA x * (y * z) = (x * y) * z    %% often want to rewrite this way
   
     AUTO_REWRITE+ one_left  
     AUTO_REWRITE+ one_right

  END group

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

  % Assuming TCC generated (at line 49, column 33) for  monoid[T, *, one]
      % generated from assumption monoid.fullset_is_monoid
  IMP_monoid_TCC1: OBLIGATION monoid?[T, *, one](fullset[T]);

  % Subtype TCC generated (at line 51, column 38) for  fullset[T]
      % expected type  group
  group_TCC1: OBLIGATION group?[T, *, one](fullset[T]);

  % Judgement subtype TCC generated (at line 55, column 30) for  x
      % expected type  monoid[T, *, one]
  group_is_monoid: OBLIGATION FORALL (x: group): monoid?[T, *, one](x);

  % Existence TCC generated (at line 58, column 3) for
      % finite_group: TYPE+ = (finite_group?)
  finite_group_TCC1: OBLIGATION
    EXISTS (x: {x: set[T] | finite_group?[T, *, one](x)}): TRUE;

  % Judgement subtype TCC generated (at line 60, column 36) for  x
      % expected type  group
  finite_group_is_group: OBLIGATION
    FORALL (x: finite_group): group?[T, *, one](x);

  % Judgement subtype TCC generated (at line 62, column 36) for  x
      % expected type  finite_monoid[T, *, one]
  finite_group_is_finite_monoid: OBLIGATION
    FORALL (x: finite_group): finite_monoid?[T, *, one](x);

  % Subtype TCC generated (at line 72, column 29) for  singleton[T](one)
      % expected type  finite_group
  one_group_TCC1: OBLIGATION finite_group?[T, *, one](singleton[T](one));

  % Subtype TCC generated (at line 74, column 57) for  G
      % expected type  S: finite_set[T]
  group_card_gt_0_TCC1: OBLIGATION FORALL (G: finite_group): is_finite[T](G);

  % Existence TCC generated (at line 84, column 3) for
      % inv(x): {y | x * y = one AND y * x = one}
  inv_TCC1: OBLIGATION
    EXISTS (x1: [x: T -> {y | x * y = one AND y * x = one}]): TRUE;

  % Subtype TCC generated (at line 135, column 42) for  -i
      % expected type  nat
  caret_TCC1: OBLIGATION FORALL (i: int): i < 0 IMPLIES -i >= 0;

  % Subtype TCC generated (at line 135, column 59) for  i
      % expected type  nat
  caret_TCC2: OBLIGATION FORALL (i: int): NOT i < 0 IMPLIES i >= 0;

  % Subtype TCC generated (at line 157, column 27) for
      % {t: T | EXISTS (i: int): t = a ^ i}
      % expected type  group
  generated_by_TCC1: OBLIGATION
    FORALL (a: T): group?[T, *, one]({t: T | EXISTS (i: int): t = a ^ i});

  % Subtype TCC generated (at line 173, column 43) for
      % extend[T, (G), bool, FALSE]({s: (G) | FORALL (x: (G)): x * s = s * x})
      % expected type  {s: set[T] | subset?(s, G)}
  center_TCC1: OBLIGATION
    FORALL (G: group):
      subset?[T]
          (extend[T, (G), bool, FALSE]
               ({s: (G) | FORALL (x: (G)): x * s = s * x}),
           G);


body:
  %------------------------------------------------------------------------------
  % Abelian Groups
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  abelian_group[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN

     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_abelian_group: ASSUMPTION abelian_group?(fullset[T])

     ENDASSUMING

     IMPORTING monoid_def, group_def,
               group[T,*,one]

     abelian_group: NONEMPTY_TYPE = (abelian_group?) CONTAINING fullset[T]

     A:   VAR abelian_group
     S:   VAR set[T]

     abelian_group_is_group: JUDGEMENT abelian_group SUBTYPE_OF group

     abelian_group_is_commutative_monoid:
                            JUDGEMENT abelian_group SUBTYPE_OF commutative_monoid

     abelian_subgroups:     LEMMA subgroup?(S,A) IMPLIES abelian_group?(S)

     finite_abelian_group: TYPE+ = (finite_abelian_group?) 

     G: VAR finite_abelian_group
   
     finite_abelian_group_is_abelian_group:
         JUDGEMENT finite_abelian_group SUBTYPE_OF abelian_group

     finite_abelian_group_is_finite_group:
         JUDGEMENT finite_abelian_group SUBTYPE_OF finite_group

     finite_abelian_subgroups:
                      LEMMA subgroup?(S,G) IMPLIES finite_abelian_group?(S)



  END abelian_group

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

  % Assuming TCC generated (at line 23, column 13) for  group[T, *, one]
      % generated from assumption group.fullset_is_group
  IMP_group_TCC1: OBLIGATION group?[T, *, one](fullset[T]);

  % Subtype TCC generated (at line 25, column 62) for  fullset[T]
      % expected type  abelian_group
  abelian_group_TCC1: OBLIGATION abelian_group?[T, *, one](fullset[T]);

  % Judgement subtype TCC generated (at line 30, column 37) for  x
      % expected type  group[T, *, one]
  abelian_group_is_group: OBLIGATION
    FORALL (x: abelian_group): group?[T, *, one](x);

  % Judgement subtype TCC generated (at line 33, column 36) for  x
      % expected type  commutative_monoid[T, *, one]
  abelian_group_is_commutative_monoid: OBLIGATION
    FORALL (x: abelian_group): commutative_monoid?[T, *, one](x);

  % Existence TCC generated (at line 37, column 3) for
      % finite_abelian_group: TYPE+ = (finite_abelian_group?)
  finite_abelian_group_TCC1: OBLIGATION
    EXISTS (x: {x: set[T] | finite_abelian_group?[T, *, one](x)}): TRUE;

  % Judgement subtype TCC generated (at line 42, column 17) for  x
      % expected type  abelian_group
  finite_abelian_group_is_abelian_group: OBLIGATION
    FORALL (x: finite_abelian_group): abelian_group?[T, *, one](x);

  % Judgement subtype TCC generated (at line 45, column 17) for  x
      % expected type  finite_group[T, *, one]
  finite_abelian_group_is_finite_group: OBLIGATION
    FORALL (x: finite_abelian_group): finite_group?[T, *, one](x);


body:
  %------------------------------------------------------------------------------
  % Rings definition file
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  ring_def[T:Type+,+,*:[T,T->T],zero:T]: THEORY

  BEGIN

    IMPORTING semigroup_def, group_def, operator_defs_more

    S: VAR set[T]

    ring?(S): bool = abelian_group?[T,+,zero](S)  AND
                     semigroup?[T,*](S)           AND
                     left_distributive?[(S)](*,+) AND
                     right_distributive?[(S)](*,+)

    finite_ring?(S): bool              = ring?(S) AND is_finite(S)
    commutative_ring?(S): bool         = ring?(S) AND commutative?[(S)](*)
    finite_commutative_ring?(S): bool  = finite_ring?(S) AND commutative?[(S)](*)

    subring?(S:set[T],R:(ring?)): bool = subset?(S,R) AND ring?(S)

  END ring_def

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

  % Subtype TCC generated (at line 22, column 43) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  ring?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      star_closed?(S) AND
       associative?[(S)](restrict[[T, T], [(S), (S)], T](*)) AND
        abelian_group?[T, +, zero](S)
       IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));

  % Subtype TCC generated (at line 22, column 45) for
      % restrict[[T, T], [(S), (S)], T](+)
      % expected type  [[(S), (S)] -> (S)]
  ring?_TCC2: OBLIGATION
    FORALL (S: set[T]):
      star_closed?(S) AND
       associative?[(S)](restrict[[T, T], [(S), (S)], T](*)) AND
        abelian_group?[T, +, zero](S)
       IMPLIES (FORALL (x1: [(S), (S)]): S(+x1));

  % Subtype TCC generated (at line 26, column 70) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  commutative_ring?_TCC1: OBLIGATION
    FORALL (S: set[T]): ring?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));

  % Subtype TCC generated (at line 27, column 77) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  finite_commutative_ring?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      finite_ring?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));


body:
  %------------------------------------------------------------------------------
  % Rings
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %             
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  ring[T:Type+,+:[T,T->T],*:[T,T->T],zero:T]: THEORY

  BEGIN

     ASSUMING IMPORTING ring_def[T,+,*,zero]

         fullset_is_ring: ASSUMPTION ring?(fullset[T])

     ENDASSUMING

     IMPORTING abelian_group[T,+,zero],
               operator_defs_more[T]

     ring: NONEMPTY_TYPE = (ring?) CONTAINING fullset[T]

  % To bring elegance into this theory we define unary and binary minus.
  ;
     -: MACRO [T->T]   = inv;
     -: MACRO [T,T->T] = (LAMBDA (x,y:T): x + inv[T,+,zero](y))

     w,x,y,z: VAR T
     R:       VAR ring
     S:       VAR set[T]

     plus_associative       : LEMMA (x + y) + z = x + (y + z)
     plus_commutative       : LEMMA x + y       = y + x
     times_associative      : LEMMA (x * y) * z = x * (y * z)
     right_distributive     : LEMMA x * (y + z) = (x * y) + (x * z)
     left_distributive      : LEMMA (x + y) * z = (x * z) + (y * z)

     zero_plus              : LEMMA zero + x  = x
     plus_zero              : LEMMA x + zero  = x
     negate_is_left_inv     : LEMMA -x + x = zero
     negate_is_right_inv    : LEMMA x + -x = zero
     cancel_right_plus      : LEMMA x + z = y + z IFF x = y
     cancel_left_plus       : LEMMA z + x = z + y IFF x = y
     negate_negate          : LEMMA -(-x) = x
     cancel_right_minus     : LEMMA x - z = y - z IFF x = y
     cancel_left_minus      : LEMMA z - x = z - y IFF x = y
     negate_zero            : LEMMA -zero = zero
     negate_plus            : LEMMA -(x + y) = -y - x
     times_plus             : LEMMA (x + y) * (z + w) = x*z + x*w + y*z + y*w
     idempotent_add_is_zero : LEMMA x + x = x IMPLIES x = zero
     zero_times             : LEMMA zero * x = zero
     times_zero             : LEMMA x * zero = zero
     negative_times         : LEMMA (-x) * y = - (x * y)
     times_negative         : LEMMA x * (-y) = - (x * y)
     negative_times_negative: LEMMA (-x) * (-y) = x * y

     ring_is_abelian_group  : JUDGEMENT ring SUBTYPE_OF abelian_group

     subring_is_ring        : LEMMA subring?(S,R) IMPLIES ring?(S)

     sq(x):T = x*x

     sq_rew      : LEMMA x*x      = sq(x)
     sq_neg      : LEMMA sq(-x)   = sq(x)
     sq_plus     : LEMMA sq(x+y)  = sq(x) + x*y + y*x + sq(y)
     sq_minus    : LEMMA sq(x-y)  = sq(x) - x*y - y*x + sq(y)
     sq_neg_minus: LEMMA sq(x-y)  = sq(y-x)
     sq_zero     : LEMMA sq(zero) = zero


     AUTO_REWRITE+ zero_plus               % zero + x  = x
     AUTO_REWRITE+ plus_zero               % x + zero  = x
     AUTO_REWRITE+ negate_is_left_inv  % -x + x = zero
     AUTO_REWRITE+ negate_is_right_inv % x + -x = zero
     AUTO_REWRITE+ negate_negate           % -(-x) = x
     AUTO_REWRITE+ negate_zero             % -zero = zero
     AUTO_REWRITE+ zero_times              % zero * x = zero
     AUTO_REWRITE+ times_zero              % x * zero = zero


  END ring

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

  % Assuming TCC generated (at line 22, column 13) for
      % abelian_group[T, +, zero]
      % generated from assumption abelian_group.fullset_is_abelian_group
  IMP_abelian_group_TCC1: OBLIGATION abelian_group?[T, +, zero](fullset[T]);

  % Subtype TCC generated (at line 25, column 44) for  fullset[T]
      % expected type  ring
  ring_TCC1: OBLIGATION ring?[T, +, *, zero](fullset[T]);

  % Judgement subtype TCC generated (at line 61, column 38) for  x
      % expected type  abelian_group[T, +, zero]
  ring_is_abelian_group: OBLIGATION
    FORALL (x: ring): abelian_group?[T, +, zero](x);


body:
  %------------------------------------------------------------------------------
  % Commutative Rings
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  commutative_ring[T:Type+,+,*:[T,T->T],zero:T]: THEORY

  BEGIN

     ASSUMING IMPORTING ring_def[T,+,*,zero]

         fullset_is_commutative_ring: ASSUMPTION commutative_ring?(fullset[T])

     ENDASSUMING

     IMPORTING ring_def[T,+,*,zero], ring[T,+,*,zero]

     commutative_ring: NONEMPTY_TYPE = (commutative_ring?) CONTAINING fullset[T]

     R:   VAR commutative_ring
     S:   VAR set[T]
     x,y: VAR T

     times_commutative:   LEMMA x * y = y * x

     commutative_ring_is_ring: JUDGEMENT commutative_ring SUBTYPE_OF ring

     commutative_subrings:     LEMMA subring?(S,R) IMPLIES commutative_ring?(S)

     sq_times    : LEMMA sq(x*y)  = sq(x) * sq(y)

  END commutative_ring

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

  % Assuming TCC generated (at line 22, column 35) for  ring[T, +, *, zero]
      % generated from assumption ring.fullset_is_ring
  IMP_ring_TCC1: OBLIGATION ring?[T, +, *, zero](fullset[T]);

  % Subtype TCC generated (at line 24, column 68) for  fullset[T]
      % expected type  commutative_ring
  commutative_ring_TCC1: OBLIGATION
    commutative_ring?[T, +, *, zero](fullset[T]);

  % Judgement subtype TCC generated (at line 32, column 39) for  x
      % expected type  ring[T, +, *, zero]
  commutative_ring_is_ring: OBLIGATION
    FORALL (x: commutative_ring): ring?[T, +, *, zero](x);


body:
  %------------------------------------------------------------------------------
  % Rings in which the nonzero elements are closed under *, definition file
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  ring_nz_closed_def[T:Type+,+,*:[T,T->T],zero:T]: THEORY

  BEGIN

     IMPORTING ring_def[T,+,*,zero], groupoid_def

     S: VAR set[T]

     nz_T: Type = {x:T | x /= zero}

     nz_closed?(S): bool = star_closed?[T,*](remove(zero,S))

     ring_nz_closed?(S):bool = ring?(S) AND nz_closed?(S)

  END ring_nz_closed_def


body:
  %------------------------------------------------------------------------------
  % Integral domains definition file
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  integral_domain_def[T:Type+,+,*:[T,T->T],zero:T]: THEORY

  BEGIN

     IMPORTING ring_def[T,+,*,zero],
               ring_nz_closed_def[T,+,*,zero]

     integral_domain?(S:set[T]) : bool = commutative_ring?(S) AND nz_closed?(S)

  END integral_domain_def


body:
  %------------------------------------------------------------------------------
  % Integral domains
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  integral_domain[T:Type+,+,*:[T,T->T],zero:T]: THEORY

  BEGIN

     ASSUMING IMPORTING integral_domain_def[T,+,*,zero]

         fullset_is_integral_domain: ASSUMPTION integral_domain?(fullset[T])

     ENDASSUMING

     IMPORTING ring_def[T,+,*,zero],
               integral_domain_def[T,+,*,zero],
               commutative_ring[T,+,*,zero]

     integral_domain: NONEMPTY_TYPE = (integral_domain?) CONTAINING fullset[T]

     I: VAR integral_domain

     integral_domain_is: LEMMA integral_domain?(I)

     integral_domain_is_ring: JUDGEMENT integral_domain SUBTYPE_OF 
                                                             commutative_ring

  END integral_domain

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

  % Assuming TCC generated (at line 24, column 13) for
      % commutative_ring[T, +, *, zero]
      % generated from assumption commutative_ring.fullset_is_commutative_ring
  IMP_commutative_ring_TCC1: OBLIGATION
    commutative_ring?[T, +, *, zero](fullset[T]);

  % Subtype TCC generated (at line 26, column 66) for  fullset[T]
      % expected type  integral_domain
  integral_domain_TCC1: OBLIGATION
    integral_domain?[T, +, *, zero](fullset[T]);

  % Judgement subtype TCC generated (at line 32, column 38) for  x
      % expected type  commutative_ring[T, +, *, zero]
  integral_domain_is_ring: OBLIGATION
    FORALL (x: integral_domain): commutative_ring?[T, +, *, zero](x);


body:
  %------------------------------------------------------------------------------
  % Rings in which the nonzero elements are closed under *
  %
  %     This is defined so that inheriting properties of nz_T work
  %     correctly in field, where we rejoin properties from divison rings
  %     and intgral domains.
  %
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  ring_nz_closed[T:Type+,+,*:[T,T->T],zero:T]: THEORY

  BEGIN

     ASSUMING IMPORTING ring_def[T,+,*,zero],
                        ring_nz_closed_def[T,+,*,zero]

         fullset_is_ring_nz_closed: ASSUMPTION ring_nz_closed?(fullset[T])

     ENDASSUMING

     IMPORTING ring_nz_closed_def[T,+,*,zero],
               ring[T,+,*,zero], monoid, operator_defs_more[T]

     ring_nz_closed: TYPE+ = (ring_nz_closed?) CONTAINING fullset[T]

     R:       VAR ring_nz_closed
     x,y:     VAR T
     nzx,nzy: VAR nz_T

     ring_nz_closed_is          : LEMMA ring_nz_closed?(R)
     ring_nz_closed_is_ring     : JUDGEMENT ring_nz_closed SUBTYPE_OF ring

     nz_T_times_nz_T_is_nz_T    : JUDGEMENT *(nzx, nzy)  HAS_TYPE nz_T
     negate_nz_T_is_nz_T        : JUDGEMENT inv(nzx) HAS_TYPE nz_T
     times_is_zero              : LEMMA x * y = zero IFF x = zero OR y = zero
     nz_T_times                 : LEMMA nzx * y = zero IFF y = zero
     times_nz_T                 : LEMMA x * nzy = zero IFF x = zero
     nz_T_times_nz_T_is_not_zero: LEMMA nzx * nzy /= zero

     sq_nz_is_nz : JUDGEMENT sq(nzx) HAS_TYPE nz_T
     sq_eq_zero  : LEMMA sq(x)    = zero IFF x = zero

  END ring_nz_closed

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

  % Assuming TCC generated (at line 29, column 13) for  ring[T, +, *, zero]
      % generated from assumption ring.fullset_is_ring
  IMP_ring_TCC1: OBLIGATION ring?[T, +, *, zero](fullset[T]);

  % Subtype TCC generated (at line 31, column 56) for  fullset[T]
      % expected type  ring_nz_closed
  ring_nz_closed_TCC1: OBLIGATION ring_nz_closed?[T, +, *, zero](fullset[T]);

  % Judgement subtype TCC generated (at line 38, column 42) for  x
      % expected type  ring[T, +, *, zero]
  ring_nz_closed_is_ring: OBLIGATION
    FORALL (x: ring_nz_closed): ring?[T, +, *, zero](x);

  % Judgement subtype TCC generated (at line 40, column 42) for  nzx * nzy
      % expected type  nz_T[T, +, *, zero]
  nz_T_times_nz_T_is_nz_T: OBLIGATION FORALL (nzx, nzy): nzx * nzy /= zero;

  % Judgement subtype TCC generated (at line 41, column 42) for  inv(nzx)
      % expected type  nz_T[T, +, *, zero]
  negate_nz_T_is_nz_T: OBLIGATION FORALL (nzx): inv[T, +, zero](nzx) /= zero;

  % Judgement subtype TCC generated (at line 47, column 27) for  sq(nzx)
      % expected type  nz_T[T, +, *, zero]
  sq_nz_is_nz: OBLIGATION FORALL (nzx): sq[T, +, *, zero](nzx) /= zero;


body:
  %------------------------------------------------------------------------------
  % Rings with one definition file
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  ring_with_one_def[T:Type+,+,*:[T,T->T],zero,one:T]: THEORY

  BEGIN

     IMPORTING ring_def[T,+,*,zero], monoid_def[T,*,one]

     S: VAR set[T]

     ring_with_one?(S):bool              = ring?(S) AND monoid?[T,*,one](S)
     finite_ring_with_one?(S): bool      = ring_with_one?(S) AND is_finite(S)
     commutative_ring_with_one?(S): bool = ring_with_one?(S) AND
                                           commutative?[(S)](*)
     finite_commutative_ring_with_one?(S): bool = finite_ring_with_one?(S) AND
                                                  commutative?[(S)](*)

  END ring_with_one_def

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

  % Subtype TCC generated (at line 23, column 59) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  commutative_ring_with_one?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      ring_with_one?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));

  % Subtype TCC generated (at line 25, column 66) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  finite_commutative_ring_with_one?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      finite_ring_with_one?(S) IMPLIES (FORALL (x1: [(S), (S)]): S(*(x1)));


body:
  %------------------------------------------------------------------------------
  % Rings with one
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  ring_with_one[T:Type+,+,*:[T,T->T],zero,one:T]: THEORY

  BEGIN

     ASSUMING IMPORTING ring_def[T,+,*,zero],
                        ring_with_one_def[T,+,*,zero,one]

         fullset_is_ring_with_one: ASSUMPTION ring_with_one?(fullset[T])

     ENDASSUMING

     IMPORTING ring_with_one_def[T,+,*,zero,one],
               ring[T,+,*,zero], monoid[T,*,one], operator_defs_more[T]

     ring_with_one: NONEMPTY_TYPE = (ring_with_one?) CONTAINING fullset[T]

     R:   VAR ring_with_one
     x,y: VAR T

     one_times              : LEMMA one * x = x
     times_one              : LEMMA x * one = x
     unique_left_identity   : LEMMA (FORALL x: y*x = x) IFF y = one
     
     unique_right_identity  : LEMMA (FORALL x: x*y = x) IFF y = one
     minus_one_times        : LEMMA (-one)*x = -x
     times_minus_one        : LEMMA x*(-one) = -x
     minus_one_sq_is_one    : LEMMA (-one)*(-one) = one

     ring_with_one_is_ring  : JUDGEMENT ring_with_one SUBTYPE_OF ring
     ring_with_one_is_monoid: JUDGEMENT ring_with_one SUBTYPE_OF monoid[T,*,one]



     AUTO_REWRITE+ one_times              % one * x = x
     AUTO_REWRITE+ times_one              % x * one = x
     AUTO_REWRITE+ minus_one_times        % (-one)*x = -x
     AUTO_REWRITE+ times_minus_one        % x*(-one) = -x
     AUTO_REWRITE+ minus_one_sq_is_one    % (-one)*(-one) = one

  END ring_with_one

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

  % Assuming TCC generated (at line 24, column 13) for  ring[T, +, *, zero]
      % generated from assumption ring.fullset_is_ring
  IMP_ring_TCC1: OBLIGATION ring?[T, +, *, zero](fullset[T]);

  % Assuming TCC generated (at line 24, column 31) for  monoid[T, *, one]
      % generated from assumption monoid.fullset_is_monoid
  IMP_monoid_TCC1: OBLIGATION monoid?[T, *, one](fullset[T]);

  % Subtype TCC generated (at line 26, column 62) for  fullset[T]
      % expected type  ring_with_one
  ring_with_one_TCC1: OBLIGATION
    ring_with_one?[T, +, *, zero, one](fullset[T]);

  % Judgement subtype TCC generated (at line 40, column 38) for  x
      % expected type  ring[T, +, *, zero]
  ring_with_one_is_ring: OBLIGATION
    FORALL (x: ring_with_one): ring?[T, +, *, zero](x);

  % Judgement subtype TCC generated (at line 41, column 38) for  x
      % expected type  monoid[T, *, one]
  ring_with_one_is_monoid: OBLIGATION
    FORALL (x: ring_with_one): monoid?[T, *, one](x);


body:
  %------------------------------------------------------------------------------
  % Division rings definition file
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  division_ring_def[T:Type+,+,*:[T,T->T],zero,one:T]: THEORY

  BEGIN

     IMPORTING ring_def, ring_with_one_def[T,+,*,zero,one], group_def

     division_ring?(S:set[T]):bool = ring_with_one?(S) AND
                                     group?[T,*,one](remove(zero,S))

  END division_ring_def


body:
  %------------------------------------------------------------------------------
  % Division rings
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  division_ring[T:Type+,+,*:[T,T->T],zero,one:T]: THEORY

  BEGIN

     ASSUMING IMPORTING ring_with_one_def[T,+,*,zero,one], group_def,
                        division_ring_def[T,+,*,zero,one]

         fullset_is_division_ring: ASSUMPTION division_ring?(fullset[T])

     ENDASSUMING

     IMPORTING monoid_def, group_def, ring_nz_closed_def,
               division_ring_def[T,+,*,zero,one],
               ring_with_one[T,+,*,zero,one], ring_nz_closed[T,+,*,zero],
               group[nz_T,*,one]

     division_ring: NONEMPTY_TYPE = (division_ring?) CONTAINING fullset[T]

  % To bring elegance into this theory we define unary and binary minus and
  % divide.
  ;
     recip: MACRO [nz_T->nz_T] = inv[nz_T,*,one];
     /: MACRO [T,nz_T->T]      = (LAMBDA (x:T,n0y:nz_T): x * recip(n0y))

     R:   VAR division_ring
     x,y: VAR T
     n0x,n0y,n0z: VAR nz_T

     division_ring_is       : LEMMA division_ring?(R)

     division_ring_is_ring_with_one:
                              JUDGEMENT division_ring SUBTYPE_OF ring_with_one

     division_ring_is_ring_nz_closed:
                              JUDGEMENT division_ring SUBTYPE_OF ring_nz_closed

     division_ring_is_group : LEMMA group?[nz_T,*,one](remove(zero,R))

     one_ne_zero            : LEMMA one /= zero
     cancel_times_right     : LEMMA (x * n0z = y * n0z) IFF x = y
     cancel_times_left      : LEMMA (n0z * x = n0z * y) IFF x = y
     idempotent_times       : LEMMA x * x = x IFF x = zero OR x = one
     recip_ne_zero          : LEMMA recip(n0x) /= zero
     nz_T_div_nz_T_is_nz_T  : JUDGEMENT /(n0x, n0y) HAS_TYPE nz_T
     div_simplify           : LEMMA n0x/n0x = one
     cancel_div_right       : LEMMA (x/n0z = y/n0z) IFF x = y
     cancel_div_left        : LEMMA (n0z/n0x = n0z/n0y) IFF n0x = n0y
     times_div_left         : LEMMA x * (y/n0z) = (x * y)/n0z
     div_eq_zero            : LEMMA x/n0z = zero IFF x = zero
     div_mult               : LEMMA (x/n0z) * n0z = x
     div_mult_left          : LEMMA x/n0z = y IFF x = y * n0z
     div_mult_right         : LEMMA y = x/n0z IFF y * n0z = x
     div_distributes        : LEMMA (x/n0z) + (y/n0z) = (x + y)/n0z
     div_distributes_minus  : LEMMA (x/n0z) - (y/n0z) = (x - y)/n0z
     div_div1               : LEMMA (x / (n0y / n0z)) = ((x * n0z) / n0y)
     div_div2               : LEMMA ((x / n0y) / n0z) = (x / (n0z * n0y))


     AUTO_REWRITE+ one_ne_zero            %% one /= zero
     AUTO_REWRITE+ div_simplify           %% n0x/n0x = one

  END division_ring

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

  % Assuming TCC generated (at line 25, column 13) for
      % ring_with_one[T, +, *, zero, one]
      % generated from assumption ring_with_one.fullset_is_ring_with_one
  IMP_ring_with_one_TCC1: OBLIGATION
    ring_with_one?[T, +, *, zero, one](fullset[T]);

  % Assuming TCC generated (at line 25, column 44) for
      % ring_nz_closed[T, +, *, zero]
      % generated from assumption ring_nz_closed.fullset_is_ring_nz_closed
  IMP_ring_nz_closed_TCC1: OBLIGATION
    ring_nz_closed?[T, +, *, zero](fullset[T]);

  % Subtype TCC generated (at line 26, column 24) for
      % restrict[[T, T], [nz_T[T, +, *, zero], nz_T[T, +, *, zero]], T](*)
      % expected type  [[nz_T[T, +, *, zero], nz_T[T, +, *, zero]] ->
                     %    nz_T[T, +, *, zero]]
  IMP_group_TCC1: OBLIGATION
    FORALL (x1: [nz_T[T, +, *, zero], nz_T[T, +, *, zero]]): *(x1) /= zero;

  % Subtype TCC generated (at line 26, column 26) for  one
      % expected type  nz_T[T, +, *, zero]
  IMP_group_TCC2: OBLIGATION one /= zero;

  % Assuming TCC generated (at line 26, column 13) for
      % group
      %     [nz_T,
      %      restrict[[T, T], [nz_T[T, +, *, zero], nz_T[T, +, *, zero]], T]
      %          (*),
      %      one]
      % generated from assumption group.fullset_is_group
  IMP_group_TCC3: OBLIGATION
    group?
        [nz_T,
         restrict[[T, T], [nz_T[T, +, *, zero], nz_T[T, +, *, zero]], T](*),
         one]
        (fullset[nz_T[T, +, *, zero]]);

  % Existence TCC generated (at line 26, column 13) for
      % group
      %     [nz_T,
      %      restrict[[T, T], [nz_T[T, +, *, zero], nz_T[T, +, *, zero]], T]
      %          (*),
      %      one]
  IMP_group_TCC4: OBLIGATION EXISTS (x: nz_T[T, +, *, zero]): TRUE;

  % Subtype TCC generated (at line 28, column 62) for  fullset[T]
      % expected type  division_ring
  division_ring_TCC1: OBLIGATION
    division_ring?[T, +, *, zero, one](fullset[T]);

  % Judgement subtype TCC generated (at line 43, column 38) for  x
      % expected type  ring_with_one[T, +, *, zero, one]
  division_ring_is_ring_with_one: OBLIGATION
    FORALL (x: division_ring): ring_with_one?[T, +, *, zero, one](x);

  % Judgement subtype TCC generated (at line 46, column 38) for  x
      % expected type  ring_nz_closed[T, +, *, zero]
  division_ring_is_ring_nz_closed: OBLIGATION
    FORALL (x: division_ring): ring_nz_closed?[T, +, *, zero](x);

  % Judgement subtype TCC generated (at line 34, column 55) for
      % n0x *
      %  inv
      %      [nz_T,
      %       restrict[[T, T], [nz_T[T, +, *, zero], nz_T[T, +, *, zero]], T]
      %           (*),
      %       one]
      %      (n0y)
      % expected type  nz_T[T, +, *, zero]
  nz_T_div_nz_T_is_nz_T: OBLIGATION
    FORALL (n0x, n0y):
      n0x *
       inv
           [nz_T[T, +, *, zero],
            restrict[[T, T], [nz_T[T, +, *, zero], nz_T[T, +, *, zero]], T]
                (*),
            one]
           (n0y)
       /= zero;

  % Subtype TCC generated (at line 67, column 60) for  (n0z * n0y)
      % expected type  x: nz_T[T, +, *, zero]
  div_div2_TCC1: OBLIGATION
    FORALL (n0y, n0z: nz_T[T, +, *, zero]): (n0z * n0y) /= zero;


body:
  %------------------------------------------------------------------------------
  % Fields definition file
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  field_def[T:Type+,+,*:[T,T->T],zero,one:T]: THEORY

  BEGIN

     IMPORTING division_ring_def[T,+,*,zero,one]

     field?(S:set[T]): bool = division_ring?(S) AND commutative?[(S)](*)

  END field_def

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

  % Subtype TCC generated (at line 18, column 68) for
      % restrict[[T, T], [(S), (S)], T](*)
      % expected type  [[(S), (S)] -> (S)]
  field?_TCC1: OBLIGATION
    FORALL (S: set[T]):
      division_ring?(S) IMPLIES (FORALL (x1: [(S), (S)]): (S)(*(x1)));


body:
  %------------------------------------------------------------------------------
  % Fields
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  field[T:Type+,+,*:[T,T->T],zero,one:T]: THEORY

  BEGIN

     ASSUMING IMPORTING division_ring_def[T,+,*,zero,one],
                        integral_domain_def[T,+,*,zero],
                        field_def[T,+,*,zero,one]

         fullset_is_field: ASSUMPTION field?(fullset[T])

     ENDASSUMING

     IMPORTING abelian_group,
               division_ring_def[T,+,*,zero,one],
               field_def[T,+,*,zero,one],
               division_ring[T,+,*,zero,one],
               integral_domain[T,+,*,zero]

     field: NONEMPTY_TYPE = (field?) CONTAINING fullset[T]

     nz_star:[nz_T,nz_T->nz_T]
                       = restrict[[T,T],[nz_T[T,+,*,zero],nz_T[T,+,*,zero]],T](*)

     F:           VAR field
     S:           VAR set[T]
     x,y:         VAR T
     n0x,n0y,n0z: VAR nz_T

     field_is_division_ring:   JUDGEMENT field SUBTYPE_OF division_ring
     field_is_integral_domain: JUDGEMENT field SUBTYPE_OF integral_domain
     field_is_abelian_group:
                           LEMMA abelian_group?[nz_T,nz_star,one](remove(zero,F))

     mult_div:        LEMMA n0z * (x/n0z) = x
     times_div_right: LEMMA (x/n0z) * y = (x * y)/n0z
     div_times:       LEMMA (x/n0x) * (y/n0y) = (x*y)/(n0x*n0y)
     cross_mult:      LEMMA (x/n0x = y/n0y) IFF (x * n0y = y * n0x)
     add_div:         LEMMA (x/n0x) + (y/n0y) = (x * n0y + y * n0x)/(n0x * n0y)
     minus_div1:      LEMMA (x/n0x) - (y/n0y) = (x * n0y - y * n0x)/(n0x * n0y)

     sq_div:          LEMMA sq(x/n0z) = sq(x)/sq(n0z)

  END field

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

  % Assuming TCC generated (at line 27, column 13) for
      % division_ring[T, +, *, zero, one]
      % generated from assumption division_ring.fullset_is_division_ring
  IMP_division_ring_TCC1: OBLIGATION
    division_ring?[T, +, *, zero, one](fullset[T]);

  % Assuming TCC generated (at line 28, column 13) for
      % integral_domain[T, +, *, zero]
      % generated from assumption integral_domain.fullset_is_integral_domain
  IMP_integral_domain_TCC1: OBLIGATION
    integral_domain?[T, +, *, zero](fullset[T]);

  % Subtype TCC generated (at line 30, column 46) for  fullset[T]
      % expected type  field
  field_TCC1: OBLIGATION field?[T, +, *, zero, one](fullset[T]);

  % Subtype TCC generated (at line 33, column 23) for
      % restrict[[T, T], [nz_T[T, +, *, zero], nz_T[T, +, *, zero]], T](*)
      % expected type  [[nz_T[T, +, *, zero], nz_T[T, +, *, zero]] ->
                     %    nz_T[T, +, *, zero]]
  nz_star_TCC1: OBLIGATION
    FORALL (x1: [nz_T[T, +, *, zero], nz_T[T, +, *, zero]]):
      restrict[[T, T], [nz_T[T, +, *, zero], nz_T[T, +, *, zero]], T](*)(x1)
       /= zero;

  % Judgement subtype TCC generated (at line 40, column 39) for  x
      % expected type  division_ring[T, +, *, zero, one]
  field_is_division_ring: OBLIGATION
    FORALL (x: field): division_ring?[T, +, *, zero, one](x);

  % Judgement subtype TCC generated (at line 41, column 39) for  x
      % expected type  integral_domain[T, +, *, zero]
  field_is_integral_domain: OBLIGATION
    FORALL (x: field): integral_domain?[T, +, *, zero](x);

  % Subtype TCC generated (at line 43, column 59) for  one
      % expected type  nz_T[T, +, *, zero]
  field_is_abelian_group_TCC1: OBLIGATION one /= zero;

  % Existence TCC generated (at line 43, column 31) for
      % abelian_group?[nz_T, nz_star, one]
  field_is_abelian_group_TCC2: OBLIGATION
    EXISTS (x: nz_T[T, +, *, zero]): TRUE;

  % Subtype TCC generated (at line 26, column 24) for
      % restrict[[T, T], [nz_T[T, +, *, zero], nz_T[T, +, *, zero]], T](*)
      % expected type  [[nz_T[T, +, *, zero], nz_T[T, +, *, zero]] ->
                     %    nz_T[T, +, *, zero]]
  mult_div_TCC1: OBLIGATION
    FORALL (x1: [nz_T[T, +, *, zero], nz_T[T, +, *, zero]]): *(x1) /= zero;

  % Subtype TCC generated (at line 47, column 53) for  (n0x * n0y)
      % expected type  x: nz_T[T, +, *, zero]
  div_times_TCC1: OBLIGATION
    FORALL (n0x, n0y: nz_T[T, +, *, zero]): (n0x * n0y) /= zero;


body:
  %------------------------------------------------------------------------------
  % Commutative rings with one
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  commutative_ring_with_one[T:Type+,+,*:[T,T->T],zero,one:T]: THEORY

  BEGIN

     ASSUMING IMPORTING ring_with_one_def[T,+,*,zero,one]

        fullset_is_commutative_ring_with_one: ASSUMPTION
                                           commutative_ring_with_one?(fullset[T])

     ENDASSUMING

     IMPORTING operator_defs_more[T], ring_with_one[T,+,*,zero,one],
               commutative_ring[T,+,*,zero]

     commutative_ring_with_one: TYPE+ = (commutative_ring_with_one?)
                                                            CONTAINING fullset[T]

     R: VAR commutative_ring_with_one

     commutative_ring_with_one_is: LEMMA commutative_ring_with_one?(R)

     commutative_ring_with_one_is_commutative_ring: JUDGEMENT
                       commutative_ring_with_one SUBTYPE_OF commutative_ring

     commutative_ring_with_one_is_ring_with_one: JUDGEMENT
                       commutative_ring_with_one SUBTYPE_OF ring_with_one

     commutative_ring_with_one_is_commutative_monoid: JUDGEMENT
                 commutative_ring_with_one SUBTYPE_OF commutative_monoid[T,*,one]

  END commutative_ring_with_one

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

  % Assuming TCC generated (at line 23, column 36) for
      % ring_with_one[T, +, *, zero, one]
      % generated from assumption ring_with_one.fullset_is_ring_with_one
  IMP_ring_with_one_TCC1: OBLIGATION
    ring_with_one?[T, +, *, zero, one](fullset[T]);

  % Assuming TCC generated (at line 24, column 13) for
      % commutative_ring[T, +, *, zero]
      % generated from assumption commutative_ring.fullset_is_commutative_ring
  IMP_commutative_ring_TCC1: OBLIGATION
    commutative_ring?[T, +, *, zero](fullset[T]);

  % Subtype TCC generated (at line 27, column 69) for  fullset[T]
      % expected type  commutative_ring_with_one
  commutative_ring_with_one_TCC1: OBLIGATION
    commutative_ring_with_one?[T, +, *, zero, one](fullset[T]);

  % Judgement subtype TCC generated (at line 34, column 21) for  x
      % expected type  commutative_ring[T, +, *, zero]
  commutative_ring_with_one_is_commutative_ring: OBLIGATION
    FORALL (x: commutative_ring_with_one):
      commutative_ring?[T, +, *, zero](x);

  % Judgement subtype TCC generated (at line 37, column 21) for  x
      % expected type  ring_with_one[T, +, *, zero, one]
  commutative_ring_with_one_is_ring_with_one: OBLIGATION
    FORALL (x: commutative_ring_with_one):
      ring_with_one?[T, +, *, zero, one](x);

  % Judgement subtype TCC generated (at line 40, column 15) for  x
      % expected type  commutative_monoid[T, *, one]
  commutative_ring_with_one_is_commutative_monoid: OBLIGATION
    FORALL (x: commutative_ring_with_one): commutative_monoid?[T, *, one](x);


body:
  %------------------------------------------------------------------------------
  % Mathematical Structures (Part II)
  %
  % Ring/Field-like Mathematical Structures with signatures:
  %     [T:Type+,+,*:[T,T->T],zero:T]  or   [T:Type+,+,*:[T,T->T],zero,one:T]
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  top_field: THEORY

  BEGIN
  %----------------------------------------+------------------------------------
  %             File                       | Mathematical Structure of *
  %----------------------------------------+------------------------------------

      IMPORTING ring,                      % semigroup[T,*]
                commutative_ring,          % commutative_semigroup[T,*]
                ring_nz_closed,            % semigroup[T,*], semigroup[nz_T,*]
                ring_with_one,             % monoid[T,*,one]
                commutative_ring_with_one, % commutative_monoid[T,*,one]
                integral_domain,           % commutative_semigroup[T,*]
                                           % commutative_semigroup[nz_T,*]
                division_ring,             % monoid[T,*,one], group[nz_T,*,one]
                field                      % commutative_monoid[T,*,one]
                                           % abelian_group[nz_T,*,one]
  %             field_test

  END top_field


body:
  cosets[T:Type+,*:[T,T->T],one:T]: THEORY
  %------------------------------------------------------------------------------
  % Left and Right Cosets
  %
  %     Author: Rick Butler, NASA Langley
  %             Adapted from work done by David Lester, Manchester
  %
  %     Version 1.0           12/12/07  
  %
  % This theory defines convenient notation:
  %
  %     a*H  -- left coset
  %     H*a  -- right coset   
  %
  %------------------------------------------------------------------------------


  BEGIN
  %------------------------------------------------------------------------
  %  The imported type T with * and one must be a group.
  %  From this foundation other groups are created.  These are just subgroups of the
  %  underlying imported type.
  %------------------------------------------------------------------------
     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING

     IMPORTING group[T,*,one]

     S,R:       VAR set[T]
     H,G:       VAR group
     a,b,x,y,z: VAR T
     m:         VAR nat


  % Herstein Lemma 2.4.3

     congruent_mod(G:group,H:subgroup(G))(a,b:T):bool
                                                         = member(a*inv(b),H)
     congruence_is_equivalence: LEMMA 
          subgroup?(H,G) IMPLIES equivalence?[T](congruent_mod(G,H))


  % ---------- Special Coset Notation ------------

     ;

     *(a: T, H: set[T]): set[T] = {t:T | EXISTS (h:(H)): t = a*h} ;  %% left

     *(H: set[T], a: T): set[T] = {t:T | EXISTS (h:(H)): t = h*a} ;  %% right

     left_coset_subset : LEMMA FORALL (H: subgroup(G)),(a:(G)): subset?(a*H,G)
     right_coset_subset: LEMMA FORALL (H: subgroup(G)),(a:(G)): subset?(H*a,G)

     left_coset_one    : LEMMA one*S = S
     right_coset_one   : LEMMA S*one = S

     left_coset_assoc  : LEMMA a*(b*S) = (a*b)*S
     right_coset_assoc : LEMMA (S*a)*b = S*(a*b)

     lr_coset_assoc    : LEMMA (a*S)*b = a*(S*b)

     subset_left_coset : LEMMA subset?(S, R) IMPLIES subset?(a*S, a*R)
     subset_right_coset: LEMMA subset?(S, R) IMPLIES subset?(S*a, R*a)

  %  ------------- Cosets ------------------------

  % Herstein Lemma 2.4.4

     right_coset(G:group,H:subgroup(G))(a:(G)): { s: set[T] | subset?(s,G)}  
                                                             %% was set[(G)]
                          = H*a
  %                       = image((LAMBDA (h:(H)): h*a),(H))


     right_coset_image: LEMMA subgroup?(H,G) AND member(a,G) IMPLIES
                          right_coset(G,H)(a) = image((LAMBDA (h:(H)): h*a),(H))

     right_coset_is: LEMMA subgroup?(H,G) AND member(a,G) IMPLIES
                          right_coset(G,H)(a) = {x: T | congruent_mod(G,H)(a,x)}

     right_coset_def   : LEMMA subgroup?(H,G) AND member(a,G) IMPLIES
                          right_coset(G,H)(a) = H*a

  % Herstein Lemma 2.4.5

     nonempty_right_coset: LEMMA  subgroup?(H,G) AND member(a,G) IMPLIES
                                                   nonempty?(right_coset(G,H)(a))

     right_coset_correspondence: LEMMA FORALL (A,B:set[T]):
       subgroup?(H,G) AND member(a,G) AND member(b,G) AND
           A = right_coset(G,H)(a) AND B = right_coset(G,H)(b) IMPLIES
         EXISTS (f:[(A)->(B)]): bijective?(f)

  % left stuff

     left_coset(G:group,H:subgroup(G))(a:(G)): { s: set[T] | subset?(s,G)}   
                                                            %% was set[(G)]
                          = a*H
  %                       = image((LAMBDA (h:(H)): a*h),(H))

     left_coset_image  : LEMMA subgroup?(H,G) AND member(a,G) IMPLIES
                          left_coset(G,H)(a) = image((LAMBDA (h:(H)): a*h),(H))

     left_coset_def    : LEMMA subgroup?(H,G) AND member(a,G) IMPLIES
                          left_coset(G,H)(a) = a*H


  %  ---- Define Types ----

     left_cosets(G:group,H:subgroup(G)): TYPE = {s: set[T] |
                        EXISTS (a: (G)): s = a*H}


     right_cosets(G:group,H:subgroup(G)): TYPE = {s: set[T] |
                        EXISTS (a: (G)): s = H*a}

  %  --- retrieve a generator -- not unique

     lc_gen(G:group, H: subgroup(G),lc: left_cosets(G,H)): {a: T | G(a) AND lc = a*H} =
                  choose({a: T | G(a) AND lc = a*H})

     lc_gen_def: LEMMA subgroup?(H,G) AND G(a) IMPLIES
                           lc_gen(G,H,a*H)*H = a*H



     rc_gen(G:group, H: subgroup(G), rc: right_cosets(G,H)): {a: T | G(a) AND rc = H*a} =
                  choose({a: T | G(a) AND rc = H*a})

     rc_gen_def: LEMMA subgroup?(H,G) AND G(a) IMPLIES
                           H*rc_gen(G,H,H*a) = H*a



     lc_eq     : LEMMA subgroup?(H,G) AND a*H = b*H
                       IMPLIES (EXISTS (h: (H)): a = b*h) 


     lc_is_eq  : LEMMA subgroup?(H,G) AND (EXISTS (h: (H)): a = b*h) 
                          IMPLIES a*H = b*H



     rc_eq     : LEMMA subgroup?(H,G) AND H*a = H*b
                       IMPLIES (EXISTS (h: (H)): a = h*b) 


     rc_is_eq  : LEMMA subgroup?(H,G) AND (EXISTS (h: (H)): a = h*b) 
                          IMPLIES H*a = H*b


  END cosets

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

  % Assuming TCC generated (at line 30, column 13) for  group[T, *, one]
      % generated from assumption group.fullset_is_group
  IMP_group_TCC1: OBLIGATION group?[T, *, one](fullset[T]);

  % Subtype TCC generated (at line 74, column 26) for  H * a
      % expected type  {s: set[T] | subset?(s, G)}
  right_coset_TCC1: OBLIGATION
    FORALL (G: group[T, *, one], H: subgroup[T, *, one](G), a: (G)):
      subset?[T](H * a, G);

  % Subtype TCC generated (at line 79, column 41) for  a
      % expected type  (G)
  right_coset_image_TCC1: OBLIGATION
    FORALL (G, H: group[T, *, one], a: T):
      member(a, G) AND subgroup?(H, G) IMPLIES G(a);

  % Subtype TCC generated (at line 94, column 58) for  b
      % expected type  (G)
  right_coset_correspondence_TCC1: OBLIGATION
    FORALL (G, H: group[T, *, one], a, b: T, A: set[T]):
      A = right_coset(G, H)(a) AND
       member(b, G) AND member(a, G) AND subgroup?(H, G)
       IMPLIES G(b);

  % Subtype TCC generated (at line 101, column 26) for  a * H
      % expected type  {s: set[T] | subset?(s, G)}
  left_coset_TCC1: OBLIGATION
    FORALL (G: group[T, *, one], H: subgroup[T, *, one](G), a: (G)):
      subset?[T](a * H, G);

  % Subtype TCC generated (at line 123, column 23) for
      % {a: T | G(a) AND lc = a * H}
      % expected type  p: (nonempty?[T])
  lc_gen_TCC1: OBLIGATION
    FORALL (G: group[T, *, one], H: subgroup[T, *, one](G),
            lc: left_cosets(G, H)):
      nonempty?[T]({a: T | G(a) AND lc = a * H});

  % Subtype TCC generated (at line 126, column 36) for  a * H
      % expected type  left_cosets(G, H)
  lc_gen_def_TCC1: OBLIGATION
    FORALL (G, H: group[T, *, one], a: T):
      G(a) AND subgroup?(H, G) IMPLIES (EXISTS (a_1: (G)): a * H = a_1 * H);

  % Subtype TCC generated (at line 131, column 23) for
      % {a: T | G(a) AND rc = H * a}
      % expected type  p: (nonempty?[T])
  rc_gen_TCC1: OBLIGATION
    FORALL (G: group[T, *, one], H: subgroup[T, *, one](G),
            rc: right_cosets(G, H)):
      nonempty?[T]({a: T | G(a) AND rc = H * a});

  % Subtype TCC generated (at line 134, column 38) for  H * a
      % expected type  right_cosets(G, H)
  rc_gen_def_TCC1: OBLIGATION
    FORALL (G, H: group[T, *, one], a: T):
      G(a) AND subgroup?(H, G) IMPLIES (EXISTS (a_1: (G)): H * a = H * a_1);


body:
  normal_subgroups[T:Type+,*:[T,T->T],one:T]: THEORY
  BEGIN

     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING

    
     IMPORTING cosets[T,*,one],
               ints@primes

     AUTO_REWRITE+ member


     inv(a:T): MACRO T = inv[T,*,one](a)

     H,G,N: VAR group[T,*,one]

     normal_prep: LEMMA (FORALL (a: (G)): subset?(inv(a)*N*a,N) ) AND subgroup?(N,G) 
                        IMPLIES FORALL (a: (G)): a*N*inv(a) = N


     normal_subgroup?(N: group[T,*,one], G: group[T,*,one]): boolean = subgroup?(N,G) AND
                                            FORALL (a: (G)): subset?(inv(a)*N*a,N) ;

     normal_left_is_right: THEOREM normal_subgroup?(N,G) IFF 
                                    (subgroup?(N,G) AND 
                                    (FORALL (a:(G)): a*N = N*a))

     normal_subgroup(G): TYPE = {N: group | normal_subgroup?(N,G)}

     normal_subgroup_is_subgroup: JUDGEMENT normal_subgroup(G) SUBTYPE_OF subgroup(G)


     a,h: VAR T
     nsg_prop      : LEMMA FORALL (G: group, H: normal_subgroup(G)): 
                           G(a) and H(h) IMPLIES H(a*h*inv(a))


     nsg_prop2     : LEMMA FORALL (G: group, H: normal_subgroup(G)): 
                           G(a) and H(h) IMPLIES H(inv(a)*h*a)


     lc_gen_normal : LEMMA normal_subgroup?(H,G) AND G(a) IMPLIES
                           (EXISTS (h: (H)): lc_gen(G,H,a*H) = h*a)



     abelian_normal: LEMMA abelian_group?(G) and subgroup?(H,G)
                           IMPLIES normal_subgroup?(H,G)


  END normal_subgroups

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

  % Assuming TCC generated (at line 11, column 13) for  cosets[T, *, one]
      % generated from assumption cosets.fullset_is_group
  IMP_cosets_TCC1: OBLIGATION group?[T, *, one](fullset[T]);

  % Judgement subtype TCC generated (at line 34, column 42) for  x
      % expected type  subgroup[T, *, one](G)
  normal_subgroup_is_subgroup: OBLIGATION
    FORALL (G, x: normal_subgroup(G)): subgroup?[T, *, one](x, G);

  % Subtype TCC generated (at line 47, column 52) for  H
      % expected type  subgroup[T, *, one](G)
  lc_gen_normal_TCC1: OBLIGATION
    FORALL (G, H: group[T, *, one], a: T):
      G(a) AND normal_subgroup?(H, G) IMPLIES
       (FORALL (h: (H)): subgroup?[T, *, one](H, G));

  % Subtype TCC generated (at line 47, column 54) for  a * H
      % expected type  left_cosets[T, *, one](G, H)
  lc_gen_normal_TCC2: OBLIGATION
    FORALL (G, H: group[T, *, one], a: T):
      G(a) AND normal_subgroup?(H, G) IMPLIES
       (FORALL (h: (H)):
          EXISTS (a_1: (G)): *[T, *, one](a, H) = *[T, *, one](a_1, H));


body:
  factor_groups[T:Type+,*:[T,T->T],one:T]: THEORY
  %-----------------------------------------------------------------------------
  %  Experimental theory working towards factor groups
  %
  %     Author: Rick Butler
  %
  %-----------------------------------------------------------------------------
  BEGIN
    
     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING

     IMPORTING normal_subgroups[T,*,one]

     AUTO_REWRITE+ member


     H,G: VAR group[T,*,one]
     a,b,h:   VAR T


     p0: LEMMA FORALL (G: group, H: normal_subgroup(G), A,B: left_cosets(G, H)):
                      nonempty?[set[T]]({S: set[T] | EXISTS (a, b: (G)):
                                    A = a*H AND B = b*H AND S = (a * b)*H })

  	
     prep: LEMMA FORALL (a1,a2,b1,b2: (G)): FORALL (H: normal_subgroup(G)):
         a1*H = a2*H AND b1*H = b2*H IMPLIES (a1*b1)*H = (a2*b2)*H

     mult_prep: LEMMA FORALL (G: group, H: normal_subgroup(G), A,B: left_cosets(G, H)):
                      singleton?[set[T]] ({S: set[T] | EXISTS (a, b: (G)):
                                                    A = a*H AND B = b*H AND S = (a * b)*H })

     AUTO_REWRITE+ left_coset

     mult(G:group,H:normal_subgroup(G))(A,B: left_cosets(G,H)): left_cosets(G,H)  = 
              lc_gen(G,H,A)*lc_gen(G,H,B)*H


     mult_lem  : LEMMA FORALL (G: group, H: normal_subgroup(G), a,b: (G)): 
                          mult(G,H)(a*H,b*H) = (a*b)*H

     mult_in   : LEMMA FORALL (G: group, H: normal_subgroup(G)),(A,B: left_cosets(G,H)):
                               mult(G, H)(A,B)(a) IMPLIES G(a)     

     mult_is_coset: LEMMA FORALL (G: group, H: normal_subgroup(G)),(A,B: left_cosets(G,H)):
                             EXISTS (a: (G)): mult(G, H)(A,B) = a*H                    



     N_is_identity: LEMMA FORALL (G: group, N: normal_subgroup(G)), (A: left_cosets(G,N)):
                                 mult(G,N)(N,A) = A AND mult(G,N)(A,N) = A


     IMPORTING group               

     left_cosets_group: THEOREM FORALL (G: group, N: normal_subgroup(G)):
                group?[left_cosets(G, N), mult(G, N), N](fullset[left_cosets(G, N)])


     ; %% ----- define G/N as set of all left_cosets

     /(G: group[T,*,one], N: normal_subgroup(G)): group[left_cosets(G,N),mult(G,N),N] 
                   = fullset[left_cosets(G, N)]


     over(G: group[T,*,one], N: normal_subgroup(G)): group[left_cosets(G,N),mult(G,N),N] 
                   = fullset[left_cosets(G, N)]

    factor_type(G:group,N:normal_subgroup(G)): TYPE+ = left_cosets(G,N)
   
  END factor_groups

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

  % Assuming TCC generated (at line 16, column 13) for
      % normal_subgroups[T, *, one]
      % generated from assumption normal_subgroups.fullset_is_group
  IMP_normal_subgroups_TCC1: OBLIGATION group?[T, *, one](fullset[T]);

  % Subtype TCC generated (at line 39, column 57) for  H
      % expected type  subgroup[T, *, one](G)
  mult_TCC1: OBLIGATION
    FORALL (G: group, H: normal_subgroup(G)): subgroup?[T, *, one](H, G);

  % Subtype TCC generated (at line 40, column 12) for
      % lc_gen(G, H, A) * lc_gen(G, H, B) * H
      % expected type  left_cosets[T, *, one](G, H)
  mult_TCC2: OBLIGATION
    FORALL (G: group[T, *, one], H: normal_subgroup[T, *, one](G),
            A, B: left_cosets[T, *, one](G, H)):
      EXISTS (a: (G)):
        *[T, *, one]
            (lc_gen[T, *, one](G, H, A) * lc_gen[T, *, one](G, H, B), H)
         = *[T, *, one](a, H);

  % Subtype TCC generated (at line 44, column 34) for  a * H
      % expected type  left_cosets[T, *, one](G, H)
  mult_lem_TCC1: OBLIGATION
    FORALL (G: group[T, *, one], H: normal_subgroup[T, *, one](G),
            a, b: (G)):
      EXISTS (a_1: (G)): *[T, *, one](a, H) = *[T, *, one](a_1, H);

  % Subtype TCC generated (at line 44, column 38) for  b * H
      % expected type  left_cosets[T, *, one](G, H)
  mult_lem_TCC2: OBLIGATION
    FORALL (G: group[T, *, one], H: normal_subgroup[T, *, one](G),
            a, b: (G)):
      EXISTS (a: (G)): *[T, *, one](b, H) = *[T, *, one](a, H);

  % Subtype TCC generated (at line 55, column 41) for  N
      % expected type  left_cosets[T, *, one](G, N)
  N_is_identity_TCC1: OBLIGATION
    FORALL (G: group[T, *, one], N: normal_subgroup[T, *, one](G),
            A: left_cosets[T, *, one](G, N)):
      EXISTS (a: (G)): N = *[T, *, one](a, N);

  % Subtype TCC generated (at line 61, column 52) for  N
      % expected type  left_cosets[T, *, one](G, N)
  left_cosets_group_TCC1: OBLIGATION
    FORALL (G: group[T, *, one], N: normal_subgroup[T, *, one](G)):
      EXISTS (a: (G)): N = *[T, *, one](a, N);

  % Existence TCC generated (at line 61, column 14) for
      % group?[left_cosets(G, N), mult(G, N), N]
  left_cosets_group_TCC2: OBLIGATION
    FORALL (G: group[T, *, one], N: normal_subgroup[T, *, one](G)):
      EXISTS (x: left_cosets[T, *, one](G, N)): TRUE;

  % Assuming TCC generated (at line 66, column 48) for
      % group[left_cosets(G, N), mult(G, N), N]
      % generated from assumption group.fullset_is_group
  divide_TCC1: OBLIGATION
    FORALL (G: group[T, *, one], N: normal_subgroup(G)):
      group?[left_cosets(G, N), mult(G, N), N](fullset[left_cosets(G, N)]);


body:
  group_rew[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN
     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING

     IMPORTING group[T,*,one]

     S,R:       VAR set[T]
     H,G:       VAR group
     a,b,x,y,z: VAR T
     m:         VAR nat
     i,j:       VAR int

     inv_left      : LEMMA inv(x) * x = one 
     inv_right     : LEMMA x * inv(x) = one 
     inv_inv       : LEMMA inv(inv(x)) = x 
     inv_one       : LEMMA inv(one) = one
     inv_in        : LEMMA FORALL (a:(G)): G(inv(a))

     expt_0        : LEMMA a^0                = one
     expt_1        : LEMMA a^1                = a
     expt_m1       : LEMMA a^(-1)             = inv(a)
     one_expt      : LEMMA one^i              = one
   

     one_left      : LEMMA one * x = x
     one_right     : LEMMA x * one = x

  END group_rew

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

  % Assuming TCC generated (at line 10, column 13) for  group[T, *, one]
      % generated from assumption group.fullset_is_group
  IMP_group_TCC1: OBLIGATION group?[T, *, one](fullset[T]);


body:
  zn[N: posnat]: THEORY
  %------------------------------------------------------------------------
  % Integer Groups
  %
  %     Author:     Rick Butler, NASA Langley Research Center
  %
  % Goal: show that Z_n is isomorphic to Z/nZ             
  %
  %     Version 1.0            12/14/07
  %------------------------------------------------------------------------
  BEGIN
     
    IMPORTING group, group_rew

    ++(a,b: below(N)): below(N) = mod(a+b,N)  

    floor_help: LEMMA FORALL (x: below(N)): floor(x / N) = 0

    AUTO_REWRITE+ floor_help

    Z_group: LEMMA group?[int, +, 0](fullset[int]);

    Z: group[int,+,0] = fullset[int]

    Z_prep: LEMMA group?[below(N), ++, 0](fullset[below(N)]);


    Z_: group[below(N),++,0] = fullset[below(N)]


  %%  IMPORTING ints@primes

  %%  zn_prime_field: LEMMA prime?(N) IMPLIES field?[below(N),++,0] = fullset[below(N)]



    nZ_TYPE: TYPE = {x: int | EXISTS (k: int): x = k*N}

    nZ_plus(x,y: nZ_TYPE): nZ_TYPE = x + y

    nZ_prep: LEMMA group?[nZ_TYPE, nZ_plus, 0](fullset[(nZ_TYPE)]);

    nZ: group[nZ_TYPE, +, 0] = fullset[nZ_TYPE]


    IMPORTING factor_groups

    nZ_normal: LEMMA normal_subgroup?(nZ,Z)

  %% THE FOLLOWING currently breaks PVS 4.1 with
  %%    Break: set-type-for-application-parameters

  %  Z_fact_test: LEMMA FORALL (G: factor_type(Z,nZ)): group?[factor_type(Z,nZ),mult(Z,nZ),nZ](G)

    Z_fact_test: LEMMA group?[factor_type(Z,nZ),mult(Z,nZ),nZ](Z/nZ)

     
  END zn

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

  % Assuming TCC generated (at line 23, column 5) for
      % group[int, restrict[[numfield, numfield], [int, int], numfield](+), 0]
      % generated from assumption group.fullset_is_group
  Z_TCC1: OBLIGATION
    group?[int, restrict[[numfield, numfield], [int, int], numfield](+), 0]
        (fullset[int]);

  % Subtype TCC generated (at line 25, column 37) for  0
      % expected type  below(N)
  Z_prep_TCC1: OBLIGATION 0 < N;

  % Existence TCC generated (at line 25, column 16) for
      % group?[below(N), ++, 0]
  Z_prep_TCC2: OBLIGATION EXISTS (x: below(N)): TRUE;

  % Assuming TCC generated (at line 28, column 6) for  group[below(N), ++, 0]
      % generated from assumption group.fullset_is_group
  Z__TCC1: OBLIGATION group?[below(N), ++, 0](fullset[below(N)]);

  % Subtype TCC generated (at line 39, column 35) for  x + y
      % expected type  nZ_TYPE
  nZ_plus_TCC1: OBLIGATION
    FORALL (x, y: nZ_TYPE): EXISTS (k: int): x + y = k * N;

  % Subtype TCC generated (at line 41, column 42) for  0
      % expected type  nZ_TYPE
  nZ_prep_TCC1: OBLIGATION EXISTS (k: int): 0 = k * N;

  % Existence TCC generated (at line 41, column 17) for
      % group?[nZ_TYPE, nZ_plus, 0]
  nZ_prep_TCC2: OBLIGATION EXISTS (x: nZ_TYPE): TRUE;

  % Subtype TCC generated (at line 43, column 6) for
      % group
      %     [nZ_TYPE,
      %      restrict[[numfield, numfield], [nZ_TYPE, nZ_TYPE], numfield](+),
      %      0]
      % expected type  [[nZ_TYPE, nZ_TYPE] -> nZ_TYPE]
  nZ_TCC1: OBLIGATION
    FORALL (x1: [nZ_TYPE, nZ_TYPE]): EXISTS (k: int): +x1 = k * N;

  % Assuming TCC generated (at line 43, column 6) for
      % group
      %     [nZ_TYPE,
      %      restrict[[numfield, numfield], [nZ_TYPE, nZ_TYPE], numfield](+),
      %      0]
      % generated from assumption group.fullset_is_group
  nZ_TCC2: OBLIGATION
    group?
        [nZ_TYPE,
         restrict[[numfield, numfield], [nZ_TYPE, nZ_TYPE], numfield](+), 0]
        (fullset[nZ_TYPE]);

  % Subtype TCC generated (at line 48, column 39) for
      % restrict[int, nZ_TYPE, boolean](Z)
      % expected type  group
                     %     [nZ_TYPE,
                     %      restrict
                     %          [[numfield, numfield], [nZ_TYPE, nZ_TYPE],
                     %           numfield]
                     %          (+),
                     %      0]
  nZ_normal_TCC1: OBLIGATION
    group?
        [nZ_TYPE,
         restrict[[numfield, numfield], [nZ_TYPE, nZ_TYPE], numfield](+), 0]
        (restrict[int, nZ_TYPE, boolean](Z));

  % Subtype TCC generated (at line 55, column 63) for
      % extend[int, nZ_TYPE, bool, FALSE](nZ)
      % expected type  normal_subgroup
                     %     [int,
                     %      restrict
                     %          [[numfield, numfield], [int, int], numfield]
                     %          (+),
                     %      0](Z)
  Z_fact_test_TCC1: OBLIGATION
    group?[int, restrict[[numfield, numfield], [int, int], numfield](+), 0]
        (extend[int, nZ_TYPE, bool, FALSE](nZ))
     AND
     normal_subgroup?
         [int, restrict[[numfield, numfield], [int, int], numfield](+), 0]
         (extend[int, nZ_TYPE, bool, FALSE](nZ), Z);

  % Subtype TCC generated (at line 55, column 57) for
      % extend[int, nZ_TYPE, bool, FALSE](nZ)
      % expected type  factor_type
                     %     [int,
                     %      restrict
                     %          [[numfield, numfield], [int, int], numfield]
                     %          (+),
                     %      0](Z, extend[int, nZ_TYPE, bool, FALSE](nZ))
  Z_fact_test_TCC2: OBLIGATION
    EXISTS (a: (Z)):
      extend[int, nZ_TYPE, bool, FALSE](nZ) =
       *[int, restrict[[numfield, numfield], [int, int], numfield](+), 0]
           (a, extend[int, nZ_TYPE, bool, FALSE](nZ));


body:
  A_group[T: TYPE]: THEORY
  %-----------------------------------------------------------------------------
  %  Experimental theory :
  %
  %  In Chapter 2 Herstein introduces A(S) the group that consists of all
  %  1-1 mappings of a nonempty set onto itself.
  %
  %     Author: Rick Butler
  %
  %  the identity function is the identity element
  %  * is function composition
  %  inv is the inv function which exists because maps are 1-1
  %
  %-----------------------------------------------------------------------------
  BEGIN

     AUTO_REWRITE+ member

     S: VAR (nonempty?[T])                              %% nonempty set[T]	

     maps(S: set[T]): TYPE = (bijective?[(S),(S)])      %% 1-1 maps

     A(S): set[maps(S)] = fullset[maps(S)]


     id(S): maps(S) = identity[(S)]

     op(S): [maps(S),maps(S) -> maps(S)] = function_props[(S),(S),(S)].o


     IMPORTING group_def

     A_is_group: LEMMA group?[maps(S),op(S),id(S)](fullset[maps(S)])

   
   
  END A_group

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

  % Subtype TCC generated (at line 28, column 41) for
      % restrict
      %     [[[(S) -> (S)], [(S) -> (S)]], [maps(S), maps(S)], [(S) -> (S)]]
      %     (function_props[(S), (S), (S)].o)
      % expected type  [[maps(S), maps(S)] -> maps(S)]
  op_TCC1: OBLIGATION
    FORALL (S: (nonempty?[T])):
      FORALL (x1: [maps(S), maps(S)]):
        bijective?[(S), (S)](function_props[(S), (S), (S)].o(x1));

  % Existence TCC generated (at line 33, column 21) for
      % group?[maps(S), op(S), id(S)]
  A_is_group_TCC1: OBLIGATION
    FORALL (S: (nonempty?[T])): EXISTS (x: maps(S)): TRUE;


body:
  homomorphisms[T1: TYPE,
                *: [T1,T1 -> T1],
                one1: T1,
                T2: TYPE,
                o: [T2,T2 -> T2],
                one2: T2]: THEORY
  %-----------------------------------------------------------------------------
  %  Experimental theory 
  %
  %     Author: Rick Butler
  %
  %-----------------------------------------------------------------------------
  BEGIN

    
     ASSUMING IMPORTING group_def

         T1_is_group: ASSUMPTION group?[T1,*,one1](fullset[T1])
         T2_is_group: ASSUMPTION group?[T2,o,one2](fullset[T2])

     ENDASSUMING


     IMPORTING group[T1,*,one1], group[T2,o,one2]


     homomorphism?(G1: group[T1,*,one1],
                   G2: group[T2,o,one2],
                    phi: [(G1) -> (G2)]): bool  =
                      (FORALL (a,b: (G1)): phi(a*b) = phi(a) o phi(b))


     isomorphism?(G1: group[T1,*,one1],
                  G2: group[T2,o,one2],
                    phi: [(G1) -> (G2)]): bool  = bijective?(phi) AND
                                                  homomorphism?(G1,G2,phi)

     homomorphic?(G1: group[T1,*,one1],
                  G2: group[T2,o,one2]): bool = 
                      EXISTS (phi: [(G1) -> (G2)]): homomorphism?(G1,G2,phi)



     isomorphic?(G1: group[T1,*,one1],
                 G2: group[T2,o,one2]): bool = 
                      EXISTS (phi: [(G1) -> (G2)]): isomorphism?(G1,G2,phi)




     G:  VAR group[T1,*,one1]
     GP: VAR group[T2,o,one2]

     homomorphism(G,GP): TYPE = {phi:[(G) -> (GP)] | homomorphism?(G,GP,phi)}
     isomorphism (G,GP): TYPE = {phi:[(G) -> (GP)] |  isomorphism?(G,GP,phi)}


     homo_one: LEMMA FORALL (phi: homomorphism(G,GP)): phi(one1) = one2


     kernel(G: group[T1,*,one1],
            GP: group[T2,o,one2])(phi: homomorphism(G,GP)): subgroup[T1,*,one1](G) =
                {a: T1 | G(a) AND phi(a) = one2}
    
  END homomorphisms

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

  % Assuming TCC generated (at line 24, column 13) for  group[T1, *, one1]
      % generated from assumption group.fullset_is_group
  IMP_group_TCC1: OBLIGATION group?[T1, *, one1](fullset[T1]);

  % Assuming TCC generated (at line 24, column 31) for  group[T2, o, one2]
      % generated from assumption group.fullset_is_group
  IMP_group_TCC2: OBLIGATION group?[T2, o, one2](fullset[T2]);

  % Subtype TCC generated (at line 30, column 45) for  a * b
      % expected type  (G1)
  homomorphism?_TCC1: OBLIGATION
    FORALL (G1: group[T1, *, one1], G2: group[T2, o, one2],
            phi: [(G1) -> (G2)], a, b: (G1)):
      G1(a * b);

  % Subtype TCC generated (at line 58, column 57) for  one1
      % expected type  (G)
  homo_one_TCC1: OBLIGATION
    FORALL (G: group[T1, *, one1], GP: group[T2, o, one2],
            phi: homomorphism(G, GP)):
      G(one1);

  % Subtype TCC generated (at line 63, column 14) for
      % {a: T1 | G(a) AND phi(a) = one2}
      % expected type  subgroup[T1, *, one1](G)
  kernel_TCC1: OBLIGATION
    FORALL (G: group[T1, *, one1], GP: group[T2, o, one2],
            phi: homomorphism(G, GP)):
      group?[T1, *, one1]({a: T1 | G(a) AND phi(a) = one2}) AND
       subgroup?[T1, *, one1]({a: T1 | G(a) AND phi(a) = one2}, G);


body:
  cayleys[T: Type+, *:[T,T->T], one:T]: THEORY
  %-----------------------------------------------------------------------------
  %  Experimental theory 
  %
  %     Author: Rick Butler
  %
  %-----------------------------------------------------------------------------
  BEGIN

     ASSUMING IMPORTING group_def[T,*,one], semigroup_def

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING


     IMPORTING homomorphisms

     IMPORTING A_group[T], group
     

     S: VAR semigroup[T,*]

     al(S: set[T], a:(S)):[(S) -> T] = (LAMBDA (s:(S)): a*s);

     ML(S): set[maps(S)] = {al: [(S) -> (S)] | EXISTS (x: (S)): al = al(S,x)}


     cayley_prep: LEMMA FORALL (G: group[T,*,one]): FORALL (a: (G)):
                        bijective?[(G), (G)](LAMBDA (s: (G)): a * s)

     trans_is_group: LEMMA FORALL (G: group[T,*,one]): 
                              group?[maps[T](G), op(G), id(G)](ML(G))

     Cayleys: THEOREM FORALL (G: group[T,*,one]): 
                             isomorphic?[T,*,one,maps(G),op(G),id(G)](G, ML(G))
   
   
  END cayleys

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

  % Assuming TCC generated (at line 22, column 10) for  semigroup[T, *]
      % generated from assumption semigroup.fullset_is_semigroup
  S_TCC1: OBLIGATION
    star_closed?[T, *](fullset[T]) AND
     associative?[(fullset[T])]
         (restrict[[T, T], [(fullset[T]), (fullset[T])], T](*));

  % Assuming TCC generated (at line 45, column 7) for  group[T, *, one]
      % generated from assumption group.fullset_is_group
  cayley_prep_TCC1: OBLIGATION group?[T, *, one](fullset[T]);

  % Subtype TCC generated (at line 30, column 60) for  a * s
      % expected type  (G)
  cayley_prep_TCC2: OBLIGATION
    FORALL (G: group[T, *, one], a: (G), s: (G)): (G)(a * s);

  % Subtype TCC generated (at line 33, column 64) for  G
      % expected type  S: semigroup[T, *]
  trans_is_group_TCC1: OBLIGATION
    FORALL (G: group[T, *, one]):
      star_closed?[T, *](G) AND
       associative?[(G)](restrict[[T, T], [(G), (G)], T](*));

  % Subtype TCC generated (at line 33, column 50) for  G
      % expected type  S: (nonempty?[T])
  trans_is_group_TCC2: OBLIGATION
    FORALL (G: group[T, *, one]): nonempty?[T](G);

  % Existence TCC generated (at line 33, column 28) for
      % group?[maps[T](G), op(G), id(G)]
  trans_is_group_TCC3: OBLIGATION
    FORALL (G: group[T, *, one]): EXISTS (x: maps[T](G)): TRUE;

  % Subtype TCC generated (at line 36, column 71) for  ML(G)
      % expected type  group[maps(G), op(G), id(G)]
  Cayleys_TCC1: OBLIGATION
    FORALL (G: group[T, *, one]): group?[maps(G), op[T](G), id[T](G)](ML(G));

  % Assuming TCC generated (at line 19, column 7) for
      % homomorphisms[T, *, one, maps(G), op(G), id(G)]
      % generated from assumption homomorphisms.T2_is_group
  Cayleys_TCC2: OBLIGATION
    FORALL (G: group[T, *, one]):
      group?[maps(G), op[T](G), id[T](G)](fullset[maps(G)]);


body:
  infinite_cyclic_groups[T:Type+,*:[T,T->T],one:T]: THEORY
  BEGIN

     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING

  %  infinite cyclic groups

     IMPORTING group, group_rew

     Z: group[int,+,0] = generated_by[int,+,0](1)

     a: VAR T

     F(a: T): group[T,*,one] = generated_by(a)

     IMPORTING homomorphisms

     i: VAR int

     Z_gen: LEMMA i = group[int,+,0].^(1,i)


  %  ----- All infinite cyclic groups are isomorphic to Z
     
     inf_cyclic_is_Z: LEMMA NOT finite_group?(F(a)) IMPLIES isomorphic?(Z,F(a))


  END infinite_cyclic_groups

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

  % Assuming TCC generated (at line 14, column 6) for
      % group[int, restrict[[numfield, numfield], [int, int], numfield](+), 0]
      % generated from assumption group.fullset_is_group
  Z_TCC1: OBLIGATION
    group?[int, restrict[[numfield, numfield], [int, int], numfield](+), 0]
        (fullset[int]);

  % Assuming TCC generated (at line 18, column 12) for  group[T, *, one]
      % generated from assumption group.fullset_is_group
  F_TCC1: OBLIGATION group?[T, *, one](fullset[T]);


body:
  cyclic_group[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN
  %------------------------------------------------------------------------
  %  The imported type T with * and one must be a group.
  %  From this foundation other groups are created.  These are just subgroups of the
  %  underlying imported type.
  %------------------------------------------------------------------------
     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING

     IMPORTING group[T,*,one]

     a: VAR T
     S: VAR set[T]
     H,G: VAR group
     i: VAR int

  %  generated_by(a): group = {t: T | EXISTS (i: int): t = a^i}
  %  cyclic?(G): boolean = EXISTS (a:(G)): G = generated_by(a)

     generated_by_lem     : LEMMA generated_by(a)(a^i)

     generated_is_subgroup: LEMMA member(a,G) IMPLIES
                                                subgroup?(generated_by(a),G)

     generated_by_is_finite: LEMMA S = generated_by(a) AND 
                                   (EXISTS (k: posnat): a^k = one)
                                IMPLIES finite_group?(S)


     cyclic_abelian: THEOREM cyclic?(G) IMPLIES abelian_group?(G)


     %% TRICKY %%
     cyclic_subgroup: LEMMA subgroup?(H,G) AND cyclic?(G) IMPLIES cyclic?(H)

     
     is_cyclic   : LEMMA (EXISTS (a:(G)): FORALL (x: (G)): 
                            EXISTS (n: nat): x = a^n) IMPLIES
                                   cyclic?(G)


             
  END cyclic_group

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

  % Assuming TCC generated (at line 15, column 13) for  group[T, *, one]
      % generated from assumption group.fullset_is_group
  IMP_group_TCC1: OBLIGATION group?[T, *, one](fullset[T]);


body:
  lagrange_scaf[T:TYPE]: THEORY
  %------------------------------------------------------------------------------
  % Unions of Partitions (disjoint covering sets)
  %
  %     Author: Rick Butler, NASA Langley
  %             Adapted from equivalence_classes (David Lester)
  %
  %     Version 1.0           12/12/07     
  %
  %  THIS IS NOW OBSOLETE -- see lagrange_scaf 
  %------------------------------------------------------------------------------
  BEGIN


    SS:  VAR setofsets[T]
    a,b: VAR set[T]
    n:   VAR nat
    x,y: VAR T

  % We define a "partition" as a set of nonempty, disjoint sets.

    partition?(SS): bool = (FORALL (a,b:(SS)): a = b OR disjoint?(a,b))

    partition: TYPE = (partition?) CONTAINING emptyset[(nonempty?[T])]

    P: VAR partition

  % We now define "finite_partitions" as a finite set of finite nonempty sets.
   
    finite_partition?(SS): bool
      = partition?(SS) AND is_finite(SS) AND every(is_finite[T])(SS)

    finite_partition: TYPE = (finite_partition?) CONTAINING
                                                    emptyset[(nonempty?[T])]
    FP: VAR finite_partition

    finite_partition_is_partition:JUDGEMENT finite_partition SUBTYPE_OF partition


    IMPORTING finite_sets@finite_sets_inductions


    AUTO_REWRITE+ member

    m: VAR nat
    PP: VAR finite_partition

    card_Union_rest: LEMMA nonempty?(PP) IMPLIES Union(PP) = union(Union(rest(PP)),choose(PP))

    card_equal_partition: LEMMA card(PP) = n AND
                                (FORALL (A: (PP)): card(A) = m) AND
                                (FORALL (A,B: (PP)): A = B OR disjoint?(A,B))
                                IMPLIES
                                    card(Union(PP)) = n*m


    H: VAR set[T]
    card_eq_part: LEMMA (FORALL (A,B: (PP)): card(A) = card(B)) AND
                        (FORALL (A,B: (PP)): A = B OR disjoint?(A,B)) AND
                        PP(H)
                      IMPLIES
                         card(Union(PP)) = card(PP)*card(H)

  END lagrange_scaf

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

  % Subtype TCC generated (at line 24, column 44) for
      % extend[setof[T], (nonempty?[T]), bool, FALSE]
      %     (emptyset[(nonempty?[T])])
      % expected type  partition
  partition_TCC1: OBLIGATION
    partition?(extend[setof[T], (nonempty?[T]), bool, FALSE]
                   (emptyset[(nonempty?[T])]));

  % Subtype TCC generated (at line 34, column 50) for
      % extend[setof[T], (nonempty?[T]), bool, FALSE]
      %     (emptyset[(nonempty?[T])])
      % expected type  finite_partition
  finite_partition_TCC1: OBLIGATION
    finite_partition?(extend[setof[T], (nonempty?[T]), bool, FALSE]
                          (emptyset[(nonempty?[T])]));

  % Judgement subtype TCC generated (at line 37, column 42) for  x
      % expected type  partition
  finite_partition_is_partition: OBLIGATION
    FORALL (x: finite_partition): partition?(x);

  % Subtype TCC generated (at line 50, column 35) for  PP
      % expected type  S: finite_set[setof[T]]
  card_equal_partition_TCC1: OBLIGATION
    FORALL (PP: finite_partition): is_finite[setof[T]](PP);

  % Subtype TCC generated (at line 51, column 54) for  A
      % expected type  S: finite_set[T]
  card_equal_partition_TCC2: OBLIGATION
    FORALL (PP: finite_partition, n: nat):
      card(PP) = n IMPLIES (FORALL (A: (PP)): is_finite[T](A));

  % Subtype TCC generated (at line 54, column 39) for  Union(PP)
      % expected type  S: finite_set[T]
  card_equal_partition_TCC3: OBLIGATION
    FORALL (PP: finite_partition, m, n: nat):
      (FORALL (A, B: (PP)): A = B OR disjoint?(A, B)) AND
       (FORALL (A: (PP)): card(A) = m) AND card(PP) = n
       IMPLIES is_finite[T](Union[T](PP));

  % Subtype TCC generated (at line 58, column 48) for  A
      % expected type  S: finite_set[T]
  card_eq_part_TCC1: OBLIGATION
    FORALL (PP: finite_partition, A, B: (PP)): is_finite[T](A);

  % Subtype TCC generated (at line 58, column 58) for  B
      % expected type  S: finite_set[T]
  card_eq_part_TCC2: OBLIGATION
    FORALL (PP: finite_partition, A, B: (PP)): is_finite[T](B);

  % Subtype TCC generated (at line 62, column 28) for  Union(PP)
      % expected type  S: finite_set[T]
  card_eq_part_TCC3: OBLIGATION
    FORALL (H: set[T], PP: finite_partition):
      (PP(H) AND
        (FORALL (A, B: (PP)): A = B OR disjoint?(A, B)) AND
         (FORALL (A, B: (PP)): card(A) = card(B)))
       IMPLIES is_finite[T](Union[T](PP));

  % Subtype TCC generated (at line 62, column 55) for  H
      % expected type  S: finite_set[T]
  card_eq_part_TCC4: OBLIGATION
    FORALL (H: set[T], PP: finite_partition):
      (PP(H) AND
        (FORALL (A, B: (PP)): A = B OR disjoint?(A, B)) AND
         (FORALL (A, B: (PP)): card(A) = card(B)))
       IMPLIES is_finite[T](H);


body:
  %------------------------------------------------------------------------------
  % Lagrange
  %
  %     Author: Rick Butler
  %             David Lester, Manchester University & NIA
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  lagrange[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN

     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING

     IMPORTING group[T,*,one], cosets[T,*,one]
               

     G,H: VAR finite_group
     S:   VAR (nonempty?[T])
     a,b: VAR T
     n:   VAR nat

     IMPORTING lagrange_scaf


  % Herstein Lemma 2.4.5 (Corollary)

     right_coset_finite: LEMMA subgroup?(H,G) AND member(a,G) IMPLIES
                                 is_finite(right_coset(G,H)(a))

     finite_right_coset_correspondence: LEMMA
                 subgroup?(H,G) AND member(a,G) AND member(b,G) IMPLIES
                 card(right_coset(G,H)(a)) = card(right_coset(G,H)(b))

  % Herstein Theorem 2.4.1

    set_right_cosets_full: LEMMA FORALL (G: group, H: subgroup(G)):
                                Union(fullset[right_cosets(G,H)]) = G


    right_cosets_disjoint: LEMMA FORALL (G: group, H: subgroup(G), A,B: right_cosets(G, H)):
                                       A = B OR disjoint?(A,B)


    right_cosets_partition: LEMMA FORALL (G: finite_group, H: subgroup(G)):
                                      finite_partition?[T](fullset[right_cosets(G, H)])



    Lagrange: THEOREM subgroup?(H,G) IMPLIES divides(order(H),order(G))  %% NEW rwb


  END lagrange

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

  % Assuming TCC generated (at line 22, column 13) for  group[T, *, one]
      % generated from assumption group.fullset_is_group
  IMP_group_TCC1: OBLIGATION group?[T, *, one](fullset[T]);

  % Subtype TCC generated (at line 36, column 58) for  a
      % expected type  (G)
  right_coset_finite_TCC1: OBLIGATION
    FORALL (G, H: finite_group[T, *, one], a: T):
      member(a, G) AND subgroup?(H, G) IMPLIES G(a);

  % Subtype TCC generated (at line 40, column 20) for  right_coset(G, H)(a)
      % expected type  S: finite_set[T]
  finite_right_coset_correspondence_TCC1: OBLIGATION
    FORALL (G, H: finite_group[T, *, one], a, b: T):
      member(b, G) AND member(a, G) AND subgroup?(H, G) IMPLIES
       is_finite[T](right_coset[T, *, one](G, H)(a));

  % Subtype TCC generated (at line 40, column 65) for  b
      % expected type  (G)
  finite_right_coset_correspondence_TCC2: OBLIGATION
    FORALL (G, H: finite_group[T, *, one], a, b: T):
      member(b, G) AND member(a, G) AND subgroup?(H, G) IMPLIES G(b);

  % Subtype TCC generated (at line 40, column 48) for  right_coset(G, H)(b)
      % expected type  S: finite_set[T]
  finite_right_coset_correspondence_TCC3: OBLIGATION
    FORALL (G, H: finite_group[T, *, one], a, b: T):
      member(b, G) AND member(a, G) AND subgroup?(H, G) IMPLIES
       is_finite[T](right_coset[T, *, one](G, H)(b));


body:
  finite_groups[T:Type+,*:[T,T->T],one:T]: THEORY
  %-----------------------------------------------------------------------------
  % Cyclic Groups
  %
  %     Author: Rick Butler and David Lester
  %
  % This are groups generated by an element and repeated multiplication
  % using the following defined in theory group.
  %
  %      generated_by(a): group = {t: T | EXISTS (i: int): t = a^i}
  %
  %      cyclic?(G): boolean = EXISTS (a:(G)): G = generated_by(a)
  %
  %-----------------------------------------------------------------------------
  BEGIN

     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING


     IMPORTING group[T,*,one],
               ints@primes


     G,H: VAR finite_group
     S:   VAR (nonempty?[T])
     a,b: VAR T
     n:   VAR nat


     finite_generated_by: LEMMA member(a,G) IMPLIES 
                                    is_finite(generated_by(a))   %% RWB

     finite_generated_by_def: LEMMA member(a,G) AND S = generated_by(a) 
                                    IMPLIES S = {t:T | EXISTS (n:posnat): n <= card(S) AND t = a^n}

     finite_generated_by_one: LEMMA member(a,G) AND S = generated_by(a) 
                                    IMPLIES a^card(S) = one


     generated_by_card_1: LEMMA member(a,G) AND 
                                card(generated_by(a)) = 1
                                   IMPLIES a = one AND
                                           generated_by(a) = singleton[T](one)

     
     finite_group_elements: LEMMA member(a,G) IMPLIES finite_order?(a)

     period(G:finite_group,a:(G)):posnat = min({n:posnat | a^n = one})

     a_hat_period:     LEMMA member(a,G) IMPLIES a^(period(G,a)) = one


     finite_subgroup_def: LEMMA
                       subgroup?(S,G) IFF (subset?(S,G) AND star_closed?(S))

     orders_equal: LEMMA order(H) = order(G) AND subgroup?(H,G)
                         IMPLIES G = H


     IMPORTING lagrange[T,*,one]

     period_is_generated_order: LEMMA member(a,G) IMPLIES 
                                           period(G,a) = order(generated_by(a))

     period_element_divides_group: COROLLARY member(a,G) IMPLIES
                                                    divides(period(G,a),order(G))


  END finite_groups

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

  % Assuming TCC generated (at line 24, column 13) for  group[T, *, one]
      % generated from assumption group.fullset_is_group
  IMP_group_TCC1: OBLIGATION group?[T, *, one](fullset[T]);

  % Subtype TCC generated (at line 38, column 82) for  S
      % expected type  S: finite_set[T]
  finite_generated_by_def_TCC1: OBLIGATION
    FORALL (G: finite_group[T, *, one], S: (nonempty?[T]), a: T):
      S = generated_by(a) AND member(a, G) IMPLIES is_finite[T](S);

  % Subtype TCC generated (at line 45, column 35) for  generated_by(a)
      % expected type  S: finite_set[T]
  generated_by_card_1_TCC1: OBLIGATION
    FORALL (G: finite_group[T, *, one], a: T):
      member(a, G) IMPLIES is_finite[T](generated_by[T, *, one](a));

  % Subtype TCC generated (at line 52, column 45) for
      % {n: posnat | a ^ n = one}
      % expected type  S: (nonempty?[posnat])
  period_TCC1: OBLIGATION
    FORALL (G: finite_group[T, *, one], a: (G)):
      nonempty?[posnat]({n: posnat | ^[T, *, one](a, n) = one});

  % Subtype TCC generated (at line 54, column 59) for  a
      % expected type  (G)
  a_hat_period_TCC1: OBLIGATION
    FORALL (G: finite_group[T, *, one], a: T): member(a, G) IMPLIES G(a);

  % Subtype TCC generated (at line 67, column 61) for  generated_by(a)
      % expected type  finite_monad[T, *, one]
  period_is_generated_order_TCC1: OBLIGATION
    FORALL (G: finite_group[T, *, one], a: T):
      member(a, G) IMPLIES
       finite_monad?[T, *, one](generated_by[T, *, one](a));


body:
  finite_cyclic_groups[T:Type+,*:[T,T->T],one:T]: THEORY
  %-----------------------------------------------------------------------------
  % Cyclic Groups
  %
  %     Author: Rick Butler
  %
  % This are groups generated by an element and repeated multiplication
  % using the following defined in theory group.
  %
  %      generated_by(a): group = {t: T | EXISTS (i: int): t = a^i}
  %
  %      cyclic?(G): boolean = EXISTS (a:(G)): G = generated_by(a)
  %
  %-----------------------------------------------------------------------------
  BEGIN

     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING


     IMPORTING finite_groups[T,*,one], cyclic_group[T,*,one],
               ints@primes


     G,H: VAR finite_group
     S:   VAR (nonempty?[T])
     a,b: VAR T
     n:   VAR nat

     prime_order_cycle: THEOREM prime?(order(G)) IMPLIES
                                cyclic?(G)


  END finite_cyclic_groups

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

  % Assuming TCC generated (at line 24, column 13) for
      % finite_groups[T, *, one]
      % generated from assumption finite_groups.fullset_is_group
  IMP_finite_groups_TCC1: OBLIGATION group?[T, *, one](fullset[T]);


body:
  %------------------------------------------------------------------------------
  % Example groups
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  group_test: THEORY

    BEGIN

    IMPORTING abelian_group

    integer_plus:      abelian_group[int,+,0]    = fullset[int]
    nz_rational_mult:  abelian_group[nzrat,*,1]  = fullset[nzrat]
    pos_rational_mult: abelian_group[posrat,*,1] = fullset[posrat]

    END group_test

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

  % Assuming TCC generated (at line 18, column 21) for
      % abelian_group
      %     [int, restrict[[numfield, numfield], [int, int], numfield](+), 0]
      % generated from assumption abelian_group.fullset_is_abelian_group
  integer_plus_TCC1: OBLIGATION
    abelian_group?
        [int, restrict[[numfield, numfield], [int, int], numfield](+), 0]
        (fullset[int]);

  % Assuming TCC generated (at line 19, column 21) for
      % abelian_group
      %     [nzrat,
      %      restrict[[numfield, numfield], [nzrat, nzrat], numfield](*), 1]
      % generated from assumption abelian_group.fullset_is_abelian_group
  nz_rational_mult_TCC1: OBLIGATION
    abelian_group?
        [nzrat, restrict[[numfield, numfield], [nzrat, nzrat], numfield](*),
         1]
        (fullset[nzrat]);

  % Assuming TCC generated (at line 20, column 21) for
      % abelian_group
      %     [posrat,
      %      restrict[[numfield, numfield], [posrat, posrat], numfield](*), 1]
      % generated from assumption abelian_group.fullset_is_abelian_group
  pos_rational_mult_TCC1: OBLIGATION
    abelian_group?
        [posrat,
         restrict[[numfield, numfield], [posrat, posrat], numfield](*), 1]
        (fullset[posrat]);


body:
  symmetric_groups[N: posnat]: THEORY
  %
  %  RWB: adapted from old algebra library
  %
  BEGIN

     S: set[posnat] = fullset[{n: posnat | n <= N}]

     perm: TYPE = (bijective?[(S),(S)])

     Sym: set[perm] = fullset[perm]

     IMPORTING group_def

     id: perm = identity[(S)]

     op: [perm,perm -> perm] = function_props[(S),(S),(S)].o

     Sym_is_group: LEMMA group?[perm,op,identity[(S)]](Sym)

  %   Sym_finite: LEMMA is_finite[perm](Sym)   %% UNPROVED %%

  %   IMPORTING factorial

  %   order_Sym: LEMMA order[perm,op,id](Sym) = factorial(N)  %% UNPROVED %%

  END symmetric_groups

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

  % Subtype TCC generated (at line 17, column 29) for
      % restrict[[[(S) -> (S)], [(S) -> (S)]], [perm, perm], [(S) -> (S)]]
      %     (function_props[(S), (S), (S)].o)
      % expected type  [[perm, perm] -> perm]
  op_TCC1: OBLIGATION
    FORALL (x1: [perm, perm]):
      bijective?[(S), (S)](function_props[(S), (S), (S)].o(x1));


body:
  %------------------------------------------------------------------------------
  % SubGroups
  %
  %------------------------------------------------------------------------------

  subgroups[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN
     ASSUMING IMPORTING group_def[T,*,one]

         fullset_is_group: ASSUMPTION group?(fullset[T])

     ENDASSUMING

     IMPORTING group, group_rew

     G: VAR group[T,*,one]

     subgroup(G): TYPE = { s: set[T] | subset?(s,G) AND group?(s)}

     A,B: VAR set[T]


     pg64_1: LEMMA 
        subgroup?(A,G) AND subgroup?(B,G) 
           IMPLIES subgroup?(intersection(A,B),G)


     IMPORTING normal_subgroups[T,*,one]
  	
     center_normal: LEMMA  normal_subgroup?(center(G),G)

  END subgroups

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

  % Assuming TCC generated (at line 17, column 10) for  group[T, *, one]
      % generated from assumption group.fullset_is_group
  G_TCC1: OBLIGATION group?[T, *, one](fullset[T]);

  % Subtype TCC generated (at line 31, column 42) for  center(G)
      % expected type  group[T, *, one]
  center_normal_TCC1: OBLIGATION
    FORALL (G: group[T, *, one]): group?[T, *, one](center[T, *, one](G));


body:
  %------------------------------------------------------------------------------
  % Cyclic monoid definition file
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %             
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  cyclic_monoid_def[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN

     IMPORTING monoid_def[T,*,one]

     S: VAR set[T]
     a: VAR T

     cyclic_monoid?(S):bool = monoid?(S) AND EXISTS (a:(S)): S = generated_set(a)

     finite_cyclic_monoid?(S): bool          = cyclic_monoid?(S) AND is_finite(S)

     commutative_cyclic_monoid?(S): bool        = cyclic_monoid?(S)

     finite_commutative_cyclic_monoid?(S): bool = finite_cyclic_monoid?(S)

  END cyclic_monoid_def


body:
  %------------------------------------------------------------------------------
  % Cyclic monoids
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  cyclic_monoid[T:Type+,*:[T,T->T],one:T]: THEORY

  BEGIN

     ASSUMING IMPORTING cyclic_monoid_def[T,*,one]

         fullset_is_cyclic_monoid: ASSUMPTION cyclic_monoid?(fullset[T])

     ENDASSUMING

     IMPORTING monoid[T,*,one]

     cyclic_monoid: TYPE+ = (cyclic_monoid?) CONTAINING fullset[T]

     M: VAR cyclic_monoid
     a: VAR T
     n: VAR nat

     cyclic_monoid_is: LEMMA cyclic_monoid?(M)

     cyclic_monoid_is_monoid: JUDGEMENT cyclic_monoid SUBTYPE_OF monoid

     cyclic_monoid_is_commutative_monoid:
                          JUDGEMENT cyclic_monoid SUBTYPE_OF commutative_monoid

  END cyclic_monoid

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

  % Assuming TCC generated (at line 22, column 13) for  monoid[T, *, one]
      % generated from assumption monoid.fullset_is_monoid
  IMP_monoid_TCC1: OBLIGATION monoid?[T, *, one](fullset[T]);

  % Subtype TCC generated (at line 24, column 54) for  fullset[T]
      % expected type  cyclic_monoid
  cyclic_monoid_TCC1: OBLIGATION cyclic_monoid?[T, *, one](fullset[T]);

  % Judgement subtype TCC generated (at line 32, column 38) for  x
      % expected type  monoid[T, *, one]
  cyclic_monoid_is_monoid: OBLIGATION
    FORALL (x: cyclic_monoid): monoid?[T, *, one](x);

  % Judgement subtype TCC generated (at line 35, column 34) for  x
      % expected type  commutative_monoid[T, *, one]
  cyclic_monoid_is_commutative_monoid: OBLIGATION
    FORALL (x: cyclic_monoid): commutative_monoid?[T, *, one](x);


body:
  %------------------------------------------------------------------------------
  % Commutative groupoids
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  commutative_groupoid[T:Type+,*:[T,T->T]]: THEORY

  BEGIN

     ASSUMING IMPORTING groupoid_def[T,*]

         fullset_is_commutative_groupoid: ASSUMPTION
                                                commutative_groupoid?(fullset[T])

     ENDASSUMING

     IMPORTING groupoid_def, groupoid[T,*]

     commutative_groupoid: TYPE+ = (commutative_groupoid?) CONTAINING fullset[T]

     G:   VAR commutative_groupoid
     x,y: VAR T

     commutative:          LEMMA x * y = y * x

     commutative_groupoid_is_groupoid:
                               JUDGEMENT commutative_groupoid SUBTYPE_OF groupoid

  END commutative_groupoid

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

  % Subtype TCC generated (at line 25, column 68) for  fullset[T]
      % expected type  commutative_groupoid
  commutative_groupoid_TCC1: OBLIGATION
    commutative_groupoid?[T, *](fullset[T]);

  % Judgement subtype TCC generated (at line 33, column 39) for  x
      % expected type  groupoid[T, *]
  commutative_groupoid_is_groupoid: OBLIGATION
    FORALL (x: commutative_groupoid): star_closed?[T, *](x);


body:
  %------------------------------------------------------------------------------
  % Commutative semigroups
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  commutative_semigroup[T:Type+,*:[T,T->T]]: THEORY

  BEGIN

     ASSUMING IMPORTING semigroup_def[T,*]

         fullset_is_commutative_semigroup:
                                    ASSUMPTION commutative_semigroup?(fullset[T])

     ENDASSUMING

     IMPORTING semigroup_def, commutative_groupoid[T,*], semigroup[T,*]

     commutative_semigroup: TYPE+ = (commutative_semigroup?)
                                                            CONTAINING fullset[T]

     commutative_semigroup_is_semigroup:
                 JUDGEMENT commutative_semigroup SUBTYPE_OF semigroup
     commutative_semigroup_is_commutative_groupoid:
                 JUDGEMENT commutative_semigroup SUBTYPE_OF commutative_groupoid

  END commutative_semigroup

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

  % Assuming TCC generated (at line 23, column 28) for
      % commutative_groupoid[T, *]
      % generated from assumption commutative_groupoid.fullset_is_commutative_groupoid
  IMP_commutative_groupoid_TCC1: OBLIGATION
    commutative_groupoid?[T, *](fullset[T]);

  % Assuming TCC generated (at line 23, column 55) for  semigroup[T, *]
      % generated from assumption semigroup.fullset_is_semigroup
  IMP_semigroup_TCC1: OBLIGATION
    star_closed?[T, *](fullset[T]) AND
     associative?[(fullset[T])]
         (restrict[[T, T], [(fullset[T]), (fullset[T])], T](*));

  % Subtype TCC generated (at line 26, column 69) for  fullset[T]
      % expected type  commutative_semigroup
  commutative_semigroup_TCC1: OBLIGATION
    commutative_semigroup?[T, *](fullset[T]);

  % Judgement subtype TCC generated (at line 29, column 25) for  x
      % expected type  semigroup[T, *]
  commutative_semigroup_is_semigroup: OBLIGATION
    FORALL (x: commutative_semigroup):
      star_closed?[T, *](x) AND
       associative?[(x)](restrict[[T, T], [(x), (x)], T](*));

  % Judgement subtype TCC generated (at line 31, column 25) for  x
      % expected type  commutative_groupoid[T, *]
  commutative_semigroup_is_commutative_groupoid: OBLIGATION
    FORALL (x: commutative_semigroup): commutative_groupoid?[T, *](x);


body:
  %------------------------------------------------------------------------------
  % Mathematical Structures (Part I)
  %
  % Group-like Structures with signature [T:Type+,*:[T,T->T],one:T])
  %
  %     Author: David Lester, Manchester University & NIA
  %             Rick Butler
  %
  %     Version 1.0            3/1/02
  %     Version 1.1           12/3/03   New library structure
  %     Version 1.2            5/5/04   Reworked for definition files DRL
  %------------------------------------------------------------------------------

  top_group: THEORY

  BEGIN

     IMPORTING groupoid,              
               commutative_groupoid,  
               monad,                 
               semigroup,             
               commutative_semigroup, 
               monoid,                
               cyclic_monoid,
               cyclic_group,
               group,           
               abelian_group,         
               symmetric_groups,
               group_test,


               finite_cyclic_groups,
               infinite_cyclic_groups,
               factor_groups,          %% RWB experimental
               A_group,                %% RWB experimental
               homomorphisms,        
               cayleys,       
               zn                   

  %            homomorphism_theorems   %% RWB breaks PVS 
  %            cayleys                 %% RWB experimental

  END top_group


body:
  %-----------------------------------------------------------------------------
  % Sequences of countable length defined as coalgebraic datatypes.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 11: PVS 6.0 version
  %-----------------------------------------------------------------------------
  top: THEORY
   BEGIN

    IMPORTING
     ascending_chains,              % Monotonically nondecreasing prefixes
     csequence,                     % Basic definitions
     csequence_add,                 % Properties of the add operator
     csequence_append,              % Append an element to a csequence
     csequence_concatenate,         % The o operator for csequences
     csequence_concatenate_extract, % Eta rule for o and ^
     csequence_constant,            % A single repeated element
     csequence_extract,             % The ^ operator for csequences
     csequence_filter,              % Filter with a predicate
     csequence_filter_map,          % Conjunction of filter and map
     csequence_filter_of,           % Whether one seq is the filter of another
     csequence_finseq,              % Conversions to/from finseq
     csequence_first_p,             % The first element satisfying predicate p
     csequence_flatten,             % Sequence of sequences -> sequence
     csequence_generate,            % Sequences made from generator functions
     csequence_generate_limit,      % Ditto with a limit predicate
     csequence_induction,           % More induction rules for csequences
     csequence_insert,              % Insert an element into a csequence
     csequence_insert_remove,       % Eta rule for insert and remove
     csequence_length,              % Compute the length of a csequence
     csequence_length_comp,         % Length comparisons for all csequences
     csequence_limit,               % The limit of an ascending chain
     csequence_list,                % Conversions to/from list
     csequence_map_composition,     % Composed maps on csequences
     csequence_map_props,           % Properties of the map operator
     csequence_merge,               % Element-by-element merge of 2 csequences
     csequence_merge_split,         % Eta rules for merge and split
     csequence_nth,                 % Find the nth element of a csequence
     csequence_prefix,              % Prefixes of csequences
     csequence_prefix_append,       % Eta rule for prefix and append
     csequence_prefix_suffix,       % Eta rule for prefix and suffix
     csequence_props,               % Basic properties of csequences
     csequence_remove,              % Remove an element from a csequence
     csequence_rest,                % Properties of the rest operator
     csequence_reverse,             % Reverse a finite csequence
     csequence_sequence,            % Conversions to/from sequence
     csequence_singleton,           % Csequences with exactly one element
     csequence_split,               % Split a csequence into two csequences
     csequence_strict_prefix,       % Well-ordered prefixes of a given csequence
     csequence_subsequence,         % Subsequence definition and properties
     csequence_suffix,              % Suffixes of csequences
     csequence_unzip,               % Csequence of pairs to pair of csequences
     csequence_zip,                 % Pair of csequences to csequence of pairs
     csequence_zip_unzip            % Eta rules for zip and unzip

   END top


body:
  %-----------------------------------------------------------------------------
  % Sequences of countable length defined as coalgebraic datatypes.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence[T: TYPE]: CODATATYPE
   BEGIN

    empty_cseq: empty?
    add(first: T, rest: csequence): nonempty?

   END csequence


body:
  %-----------------------------------------------------------------------------
  % Finite and infinite sequences, and also the nonempty subtype, part of the
  % theory of sequences of countable length defined as coalgebraic datatypes.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence_props[T: TYPE]: THEORY
   BEGIN

    IMPORTING csequence[T]

    t: VAR T
    p, q: VAR pred[T]
    cseq, cseq_rest: VAR csequence
    n, m: VAR nat

    % This predicate is TRUE iff cseq is finite and of length n
    has_length(cseq, n): RECURSIVE bool =
      IF empty?(cseq) THEN n = 0
      ELSE n > 0 AND has_length(rest(cseq), n - 1)
      ENDIF
       MEASURE n

    has_length_injective: THEOREM
      FORALL cseq, n, m:
        has_length(cseq, n) AND has_length(cseq, m) IMPLIES n = m

    % This predicate is TRUE iff cseq is finite
    is_finite(cseq): INDUCTIVE bool = empty?(cseq) OR is_finite(rest(cseq))

    is_finite_def: THEOREM
      FORALL cseq: is_finite(cseq) IFF (EXISTS n: has_length(cseq, n))

    is_infinite(cseq): MACRO bool = NOT is_finite(cseq)


    % Various useful subtypes of the csequence type

    finite_csequence: TYPE+ = (is_finite) CONTAINING empty_cseq

    infinite_csequence: TYPE = (is_infinite)

    empty_csequence: TYPE+ = (empty?) CONTAINING empty_cseq

    nonempty_csequence: TYPE = (nonempty?)

    nonempty_finite_csequence: TYPE = {cseq: finite_csequence | nonempty?(cseq)}


    % Judgements relating the types

    empty_csequence_is_finite: JUDGEMENT
      empty_csequence SUBTYPE_OF finite_csequence

    infinite_csequence_is_nonempty: JUDGEMENT
      infinite_csequence SUBTYPE_OF nonempty_csequence


    % Properties of some and every

    pred_NOT(p)(t): bool = NOT p(t)

    pred_AND(p, q)(t): bool = p(t) AND q(t)

    pred_OR(p, q)(t): bool = p(t) OR q(t)

    pred_IMPLIES(p, q)(t): bool = p(t) IMPLIES q(t)

    some_every_rew: THEOREM
      FORALL p, cseq: some(p)(cseq) IFF NOT every(pred_NOT(p))(cseq)

    every_some_rew: THEOREM
      FORALL p, cseq: every(p)(cseq) IFF NOT some(pred_NOT(p))(cseq)

    some_implies: THEOREM
      FORALL cseq, p, q:
        (FORALL t: pred_IMPLIES(p, q)(t)) AND some(p)(cseq) IMPLIES
         some(q)(cseq)

    every_implies: THEOREM
      FORALL cseq, p, q:
        (FORALL t: pred_IMPLIES(p, q)(t)) AND every(p)(cseq) IMPLIES
         every(q)(cseq)

   END csequence_props

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

  is_finite_weak_induction: AXIOM
    FORALL (P: [csequence[T] -> boolean]):
      (FORALL (cseq): empty?(cseq) OR P(rest(cseq)) IMPLIES P(cseq)) IMPLIES
       (FORALL (cseq): is_finite(cseq) IMPLIES P(cseq));

  is_finite_induction: AXIOM
    FORALL (P: [csequence[T] -> boolean]):
      (FORALL (cseq):
         empty?(cseq) OR is_finite(rest(cseq)) AND P(rest(cseq)) IMPLIES
          P(cseq))
       IMPLIES (FORALL (cseq): is_finite(cseq) IMPLIES P(cseq));

  % Subtype TCC generated (at line 28, column 35) for  cseq
      % expected type  (nonempty?)
  has_length_TCC1: OBLIGATION
    FORALL (cseq: csequence[T], n: nat):
      n > 0 AND NOT empty?(cseq) IMPLIES nonempty?[T](cseq);

  % Subtype TCC generated (at line 28, column 42) for  n - 1
      % expected type  nat
  has_length_TCC2: OBLIGATION
    FORALL (cseq: csequence[T], n: nat):
      n > 0 AND NOT empty?(cseq) IMPLIES n - 1 >= 0;

  % Termination TCC generated (at line 28, column 19) for
      % has_length(rest(cseq), n - 1)
  has_length_TCC3: OBLIGATION
    FORALL (cseq: csequence[T], n: nat):
      n > 0 AND NOT empty?(cseq) IMPLIES n - 1 < n;

  % Subtype TCC generated (at line 37, column 67) for  cseq
      % expected type  (nonempty?)
  is_finite_TCC1: OBLIGATION
    FORALL (cseq: csequence[T]): NOT empty?(cseq) IMPLIES nonempty?[T](cseq);

  % Subtype TCC generated (at line 47, column 51) for  empty_cseq
      % expected type  finite_csequence
  finite_csequence_TCC1: OBLIGATION is_finite(empty_cseq[T]);

  % Judgement subtype TCC generated (at line 61, column 4) for  x
      % expected type  finite_csequence
  empty_csequence_is_finite: OBLIGATION
    FORALL (x: empty_csequence): is_finite(x);

  % Judgement subtype TCC generated (at line 64, column 4) for  x
      % expected type  nonempty_csequence
  infinite_csequence_is_nonempty: OBLIGATION
    FORALL (x: infinite_csequence): nonempty?[T](x);


body:
  %-----------------------------------------------------------------------------
  % Length of a finite sequence, part of the theory of sequences of countable
  % length defined as coalgebraic datatypes.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence_length[T: TYPE]: THEORY
   BEGIN

    IMPORTING csequence_props[T]

    n: VAR nat
    cseq, cseq1, cseq2: VAR csequence
    fseq: VAR finite_csequence
    nfseq: VAR nonempty_finite_csequence

    length(fseq): RECURSIVE {n | has_length(fseq, n)} =
      IF empty?(fseq) THEN 0 ELSE 1 + length(rest(fseq)) ENDIF
       MEASURE choose({n | has_length(fseq, n)})

    length_def: THEOREM
      FORALL fseq, n: length(fseq) = n IFF has_length(fseq, n)

    length_empty?_rew: THEOREM
      FORALL cseq: empty?(cseq) IFF is_finite(cseq) AND length(cseq) = 0

    length_nonempty?_rew: COROLLARY
      FORALL cseq: nonempty?(cseq) IFF is_infinite(cseq) OR length(cseq) > 0

    length_rest: THEOREM FORALL nfseq: length(rest(nfseq)) = length(nfseq) - 1

   END csequence_length

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

  % Subtype TCC generated (at line 27, column 20) for
      % {n | has_length(fseq, n)}
      % expected type  p: (nonempty?[nat])
  length_TCC1: OBLIGATION
    FORALL (fseq: finite_csequence[T]):
      nonempty?[nat]({n | has_length[T](fseq, n)});

  % Subtype TCC generated (at line 26, column 25) for  0
      % expected type  {n | has_length(fseq, n)}
  length_TCC2: OBLIGATION
    FORALL (fseq: finite_csequence[T]):
      empty?(fseq) IMPLIES has_length[T](fseq, 0);

  % Subtype TCC generated (at line 26, column 48) for  fseq
      % expected type  (nonempty?[T])
  length_TCC3: OBLIGATION
    FORALL (fseq: finite_csequence[T]):
      NOT empty?(fseq) IMPLIES nonempty?[T](fseq);

  % Subtype TCC generated (at line 26, column 43) for  rest(fseq)
      % expected type  fseq: finite_csequence[T]
  length_TCC4: OBLIGATION
    FORALL (fseq: finite_csequence[T]):
      NOT empty?(fseq) IMPLIES is_finite[T](rest[T](fseq));

  % Termination TCC generated (at line 26, column 36) for  length(rest(fseq))
  length_TCC5: OBLIGATION
    FORALL (fseq: finite_csequence[T]):
      NOT empty?(fseq) IMPLIES
       choose[nat]({n | has_length[T](rest[T](fseq), n)}) <
        choose[nat]({n | has_length[T](fseq, n)});

  % Subtype TCC generated (at line 26, column 32) for  1 + length(rest(fseq))
      % expected type  {n | has_length(fseq, n)}
  length_TCC6: OBLIGATION
    FORALL (fseq: finite_csequence[T],
            v:
              [fseq1:
                 {z: finite_csequence[T] |
                          choose({n | has_length(z, n)}) <
                           choose({n | has_length(fseq, n)})} ->
                 {n | has_length(fseq1, n)}]):
      NOT empty?(fseq) IMPLIES has_length[T](fseq, 1 + v(rest[T](fseq)));

  % Subtype TCC generated (at line 38, column 44) for  rest(nfseq)
      % expected type  fseq: finite_csequence[T]
  length_rest_TCC1: OBLIGATION FORALL (nfseq): is_finite[T](rest[T](nfseq));


body:
  %-----------------------------------------------------------------------------
  % Operators for convenience in writing length comparisons that include
  % possibly infinite csequences.
  %
  % It might be nicer to have an "extended nat" type that includes a special
  % "infinity" value.  Then we could define the length operator on all
  % sequences, which would simplify some other definitions.  If you are
  % interested in trying this approach, please contact me.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence_length_comp[T1, T2: TYPE]: THEORY
   BEGIN

    IMPORTING csequence_length[T1], csequence_length[T2]

    cseq1: VAR csequence[T1]
    cseq2: VAR csequence[T2]
    nseq1: VAR nonempty_csequence[T1]
    nseq2: VAR nonempty_csequence[T2]

    length_lt(cseq1, cseq2): bool =
        is_finite(cseq1) AND
         (is_finite(cseq2) IMPLIES length(cseq1) < length(cseq2))

    length_le(cseq1, cseq2): bool =
        is_finite(cseq2) IMPLIES
         is_finite(cseq1) AND length(cseq1) <= length(cseq2)

    length_eq(cseq1, cseq2): bool =
        (is_infinite(cseq1) AND is_infinite(cseq2)) OR
         (is_finite(cseq1) AND
           is_finite(cseq2) AND length(cseq1) = length(cseq2))

    length_ge(cseq1, cseq2): bool =
        is_finite(cseq1) IMPLIES
         is_finite(cseq2) AND length(cseq1) >= length(cseq2)

    length_gt(cseq1, cseq2): bool =
        is_finite(cseq2) AND
         (is_finite(cseq1) IMPLIES length(cseq1) > length(cseq2))

    length_lt_le: THEOREM
      FORALL cseq1, cseq2:
        length_lt(cseq1, cseq2) IMPLIES length_le(cseq1, cseq2)

    length_gt_ge: THEOREM
      FORALL cseq1, cseq2:
        length_gt(cseq1, cseq2) IMPLIES length_ge(cseq1, cseq2)

    length_eq_le: THEOREM
      FORALL cseq1, cseq2:
        length_eq(cseq1, cseq2) IMPLIES length_le(cseq1, cseq2)

    length_eq_ge: THEOREM
      FORALL cseq1, cseq2:
        length_eq(cseq1, cseq2) IMPLIES length_ge(cseq1, cseq2)

    length_lt_neq: THEOREM
      FORALL cseq1, cseq2:
        length_lt(cseq1, cseq2) IMPLIES NOT length_eq(cseq1, cseq2)

    length_gt_neq: THEOREM
      FORALL cseq1, cseq2:
        length_gt(cseq1, cseq2) IMPLIES NOT length_eq(cseq1, cseq2)

    length_eq_empty: THEOREM
      FORALL cseq1, cseq2:
        length_eq(cseq1, cseq2) IMPLIES (empty?(cseq1) IFF empty?(cseq2))

    length_eq_rest: THEOREM
      FORALL nseq1, nseq2:
        length_eq(nseq1, nseq2) IFF length_eq(rest(nseq1), rest(nseq2))

   END csequence_length_comp


body:
  %-----------------------------------------------------------------------------
  % Last and nth elements of a sequence of countable length, as well as the
  % valid indexes.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence_nth[T: TYPE]: THEORY
   BEGIN

    IMPORTING csequence_length[T]

    n: VAR nat
    p: VAR pred[T]
    cseq, cseq1, cseq2: VAR csequence
    fseq: VAR finite_csequence
    nseq: VAR nonempty_csequence
    nfseq: VAR nonempty_finite_csequence
    iseq: VAR infinite_csequence

    % The valid indexes of a csequence.
    index?(cseq)(n): RECURSIVE bool =
      nonempty?(cseq) AND (n = 0 OR index?(rest(cseq))(n - 1))
       MEASURE n

    indexes(cseq): TYPE = (index?(cseq))

    index?_0: THEOREM FORALL cseq: nonempty?(cseq) IFF index?(cseq)(0)

    index?_ub: THEOREM FORALL cseq, n: index?(cseq)(n) OR is_finite(cseq)

    index?_lt: THEOREM
      FORALL cseq, (i: indexes(cseq)), n: n < i IMPLIES index?(cseq)(n)  

    index?_finite: THEOREM FORALL fseq, n: index?(fseq)(n) IFF n < length(fseq)

    index?_finite_bound: THEOREM FORALL fseq: EXISTS n: NOT index?(fseq)(n)

    index?_infinite: THEOREM FORALL iseq, n: index?(iseq)(n)

    index?_infinite_full: THEOREM
      FORALL cseq: is_infinite(cseq) IFF full?(index?(cseq))

    index?_prop: THEOREM
      FORALL cseq, n:
        index?(cseq)(n) IFF (is_finite(cseq) IMPLIES n < length(cseq))

    index?_nonempty: THEOREM FORALL cseq, (n: indexes(cseq)): nonempty?(cseq)

    % The nth element of a sequence
    nth(cseq, (n: indexes(cseq))): RECURSIVE T =
      IF n = 0 THEN first(cseq) ELSE nth(rest(cseq), n - 1) ENDIF
       MEASURE n

    nth_extensionality: THEOREM
      FORALL cseq1, cseq2:
        index?(cseq1) = index?(cseq2) AND
         (FORALL (n: indexes(cseq1)): nth(cseq1, n) = nth(cseq2, n))
         IMPLIES cseq1 = cseq2

    nth_every: THEOREM
      FORALL cseq, p:
        every(p)(cseq) IFF (FORALL (i: indexes(cseq)): p(nth(cseq, i)))

    nth_some: THEOREM
      FORALL cseq, p:
        some(p)(cseq) IFF (EXISTS (i: indexes(cseq)): p(nth(cseq, i)))

    % The last element of a sequence
    last(nfseq): T = nth(nfseq, length(nfseq) - 1)

    last_rest: THEOREM
      FORALL nfseq: empty?(rest(nfseq)) OR last(rest(nfseq)) = last(nfseq)

   END csequence_nth

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

  % Subtype TCC generated (at line 30, column 53) for  n - 1
      % expected type  nat
  index?_TCC1: OBLIGATION
    FORALL (cseq: csequence[T], n: nat):
      NOT n = 0 AND nonempty?(cseq) IMPLIES n - 1 >= 0;

  % Termination TCC generated (at line 30, column 34) for
      % index?(rest(cseq))(n - 1)
  index?_TCC2: OBLIGATION
    FORALL (cseq: csequence[T], n: nat):
      NOT n = 0 AND nonempty?(cseq) IMPLIES n - 1 < n;

  % Subtype TCC generated (at line 59, column 24) for  cseq
      % expected type  (nonempty?[T])
  nth_TCC1: OBLIGATION
    FORALL (cseq: csequence[T], (n: indexes(cseq))):
      n = 0 IMPLIES nonempty?[T](cseq);

  % Subtype TCC generated (at line 59, column 44) for  cseq
      % expected type  (nonempty?[T])
  nth_TCC2: OBLIGATION
    FORALL (cseq: csequence[T], (n: indexes(cseq))):
      NOT n = 0 IMPLIES nonempty?[T](cseq);

  % Subtype TCC generated (at line 59, column 51) for  n - 1
      % expected type  indexes(rest(cseq))
  nth_TCC3: OBLIGATION
    FORALL (cseq: csequence[T], (n: indexes(cseq))):
      NOT n = 0 IMPLIES n - 1 >= 0 AND index?(rest[T](cseq))(n - 1);

  % Termination TCC generated (at line 59, column 35) for
      % nth(rest(cseq), n - 1)
  nth_TCC4: OBLIGATION
    FORALL (cseq: csequence[T], (n: indexes(cseq))):
      NOT n = 0 IMPLIES n - 1 < n;

  % Subtype TCC generated (at line 65, column 63) for  n
      % expected type  indexes(cseq2)
  nth_extensionality_TCC1: OBLIGATION
    FORALL (cseq1, cseq2):
      index?(cseq1) = index?(cseq2) IMPLIES
       (FORALL (n: indexes(cseq1)): index?(cseq2)(n));

  % Subtype TCC generated (at line 77, column 30) for  length(nfseq) - 1
      % expected type  indexes(nfseq)
  last_TCC1: OBLIGATION
    FORALL (nfseq: nonempty_finite_csequence[T]):
      length[T](nfseq) - 1 >= 0 AND index?(nfseq)(length[T](nfseq) - 1);

  % Subtype TCC generated (at line 80, column 46) for  rest(nfseq)
      % expected type  nonempty_finite_csequence[T]
  last_rest_TCC1: OBLIGATION
    FORALL (nfseq):
      NOT empty?(rest(nfseq)) IMPLIES
       is_finite[T](rest[T](nfseq)) AND nonempty?[T](rest[T](nfseq));


body:
  %-----------------------------------------------------------------------------
  % Zip two sequences of countable length together to form a single sequence of
  % pairs.  The length of the new sequence is the minimum length of the original
  % two sequences.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence_zip[T1, T2: TYPE]: THEORY
   BEGIN

    IMPORTING csequence_nth[T1], csequence_nth[T2], csequence_nth[[T1, T2]]
    IMPORTING csequence_length_comp[T1, T2]
    IMPORTING csequence_codt_coreduce[[T1, T2], [csequence[T1], csequence[T2]]]

    n: VAR nat
    t: VAR [[T1, T2]]
    p1: VAR pred[T1]
    p2: VAR pred[T2]
    cseq1: VAR csequence[T1]
    fseq1: VAR finite_csequence[T1]
    iseq1: VAR infinite_csequence[T1]
    nseq1: VAR nonempty_csequence[T1]
    nfseq1: VAR nonempty_finite_csequence[T1]
    cseq2: VAR csequence[T2]
    fseq2: VAR finite_csequence[T2]
    iseq2: VAR infinite_csequence[T2]
    nseq2: VAR nonempty_csequence[T2]
    nfseq2: VAR nonempty_finite_csequence[T2]
    state: VAR [csequence[T1], csequence[T2]]

    zip_struct(state):
          csequence_struct[[T1, T2], [csequence[T1], csequence[T2]]] =
        IF empty?(state`1) OR empty?(state`2) THEN inj_empty_cseq
        ELSE inj_add((first(state`1), first(state`2)),
                     (rest(state`1), rest(state`2)))
        ENDIF

    zip(cseq1, cseq2): csequence[[T1, T2]] =
        coreduce(zip_struct)(cseq1, cseq2)

    zip_finite1: JUDGEMENT zip(fseq1, cseq2) HAS_TYPE finite_csequence[[T1, T2]]
    zip_finite2: JUDGEMENT zip(cseq1, fseq2) HAS_TYPE finite_csequence[[T1, T2]]

    zip_infinite: JUDGEMENT
      zip(iseq1, iseq2) HAS_TYPE infinite_csequence[[T1, T2]]

    zip_nonempty: JUDGEMENT
       zip(nseq1, nseq2) HAS_TYPE nonempty_csequence[[T1, T2]]

    zip_empty: THEOREM
      FORALL cseq1, cseq2:
        empty?(zip(cseq1, cseq2)) IFF empty?(cseq1) OR empty?(cseq2)

    zip_first: THEOREM
      FORALL nseq1, nseq2:
        first(zip(nseq1, nseq2)) = (first(nseq1), first(nseq2))

    zip_rest: THEOREM
      FORALL nseq1, nseq2:
        rest(zip(nseq1, nseq2)) = zip(rest(nseq1), rest(nseq2))

    zip_add: THEOREM
      FORALL cseq1, cseq2, (a: T1), (b: T2):
        zip(add(a, cseq1), add(b, cseq2)) = add((a, b), zip(cseq1, cseq2))

    zip_length: THEOREM
      FORALL cseq1, cseq2:
        is_finite(zip(cseq1, cseq2)) IMPLIES
         length(zip(cseq1, cseq2)) =
          IF is_finite(cseq1)
            THEN IF is_finite(cseq2) THEN min(length(cseq1), length(cseq2))
                 ELSE length(cseq1)
                 ENDIF
          ELSE length(cseq2)
          ENDIF

    zip_index: THEOREM
      FORALL cseq1, cseq2, n:
        index?(zip(cseq1, cseq2))(n) IFF index?(cseq1)(n) AND index?(cseq2)(n)

    zip_nth: THEOREM
      FORALL cseq1, cseq2, (n: indexes(zip(cseq1, cseq2))):
        nth(zip(cseq1, cseq2), n) = (nth(cseq1, n), nth(cseq2, n))

    zip_last: THEOREM
      FORALL nseq1, nseq2:
        is_finite(zip(nseq1, nseq2)) IMPLIES
         last(zip(nseq1, nseq2)) =
          COND length_lt(nseq1, nseq2) ->
                 (last(nseq1), nth(nseq2, length(nseq1) - 1)),
               length_gt(nseq1, nseq2) ->
                 (nth(nseq1, length(nseq2) - 1), last(nseq2)),
               ELSE -> (last(nseq1), last(nseq2))
          ENDCOND

    zip_extensionality: THEOREM
      FORALL (cseq1, cseq3: csequence[T1]), (cseq2, cseq4: csequence[T2]):
        length_eq(cseq1, cseq2) AND
         length_eq(cseq3, cseq4) AND zip(cseq1, cseq2) = zip(cseq3, cseq4)
         IMPLIES cseq1 = cseq3 AND cseq2 = cseq4

    zip_some: THEOREM
      FORALL cseq1, cseq2, p1, p2:
        some(LAMBDA t: p1(t`1) OR p2(t`2))(zip(cseq1, cseq2)) IFF
         COND length_lt(cseq1, cseq2) ->
                some(p1)(cseq1) OR
                 (EXISTS (i: indexes(cseq2)):
                    i < length(cseq1) AND p2(nth(cseq2, i))),
              length_gt(cseq1, cseq2) ->
                (EXISTS (i: indexes(cseq1)):
                   i < length(cseq2) AND p1(nth(cseq1, i)))
                 OR some(p2)(cseq2),
              ELSE -> some(p1)(cseq1) OR some(p2)(cseq2)
         ENDCOND

    zip_every: THEOREM
      FORALL cseq1, cseq2, p1, p2:
        every(LAMBDA t: p1(t`1) AND p2(t`2))(zip(cseq1, cseq2)) IFF
         COND length_lt(cseq1, cseq2) ->
                every(p1)(cseq1) AND
                 (FORALL (i: indexes(cseq2)):
                    i < length(cseq1) IMPLIES p2(nth(cseq2, i))),
              length_gt(cseq1, cseq2) ->
                (FORALL (i: indexes(cseq1)):
                   i < length(cseq2) IMPLIES p1(nth(cseq1, i)))
                 AND every(p2)(cseq2),
              ELSE -> every(p1)(cseq1) AND every(p2)(cseq2)
         ENDCOND

   END csequence_zip

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

  % Subtype TCC generated (at line 42, column 26) for  state`1
      % expected type  (nonempty?[T1])
  zip_struct_TCC1: OBLIGATION
    FORALL (state: [csequence[T1], csequence[T2]]):
      NOT empty?(state`1) AND NOT empty?(state`2) IMPLIES
       nonempty?[T1](state`1);

  % Subtype TCC generated (at line 42, column 42) for  state`2
      % expected type  (nonempty?[T2])
  zip_struct_TCC2: OBLIGATION
    FORALL (state: [csequence[T1], csequence[T2]]):
      NOT empty?(state`1) AND NOT empty?(state`2) IMPLIES
       nonempty?[T2](state`2);

  % Judgement subtype TCC generated (at line 49, column 25) for
      % zip(fseq1, cseq2)
      % expected type  finite_csequence[[T1, T2]]
  zip_finite1: OBLIGATION
    FORALL (cseq2, fseq1): is_finite[[T1, T2]](zip(fseq1, cseq2));

  % Judgement subtype TCC generated (at line 50, column 25) for
      % zip(cseq1, fseq2)
      % expected type  finite_csequence[[T1, T2]]
  zip_finite2: OBLIGATION
    FORALL (cseq1, fseq2): is_finite[[T1, T2]](zip(cseq1, fseq2));

  % Judgement subtype TCC generated (at line 53, column 4) for
      % zip(iseq1, iseq2)
      % expected type  infinite_csequence[[T1, T2]]
  zip_infinite: OBLIGATION
    FORALL (iseq1, iseq2): NOT is_finite[[T1, T2]](zip(iseq1, iseq2));

  % Judgement subtype TCC generated (at line 56, column 5) for
      % zip(nseq1, nseq2)
      % expected type  nonempty_csequence[[T1, T2]]
  zip_nonempty: OBLIGATION
    FORALL (nseq1, nseq2): nonempty?[[T1, T2]](zip(nseq1, nseq2));

  % Subtype TCC generated (at line 82, column 20) for  cseq2
      % expected type  fseq: finite_csequence[T2]
  zip_length_TCC1: OBLIGATION
    FORALL (cseq1, cseq2):
      NOT is_finite(cseq1) AND is_finite(zip(cseq1, cseq2)) IMPLIES
       is_finite[T2](cseq2);

  % Subtype TCC generated (at line 91, column 46) for  n
      % expected type  indexes[T1](cseq1)
  zip_nth_TCC1: OBLIGATION
    FORALL (cseq1, cseq2, n: indexes[[T1, T2]](zip(cseq1, cseq2))):
      index?[T1](cseq1)(n);

  % Subtype TCC generated (at line 91, column 61) for  n
      % expected type  indexes[T2](cseq2)
  zip_nth_TCC2: OBLIGATION
    FORALL (cseq1, cseq2, n: indexes[[T1, T2]](zip(cseq1, cseq2))):
      index?[T2](cseq2)(n);

  % Subtype TCC generated (at line 98, column 21) for  nseq1
      % expected type  nonempty_finite_csequence[T1]
  zip_last_TCC1: OBLIGATION
    FORALL (nseq1, nseq2):
      length_lt(nseq1, nseq2) AND is_finite(zip(nseq1, nseq2)) IMPLIES
       is_finite[T1](nseq1) AND nonempty?[T1](nseq1);

  % Subtype TCC generated (at line 98, column 47) for  nseq1
      % expected type  fseq: finite_csequence[T1]
  zip_last_TCC2: OBLIGATION
    FORALL (nseq1, nseq2):
      length_lt(nseq1, nseq2) AND is_finite(zip(nseq1, nseq2)) IMPLIES
       is_finite[T1](nseq1);

  % Subtype TCC generated (at line 98, column 40) for  length(nseq1) - 1
      % expected type  indexes[T2](nseq2)
  zip_last_TCC3: OBLIGATION
    FORALL (nseq1, nseq2):
      length_lt(nseq1, nseq2) AND is_finite(zip(nseq1, nseq2)) IMPLIES
       length[T1](nseq1) - 1 >= 0 AND
        index?[T2](nseq2)(length[T1](nseq1) - 1);

  % Subtype TCC generated (at line 100, column 34) for  nseq2
      % expected type  fseq: finite_csequence[T2]
  zip_last_TCC4: OBLIGATION
    FORALL (nseq1, nseq2):
      length_gt(nseq1, nseq2) AND
       NOT length_lt(nseq1, nseq2) AND is_finite(zip(nseq1, nseq2))
       IMPLIES is_finite[T2](nseq2);

  % Subtype TCC generated (at line 100, column 27) for  length(nseq2) - 1
      % expected type  indexes[T1](nseq1)
  zip_last_TCC5: OBLIGATION
    FORALL (nseq1, nseq2):
      length_gt(nseq1, nseq2) AND
       NOT length_lt(nseq1, nseq2) AND is_finite(zip(nseq1, nseq2))
       IMPLIES
       length[T2](nseq2) - 1 >= 0 AND
        index?[T1](nseq1)(length[T2](nseq2) - 1);

  % Subtype TCC generated (at line 100, column 52) for  nseq2
      % expected type  nonempty_finite_csequence[T2]
  zip_last_TCC6: OBLIGATION
    FORALL (nseq1, nseq2):
      length_gt(nseq1, nseq2) AND
       NOT length_lt(nseq1, nseq2) AND is_finite(zip(nseq1, nseq2))
       IMPLIES is_finite[T2](nseq2) AND nonempty?[T2](nseq2);

  % Subtype TCC generated (at line 101, column 27) for  nseq1
      % expected type  nonempty_finite_csequence[T1]
  zip_last_TCC7: OBLIGATION
    FORALL (nseq1, nseq2):
      NOT length_gt(nseq1, nseq2) AND
       NOT length_lt(nseq1, nseq2) AND is_finite(zip(nseq1, nseq2))
       IMPLIES is_finite[T1](nseq1) AND nonempty?[T1](nseq1);

  % Subtype TCC generated (at line 101, column 40) for  nseq2
      % expected type  nonempty_finite_csequence[T2]
  zip_last_TCC8: OBLIGATION
    FORALL (nseq1, nseq2):
      NOT length_gt(nseq1, nseq2) AND
       NOT length_lt(nseq1, nseq2) AND is_finite(zip(nseq1, nseq2))
       IMPLIES is_finite[T2](nseq2) AND nonempty?[T2](nseq2);

  % Disjointness TCC generated (at line 97, column 8) for
      % COND length_lt(nseq1, nseq2) ->
      %        (last(nseq1), nth(nseq2, length(nseq1) - 1)),
      %      length_gt(nseq1, nseq2) ->
      %        (nth(nseq1, length(nseq2) - 1), last(nseq2)),
      %      ELSE -> (last(nseq1), last(nseq2))
      % ENDCOND
  zip_last_TCC9: OBLIGATION
    FORALL (nseq1, nseq2):
      is_finite(zip(nseq1, nseq2)) IMPLIES
       NOT (length_lt[T1, T2](nseq1, nseq2) AND
             length_gt[T1, T2](nseq1, nseq2));

  % Subtype TCC generated (at line 116, column 29) for  cseq1
      % expected type  fseq: finite_csequence[T1]
  zip_some_TCC1: OBLIGATION
    FORALL (cseq1, cseq2, p1):
      NOT some(p1)(cseq1) AND length_lt(cseq1, cseq2) IMPLIES
       (FORALL (i: indexes[T2](cseq2)): is_finite[T1](cseq1));

  % Subtype TCC generated (at line 119, column 28) for  cseq2
      % expected type  fseq: finite_csequence[T2]
  zip_some_TCC2: OBLIGATION
    FORALL (cseq1, cseq2):
      length_gt(cseq1, cseq2) AND NOT length_lt(cseq1, cseq2) IMPLIES
       (FORALL (i: indexes[T1](cseq1)): is_finite[T2](cseq2));

  % Disjointness TCC generated (at line 113, column 7) for
      % COND length_lt(cseq1, cseq2) ->
      %        some(p1)(cseq1) OR
      %         (EXISTS (i: indexes(cseq2)):
      %            i < length(cseq1) AND p2(nth(cseq2, i))),
      %      length_gt(cseq1, cseq2) ->
      %        (EXISTS (i: indexes(cseq1)):
      %           i < length(cseq2) AND p1(nth(cseq1, i)))
      %         OR some(p2)(cseq2),
      %      ELSE -> some(p1)(cseq1) OR some(p2)(cseq2)
      % ENDCOND
  zip_some_TCC3: OBLIGATION
    FORALL (cseq1, cseq2):
      NOT (length_lt[T1, T2](cseq1, cseq2) AND
            length_gt[T1, T2](cseq1, cseq2));

  % Subtype TCC generated (at line 130, column 29) for  cseq1
      % expected type  fseq: finite_csequence[T1]
  zip_every_TCC1: OBLIGATION
    FORALL (cseq1, cseq2, p1):
      every(p1)(cseq1) AND length_lt(cseq1, cseq2) IMPLIES
       (FORALL (i: indexes[T2](cseq2)): is_finite[T1](cseq1));


body:
  %-----------------------------------------------------------------------------
  % Unzip a countable sequence of pairs into a pair of sequences.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence_unzip[T1, T2: TYPE]: THEORY
   BEGIN

    IMPORTING csequence_nth[T1], csequence_nth[T2], csequence_nth[[T1, T2]]
    IMPORTING csequence_codt_coreduce[T1, csequence[[T1, T2]]]
    IMPORTING csequence_codt_coreduce[T2, csequence[[T1, T2]]]
    IMPORTING csequence_codt_map[[T1, T2], T1]
    IMPORTING csequence_codt_map[[T1, T2], T2]

    n: VAR nat
    t12: VAR [T1, T2]
    p1: VAR pred[T1]
    p2: VAR pred[T2]
    cseq, cseq1, cseq2: VAR csequence[[T1, T2]]
    fseq: VAR finite_csequence[[T1, T2]]
    iseq: VAR infinite_csequence[[T1, T2]]
    nseq: VAR nonempty_csequence[[T1, T2]]
    nfseq: VAR nonempty_finite_csequence[[T1, T2]]

    unzip_left_struct(cseq): csequence_struct[T1, csequence[[T1, T2]]] =
        IF empty?(cseq) THEN inj_empty_cseq
        ELSE inj_add(first(cseq)`1, rest(cseq))
        ENDIF

    unzip_right_struct(cseq): csequence_struct[T2, csequence[[T1, T2]]] =
        IF empty?(cseq) THEN inj_empty_cseq
        ELSE inj_add(first(cseq)`2, rest(cseq))
        ENDIF

    unzip(cseq): [csequence[T1], csequence[T2]] =
        (coreduce(unzip_left_struct)(cseq),
         coreduce(unzip_right_struct)(cseq))

    unzip_finite: JUDGEMENT
      unzip(fseq) HAS_TYPE [finite_csequence[T1], finite_csequence[T2]]

    unzip_infinite: JUDGEMENT
      unzip(iseq) HAS_TYPE [infinite_csequence[T1], infinite_csequence[T2]]

    unzip_nonempty: JUDGEMENT
      unzip(nseq) HAS_TYPE [nonempty_csequence[T1], nonempty_csequence[T2]]

    unzip_empty_left: THEOREM
      FORALL cseq: empty?(unzip(cseq)`1) IFF empty?(cseq)

    unzip_empty_right: THEOREM
      FORALL cseq: empty?(unzip(cseq)`2) IFF empty?(cseq)

    unzip_first_left: THEOREM
      FORALL nseq: first(unzip(nseq)`1) = first(nseq)`1

    unzip_first_right: THEOREM
      FORALL nseq: first(unzip(nseq)`2) = first(nseq)`2

    unzip_rest_left: THEOREM
      FORALL nseq: rest(unzip(nseq)`1) = unzip(rest(nseq))`1

    unzip_rest_right: THEOREM
      FORALL nseq: rest(unzip(nseq)`2) = unzip(rest(nseq))`2

    unzip_length_left: THEOREM
      FORALL fseq: length(unzip(fseq)`1) = length(fseq)

    unzip_length_right: THEOREM
      FORALL fseq: length(unzip(fseq)`2) = length(fseq)

    unzip_index_left: THEOREM
      FORALL cseq, n: index?(unzip(cseq)`1)(n) IFF index?(cseq)(n)

    unzip_index_right: THEOREM
      FORALL cseq, n: index?(unzip(cseq)`2)(n) IFF index?(cseq)(n)

    unzip_nth_left: THEOREM
      FORALL cseq, (n: indexes(cseq)): nth(unzip(cseq)`1, n) = nth(cseq, n)`1

    unzip_nth_right: THEOREM
      FORALL cseq, (n: indexes(cseq)): nth(unzip(cseq)`2, n) = nth(cseq, n)`2

    unzip_map: THEOREM
      FORALL cseq:
        unzip(cseq) =
         (map[[T1, T2], T1](PROJ_1, cseq), map[[T1, T2], T2](PROJ_2, cseq))

    unzip_extensionality: THEOREM
      FORALL cseq1, cseq2: unzip(cseq1) = unzip(cseq2) IMPLIES cseq1 = cseq2

    unzip_add: THEOREM
      FORALL cseq, t12:
        unzip(add(t12, cseq)) =
         (add(t12`1, unzip(cseq)`1), add(t12`2, unzip(cseq)`2))

    unzip_last_left: THEOREM
      FORALL nfseq: last(unzip(nfseq)`1) = last(nfseq)`1

    unzip_last_right: THEOREM
      FORALL nfseq: last(unzip(nfseq)`2) = last(nfseq)`2

    unzip_some: THEOREM
      FORALL cseq, p1, p2:
        some(p1)(unzip(cseq)`1) OR some(p2)(unzip(cseq)`2) IFF
         some(LAMBDA t12: p1(t12`1) OR p2(t12`2))(cseq)

    unzip_every: THEOREM
      FORALL cseq, p1, p2:
        every(p1)(unzip(cseq)`1) AND every(p2)(unzip(cseq)`2) IFF
         every(LAMBDA t12: p1(t12`1) AND p2(t12`2))(cseq)

   END csequence_unzip

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

  % Subtype TCC generated (at line 35, column 25) for  cseq
      % expected type  (nonempty?[[T1, T2]])
  unzip_left_struct_TCC1: OBLIGATION
    FORALL (cseq: csequence[[T1, T2]]):
      NOT empty?(cseq) IMPLIES nonempty?[[T1, T2]](cseq);

  % Judgement subtype TCC generated (at line 48, column 4) for  unzip(fseq)
      % expected type  [finite_csequence[T1], finite_csequence[T2]]
  unzip_finite: OBLIGATION
    FORALL (fseq):
      is_finite[T2](unzip(fseq)`2) AND is_finite[T1](unzip(fseq)`1);

  % Judgement subtype TCC generated (at line 51, column 4) for  unzip(iseq)
      % expected type  [infinite_csequence[T1], infinite_csequence[T2]]
  unzip_infinite: OBLIGATION
    FORALL (iseq):
      NOT is_finite[T2](unzip(iseq)`2) AND NOT is_finite[T1](unzip(iseq)`1);

  % Judgement subtype TCC generated (at line 54, column 4) for  unzip(nseq)
      % expected type  [nonempty_csequence[T1], nonempty_csequence[T2]]
  unzip_nonempty: OBLIGATION
    FORALL (nseq):
      nonempty?[T2](unzip(nseq)`2) AND nonempty?[T1](unzip(nseq)`1);

  % Subtype TCC generated (at line 87, column 56) for  n
      % expected type  indexes[T1](unzip(cseq)`1)
  unzip_nth_left_TCC1: OBLIGATION
    FORALL (cseq, n: indexes[[T1, T2]](cseq)): index?[T1](unzip(cseq)`1)(n);

  % Subtype TCC generated (at line 90, column 56) for  n
      % expected type  indexes[T2](unzip(cseq)`2)
  unzip_nth_right_TCC1: OBLIGATION
    FORALL (cseq, n: indexes[[T1, T2]](cseq)): index?[T2](unzip(cseq)`2)(n);

  % Subtype TCC generated (at line 106, column 23) for  unzip(nfseq)`1
      % expected type  nonempty_finite_csequence[T1]
  unzip_last_left_TCC1: OBLIGATION
    FORALL (nfseq): nonempty?[T1](unzip(nfseq)`1);

  % Subtype TCC generated (at line 109, column 23) for  unzip(nfseq)`2
      % expected type  nonempty_finite_csequence[T2]
  unzip_last_right_TCC1: OBLIGATION
    FORALL (nfseq): nonempty?[T2](unzip(nfseq)`2);


body:
  %-----------------------------------------------------------------------------
  % The combination of the zip and unzip operators on sequences of countable
  % length.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence_zip_unzip[T1, T2: TYPE]: THEORY
   BEGIN

    IMPORTING csequence_unzip[T1, T2], csequence_zip[T1, T2]

    cseq: VAR csequence[[T1, T2]]
    cseq1: VAR csequence[T1]
    cseq2: VAR csequence[T2]

    zip_unzip_eta: THEOREM FORALL cseq: zip(unzip(cseq)) = cseq

    unzip_zip_eta: THEOREM
      FORALL cseq1, cseq2:
        length_eq(cseq1, cseq2) IMPLIES
         unzip(zip(cseq1, cseq2)) = (cseq1, cseq2)

   END csequence_zip_unzip


body:
  %-----------------------------------------------------------------------------
  % Concatenation (or composition) of sequences of countable length.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence_concatenate[T: TYPE]: THEORY
   BEGIN

    IMPORTING csequence_nth[T]
    IMPORTING csequence_codt_coreduce[T, [csequence, csequence]]

    n: VAR nat
    t: VAR T
    p: VAR pred[T]
    cseq, cseq1, cseq2: VAR csequence
    fseq, fseq1, fseq2: VAR finite_csequence
    iseq: VAR infinite_csequence
    eseq: VAR empty_csequence
    nseq, nseq1, nseq2: VAR nonempty_csequence

    % Note that this definition makes the concatenation of an infinite
    % sequence with another sequence be just the first sequence.

    concatenate_struct(cseq1, cseq2): csequence_struct =
        IF empty?(cseq1)
          THEN IF empty?(cseq2) THEN inj_empty_cseq
               ELSE inj_add(first(cseq2), (cseq1, rest(cseq2)))
               ENDIF
        ELSE inj_add(first(cseq1), (rest(cseq1), cseq2))
        ENDIF;

    o(cseq1, cseq2): csequence = coreduce(concatenate_struct)(cseq1, cseq2)

    o_finite: JUDGEMENT o(fseq1, fseq2) HAS_TYPE finite_csequence

    % This lemma lets us avoid nearly identical proofs for the next 2 judgements
    o_finiteness: LEMMA
      FORALL cseq1, cseq2:
        is_finite(cseq1 o cseq2) IMPLIES is_finite(cseq1) AND is_finite(cseq2)

    o_infinite1: JUDGEMENT o(iseq, cseq) HAS_TYPE infinite_csequence
    o_infinite2: JUDGEMENT o(cseq, iseq) HAS_TYPE infinite_csequence

    o_empty: THEOREM
      FORALL cseq1, cseq2:
        empty?(cseq1 o cseq2) IFF empty?(cseq1) AND empty?(cseq2)

    o_nonempty: COROLLARY
      FORALL cseq1, cseq2:
        nonempty?(cseq1 o cseq2) IFF nonempty?(cseq1) OR nonempty?(cseq2)

    o_nonempty_left:  JUDGEMENT o(nseq, cseq) HAS_TYPE nonempty_csequence
    o_nonempty_right: JUDGEMENT o(cseq, nseq) HAS_TYPE nonempty_csequence

    o_empty_left:  THEOREM FORALL eseq, cseq: eseq o cseq = cseq
    o_empty_right: THEOREM FORALL cseq, eseq: cseq o eseq = cseq

    o_first: THEOREM
      FORALL cseq1, cseq2:
        nonempty?(cseq1 o cseq2) IMPLIES
         first(cseq1 o cseq2) =
          IF empty?(cseq1) THEN first(cseq2) ELSE first(cseq1) ENDIF

    o_rest: THEOREM
      FORALL cseq1, cseq2:
        nonempty?(cseq1 o cseq2) IMPLIES
         rest(cseq1 o cseq2) =
          IF empty?(cseq1) THEN rest(cseq2) ELSE rest(cseq1) o cseq2 ENDIF

    o_first_rest: THEOREM
      FORALL nseq1, nseq2, cseq:
        first(nseq1) = first(nseq2) AND rest(nseq1) o cseq = rest(nseq2)
         IMPLIES nseq1 o cseq = nseq2

    o_length: THEOREM
      FORALL fseq1, fseq2:
        length(fseq1 o fseq2) = length(fseq1) + length(fseq2)

    o_index: THEOREM
      FORALL cseq1, cseq2, n:
        index?(cseq1 o cseq2)(n) IFF
         (is_finite(cseq1) AND is_finite(cseq2) IMPLIES
           n < length(cseq1) + length(cseq2))

    o_nth: THEOREM
      FORALL cseq1, cseq2, (n: indexes(cseq1 o cseq2)):
        nth(cseq1 o cseq2, n) =
         IF is_finite(cseq1) AND n >= length(cseq1)
           THEN nth(cseq2, n - length(cseq1))
         ELSE nth(cseq1, n)
         ENDIF

    o_add: THEOREM
      FORALL cseq1, cseq2, t: add(t, cseq1) o cseq2 = add(t, cseq1 o cseq2)

    o_last: THEOREM
      FORALL cseq1, cseq2:
        is_finite(cseq1 o cseq2) AND nonempty?(cseq1 o cseq2) IMPLIES
         last(cseq1 o cseq2) =
          IF empty?(cseq2) THEN last(cseq1) ELSE last(cseq2) ENDIF

    o_infinite: THEOREM FORALL iseq, cseq: iseq o cseq = iseq

    o_assoc: THEOREM
      FORALL cseq, cseq1, cseq2:
        cseq o (cseq1 o cseq2) = (cseq o cseq1) o cseq2

    o_extensionality_left: THEOREM
      FORALL fseq, cseq1, cseq2:
        fseq o cseq1 = fseq o cseq2 IMPLIES cseq1 = cseq2

    o_extensionality_right: THEOREM
      FORALL fseq, cseq1, cseq2:
        cseq1 o fseq = cseq2 o fseq IMPLIES cseq1 = cseq2

    o_some: THEOREM
      FORALL cseq1, cseq2, p:
        some(p)(cseq1 o cseq2) IFF
         some(p)(cseq1) OR (is_finite(cseq1) AND some(p)(cseq2))

    o_every: THEOREM
      FORALL cseq1, cseq2, p:
        every(p)(cseq1 o cseq2) IFF
         every(p)(cseq1) AND (is_infinite(cseq1) OR every(p)(cseq2))

   END csequence_concatenate

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

  % Subtype TCC generated (at line 35, column 32) for  cseq2
      % expected type  (nonempty?[T])
  concatenate_struct_TCC1: OBLIGATION
    FORALL (cseq1: csequence[T], cseq2: csequence[T]):
      NOT empty?(cseq2) AND empty?(cseq1) IMPLIES nonempty?[T](cseq2);

  % Subtype TCC generated (at line 37, column 25) for  cseq1
      % expected type  (nonempty?[T])
  concatenate_struct_TCC2: OBLIGATION
    FORALL (cseq1: csequence[T]):
      NOT empty?(cseq1) IMPLIES nonempty?[T](cseq1);

  % Judgement subtype TCC generated (at line 42, column 22) for  fseq1 o fseq2
      % expected type  finite_csequence[T]
  o_finite: OBLIGATION FORALL (fseq1, fseq2): is_finite[T](fseq1 o fseq2);

  % Judgement subtype TCC generated (at line 49, column 25) for  iseq o cseq
      % expected type  infinite_csequence[T]
  o_infinite1: OBLIGATION FORALL (cseq, iseq): NOT is_finite[T](iseq o cseq);

  % Judgement subtype TCC generated (at line 50, column 25) for  cseq o iseq
      % expected type  infinite_csequence[T]
  o_infinite2: OBLIGATION FORALL (cseq, iseq): NOT is_finite[T](cseq o iseq);

  % Judgement subtype TCC generated (at line 60, column 30) for  nseq o cseq
      % expected type  nonempty_csequence[T]
  o_nonempty_left: OBLIGATION FORALL (cseq, nseq): nonempty?[T](nseq o cseq);

  % Judgement subtype TCC generated (at line 61, column 30) for  cseq o nseq
      % expected type  nonempty_csequence[T]
  o_nonempty_right: OBLIGATION FORALL (cseq, nseq): nonempty?[T](cseq o nseq);

  % Subtype TCC generated (at line 70, column 36) for  cseq2
      % expected type  (nonempty?[T])
  o_first_TCC1: OBLIGATION
    FORALL (cseq1, cseq2):
      empty?(cseq1) AND nonempty?(cseq1 o cseq2) IMPLIES nonempty?[T](cseq2);

  % Subtype TCC generated (at line 97, column 25) for  n - length(cseq1)
      % expected type  indexes[T](cseq2)
  o_nth_TCC1: OBLIGATION
    FORALL (cseq1, cseq2, n: indexes[T](cseq1 o cseq2)):
      is_finite(cseq1) AND n >= length(cseq1) IMPLIES
       n - length[T](cseq1) >= 0 AND index?[T](cseq2)(n - length[T](cseq1));

  % Subtype TCC generated (at line 98, column 23) for  n
      % expected type  indexes[T](cseq1)
  o_nth_TCC2: OBLIGATION
    FORALL (cseq1, cseq2, n: indexes[T](cseq1 o cseq2)):
      NOT (is_finite(cseq1) AND n >= length(cseq1)) IMPLIES
       index?[T](cseq1)(n);

  % Subtype TCC generated (at line 108, column 35) for  cseq1
      % expected type  nonempty_finite_csequence[T]
  o_last_TCC1: OBLIGATION
    FORALL (cseq1, cseq2):
      empty?(cseq2) AND is_finite(cseq1 o cseq2) AND nonempty?(cseq1 o cseq2)
       IMPLIES is_finite[T](cseq1) AND nonempty?[T](cseq1);

  % Subtype TCC generated (at line 108, column 52) for  cseq2
      % expected type  nonempty_finite_csequence[T]
  o_last_TCC2: OBLIGATION
    FORALL (cseq1, cseq2):
      NOT empty?(cseq2) AND
       is_finite(cseq1 o cseq2) AND nonempty?(cseq1 o cseq2)
       IMPLIES is_finite[T](cseq2) AND nonempty?[T](cseq2);


body:
  %-----------------------------------------------------------------------------
  % Suffixes of sequences of countable length.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence_suffix[T: TYPE]: THEORY
   BEGIN

    IMPORTING csequence_concatenate[T], orders[csequence]

    p: VAR pred[T]
    n, m: VAR nat
    cseq, cseq1, cseq2: VAR csequence
    fseq, fseq1, fseq2: VAR finite_csequence
    iseq: VAR infinite_csequence
    nseq: VAR nonempty_csequence
    eseq: VAR empty_csequence

    suffix?(cseq1, cseq2): INDUCTIVE bool =
        cseq1 = cseq2 OR (nonempty?(cseq2) AND suffix?(cseq1, rest(cseq2)))

    suffix?(cseq2)(cseq1): MACRO bool = suffix?(cseq1, cseq2)

    suffix?_empty: THEOREM
      FORALL eseq, cseq: suffix?(eseq, cseq) IFF is_finite(cseq)

    suffix?_rest_left: THEOREM
      FORALL nseq, cseq: suffix?(nseq, cseq) IMPLIES suffix?(rest(nseq), cseq)

    suffix?_rest_right: THEOREM
      FORALL cseq, nseq: suffix?(cseq, rest(nseq)) IMPLIES suffix?(cseq, nseq)

    suffix?_finite_left: THEOREM
      FORALL fseq, cseq: suffix?(fseq, cseq) IMPLIES is_finite(cseq)

    suffix?_finite_right: THEOREM
      FORALL cseq, fseq: suffix?(cseq, fseq) IMPLIES is_finite(cseq)

    suffix?_infinite_left: THEOREM
      FORALL iseq, cseq: suffix?(iseq, cseq) IMPLIES is_infinite(cseq)

    suffix?_infinite_right: THEOREM
      FORALL cseq, iseq: suffix?(cseq, iseq) IMPLIES is_infinite(cseq)

    suffix?_length: THEOREM
      FORALL fseq1, fseq2:
        suffix?(fseq1, fseq2) IMPLIES length(fseq1) <= length(fseq2)

    suffix?_length_eq: THEOREM
      FORALL fseq1, fseq2:
        suffix?(fseq1, fseq2) AND length(fseq1) = length(fseq2) IMPLIES
         fseq1 = fseq2

    suffix?_index: THEOREM
      FORALL cseq1, cseq2, n:
        suffix?(cseq1, cseq2) AND index?(cseq1)(n) IMPLIES index?(cseq2)(n)

    suffix?_concatenate: THEOREM FORALL fseq, cseq: suffix?(cseq, fseq o cseq)

    suffix?_def: THEOREM
      FORALL cseq1, cseq2:
        suffix?(cseq1, cseq2) IFF (EXISTS fseq: fseq o cseq1 = cseq2)

    %  Note that suffix? is not a partial order, because it is not
    %  antisymmetric.  These two sequences are suffixes of each other,
    %  but are not equal:
    %
    %    1, 2, 1, 2, 1, 2, ...
    %    2, 1, 2, 1, 2, 1, ...

    suffix?_is_preorder: JUDGEMENT suffix? HAS_TYPE (preorder?[csequence])

    %  However, suffix? is a partial order when restricted to finite
    %  sequences.

    suffix?_finite_antisymmetric: THEOREM
      partial_order?[finite_csequence]
          (restrict
               [[csequence, csequence], [finite_csequence, finite_csequence],
                bool]
               (suffix?))

    % A dichotomous?-like property for suffixes of a given sequence.
    suffix?_order: THEOREM
      FORALL cseq, cseq1, cseq2:
        suffix?(cseq1, cseq) AND suffix?(cseq2, cseq) IMPLIES
         suffix?(cseq1, cseq2) OR suffix?(cseq2, cseq1)


    % The suffix of cseq after skipping over n elements
    suffix(cseq, n): RECURSIVE (suffix?(cseq)) =
      IF n = 0 OR empty?(cseq) THEN cseq ELSE suffix(rest(cseq), n - 1) ENDIF
       MEASURE n

    suffix_is_finite: JUDGEMENT suffix(fseq, n) HAS_TYPE finite_csequence

    suffix_is_infinite: JUDGEMENT suffix(iseq, n) HAS_TYPE infinite_csequence

    suffix_0: THEOREM FORALL cseq: suffix(cseq, 0) = cseq

    suffix_1: THEOREM FORALL nseq: suffix(nseq, 1) = rest(nseq)

    suffix_rest1: THEOREM
      FORALL nseq, n: suffix(rest(nseq), n) = suffix(nseq, n + 1)

    suffix_rest2: THEOREM
      FORALL cseq, (n: indexes(cseq)):
        rest(suffix(cseq, n)) = suffix(cseq, n + 1)

    suffix_suffix: THEOREM
      FORALL cseq, n, m: suffix(suffix(cseq, n), m) = suffix(cseq, n + m)

    suffix_length: THEOREM
      FORALL fseq, n: length(suffix(fseq, n)) = max(0, length(fseq) - n)

    suffix_first: THEOREM
      FORALL nseq, (n: indexes(nseq)): first(suffix(nseq, n)) = nth(nseq, n)

    suffix_index: THEOREM
      FORALL cseq, n, m: index?(suffix(cseq, n))(m) IFF index?(cseq)(n + m)

    suffix_nth: THEOREM
      FORALL cseq, n, (m: indexes(suffix(cseq, n))):
        nth(suffix(cseq, n), m) = nth(cseq, n + m)

    suffix_empty: THEOREM
      FORALL cseq, n: empty?(suffix(cseq, n)) IFF NOT index?(cseq)(n)

    suffix_nonempty: THEOREM
      FORALL cseq, n: nonempty?(suffix(cseq, n)) IFF index?(cseq)(n)

    suffix_concatenate: THEOREM
      FORALL cseq1, cseq2, n:
        suffix(cseq1 o cseq2, n) =
         IF index?(cseq1)(n) THEN suffix(cseq1, n) o cseq2
         ELSE suffix(cseq2, n - length(cseq1))
         ENDIF

    suffix?_suffix: THEOREM
      FORALL cseq1, cseq2:
        suffix?(cseq1, cseq2) IFF (EXISTS n: cseq1 = suffix(cseq2, n))

    suffix_some: THEOREM
      FORALL cseq, n, p:
        some(p)(suffix(cseq, n)) IFF
         (EXISTS (i: indexes(cseq)): i >= n AND p(nth(cseq, i)))

    suffix_every: THEOREM
      FORALL cseq, n, p:
        every(p)(suffix(cseq, n)) IFF
         (FORALL (i: indexes(cseq)): i >= n IMPLIES p(nth(cseq, i)))

   END csequence_suffix

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

  suffix?_weak_induction: AXIOM
    FORALL (cseq1, P: [csequence[T] -> boolean]):
      (FORALL (cseq2):
         cseq1 = cseq2 OR (nonempty?(cseq2) AND P(rest(cseq2))) IMPLIES
          P(cseq2))
       IMPLIES (FORALL (cseq2): suffix?(cseq1, cseq2) IMPLIES P(cseq2));

  suffix?_induction: AXIOM
    FORALL (cseq1, P: [csequence[T] -> boolean]):
      (FORALL (cseq2):
         cseq1 = cseq2 OR
          (nonempty?(cseq2) AND
            suffix?(cseq1, rest(cseq2)) AND P(rest(cseq2)))
          IMPLIES P(cseq2))
       IMPLIES (FORALL (cseq2): suffix?(cseq1, cseq2) IMPLIES P(cseq2));

  % Judgement subtype TCC generated (at line 79, column 33) for  suffix?
      % expected type  (preorder?[csequence])
  suffix?_is_preorder: OBLIGATION preorder?[csequence[T]](suffix?);

  % Subtype TCC generated (at line 100, column 34) for  cseq
      % expected type  (LAMBDA (cseq1): suffix?(cseq1, cseq))
  suffix_TCC1: OBLIGATION
    FORALL (cseq: csequence[T], n: nat):
      n = 0 OR empty?(cseq) IMPLIES suffix?(cseq, cseq);

  % Subtype TCC generated (at line 100, column 56) for  cseq
      % expected type  (nonempty?[T])
  suffix_TCC2: OBLIGATION
    FORALL (cseq: csequence[T], n: nat):
      NOT n = 0 AND NOT empty?(cseq) IMPLIES nonempty?[T](cseq);

  % Subtype TCC generated (at line 100, column 63) for  n - 1
      % expected type  nat
  suffix_TCC3: OBLIGATION
    FORALL (cseq: csequence[T], n: nat):
      NOT n = 0 AND NOT empty?(cseq) IMPLIES n - 1 >= 0;

  % Termination TCC generated (at line 100, column 44) for
      % suffix(rest(cseq), n - 1)
  suffix_TCC4: OBLIGATION
    FORALL (cseq: csequence[T], n: nat):
      NOT n = 0 AND NOT empty?(cseq) IMPLIES n - 1 < n;

  % Subtype TCC generated (at line 100, column 44) for
      % suffix(rest(cseq), n - 1)
      % expected type  (LAMBDA (cseq1): suffix?(cseq1, cseq))
  suffix_TCC5: OBLIGATION
    FORALL (cseq: csequence[T], n: nat,
            v:
              [d1: {z: [csequence[T], nat] | z`2 < n} ->
                 (LAMBDA (cseq1): suffix?(cseq1, d1`1))]):
      NOT n = 0 AND NOT empty?(cseq) IMPLIES
       suffix?(v(rest[T](cseq), n - 1), cseq);

  % Judgement subtype TCC generated (at line 103, column 30) for
      % suffix(fseq, n)
      % expected type  finite_csequence[T]
  suffix_is_finite: OBLIGATION
    FORALL (fseq, n): is_finite[T](suffix(fseq, n));

  % Judgement subtype TCC generated (at line 105, column 32) for
      % suffix(iseq, n)
      % expected type  infinite_csequence[T]
  suffix_is_infinite: OBLIGATION
    FORALL (iseq, n): NOT is_finite[T](suffix(iseq, n));

  % Subtype TCC generated (at line 116, column 11) for  suffix(cseq, n)
      % expected type  (nonempty?[T])
  suffix_rest2_TCC1: OBLIGATION
    FORALL (cseq, n: indexes[T](cseq)): nonempty?[T](suffix(cseq, n));

  % Subtype TCC generated (at line 125, column 43) for  suffix(nseq, n)
      % expected type  (nonempty?[T])
  suffix_first_TCC1: OBLIGATION
    FORALL (nseq, n: indexes[T](nseq)): nonempty?[T](suffix(nseq, n));

  % Subtype TCC generated (at line 132, column 42) for  n + m
      % expected type  indexes[T](cseq)
  suffix_nth_TCC1: OBLIGATION
    FORALL (cseq, n, m: indexes[T](suffix(cseq, n))): index?[T](cseq)(n + m);

  % Subtype TCC generated (at line 144, column 37) for  cseq1
      % expected type  fseq: finite_csequence[T]
  suffix_concatenate_TCC1: OBLIGATION
    FORALL (cseq1, n): NOT index?(cseq1)(n) IMPLIES is_finite[T](cseq1);

  % Subtype TCC generated (at line 144, column 26) for  n - length(cseq1)
      % expected type  nat
  suffix_concatenate_TCC2: OBLIGATION
    FORALL (cseq1, n): NOT index?(cseq1)(n) IMPLIES n - length[T](cseq1) >= 0;


body:
  %-----------------------------------------------------------------------------
  % Properties of the add operator on sequences of countable length defined as
  % coalgebraic datatypes.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence_add[T: TYPE]: THEORY
   BEGIN

    IMPORTING csequence_nth[T]

    n: VAR nat
    t: VAR T
    p: VAR pred[T]
    cseq: VAR csequence
    fseq: VAR finite_csequence
    iseq: VAR infinite_csequence

    add_finite: JUDGEMENT add(t, fseq) HAS_TYPE nonempty_finite_csequence

    add_infinite: JUDGEMENT add(t, iseq) HAS_TYPE infinite_csequence

    add_length: THEOREM
      FORALL t, fseq: length(add(t, fseq)) = length(fseq) + 1

    add_index: THEOREM
      FORALL t, cseq, n:
        index?(add(t, cseq))(n) IFF n = 0 OR index?(cseq)(n - 1)

    add_nth: THEOREM
      FORALL t, cseq, (n: indexes(cseq)):
        nth(add(t, cseq), n + 1) = nth(cseq, n)

    add_last: THEOREM
      FORALL t, fseq:
        last(add(t, fseq)) = IF empty?(fseq) THEN t ELSE last(fseq) ENDIF

    add_some: THEOREM
      FORALL t, cseq, p: some(p)(add(t, cseq)) IFF p(t) OR some(p)(cseq)    

    add_every: THEOREM
      FORALL t, cseq, p: every(p)(add(t, cseq)) IFF p(t) AND every(p)(cseq)

   END csequence_add

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

  % Judgement subtype TCC generated (at line 27, column 24) for  add(t, fseq)
      % expected type  nonempty_finite_csequence[T]
  add_finite: OBLIGATION
    FORALL (fseq, t):
      is_finite[T](add[T](t, fseq)) AND nonempty?[T](add[T](t, fseq));

  % Judgement subtype TCC generated (at line 29, column 26) for  add(t, iseq)
      % expected type  infinite_csequence[T]
  add_infinite: OBLIGATION
    FORALL (iseq, t): NOT is_finite[T](add[T](t, iseq));

  % Subtype TCC generated (at line 36, column 56) for  n - 1
      % expected type  nat
  add_index_TCC1: OBLIGATION FORALL (t, n): NOT n = 0 IMPLIES n - 1 >= 0;

  % Subtype TCC generated (at line 40, column 24) for  n + 1
      % expected type  indexes[T](add(t, cseq))
  add_nth_TCC1: OBLIGATION
    FORALL (t, cseq, n: indexes[T](cseq)): index?[T](add[T](t, cseq))(n + 1);

  % Subtype TCC generated (at line 44, column 60) for  fseq
      % expected type  nonempty_finite_csequence[T]
  add_last_TCC1: OBLIGATION
    FORALL (t, fseq): NOT empty?(fseq) IMPLIES nonempty?[T](fseq);


body:
  %-----------------------------------------------------------------------------
  % Extraction of contiguous subsequences of a sequence of countable length.
  %
  % Author: Jerry James <loganjerry@gmail.com>
  %
  % This file and its accompanying proof file are distributed under the CC0 1.0
  % Universal license: http://creativecommons.org/publicdomain/zero/1.0/.
  %
  % Version history:
  %   2007 Feb 14: PVS 4.0 version
  %   2011 May  6: PVS 5.0 version
  %   2013 Jan 14: PVS 6.0 version
  %-----------------------------------------------------------------------------
  csequence_extract[T: TYPE]: THEORY
   BEGIN

    IMPORTING csequence_nth[T]
    IMPORTING csequence_add[T]  % Proofs only

    t: VAR T
    p: VAR pred[T]
    index, n, m: VAR nat
    range, range2: VAR [nat, nat]
    cseq, cseq1, cseq2: VAR csequence
    fseq: VAR finite_csequence
    nfseq: VAR nonempty_finite_csequence

    ^(cseq, range): RECURSIVE finite_csequence =
      LET (m, n) = range IN
        IF empty?(cseq) OR m > n THEN empty_cseq
        ELSIF m > 0 THEN rest(cseq) ^ (m - 1, n - 1)
        ELSE add(first(cseq),
                 IF n = 0 THEN empty_cseq ELSE rest(cseq) ^ (m, n - 1) ENDIF)
        ENDIF
       MEASURE range`2

    extract_empty: THEOREM
      FORALL cseq, range:
        empty?(cseq ^ range) IFF
         range`1 > range`2 OR (is_finite(cseq) AND NOT index?(cseq)(range`1))

    extract_nonempty: COROLLARY
      FORALL cseq, range:
        nonempty?(cseq ^ range) IFF
         range`1 <= range`2 AND (is_infinite(cseq) OR index?(cseq)(range`1))

    extract_length: THEOREM
      FORALL cseq, range:
        length(cseq ^ range) =
         IF (range`1 > range`2 OR (is_finite(cseq) AND range`1 >= length(cseq)))
           THEN 0
         ELSIF is_finite(cseq) AND range`2 >= length(cseq)
           THEN length(cseq) - range`1
         ELSE range`2 - range`1 + 1
         ENDIF

    extract_def: THEOREM
      FORALL nfseq, n: n >= length(nfseq) - 1 IMPLIES nfseq ^ (0, n) = nfseq

    extract_rest: THEOREM
      FORALL nfseq: nfseq ^ (1, length(nfseq) - 1) = rest(nfseq)

    extract_rest2: THEOREM
      FORALL cseq, m, n:
        nonempty?(cseq ^ (m, n)) IMPLIES
         rest(cseq ^ (m, n)) = cseq ^ (m + 1, n)

    extract_extract: THEOREM
      FORALL cseq, range, range2:
        (cseq ^ range) ^ range2 =
         cseq ^ (range`1 + range2`1, min(range`2, range`1 + range2`2))

    extract_index: THEOREM
      FORALL cseq, m, n, index:
        index?(cseq ^ (m, n))(index) IFF
         m + index <= n AND index?(cseq)(m + index)

    extract_first: THEOREM
      FORALL cseq, m, n:
        nonempty?(cseq ^ (m, n)) IMPLIES first(cseq ^ (m, n)) = nth(cseq, m)

    extract_nth: THEOREM
      FORALL cseq, (m: indexes(cseq)), (n: nat), (i: indexes(cseq ^ (m, n))):
        nth(cseq ^ (m, n), i) = nth(cseq, m + i)

    extract_add: THEOREM
      FORALL cseq, t, m, n:
        add(t, cseq) ^ (m, n) =
         IF m > n THEN empty_cseq
         ELSIF m > 0 THEN cseq ^ (m - 1, max(0, n - 1))
         ELSIF n > 0 THEN add(t, cseq ^ (m, n - 1))
         ELSE add(t, empty_cseq)
         ENDIF

    extract_last: THEOREM
      FORALL cseq, m, n:
        nonempty?(cseq ^ (m, n)) IMPLIES
         last(cseq ^ (m, n)) =
          IF index?(cseq)(n) THEN nth(cseq, n) ELSE last(cseq) ENDIF

    extract_extensionality: THEOREM
      FORALL cseq1, cseq2:
        (FORALL range: cseq1 ^ range = cseq2 ^ range) IMPLIES cseq1 = cseq2

    extract_some: THEOREM
      FORALL cseq, m, n, p:
        some(p)(cseq ^ (m, n)) IFF
         (EXISTS index:
            m <= index AND
             index <= n AND index?(cseq)(index) AND p(nth(cseq, index)))

    extract_every: THEOREM
      FORALL cseq, m, n, p:
        every(p)(cseq ^ (m, n)) IFF
         (FORALL index:
            m <= index AND index <= n AND index?(cseq)(index) IMPLIES
             p(nth(cseq, index)))

   END csequence_extract

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

  % Subtype TCC generated (at line 31, column 28) for  cseq
      % expected type  (nonempty?[T])
  caret_TCC1: OBLIGATION
    FORALL (cseq: csequence[T], range: [nat, nat], m: nat, n: nat):
           m > 0 AND NOT empty?(cseq) AND NOT m > n AND n = range`2
       AND m = range`1
       IMPLIES nonempty?[T](cseq);

  % Subtype TCC generated (at line 31, column 37) for  m - 1
      % expected type  nat
  caret_TCC2: OBLIGATION
    FORALL (cseq: csequence[T], range: [nat, nat], m: nat, n: nat):
           m > 0 AND NOT empty?(cseq) AND NOT m > n AND n = range`2
       AND m = range`1
       IMPLIES m - 1 >= 0;

  % Subtype TCC generated (at line 31, column 44) for  n - 1
      % expected type  nat
  caret_TCC3: OBLIGATION
    FORALL (cseq: csequence[T], range: [nat, nat], m: nat, n: nat):
           m > 0 AND NOT empty?(cseq) AND NOT m > n AND n = range`2
       AND m = range`1
       IMPLIES n - 1 >= 0;

  % Termination TCC generated (at line 31, column 23) for
      % rest(cseq) ^ (m - 1, n - 1)
  caret_TCC4: OBLIGATION
    FORALL (cseq: csequence[T], range: [nat, nat], m: nat, n: nat):
           m > 0 AND NOT empty?(cseq) AND NOT m > n AND n = range`2
       AND m = range`1
       IMPLIES n - 1 < range`2;

  % Subtype TCC generated (at line 32, column 21) for  cseq
      % expected type  (nonempty?[T])
  caret_TCC5: OBLIGATION
    FORALL (cseq: csequence[T], range: [nat, nat], m: nat, n: nat):
           NOT m > 0 AND NOT empty?(cseq) AND NOT m > n AND n = range`2
       AND m = range`1
       IMPLIES nonempty?[T](cseq);

  % Subtype TCC generated (at line 33, column 62) for  n - 1
      % expected type  nat
  caret_TCC6: OBLIGATION
    FORALL (cseq: csequence[T], range: [nat, nat], m: nat, n: nat):
           NOT n = 0 AND NOT m > 0 AND NOT empty?(cseq) AND NOT m > n
       AND n = range`2 AND m = range`1
       IMPLIES n - 1 >= 0;

  % Termination TCC generated (at line 33, column 45) for
      % rest(cseq) ^ (m, n - 1)
  caret_TCC7: OBLIGATION
    FORALL (cseq: csequence[T], range: [nat, nat], m: nat, n: nat):
           NOT n = 0 AND NOT m > 0 AND NOT empty?(cseq) AND NOT m > n
       AND n = range`2 AND m = range`1
       IMPLIES n - 1 < range`2;

  % Subtype TCC generated (at line 32, column 11) for
      % add(first(cseq),
      %     IF n = 0 THEN empty_cseq ELSE rest(cseq) ^ (m, n - 1) ENDIF)
      % expected type  finite_csequence[T]
  caret_TCC8: OBLIGATION
    FORALL (cseq: csequence[T], range: [nat, nat],
            v:
              [{z: [csequence[T], [nat, nat]] | z`2`2 < range`2} ->
                 finite_csequence[T]],
            m: nat, n: nat):
           NOT m > 0 AND NOT empty?(cseq) AND NOT m > n AND n = range`2
       AND m = range`1
       IMPLIES
       is_finite[T]
           (add[T]
                (first[T](cseq),
                 IF n = 0 THEN empty_cseq[T]
                 ELSE v(rest[T](cseq), (m, n - 1))
                 ENDIF));

  % Subtype TCC generated (at line 61, column 30) for  length(nfseq) - 1
      % expected type  nat
  extract_rest_TCC1: OBLIGATION FORALL (nfseq): length[T](nfseq) - 1 >= 0;

  % Subtype TCC generated (at line 80, column 72) for  m
      % expected type  indexes[T](cseq)
  extract_first_TCC1: OBLIGATION
    FORALL (cseq, m, n): nonempty?(cseq ^ (m, n)) IMPLIES index?[T](cseq)(m);

  % Subtype TCC generated (at line 84, column 40) for  m + i
      % expected type  indexes[T](cseq)
  extract_nth_TCC1: OBLIGATION
    FORALL (cseq, m: indexes[T](cseq), n: nat, i: indexes[T](cseq ^ (m, n))):
      index?[T](cseq)(m + i);

  % Subtype TCC generated (at line 90, column 32) for  m - 1
      % expected type  nat
  extract_add_TCC1: OBLIGATION
    FORALL (t, m, n): m > 0 AND NOT m > n IMPLIES m - 1 >= 0;

  % Subtype TCC generated (at line 90, column 39) for  max(0, n - 1)
      % expected type  nat
  extract_add_TCC2: OBLIGATION
    FORALL (t, m, n): m > 0 AND NOT m > n IMPLIES max(0, n - 1) >= 0;

  % Subtype TCC generated (at line 91, column 42) for  n - 1
      % expected type  nat
  extract_add_TCC3: OBLIGATION
    FORALL (t, m, n): n > 0 AND NOT m > 0 AND NOT m > n IMPLIES n - 1 >= 0;

  % Subtype TCC generated (at line 99, column 55) for  cseq
      % expected type  nonempty_finite_csequence[T]
  extract_last_TCC1: OBLIGATION
    FORALL (cseq, m, n):
      NOT index?(cseq)(n) AND nonempty?(cseq ^ (m, n)) IMPLIES
       is_finite[T](cseq) AND nonempty?[T](cseq);


