//
// Course: BU CAS CS 520, Fall 2010
// Instructor: Hongwei Xi (hwxi AT cs DOT bu DOT edu)
// Lecture on Tuesday, Sep. 14, 2010
//

//
// How to compile:
//   atscc-o tally3 tally3.dats
// How to test:
//   ./tally3
//

(* ****** ****** *)

dataprop TALLY (int, int) =
  | TALLYbas (0, 0) of ()
  | {n:nat} {s:int}
    TALLYind (n+1, s+n+1) of TALLY (n, s)
// end of [TALLY]

(* ****** ****** *)
//
// [TALLY] is a total relation
//
prfun TALLYistot
  {n:nat} .<n>. (): [r:int] TALLY (n, r) =
  sif n > 0 then TALLYind (TALLYistot {n-1} ()) else TALLYbas ()
// end of [TALLYistot]

//
// [TALLY] is a functional relation
//
prfun TALLYisfun {n:nat} {r1,r2:int} .<n>.
  (pf1: TALLY (n, r1), pf2: TALLY (n, r2)): [r1==r2] void =
  sif n > 0 then let
    prval TALLYind pf1 = pf1 and TALLYind pf2 = pf2
  in
    TALLYisfun (pf1, pf2)
  end else let
    prval TALLYbas () = pf1 and TALLYbas () = pf2
  in
    // nothing
  end // end of [sif]
// end of [TALLYisfun]

(* ****** ****** *)

prfun lemma {n:nat} {s,p:int} .<n>.
  (pf1: TALLY (n, s), pf2: MUL (n, n+1, p)): [2*s == p] void =
  sif n == 0 then let
    prval TALLYbas () = pf1 and MULbas () = pf2
  in
    // nothing
  end else let // n > 0
    prval TALLYind (pf1) = pf1 // pf1: TALLY (n-1, s-n)
    prval pf2 = mul_commute (pf2) // pf2: MUL (n+1, n, p)
    prval MULind (pf2) = pf2 // pf2: MUL (n, n, p-n)
    prval MULind (pf2) = pf2 // pf2: MUL (n-1, n, p-n-n)
    prval () = lemma (pf1, pf2) // [2*(s-n) == (p-n-n)]
  in
    // nothing
  end // end of [sif]
// end of [lemma]

(* ****** ****** *)

fun tally3 {n:nat} .<>. (n: int n)
  :<> [s:int] (TALLY (n, s) | int (s)) = let
//
  prval pf1 = TALLYistot ()
  val (pf2 | p) = n imul2 (n+1)
  prval () = lemma (pf1, pf2)
//
in
  (pf1 | p / 2)
end // end of [tally3]

(* ****** ****** *)

implement
main () = () where {
  #define N 100
  val (pf | ans) = tally3 (N)
  val () = printf ("sum(1 ... %i) = %i\n", @(N, ans))
} // end [main]

(* ****** ****** *)

(* end of [tally3.dats] *)