(load-file "general-alloy-lemmas.ath")


;; --------------- FIRST DIRECTION (Soundness) --------------- 

(define lemma1 "ALL n x | [n x] in data ==> [x] in elms(n)")

(!pf lemma1 [scalar-lemma elms-uber-axiom union-axiom])
               
(define ind-lemma "ALL k m n x | [n m] in next^k & [m x] in data ==> [x] in elms(n)")

(define (goal k)
  (forall ?m ?n ?x "[n m] in next^k & [m x] in data ==> [x] in elms(n)"))

(by-induction-on ?k (goal ?k)
  (zero (!pf (goal zero) [lemma1 elms-uber-axiom pow-axiom-1 id-axiom]))
  ((succ k) (pick-any m n x 
	      (assume-let ((hyp "[n m] in next^k+1 & [m x] in data"))
 	      (!pf "[x] in elms(n)" [hyp (goal k) pow-axiom-2 elms-uber-axiom union-axiom])))))

(define inclusion-1
  (pick-any n
    (!prove-subsets (sbdot (sbdot (scalar n) (rtc next)) data) (elms n)
      [elms-uber-axiom star-pow-lemma sbdot-axiom scalar-lemma ind-lemma])))

;; ---------------  SECOND DIRECTION (Completeness) --------------- 

(define base-step "ALL n | ~(EXISTS m | [n m] in next) ==> elms(n) subset ({[n]}.next*).data)")
(!pf base-step [elms-uber-axiom lemma-L1])

(define (ind-goal n)
  (subset "elms(n)" 
          "({[n]}.next*).data"))

(define ind-step
  (pick-any x y
      (assume-let ((hyp "[x y] in next")
                   (ihyp (ind-goal y)))
        (dlet ((P1 (!pf "elms(x) = {[x]}.data union elms(y)" [elms-uber-axiom hyp]))
	       (P2 (!pf "{[y]}.next* subset {[x]}.next*" [hyp comp-monotonicity scalar-lemma first-power-lemma-2]))
               (P3 (!pf "({[y]}.next*).data subset ({[x]}.next*).data" [P2 dot-theorem]))
               (P4 (!pf "elms(y) subset ({[x]}.next*).data" [P3 ihyp subset-trans])))
          (!pf "elms(x) subset ({[x]}.next*).data" [P1 lemma-L1 P4 union-lemma-1 id-axiom])))))

(define inclusion-2 (!list-induction ind-goal))

;; -------------- FINAL EQUALITY CONCLUSION --------------- 

(!pf "ALL n | elms(n) = ({[n]}.next*).data" [inclusion-1 inclusion-2 set-equality])
