Definition: bag
bag(T) ==  as,bs:T List//permutation(T;as;bs)

Lemma: bag_wf
[T:Type]. (bag(T) ∈ Type)

Lemma: bag-valueall-type
[T:Type]. valueall-type(bag(T)) supposing valueall-type(T)

Lemma: bag-value-type
[T:Type]. value-type(bag(T))

Lemma: list-subtype-bag
[A,B:Type].  (A List) ⊆bag(B) supposing A ⊆B

Lemma: bag-subtype-fset
[A:Type]. (bag(A) ⊆fset(A))

Lemma: bag-subtype-list
T:Type. (bag(T) ⊆(Top List))

Lemma: bag-equality
[A,B:Type]. ∀[f,g:bag(A) ⟶ bag(B)].  ∀[b:bag(A)]. (f[b] g[b] ∈ bag(B)) supposing ∀[b:A List]. (f[b] g[b] ∈ bag(B))

Lemma: bag_to_squash_list
[T:Type]. ∀[b:bag(T)].  (↓∃L:T List. (b L ∈ bag(T)))

Lemma: respects-equality-bag
[A,B:Type].  respects-equality(bag(A);bag(B)) supposing respects-equality(A;B)

Lemma: respects-equality-list-bag
[A,B:Type].  respects-equality(A List;bag(B)) supposing respects-equality(A;B)

Definition: eval_bag
eval_bag(b) ==  eval_list(b)

Lemma: eval_bag_wf
[T:Type]. ∀[b:bag(T)].  (eval_bag(b) ∈ bag(T))

Definition: mk_bag
mk_bag(L) ==  L

Lemma: mk_bag_wf
[T:Type]. ∀[L:T List].  (mk_bag(L) ∈ bag(T))

Definition: empty-bag
{} ==  []

Lemma: empty-bag_wf
[T:Type]. ({} ∈ bag(T))

Lemma: empty-bag-wf-list-test
[T:Type]. ({} ∈ List)

Lemma: equal-empty-bag
[T:Type]. ∀x:bag(T). ((x {} ∈ bag(T))  (x {}))

Lemma: bag-void-sq-empty
[T:Type]. ∀x:bag(T). {} supposing ¬T

Definition: single-bag
{x} ==  [x]

Lemma: single-bag_wf
T:Type. ∀x:T.  ({x} ∈ bag(T))

Definition: cons-bag
x.b ==  [x b]

Lemma: cons-bag_wf
[T:Type]. ∀[x:T]. ∀[b:bag(T)].  (x.b ∈ bag(T))

Lemma: cons_bag_empty_lemma
x:Top. (x.{} {x})

Lemma: reverse-bag
[T:Type]. ∀[b:bag(T)].  (rev(b) b ∈ bag(T))

Definition: bag-upto
bag-upto(n) ==  upto(n)

Lemma: bag-upto_wf
[n:ℤ]. (bag-upto(n) ∈ bag(ℤ))

Definition: bag-map
bag-map(f;bs) ==  map(f;bs)

Lemma: bag-map_wf
[B,A:Type]. ∀[f:A ⟶ B]. ∀[bs:bag(A)].  (bag-map(f;bs) ∈ bag(B))

Lemma: bag_map_empty_lemma
f:Top. (bag-map(f;{}) {})

Lemma: bag_map_single_lemma
x,f:Top.  (bag-map(f;{x}) {f x})

Lemma: subtype_rel_bag
[B,A:Type].  bag(A) ⊆bag(B) supposing A ⊆B

Definition: bag-append
as bs ==  as bs

Lemma: bag-append_wf
[T:Type]. ∀[as,bs:bag(T)].  (as bs ∈ bag(T))

Lemma: bag-append-comm
[T:Type]. ∀[as,bs:bag(T)].  ((as bs) (bs as) ∈ bag(T))

Lemma: bag-append-assoc
[as,bs,cs:Top].  ((as bs) cs as bs cs)

Lemma: bag-append-assoc2
[as,bs,cs:Top].  (as bs cs (as bs) cs)

Lemma: bag-append-assoc-comm
[T:Type]. ∀[as,bs,cs:bag(T)].  ((as bs cs) (bs as cs) ∈ bag(T))

Lemma: bag-append-comm-assoc
[T:Type]. ∀[as,bs,cs:bag(T)].  ((as bs cs) ((as cs) bs) ∈ bag(T))

Lemma: bag-append-empty
[as:Top List]. (as {} as)

Lemma: bag-append-cancel
[T:Type]. ∀[as,bs,cs:bag(T)].  uiff((as bs) (as cs) ∈ bag(T);bs cs ∈ bag(T))

Lemma: empty_bag_append_lemma
b:Top. ({} b)

Lemma: cons_bag_append_lemma
b2,b1,x:Top.  (x.b1 b2 x.b1 b2)

Lemma: bag-empty-append
[as:Top]. ({} as as)

Lemma: bag-append-ident
[T:Type]. ∀[as:bag(T)].  (((as {}) as ∈ bag(T)) ∧ (({} as) as ∈ bag(T)))

Lemma: bag-append-eq-empty
[T:Type]. ∀[b1,b2:bag(T)].  uiff((b1 b2) {} ∈ bag(T);(b1 {} ∈ bag(T)) ∧ (b2 {} ∈ bag(T)))

Lemma: bag-append-ac
[T:Type]. ∀[as,bs,cs:bag(T)].  ((as bs cs) (bs as cs) ∈ bag(T))

Lemma: cons-bag-as-append
[x,b:Top].  (x.b {x} b)

Lemma: bag-function
[T,A:Type]. ∀[f:(T List) ⟶ bag(A)].
  f ∈ bag(T) ⟶ bag(A) supposing ∀as,bs:T List.  (f[as bs] (f[as] f[bs]) ∈ bag(A))

Definition: bag-product
bs × cs ==  rec-case(bs) of [] => {} b::as => r.bag-map(λx.<b, x>;cs) r

Lemma: bag-product_wf
[A,B:Type]. ∀[as:bag(A)]. ∀[bs:bag(B)].  (as × bs ∈ bag(A × B))

Lemma: bag-product-empty
[bs:Top]. ({} × bs {})

Lemma: bag-product-single
[bs:Top List]. ∀[a:Top].  ({a} × bs bag-map(λx.<a, x>;bs))

Lemma: bag-product-append
[as,bs,cs:Top List].  (as bs × cs as × cs bs × cs)

Definition: bag-filter
[x∈b|p[x]] ==  filter(λx.p[x];b)

Lemma: bag-filter_wf
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[bs:bag(T)].  ([x∈bs|p[x]] ∈ bag({x:T| ↑p[x]} ))

Lemma: bag-filter-wf3
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[bs:bag(T)].  ([x∈bs|p[x]] ∈ bag(T))

Lemma: bag-filter-is-nil
[T:Type]. ∀[p:T ⟶ 𝔹].  ∀[bs:bag(T)]. ([x∈bs|p[x]] []) supposing ∀x:T. (¬↑p[x])

Lemma: bag-filter-trivial
[T:Type]. ∀[p:T ⟶ 𝔹].  ∀[bs:bag(T)]. ([x∈bs|p[x]] bs ∈ bag(T)) supposing ∀x:T. (↑p[x])

Lemma: bag-filter-append
[p,as,bs:Top].  ([x∈as bs|p[x]] [x∈as|p[x]] [x∈bs|p[x]])

Lemma: bag-filter-filter
[p,q,bs:Top].  ([x∈[x∈bs|p[x]]|q[x]] [x∈bs|p[x] ∧b q[x]])

Lemma: bag-filter-filter2
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[q:{x:T| ↑p[x]}  ⟶ 𝔹]. ∀[bs:bag(T)].
  ([x∈[x∈bs|p[x]]|q[x]] [x∈bs|p[x] ∧b q[x]] ∈ bag({x:T| ↑(p[x] ∧b q[x])} ))

Lemma: bag-filter-singleton
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[v:T].  ([x∈{v}|p[x]] if p[v] then {v} else {} fi )

Lemma: bag-filter-split
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[bs:bag(T)].  (([x∈bs|p[x]] [x∈bs|¬bp[x]]) bs ∈ bag(T))

Lemma: bag-filter-map
[f,p,as:Top].  ([x∈bag-map(f;as)|p[x]] bag-map(f;[x∈as|p[f x]]))

Lemma: bag-filter-map2
[T,A:Type]. ∀[f:A ⟶ T]. ∀[p:T ⟶ 𝔹]. ∀[as:bag(A)].
  ([x∈bag-map(f;as)|p[x]] bag-map(f;[x∈as|p[f x]]) ∈ bag({x:T| ↑p[x]} ))

Lemma: bag_filter_empty_lemma
p:Top. ([x∈{}|p[x]] {})

Lemma: bag_filter_cons_lemma
p,v,u:Top.  ([x∈u.v|p[x]] if p[u] then u.[x∈v|p[x]] else [x∈v|p[x]] fi )

Lemma: test-bag-filter-empty
[p:Top]. ([b∈{}|p[b]] {})

Lemma: bag-split
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[as:bag(T)].  (as ([x∈as|p[x]] [x∈as|¬bp[x]]) ∈ bag(T))

Lemma: bag-map-null
f,bs:Top.  (null(bag-map(f;bs)) null(bs))

Definition: bag-mapfilter
bag-mapfilter(f;P;bs) ==  bag-map(f;[x∈bs|P x])

Lemma: bag-mapfilter_wf
[T,A:Type].  ∀P:T ⟶ 𝔹. ∀f:{x:T| ↑(P x)}  ⟶ A. ∀bs:bag(T).  (bag-mapfilter(f;P;bs) ∈ bag(A))

Lemma: bag-mapfilter-null
P,f,bs:Top.  (null(bag-mapfilter(f;P;bs)) null([x∈bs|P x]))

Lemma: bag-mapfilter-empty
P,f:Top.  (bag-mapfilter(f;P;{}) {})

Definition: bag-null
bag-null(bs) ==  null(bs)

Lemma: bag-null_wf
T:Type. ∀bs:bag(T).  (bag-null(bs) ∈ 𝔹)

Lemma: bag_null_empty_lemma
bag-null({}) tt

Lemma: bag_null_cons_lemma
v,u:Top.  (bag-null(u.v) ff)

Lemma: bag-null-append
[T:Type]. ∀[as,bs:bag(T)].  bag-null(as bs) bag-null(as) ∧b bag-null(bs)

Lemma: assert-bag-null
[T:Type]. ∀[bs:bag(T)].  uiff(↑bag-null(bs);bs {} ∈ bag(T))

Lemma: null-bag-mapfilter
P,f,bs:Top.  (bag-null(bag-mapfilter(f;P;bs)) bag-null([x∈bs|P x]))

Lemma: bag-map-equal
[T,A:Type].
  ∀f,g:T ⟶ A. ∀P:T ⟶ 𝔹.
    ((∀x:T. ((¬↑(P x))  ((f x) (g x) ∈ A)))
     (∀as:bag(T). ((↑null([x∈as|P x]))  (bag-map(f;as) bag-map(g;as) ∈ bag(A)))))

Lemma: null-bag-filter-map
[T,A:Type]. ∀[f:A ⟶ T]. ∀[p:T ⟶ 𝔹]. ∀[as:bag(A)].  null([x∈bag-map(f;as)|p[x]]) null([x∈as|p[f x]])

Definition: bag-size
#(bs) ==  ||bs||

Lemma: bag-size_wf
[C:Type]. ∀[bs:bag(C)].  (#(bs) ∈ ℕ)

Lemma: bag_size_single_lemma
x:Top. (#({x}) 1)

Lemma: bag_size_cons_lemma
b,x:Top.  (#(x.b) #(b) 1)

Lemma: bag-size-map
[bs,f:Top].  (#(bag-map(f;bs)) #(bs))

Lemma: bag-size-append
[as,bs:Top].  (#(as bs) #(as) #(bs))

Lemma: bag-size-cons
[b:bag(Top)]. ∀[x:Top].  (#(x.b) #(b))

Lemma: bag-size-zero
[C:Type]. ∀[bs:bag(C)].  bs {} supposing #(bs) ≤ 0

Lemma: bag_size_empty_lemma
#({}) 0

Lemma: bag-size-is-zero
[C:Type]. ∀[bs:bag(C)].  bs {} supposing #(bs) 0 ∈ ℤ

Lemma: bag-size-bound
[T:Type]. ∀[as,bs:bag(T)]. ∀[n:ℕ].  #(as bs) n < #(bs) supposing #(as) < n

Lemma: null-bag
[T:Type]. ∀[x:bag(T)].  uiff(↑null(x);x {} ∈ bag(T))

Lemma: assert-bag-null-sq
bs:bag(Top). ((↑bag-null(bs))  (bs {}))

Lemma: smallbag-subtype-list
T:Type. ({b:bag(T)| #(b) < 2}  ⊆{b:T List| ||b|| < 2} )

Lemma: bag-cases
[T:Type]. ∀bs:bag(T). ((bs {} ∈ bag(T)) ∨ (↓∃x:T. ∃bs':bag(T). (bs ({x} bs') ∈ bag(T))))

Lemma: null-bag-size
[T:Type]. ∀[x:bag(T)].  (bag-null(x) (#(x) =z 0))

Lemma: bag-map-append
[as:bag(Top)]. ∀[bs,f:Top].  (bag-map(f;as bs) bag-map(f;as) bag-map(f;bs))

Lemma: bag-map-cons
[b,x,f:Top].  (bag-map(f;x.b) x.bag-map(f;b))

Lemma: bag-map-single
[x,f:Top].  (bag-map(f;{x}) {f x})

Lemma: bag-map-map
[as,f,g:Top].  (bag-map(f;bag-map(g;as)) bag-map(f g;as))

Lemma: bag-map-filter
[T,A:Type]. ∀[f:T ⟶ A]. ∀[P:T ⟶ 𝔹]. ∀[Q:A ⟶ 𝔹].
  ∀[L:bag(T)]. (bag-map(f;[x∈L|P[x]]) [x∈bag-map(f;L)|Q[x]] ∈ bag(A)) supposing ∀x:T. Q[f x] P[x]

Lemma: bag-map-trivial
[A:Type]. ∀[as:bag(A)]. ∀[f:A ⟶ A].  bag-map(f;as) as ∈ bag(A) supposing ∀x:A. ((f x) x ∈ A)

Lemma: bag-mapfilter-append
[T:Type]. ∀[a:bag(T)]. ∀[b:bag(Top)]. ∀[f:Top]. ∀[P:T ⟶ 𝔹].
  (bag-mapfilter(f;P;a b) bag-mapfilter(f;P;a) bag-mapfilter(f;P;b))

Lemma: bag-mapfilter-map
[A,B,C:Type]. ∀[b:bag(A)]. ∀[P:B ⟶ 𝔹]. ∀[f:{x:B| ↑P[x]}  ⟶ C]. ∀[g:A ⟶ B].
  (bag-mapfilter(f;P;bag-map(g;b)) bag-mapfilter(f g;P g;b) ∈ bag(C))

Lemma: bag-map-mapfilter
[b,P,f,g:Top].  (bag-map(g;bag-mapfilter(f;P;b)) bag-mapfilter(g f;P;b))

Lemma: bag-mapfilter-mapfilter
[A,B,C:Type]. ∀[b:bag(A)]. ∀[P:A ⟶ 𝔹]. ∀[f:{x:A| ↑P[x]}  ⟶ B]. ∀[Q:B ⟶ 𝔹]. ∀[g:{x:B| ↑Q[x]}  ⟶ C].
  (bag-mapfilter(g;Q;bag-mapfilter(f;P;b)) bag-mapfilter(g f;λx.(P[x] ∧b Q[f[x]]);b) ∈ bag(C))

Definition: bagp
Bag+ ==  {b:bag(T)| 0 < #(b)} 

Lemma: bagp_wf
[T:Type]. (T Bag+ ∈ Type)

Lemma: bagp_properties
[T:Type]. ∀[b:T Bag+].  (#(b) ≥ )

Definition: bag-val
bag-val(zero;+) ==  λb.accumulate (with value and list item x): xover list:  bwith starting value: zero)

Lemma: bag-val_wf
[T:Type]. ∀[+:T ⟶ T ⟶ T]. ∀[zero:T].  (Comm(T;+)  Assoc(T;+)  Ident(T;+;zero)  (bag-val(zero;+) ∈ bag(T) ⟶ T))

Lemma: bag-val-empty
[+,zero:Top].  (bag-val(zero;+) {} zero)

Lemma: bag-val-append
[T:Type]. ∀[+:T ⟶ T ⟶ T]. ∀[zero:T].
  (Comm(T;+)
   Assoc(T;+)
   Ident(T;+;zero)
   (∀[as,bs:bag(T)].  ((bag-val(zero;+) (as bs)) ((bag-val(zero;+) as) (bag-val(zero;+) bs)) ∈ T)))

Definition: bag-union
bag-union(bbs) ==  concat(bbs)

Lemma: bag-union_wf
[T:Type]. ∀[bbs:bag(bag(T))].  (bag-union(bbs) ∈ bag(T))

Lemma: bag_union_empty_lemma
bag-union({}) {}

Lemma: bag_union_cons_lemma
v,u:Top.  (bag-union(u.v) bag-union(v))

Lemma: bag-union-bagp
[T:Type]. ∀[bbs:bag(bag(T))].  (0 < #([b∈bbs|0 <#(b)])  (bag-union(bbs) ∈ Bag+))

Lemma: bag-induction
[T:Type]. ∀[P:bag(T) ⟶ ℙ].  ((∀x:T. P[[x]])  (∀bs:bag({b:bag(T)| P[b]} ). P[bag-union(bs)])  (∀b:bag(T). P[b]))

Lemma: bag-filter-union
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[bbs:bag(bag(T))].
  ([x∈bag-union(bbs)|p[x]] bag-union(bag-map(λb.[x∈b|p[x]];bbs)) ∈ bag({x:T| ↑p[x]} ))

Lemma: bag-filter-union2
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[bbs:bag(bag(T))].  ([x∈bag-union(bbs)|p[x]] bag-union(bag-map(λb.[x∈b|p[x]];bbs)) ∈ bag(T))

Lemma: bag-map-union
[T,S:Type]. ∀[f:T ⟶ bag(S)]. ∀[bbs:bag(bag(T))].
  (bag-map(f;bag-union(bbs)) bag-union(bag-map(λb.bag-map(f;b);bbs)) ∈ bag(bag(S)))

Lemma: bag-append-union
[T:Type]. ∀as,bs:bag(bag(T)).  (bag-union(as bs) (bag-union(as) bag-union(bs)) ∈ bag(T))

Lemma: bag-union-single
x:Top List. (bag-union({x}) x)

Lemma: bag-append-is-single
[T:Type]. ∀[x:T].
  ∀as,bs:bag(T).
    ↓((as {x} ∈ bag(T)) ∧ (bs {} ∈ bag(T))) ∨ ((bs {x} ∈ bag(T)) ∧ (as {} ∈ bag(T))) 
    supposing (as bs) {x} ∈ bag(T)

Lemma: bag-append-is-single-iff
[T:Type]. ∀[x:T].
  ∀as,bs:bag(T).
    uiff((as bs) {x} ∈ bag(T);↓((as {x} ∈ bag(T)) ∧ (bs {} ∈ bag(T)))
                                   ∨ ((bs {x} ∈ bag(T)) ∧ (as {} ∈ bag(T))))

Lemma: bag-append-is-single-iff2
[T:Type]. ∀[x:T].
  ∀as,bs:bag(T).
    uiff({x} (as bs) ∈ bag(T);↓((as {x} ∈ bag(T)) ∧ (bs {} ∈ bag(T)))
                                   ∨ ((bs {x} ∈ bag(T)) ∧ (as {} ∈ bag(T))))

Lemma: bag-append-is-empty
[T:Type]. ∀as,bs:bag(T).  uiff((as bs) {} ∈ bag(T);(as {} ∈ bag(T)) ∧ (bs {} ∈ bag(T)))

Lemma: bag-union-is-single-if
[T:Type]. ∀[x:T].  ∀bbs:bag(bag(T)). bag-union(bbs) {x} ∈ bag(T) supposing bbs {{x}} ∈ bag(bag(T))

Lemma: bag-union-is-single
[T:Type]. ∀[x:T].
  ∀bbs:bag(bag(T))
    uiff(bag-union(bbs) {x} ∈ bag(T);↓∃bbs':bag(bag(T))
                                         ((bbs {x}.bbs' ∈ bag(bag(T))) ∧ (bag-union(bbs') {} ∈ bag(T))))

Lemma: bag-union-cons
[b,a:Top].  (bag-union(a.b) bag-union(b))

Lemma: bag-union-append
[A:Type]. ∀[b1,b2:bag(bag(A))].  (bag-union(b1 b2) (bag-union(b1) bag-union(b2)) ∈ bag(A))

Lemma: non-empty-bag-union-of-list
[T:Type]. ∀L:bag(T) List. (0 < #(bag-union(L)) ⇐⇒ (∃b∈L. 0 < #(b)))

Lemma: non-empty-bag-mapfilter-union-of-list
[T:Type]
  ∀P:T ⟶ 𝔹. ∀f:T ⟶ Top. ∀L:bag(T) List.  (0 < #(bag-mapfilter(f;λx.P[x];bag-union(L))) ⇐⇒ (∃b∈L. 0 < #([x∈b|P[x]])))

Definition: bag-combine
x∈bs.f[x] ==  bag-union(bag-map(λx.f[x];bs))

Lemma: bag-combine_wf
[A,B:Type]. ∀[bs:bag(A)]. ∀[f:A ⟶ bag(B)].  (⋃x∈bs.f[x] ∈ bag(B))

Lemma: bag_combine_empty_lemma
f:Top. (⋃x∈{}.f[x] {})

Lemma: strict4-bag-combine
strict4(λx,y,z,w. ⋃b∈x.y[b])

Lemma: bag-combine-assoc
[f,g:Top]. ∀[bs:bag(Top)].  (⋃y∈⋃x∈bs.f[x].g[y] ~ ⋃x∈bs.⋃y∈f[x].g[y])

Lemma: bag-combine-unit-left
[A,B:Type]. ∀[f:A ⟶ bag(B)]. ∀[a:A].  (⋃x∈[a].f[x] f[a])

Lemma: bag-combine-unit-left-top
[f,a:Top].  (⋃x∈[a].f[x] f[a] {})

Lemma: bag-combine-single-left
[A,B:Type]. ∀[f:A ⟶ bag(B)]. ∀[a:A].  (⋃x∈{a}.f[x] f[a])

Lemma: bag-combine-empty-left
[f:Top]. (⋃x∈{}.f[x] {})

Lemma: bag-combine-empty-right
[T:Type]. ∀[bs:bag(T)].  (⋃x∈bs.{} {})

Lemma: bag-combine-unit-right
[A:Type]. ∀[bs:bag(A)].  (⋃x∈bs.[x] bs)

Lemma: bag-combine-single-right
[A:Type]. ∀[bs:bag(A)].  (⋃x∈bs.{x} bs)

Lemma: bag-combine-single-right-as-map
[bs,f:Top].  (⋃x∈bs.{f[x]} bag-map(λx.f[x];bs))

Lemma: bag-combine-append-left
[A,B:Type]. ∀[ba,bb:bag(A)]. ∀[f:A ⟶ bag(B)].  (⋃x∈ba bb.f[x] (⋃x∈ba.f[x] + ⋃x∈bb.f[x]) ∈ bag(B))

Lemma: bag-combine-append-right
[A,B:Type]. ∀[F,G:A ⟶ bag(B)]. ∀[ba:bag(A)].  (⋃x∈ba.F[x] G[x] (⋃x∈ba.F[x] + ⋃x∈ba.G[x]) ∈ bag(B))

Lemma: bag-combine-cons-left
[b,a,f:Top].  (⋃x∈a.b.f[x] f[a] + ⋃x∈b.f[x])

Lemma: bag-combine-com
[A,B,C:Type]. ∀[f:A ⟶ B ⟶ bag(C)]. ∀[ba:bag(A)]. ∀[bb:bag(B)].  (⋃a∈ba.⋃b∈bb.f[a;b] = ⋃b∈bb.⋃a∈ba.f[a;b] ∈ bag(C))

Lemma: bag-combine-filter
[A,B:Type]. ∀[p:A ⟶ 𝔹]. ∀[f:{a:A| ↑p[a]}  ⟶ bag(B)]. ∀[ba:bag(A)].
  (⋃a∈[a∈ba|p[a]].f[a] = ⋃a∈ba.if p[a] then f[a] else {} fi  ∈ bag(B))

Lemma: bag-map-combine
[A,B,C:Type]. ∀[g:A ⟶ bag(B)]. ∀[f:B ⟶ C]. ∀[bs:bag(A)].  (bag-map(f;⋃x∈bs.g[x]) = ⋃x∈bs.bag-map(f;g[x]) ∈ bag(C))

Lemma: bag-combine-map
[A,B,C:Type]. ∀[g:B ⟶ bag(C)]. ∀[f:A ⟶ B]. ∀[bs:bag(A)].  (⋃x∈bag-map(f;bs).g[x] = ⋃x∈bs.g[f x] ∈ bag(C))

Lemma: bag-combine-is-single-if
[A,B:Type]. ∀[f:A ⟶ bag(B)]. ∀[bs:bag(A)]. ∀[x:B].
  ⋃x∈bs.f[x] {x} ∈ bag(B) supposing ↓∃y:A. ((bs {y} ∈ bag(A)) ∧ (f[y] {x} ∈ bag(B)))

Lemma: bag-combine-combine
[A,B,C:Type]. ∀[b:bag(A)]. ∀[f:A ⟶ bag(B)]. ∀[g:B ⟶ bag(C)].  (⋃x∈⋃y∈b.f[y].g[x] = ⋃x∈b.⋃y∈f[x].g[y] ∈ bag(C))

Lemma: bag-map-union2
[A,B:Type]. ∀[g:A ⟶ B]. ∀[x:bag(bag(A))].  (bag-map(g;bag-union(x)) bag-union(bag-map(λz.bag-map(g;z);x)) ∈ bag(B))

Lemma: bag-union-as-combine
[A:Type]. ∀[x:bag(bag(A))].  (bag-union(x) = ⋃b∈x.b ∈ bag(A))

Lemma: bag-union-union-as-combine
[X:Type]. ∀[x:bag(bag(bag(X)))].  (bag-union(bag-union(x)) = ⋃z∈x.bag-union(z) ∈ bag(X))

Definition: bag-monad
BagMonad ==  mk_monad(λT.bag(T);λx.{x};λba,f. ⋃x∈ba.f x)

Lemma: bag-monad_wf
BagMonad ∈ Monad

Lemma: bag-combine-mapfilter
[A,B,C:Type]. ∀[b:bag(A)]. ∀[P:A ⟶ 𝔹]. ∀[f:{x:A| ↑P[x]}  ⟶ B]. ∀[g:B ⟶ bag(C)].
  (⋃x∈bag-mapfilter(f;P;b).g[x] = ⋃x∈b.if P[x] then g[f[x]] else {} fi  ∈ bag(C))

Lemma: bag-combine-is-map
[A,B:Type]. ∀[b:bag(A)]. ∀[f:A ⟶ B].  (⋃x∈b.{f[x]} bag-map(f;b) ∈ bag(B))

Definition: bag-sum
bag-sum(ba;x.f[x]) ==  accumulate (with value and list item x): f[x] sover list:  bawith starting value: 0)

Lemma: bag-sum_wf
[A:Type]. ∀[f:A ⟶ ℤ]. ∀[ba:bag(A)].  (bag-sum(ba;x.f[x]) ∈ ℤ)

Lemma: bag-sum_wf_nat
[A:Type]. ∀[f:A ⟶ ℕ]. ∀[ba:bag(A)].  (bag-sum(ba;x.f[x]) ∈ ℕ)

Lemma: bag-sum-nonneg
[A:Type]. ∀[f:A ⟶ ℤ]. ∀[ba:bag(A)].  0 ≤ bag-sum(ba;x.f[x]) supposing ∀x:A. (0 ≤ f[x])

Lemma: bag-combine-size
[A,B:Type]. ∀[f:A ⟶ bag(B)]. ∀[ba:bag(A)].  (#(⋃a∈ba.f[a]) bag-sum(ba;a.#(f[a])) ∈ ℕ)

Lemma: bag-combine-size-bound
[A,B:Type]. ∀[f:A ⟶ bag(B)]. ∀[L:A List]. ∀[a:A].  #(f[a]) ≤ #(⋃a∈L.f[a]) supposing (a ∈ L)

Definition: bag-reduce
bag-reduce(x,y.f[x; y];zero;bs) ==  reduce(λx,y. f[x; y];zero;bs)

Lemma: bag-reduce_wf
[T:Type]. ∀[zero:T]. ∀[f:T ⟶ T ⟶ T].
  (∀[bs:bag(T)]. (bag-reduce(x,y.f[x;y];zero;bs) ∈ T)) supposing (Assoc(T;λx,y. f[x;y]) and Comm(T;λx,y. f[x;y]))

Definition: bag-accum
bag-accum(v,x.f[v; x];init;bs) ==
  accumulate (with value and list item x):
   f[v; x]
  over list:
    bs
  with starting value:
   init)

Lemma: bag-accum_wf
[T,S:Type]. ∀[init:S]. ∀[f:S ⟶ T ⟶ S]. ∀[bs:bag(T)].
  bag-accum(v,x.f[v;x];init;bs) ∈ supposing ∀v:S. ∀x,y:T.  (f[f[v;y];x] f[f[v;x];y] ∈ S)

Lemma: bag-accum-map
[L,y,f,g:Top].  (bag-accum(x,a.f[x;a];y;bag-map(g;L)) bag-accum(x,a.f[x;g a];y;L))

Lemma: bag-accum-single
[init,f,x:Top].  (bag-accum(v,x.f[v;x];init;{x}) f[init;x])

Lemma: bag-map-as-accum
[A,B:Type]. ∀[f:A ⟶ B]. ∀[bs:bag(A)].  (bag-map(f;bs) bag-accum(b,x.f[x].b;{};bs) ∈ bag(B))

Lemma: bag-combine-as-accum
[A,B:Type]. ∀[f:A ⟶ bag(B)]. ∀[bs:bag(A)].  (⋃b∈bs.f[b] bag-accum(c,b.f[b] c;{};bs) ∈ bag(B))

Lemma: sum-as-bag-accum
[n:ℕ]. ∀[f:ℕn ⟶ ℤ].  (f[x] x < n) bag-accum(x,y.x y;0;[x∈bag-map(λx.f[x];upto(n))|¬b(x =z 0)]))

Lemma: bag-filter-as-accum
[A:Type]. ∀[p:A ⟶ 𝔹]. ∀[bs:bag(A)].
  ([x∈bs|p[x]] bag-accum(b,x.if p[x] then x.b else fi ;{};bs) ∈ bag({x:A| ↑p[x]} ))

Definition: bag-maximal?
bag-maximal?(bg;x;R) ==  bag-accum(b,y.b ∧b R[x;y];tt;bg)

Lemma: bag-maximal?_wf
[T:Type]. ∀[b:bag(T)]. ∀[R:T ⟶ T ⟶ 𝔹]. ∀[x:T].  (bag-maximal?(b;x;R) ∈ 𝔹)

Lemma: bag-maximal?-single
[T:Type]. ∀[R:T ⟶ T ⟶ 𝔹]. ∀[v,x:T].  uiff(↑bag-maximal?({v};x;R);↑(R v))

Lemma: bag-maximal?-append
[T:Type]. ∀[R:T ⟶ T ⟶ 𝔹]. ∀[b1,b2:bag(T)]. ∀[x:T].
  uiff(↑bag-maximal?(b1 b2;x;R);(↑bag-maximal?(b1;x;R)) ∧ (↑bag-maximal?(b2;x;R)))

Lemma: bag-maximal?-cons
[T:Type]. ∀[b:bag(T)]. ∀[R:T ⟶ T ⟶ 𝔹]. ∀[x,v:T].  uiff(↑bag-maximal?(v.b;x;R);(↑bag-maximal?(b;x;R)) ∧ (↑(R v)))

Definition: bag-maximals
bag-maximals(bg;R) ==  [x∈bg|bag-maximal?(bg;x;R)]

Lemma: bag-maximals_wf
[T:Type]. ∀[b:bag(T)]. ∀[R:T ⟶ T ⟶ 𝔹].  (bag-maximals(b;R) ∈ bag(T))

Definition: imax-bag
imax-bag(bs) ==  imax-list(bs)

Lemma: imax-bag_wf
[bs:bag(ℤ)]. imax-bag(bs) ∈ ℤ supposing 0 < #(bs)

Definition: bag-summation
Σ(x∈b). f[x] ==  bag-accum(c,x.add f[x] c;zero;b)

Lemma: bag-summation_wf
[T,R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[f:T ⟶ R]. ∀[b:bag(T)].
  Σ(x∈b). f[x] ∈ supposing Assoc(R;add) ∧ Comm(R;add)

Lemma: bag-summation-empty
[add,zero,f:Top].  (x∈{}). f[x] zero)

Lemma: bag-summation-append
[R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R].
  ∀[T:Type]. ∀[f:T ⟶ R]. ∀[b,c:bag(T)].  (x∈c). f[x] (x∈b). f[x] add Σ(x∈c). f[x]) ∈ R) 
  supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-summation-single-sq
[add,zero,f,a:Top].  (x∈{a}). f[x] add f[a] zero)

Lemma: bag-summation-single
[R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R].
  ∀[T:Type]. ∀[f:T ⟶ R]. ∀[a:T].  (x∈{a}). f[x] f[a] ∈ R) supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-summation-cons
[R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R].
  ∀[T:Type]. ∀[f:T ⟶ R]. ∀[b:bag(T)]. ∀[a:T].  (x∈a.b). f[x] (f[a] add Σ(x∈b). f[x]) ∈ R) 
  supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-summation-linear
[T,R:Type]. ∀[add,mul:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)]. ∀[f,g:T ⟶ R].
  ∀a:R. (x∈b). mul (f[x] add g[x]) (a mul (x∈b). f[x] add Σ(x∈b). g[x])) ∈ R) 
  supposing (∃minus:R ⟶ R. IsGroup(R;add;zero;minus)) ∧ Comm(R;add) ∧ BiLinear(R;add;mul)

Lemma: bag-summation-add
[T,R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[f,g:T ⟶ R]. ∀[b:bag(T)].
  Σ(x∈b). f[x] add g[x] (x∈b). f[x] add Σ(x∈b). g[x]) ∈ supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-summation-linear-right
[T,R:Type]. ∀[add,mul:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)]. ∀[f,g:T ⟶ R].
  ∀a:R. (x∈b). (f[x] add g[x]) mul ((Σ(x∈b). f[x] add Σ(x∈b). g[x]) mul a) ∈ R) 
  supposing (∃minus:R ⟶ R. IsGroup(R;add;zero;minus)) ∧ Comm(R;add) ∧ BiLinear(R;add;mul)

Lemma: bag-summation-zero
[T,R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)].
  Σ(x∈b). zero zero ∈ supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-summation-linear1
[T,R:Type]. ∀[add,mul:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)]. ∀[f:T ⟶ R].
  ∀a:R. (x∈b). mul f[x] (a mul Σ(x∈b). f[x]) ∈ R) 
  supposing (∃minus:R ⟶ R. IsGroup(R;add;zero;minus)) ∧ Comm(R;add) ∧ BiLinear(R;add;mul)

Lemma: bag-summation-constant
[T:Type]. ∀[r:Rng]. ∀[b:bag(T)].  ∀a:|r|. (x∈b). (#(b) ⋅a) ∈ |r|)

Lemma: bag-summation-minus
[T:Type]. ∀[r:Rng]. ∀[b:bag(T)]. ∀[f:T ⟶ |r|].  (x∈b). -r f[x] (-r Σ(x∈b). f[x]) ∈ |r|)

Lemma: bag-summation-linear1-right
[T,R:Type]. ∀[add,mul:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)]. ∀[f:T ⟶ R].
  ∀a:R. (x∈b). f[x] mul (x∈b). f[x] mul a) ∈ R) 
  supposing (∃minus:R ⟶ R. IsGroup(R;add;zero;minus)) ∧ Comm(R;add) ∧ BiLinear(R;add;mul)

Lemma: bag-summation-ring-linear1
[T:Type]. ∀[r:Rng]. ∀[b:bag(T)]. ∀[f:T ⟶ |r|].
  ∀a:|r|. ((Σ(x∈b). f[x] (x∈b). f[x] a) ∈ |r|) ∧ (x∈b). f[x] (a * Σ(x∈b). f[x]) ∈ |r|))

Lemma: bag-summation-map
[add,zero:Top]. ∀[b:Top List]. ∀[f,g:Top].  (x∈bag-map(g;b)). f[x] ~ Σ(x∈b). f[g x])

Lemma: bag-summation-reindex
[R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R].
  ∀[T,A:Type]. ∀[g:T ⟶ A]. ∀[h:A ⟶ T]. ∀[f:T ⟶ R].
    ∀[b:bag(T)]. (x∈b). f[x] = Σ(x∈bag-map(g;b)). f[h x] ∈ R) supposing ∀x:T. (x (h (g x)) ∈ T) 
  supposing Comm(R;add) ∧ Assoc(R;add)

Lemma: bag-summation-split
[T,R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)]. ∀[p:T ⟶ 𝔹]. ∀[f:T ⟶ R].
  Σ(x∈b). f[x] (x∈[x∈b|p[x]]). f[x] add Σ(x∈[x∈b|¬bp[x]]). f[x]) ∈ supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-summation-product
[r:Rng]. ∀[A,B:Type]. ∀[f:A ⟶ |r|]. ∀[c:bag(B)]. ∀[g:B ⟶ |r|]. ∀[b:bag(A)].
  ((Σ(x∈b). f[x] * Σ(y∈c). g[y]) = Σ(p∈b × c). f[fst(p)] g[snd(p)] ∈ |r|)

Lemma: bag-summation-hom
[r,s:Rng]. ∀[f:|r| ⟶ |s|].
  ∀[A:Type]. ∀[g:A ⟶ |r|]. ∀[b:bag(A)].  (x∈b). f[g[x]] f[Σ(x∈b). g[x]] ∈ |s|) supposing rng_hom_p(r;s;f)

Lemma: bag-double-summation1
[R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R].
  ∀[T:Type]. ∀[A:T ⟶ Type]. ∀[f:x:T ⟶ bag(A[x])]. ∀[h:x:T ⟶ A[x] ⟶ R]. ∀[b:bag(T)].
    (x∈b). Σ(y∈f[x]). h[x;y] = Σ(p∈⋃x∈b.bag-map(λy.<x, y>;f[x])). h[fst(p);snd(p)] ∈ R) 
  supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-double-summation
[R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R].
  ∀[T,A,B:Type]. ∀[f:T ⟶ bag(A)]. ∀[g:T ⟶ B]. ∀[h:B ⟶ A ⟶ R]. ∀[b:bag(T)].
    (x∈b). Σ(y∈f[x]). h[g[x];y] = Σ(p∈⋃x∈b.bag-map(λy.<g[x], y>;f[x])). h[fst(p);snd(p)] ∈ R) 
  supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-double-summation2
[R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R].
  ∀[T,A:Type]. ∀[f:T ⟶ bag(A)]. ∀[h:T ⟶ A ⟶ R]. ∀[b:bag(T)].
    (x∈b). Σ(y∈f[x]). h[x;y] = Σ(p∈⋃x∈b.bag-map(λy.<x, y>;f[x])). h[fst(p);snd(p)] ∈ R) 
  supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Definition: bag-product
Πx ∈ b. f[x] ==  Σ(x∈b). f[x]

Lemma: bag-product_wf
[T,R:Type]. ∀[mul:R ⟶ R ⟶ R]. ∀[one:R]. ∀[b:bag(T)]. ∀[f:T ⟶ R].
  Πx ∈ b. f[x] ∈ supposing Assoc(R;mul) ∧ Comm(R;mul)

Definition: int-bag-product
Π(b) ==  Πx ∈ b. x

Lemma: int-bag-product_wf
[b:bag(ℤ)]. (b) ∈ ℤ)

Lemma: int-bag-product-append
[b1,b2:bag(ℤ)].  (b1 b2) ~ Π(b1) * Π(b2))

Definition: int-bag-sum
Σ(b) ==  Σ(x∈b). x

Lemma: int-bag-sum_wf
[b:bag(ℤ)]. (b) ∈ ℤ)

Lemma: int-bag-sum-append
[b1,b2:bag(ℤ)].  (b1 b2) ~ Σ(b1) + Σ(b2))

Definition: bag-no-repeats
bag-no-repeats(T;bs) ==  ↓∃L:T List. ((L bs ∈ bag(T)) ∧ no_repeats(T;L))

Lemma: bag-no-repeats_wf
[T:Type]. ∀[bs:bag(T)].  (bag-no-repeats(T;bs) ∈ ℙ)

Lemma: sq_stable__bag-no-repeats
[T:Type]. ∀[bs:bag(T)].  SqStable(bag-no-repeats(T;bs))

Lemma: bag-single-no-repeats
[T:Type]. ∀[x:T].  bag-no-repeats(T;{x})

Lemma: empty-bag-no-repeats
[T:Type]. bag-no-repeats(T;{})

Lemma: bag-map-no-repeats
[T1,T2:Type]. ∀[f:T1 ⟶ T2]. ∀[bs:bag(T1)].
  uiff(bag-no-repeats(T2;bag-map(f;bs));bag-no-repeats(T1;bs)) supposing Inj(T1;T2;f)

Lemma: bag-filter-no-repeats
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[bs:bag(T)].  bag-no-repeats(T;[x∈bs|p[x]]) supposing bag-no-repeats(T;bs)

Definition: bag-rep
bag-rep(n;x) ==  primrec(n;{};λi,r. x.r)

Lemma: bag-rep_wf
[T:Type]. ∀[n:ℕ]. ∀[x:T].  (bag-rep(n;x) ∈ List)

Lemma: bag-size-rep
[n:ℕ]. ∀[x:Top].  (#(bag-rep(n;x)) n)

Lemma: bag-null-rep
[n:ℕ]. ∀[x:Top].  (bag-null(bag-rep(n;x)) (n =z 0))

Lemma: bag-rep-add
x:Top. ∀n,m:ℕ.  (bag-rep(n m;x) bag-rep(n;x) bag-rep(m;x))

Lemma: empty-bag-union
T:Type. ∀bs:bag(bag(T)).  ((bag-union(bs) {} ∈ bag(T))  (bs bag-rep(#(bs);{})))

Definition: bag-all
bag-all(x.p[x];bs) ==  bag-reduce(x,y.x ∧b y;tt;bag-map(λx.p[x];bs))

Lemma: bag-all_wf
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[bs:bag(T)].  (bag-all(x.p[x];bs) ∈ 𝔹)

Definition: bag_all
bag_all(b;f) ==  bag-accum(a,x.a ∧b f[x];tt;b)

Lemma: bag_all_wf
[T:Type]. ∀[f:T ⟶ 𝔹]. ∀[b:bag(T)].  (bag_all(b;f) ∈ 𝔹)

Lemma: bag_all-empty
[f:Top]. (bag_all({};f) tt)

Lemma: bag_all-cons
[T:Type]. ∀[x:T]. ∀[b:bag(T)]. ∀[f:T ⟶ 𝔹].  (bag_all(x.b;f) (f x) ∧b bag_all(b;f))

Lemma: bag_all-map
[b,f,g:Top].  (bag_all(bag-map(g;b);f) bag_all(b;f g))

Definition: bag-only
only(bs) ==  hd(bs)

Lemma: bag-only_wf
[T:Type]. ∀[bs:bag(T)].  only(bs) ∈ supposing #(bs) 1 ∈ ℤ

Lemma: bag_only_single_lemma
x:Top. (only({x}) x)

Lemma: bag-size-one
[T:Type]. ∀[bs:bag(T)].  bs {only(bs)} supposing #(bs) 1 ∈ ℤ

Lemma: subtype-bag-only
[T:Type]. ∀[bs:bag(T)].  bs ∈ bag({x:T| only(bs) ∈ T} supposing #(bs) 1 ∈ ℤ

Lemma: subtype-bag-empty
[T:Type]. ∀[bs:bag(T)].  bs ∈ bag(Void) supposing #(bs) 0 ∈ ℤ

Lemma: only-bag-map
[f:Top]. ∀[T:Type]. ∀[b:bag(T)].  only(bag-map(f;b)) only(b) supposing #(b) 1 ∈ ℤ

Lemma: equal-bag-size-le1
[T:Type]. ∀[as,bs:bag(T)].
  uiff(as bs ∈ bag(T);(as {} ∈ bag(T) ⇐⇒ bs {} ∈ bag(T))
  ∧ ((#(as) 1 ∈ ℤ (#(bs) 1 ∈ ℤ (only(as) only(bs) ∈ T))) 
  supposing (#(as) ≤ 1) ∧ (#(bs) ≤ 1)

Definition: bag-merge
bag-merge(as;bs) ==  bag-map(λx.(inl x);as) bag-map(λx.(inr );bs)

Lemma: bag-merge_wf
A,B:Type. ∀as:bag(A). ∀bs:bag(B).  (bag-merge(as;bs) ∈ bag(A B))

Definition: bag-separate
bag-separate(bs) ==  <bag-mapfilter(λt.outl(t);λt.isl(t);bs), bag-mapfilter(λt.outr(t);λt.(¬bisl(t));bs)>

Lemma: bag-separate_wf
[A,B:Type]. ∀[bs:bag(A B)].  (bag-separate(bs) ∈ bag(A) × bag(B))

Lemma: bag-separate-merge
[as,bs:Top List].  (bag-separate(bag-merge(as;bs)) ~ <as, bs>)

Definition: sub-bag
sub-bag(T;as;bs) ==  ∃cs:bag(T). (bs (as cs) ∈ bag(T))

Lemma: sub-bag_wf
[T:Type]. ∀[as,bs:bag(T)].  (sub-bag(T;as;bs) ∈ ℙ)

Lemma: sub-bag_weakening
[T:Type]. ∀[as,bs:bag(T)].  ((as bs ∈ bag(T))  sub-bag(T;as;bs))

Lemma: sub-bag_transitivity
[T:Type]. ∀[as,bs,cs:bag(T)].  (sub-bag(T;as;bs)  sub-bag(T;bs;cs)  sub-bag(T;as;cs))

Lemma: sub-bag_antisymmetry
[T:Type]. ∀[as,bs:bag(T)].  (as bs ∈ bag(T)) supposing (sub-bag(T;as;bs) and sub-bag(T;bs;as))

Lemma: sub-bag-rep
[T:Type]. ∀x:T. ∀n,m:ℕ.  uiff(sub-bag(T;bag-rep(n;x);bag-rep(m;x));n ≤ m)

Lemma: sub-bag-combine
[T,U:Type].  ∀f:T ⟶ bag(U). ∀b1,b2:bag(T).  (sub-bag(T;b1;b2)  sub-bag(U;⋃x∈b1.f[x];⋃x∈b2.f[x]))

Lemma: sub-bag-append-trivial1
[T:Type]. ∀[b,x:bag(T)].  ∀y:bag(T). (sub-bag(T;b;x)  sub-bag(T;b;x y))

Lemma: sub-bag-append-trivial2
[T:Type]. ∀[b,y:bag(T)].  ∀x:bag(T). (sub-bag(T;b;y)  sub-bag(T;b;x y))

Lemma: sub-bag-append-left
[T:Type]. ∀b1,b2,b:bag(T).  (sub-bag(T;b1 b2;b)  sub-bag(T;b1;b))

Lemma: sub-bag-append-left2
[T:Type]. ∀b1,b2,b:bag(T).  (sub-bag(T;b1 b2;b)  sub-bag(T;b2;b))

Lemma: sub-bag-cancel-right
[T:Type]. ∀b1,b2,b:bag(T).  (sub-bag(T;b1 b;b2 b) ⇐⇒ sub-bag(T;b1;b2))

Lemma: sub-bag-equal
[T:Type]. ∀[b1,b2:bag(T)].  (b1 b2 ∈ bag(T)) supposing (sub-bag(T;b1;b2) and sub-bag(T;b2;b1))

Lemma: empty-sub-bag
T:Type. ∀b:bag(T).  sub-bag(T;{};b)

Lemma: sub-bag-empty
[T:Type]. ∀[b:bag(T)].  uiff(sub-bag(T;b;{});b {} ∈ bag(T))

Definition: maximal-sub-bag
maximal-sub-bag(T;m;b;s.P[s]) ==  (∀s:bag(T). (sub-bag(T;s;b)  P[s]  sub-bag(T;s;m))) ∧ P[m]

Lemma: maximal-sub-bag_wf
[T:Type]. ∀[b,m:bag(T)]. ∀[P:bag(T) ⟶ ℙ].  (maximal-sub-bag(T;m;b;s.P[s]) ∈ ℙ)

Definition: bag-member
x ↓∈ bs ==  ↓∃L:T List. ((L bs ∈ bag(T)) ∧ (x ∈ L))

Lemma: bag-member_wf
[T:Type]. ∀[x:T]. ∀[bs:bag(T)].  (x ↓∈ bs ∈ ℙ)

Lemma: squash-bag-member
[T:Type]. ∀[x:T]. ∀[bs:bag(T)].  uiff(↓x ↓∈ bs;x ↓∈ bs)

Lemma: sq_stable__bag-member
[T:Type]. ∀[x:T]. ∀[bs:bag(T)].  SqStable(x ↓∈ bs)

Lemma: bag-member-subtype
[A,B:Type].  ∀b:bag(A). ∀x:A.  (x ↓∈  x ↓∈ b) supposing A ⊆B

Lemma: bag-member-strong-subtype
[A,B:Type].  ∀b:bag(A). ∀x:B.  (x ↓∈  (x ∈ A)) supposing strong-subtype(A;B)

Lemma: bag-member-empty
[T:Type]. ∀[x:T].  False supposing x ↓∈ {}

Lemma: bag-member-empty-iff
[T:Type]. ∀[x:T].  uiff(x ↓∈ {};False)

Lemma: bag-member-empty-weak
[T:Type]. ∀[x:T].  (x ↓∈ {} ⇐⇒ False)

Lemma: empty-bag-iff-no-member
[T:Type]. ∀[bs:bag(T)].  uiff(bs {} ∈ bag(T);∀x:T. x ↓∈ bs))

Lemma: bag-member-iff-size
[T:Type]. ∀[bs:bag(T)].  uiff(↓∃x:T. x ↓∈ bs;0 < #(bs))

Lemma: empty-bag-iff-size
[T:Type]. ∀[bs:bag(T)].  uiff(bs {} ∈ bag(T);#(bs) ≤ 0)

Lemma: non-empty-bag-implies-non-void
[T:Type]. ∀[bs:bag(T)].  ((¬(bs {} ∈ bag(T)))  (↓T))

Lemma: bag-member-single
[T:Type]. ∀[x,y:T].  uiff(x ↓∈ {y};x y ∈ T)

Lemma: single-bags-equal
[T:Type]. ∀[x,y:T].  uiff({x} {y} ∈ bag(T);x y ∈ T)

Lemma: bag-member-single-weak
[T:Type]. ∀[x,y:T].  (x ↓∈ {y} ⇐⇒ y ∈ T)

Lemma: bag-member-list
[T:Type]. ((∀x,y:T.  Dec(x y ∈ T))  (∀x:T. ∀L:T List.  (x ↓∈ ⇐⇒ (x ∈ L))))

Lemma: l_member-bag-member
[T:Type]. ∀x:T. ∀L:T List.  (x ↓∈ ⇐⇒ ↓(x ∈ L))

Lemma: bag-member-iff-hd
[T:Type]. ∀[bs:bag(T)]. ∀[x:T].  uiff(x ↓∈ bs;↓∃L:T List. (bs [x L] ∈ bag(T)))

Lemma: bag-member-append
[T:Type]. ∀x:T. ∀as,bs:bag(T).  (x ↓∈ as bs ⇐⇒ x ↓∈ as ↓∨ x ↓∈ bs)

Lemma: bag-member-iff
[T:Type]. ∀[bs:bag(T)]. ∀[x:T].  uiff(x ↓∈ bs;↓∃as:bag(T). (bs ({x} as) ∈ bag(T)))

Lemma: bag-in-subtype
[A,B:Type].  ∀[b:bag(B)]. b ∈ bag(A) supposing ∀x:B. (x ↓∈  (x ∈ A)) supposing strong-subtype(A;B)

Lemma: bag-in-subtype2
[A,B:Type].  ∀[b:bag(B)]. b ∈ bag(A) supposing ∀x:B. (x ↓∈  (∃a:bag(A). x ↓∈ a)) supposing strong-subtype(A;B)

Lemma: bag-member-combine
[A,B:Type]. ∀[bs:bag(A)]. ∀[f:A ⟶ bag(B)]. ∀[b:B].  uiff(b ↓∈ ⋃x∈bs.f[x];↓∃x:A. (x ↓∈ bs ∧ b ↓∈ f[x]))

Lemma: bag-member-select
[A:Type]. ∀[L:A List]. ∀[i:ℕ||L||].  L[i] ↓∈ L

Lemma: bag-map-list-map
[T,U:Type].  ∀L1:T List. ∀L2:U List. ∀f:T ⟶ U.  ((L2 map(f;L1) ∈ bag(U))  (∃L:U List. (L map(f;L1) ∈ (U List))))

Lemma: bag-member-cons
[T:Type]. ∀[x,u:T]. ∀[v:bag(T)].  uiff(x ↓∈ u.v;(x u ∈ T) ↓∨ x ↓∈ v)

Lemma: bag-member-map
[T,U:Type].  ∀x:U. ∀f:T ⟶ U. ∀bs:bag(T).  uiff(x ↓∈ bag-map(f;bs);↓∃v:T. (v ↓∈ bs ∧ (x (f v) ∈ U)))

Lemma: bag-member-filter
[T:Type]. ∀[P:T ⟶ 𝔹]. ∀[x:T]. ∀[bs:bag(T)].  uiff(x ↓∈ [x∈bs|P[x]];x ↓∈ bs ∧ (↑P[x]))

Lemma: bag-member-filter-set
[T:Type]. ∀[P:T ⟶ 𝔹]. ∀[x:{x:T| ↑P[x]} ]. ∀[bs:bag(T)].  uiff(x ↓∈ [x∈bs|P[x]];x ↓∈ bs)

Lemma: bag-member-mapfilter
[T,U:Type]. ∀[P:T ⟶ 𝔹]. ∀[x:U]. ∀[bs:bag(T)]. ∀[f:{x:T| ↑(P x)}  ⟶ U].
  uiff(x ↓∈ bag-mapfilter(f;P;bs);↓∃v:{x:T| ↑(P x)} (v ↓∈ bs ∧ (x (f v) ∈ U)))

Lemma: bag-member-union
[T:Type]. ∀[x:T]. ∀[bbs:bag(bag(T))].  uiff(x ↓∈ bag-union(bbs);↓∃b:bag(T). (x ↓∈ b ∧ b ↓∈ bbs))

Lemma: bag-member-list-member
[T:Type]. ((∀x,y:T.  Dec(x y ∈ T))  (∀L:T List. ∀b:bag(T). ∀x:T.  ((L b ∈ bag(T))  x ↓∈  (x ∈ L))))

Lemma: bag-member-from-upto
[n,m,x:ℤ].  uiff(x ↓∈ [n, m);(n ≤ x) ∧ x < m)

Lemma: bag-member-ifthenelse
[T:Type]. ∀[as,bs:bag(T)]. ∀[x:T].  ∀b:𝔹uiff(x ↓∈ if then as else bs fi ;if then x ↓∈ as else x ↓∈ bs fi )

Lemma: bag-member-not-bag-null
[T:Type]. ∀[bs:bag(T)].  uiff(↓∃x:T. x ↓∈ bs;¬↑bag-null(bs))

Lemma: bag-member-product
[A,B:Type]. ∀[as:bag(A)]. ∀[bs:bag(B)]. ∀[p:A × B].  uiff(p ↓∈ as × bs;fst(p) ↓∈ as ∧ snd(p) ↓∈ bs)

Lemma: bag-member-spread
[P:Top × Top]. ∀[C,p,T:Top].  (p ↓∈ let x,y in C[x;y] let x,y in p ↓∈ C[x;y])

Lemma: bag-member-spread-to-pi
[P:Top × Top]. ∀[C,p,T:Top].  (p ↓∈ let x,y in C[x;y] p ↓∈ C[fst(P);snd(P)])

Lemma: bag-member-evidence
[T:Type]. ∀[b:bag(T)]. ∀[x:T].  Ax ∈ x ↓∈ supposing x ↓∈ b

Lemma: list-member-bag-member
[T:Type]. ∀L:T List. ∀x:T.  ((x ∈ L)  x ↓∈ L)

Lemma: bag-member-sq-list-member
[T:Type]. ∀L:T List. ∀x:T.  ↓(x ∈ L) supposing x ↓∈ L

Lemma: bag-member-iff-sq-list-member
[T:Type]. ∀L:T List. ∀x:T.  uiff(x ↓∈ L;↓(x ∈ L))

Lemma: not-list-member-not-bag-member
[T:Type]. ∀[L:T List]. ∀[x:T].  ((¬(x ∈ L))  x ↓∈ L))

Lemma: int-bag-product-positive
[b:bag(ℤ)]. 0 < Π(b) supposing ∀[x:ℤ]. (x ↓∈  0 < x)

Lemma: map-member-wf
[A,B:Type]. ∀[L:A List]. ∀[f:{a:A| (a ∈ L)}  ⟶ B].  (map(f;L) ∈ List)

Lemma: bag-combine-null
[A,B:Type]. ∀[f:A ⟶ bag(B)]. ∀[b:bag(A)].  uiff(↑bag-null(⋃x∈b.f[x]);∀x:A. (x ↓∈  (↑bag-null(f[x]))))

Lemma: bag-combine-size-bound2
[A,B:Type]. ∀[f:A ⟶ bag(B)]. ∀[L:bag(A)]. ∀[a:A].  #(f[a]) ≤ #(⋃a∈L.f[a]) supposing a ↓∈ L

Lemma: bag-size-bag-member
[T:Type]. ∀[bs:bag(T)].  (0 < #(bs) ⇐⇒ ↓∃b:T. b ↓∈ bs)

Lemma: bag-member-size
[T:Type]. ∀[bs:bag(T)]. ∀[x:T].  0 < #(bs) supposing x ↓∈ bs

Lemma: sub-bag-union-of-list
[T:Type]. ∀[x:bag(T)].  ∀bs:bag(T) List. ((x ∈ bs)  sub-bag(T;x;bag-union(bs)))

Lemma: member-bag-rep
[T:Type]. ∀[n:ℕ]. ∀[x,y:T].  x ∈ supposing y ↓∈ bag-rep(n;x)

Lemma: select-bag-rep
[T:Type]. ∀[n:ℕ]. ∀[x:T]. ∀[i:ℕn].  (bag-rep(n;x)[i] x ∈ T)

Lemma: assert-bag_all
[T:Type]. ∀[f:T ⟶ 𝔹]. ∀[b:bag(T)].  (∀x:T. (x ↓∈  (↑f[x])) ⇐⇒ ↑bag_all(b;f))

Lemma: bag-null-bag-union
[T:Type]. ∀[bbs:bag(bag(T))].  ↑bag-null(bag-union(bbs)) supposing ∀bs:bag(T). (bs ↓∈ bbs  (↑bag-null(bs)))

Lemma: bag-null-filter
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[b:bag(T)].  uiff(↑bag-null([x∈b|p[x]]);∀x:T. (x ↓∈  (¬↑p[x])))

Definition: b_all
b_all(T;b;x.P[x]) ==  ∀x:T. (x ↓∈  P[x])

Lemma: b_all_wf
[T:Type]. ∀[b:bag(T)]. ∀[P:T ⟶ ℙ].  (b_all(T;b;x.P[x]) ∈ ℙ)

Lemma: b_all-wf2
[T:Type]. ∀[b:bag(T)]. ∀[P:{x:T| x ↓∈ b}  ⟶ ℙ].  (b_all(T;b;x.P[x]) ∈ ℙ)

Lemma: b_all-map
[A,B:Type].
  ∀f:A ⟶ B. ∀b:bag(A). ∀P:B ⟶ ℙ.  ((∀b:B. SqStable(P[b]))  (b_all(B;bag-map(f;b);x.P[x]) ⇐⇒ b_all(A;b;x.P[f x])))

Lemma: b_all-inst
[B:Type]. ∀b:bag(B). ∀P:B ⟶ ℙ. ∀x:B.  (x ↓∈  b_all(B;b;x.P[x])  P[x])

Lemma: b_all-cons
[B:Type]. ∀b:bag(B). ∀P:B ⟶ ℙ. ∀x:B.  ((∀b:B. SqStable(P[b]))  (b_all(B;x.b;x.P[x]) ⇐⇒ P[x] ∧ b_all(B;b;x.P[x])))

Lemma: b_all-squash-exists-bag
[A,B:Type]. ∀[as:bag(A)]. ∀[P:A ⟶ B ⟶ ℙ].
  ↓∃bs:bag(A × B). ((bag-map(λx.(fst(x));bs) as ∈ bag(A)) ∧ b_all(A × B;bs;x.let a,b in ↓P[a;b])) 
  supposing b_all(A;as;x.↓∃y:B. P[x;y])

Lemma: b_all-squash-exists-bag2
[A,B:Type]. ∀[as:bag(A)]. ∀[P:A ⟶ B ⟶ ℙ].
  ↓∃bs:bag(A × B). ((bag-map(λx.(fst(x));bs) as ∈ bag(A)) ∧ b_all(A × B;bs;x.↓P[fst(x);snd(x)])) 
  supposing b_all(A;as;x.↓∃y:B. P[x;y])

Lemma: b_all-squash-exists-list
[A,B:Type]. ∀[as:bag(A)]. ∀[P:A ⟶ B ⟶ ℙ].
  ↓∃bs:(A × B) List. ((bag-map(λx.(fst(x));bs) as ∈ bag(A)) ∧ (∀x∈bs.↓P[fst(x);snd(x)])) 
  supposing b_all(A;as;x.↓∃y:B. P[x;y])

Lemma: l_all-squash-exists-list
[A,B:Type]. ∀[as:A List]. ∀[P:A ⟶ B ⟶ ℙ].
  ↓∃bs:(A × B) List. ((map(λx.(fst(x));bs) as ∈ (A List)) ∧ (∀x∈bs.↓P[fst(x);snd(x)])) supposing (∀x∈as.↓∃y:B. P[x;y])

Lemma: l_all_implies_b_all
[A:Type]. ∀as:A List. ∀P:A ⟶ ℙ.  ((∀x,y:A.  Dec(x y ∈ A))  (∀x∈as.P[x])  b_all(A;as;x.P[x]))

Definition: bag-inject
bag-inject(A;b;B;f) ==  Inj({x:A| x ↓∈ b} ;B;f)

Lemma: bag-inject_wf
[A,B:Type]. ∀[b:bag(A)]. ∀[f:A ⟶ B].  (bag-inject(A;b;B;f) ∈ ℙ)

Definition: similar-bags
similar-bags(A;as;bs) ==  ∀a:A. (a ↓∈ as ∧ 0 < #(bs) ⇐⇒ a ↓∈ bs ∧ 0 < #(as))

Lemma: similar-bags_wf
[A:Type]. ∀[as,bs:bag(A)].  (similar-bags(A;as;bs) ∈ ℙ)

Definition: single-valued-bag
single-valued-bag(b;T) ==  ∀x,y:T.  (x ↓∈  y ↓∈  (x y ∈ T))

Lemma: single-valued-bag_wf
[T:Type]. ∀[b:bag(T)].  (single-valued-bag(b;T) ∈ ℙ)

Lemma: single-valued-bag-hd
[T:Type]. ∀[b:bag(T)].  (hd(b) ∈ T) supposing (0 < #(b) and single-valued-bag(b;T))

Lemma: single-valued-bag-if-le1
[T:Type]. ∀[b:bag(T)].  single-valued-bag(b;T) supposing #(b) ≤ 1

Lemma: single-valued-bag-single
[T:Type]. ∀[b:T].  single-valued-bag({b};T)

Lemma: single-valued-bag-empty
[T:Type]. single-valued-bag({};T)

Lemma: single-valued-bag-combine
[A,B:Type]. ∀[as:bag(A)]. ∀[f:A ⟶ bag(B)].
  (single-valued-bag(⋃x∈as.f[x];B)) supposing ((∀a:A. single-valued-bag(f[a];B)) and single-valued-bag(as;A))

Lemma: single-valued-bag-append
[A:Type]. ∀[as,bs:bag(A)].
  (single-valued-bag(as bs;A)) supposing 
     (similar-bags(A;as;bs) and 
     single-valued-bag(as;A) and 
     single-valued-bag(bs;A))

Lemma: single-valued-bag-map
[A,B:Type]. ∀[as:bag(A)]. ∀[f:A ⟶ B].  single-valued-bag(bag-map(f;as);B) supposing single-valued-bag(as;A)

Lemma: single-valued-bag-list
[T:Type]. ∀[L:T List].  single-valued-list(L;T) supposing single-valued-bag(L;T)

Lemma: single-valued-bag-is-rep
[A:Type]. ∀[as:bag(A)].  ∀a:A. (a ↓∈ as  (as bag-rep(#(as);a) ∈ bag(A))) supposing single-valued-bag(as;A)

Definition: sv-bag-only
sv-bag-only(b) ==  hd(b)

Lemma: sv-bag-only_wf
[T:Type]. ∀[b:bag(T)].  (sv-bag-only(b) ∈ T) supposing (0 < #(b) and single-valued-bag(b;T))

Lemma: bag-member-sv-bag-only
[T:Type]. ∀[b:bag(T)].  (sv-bag-only(b) ↓∈ b) supposing (0 < #(b) and single-valued-bag(b;T))

Lemma: bag-member-implies-hd-append
[T:Type]. ∀[x:T]. ∀[b:bag(T)].  ↓∃c:bag(T). (b ({x} c) ∈ bag(T)) supposing x ↓∈ b

Lemma: sv-bag-only-single
[x:Top]. (sv-bag-only({x}) x)

Lemma: sv_bag_only_single_lemma
x:Top. (sv-bag-only({x}) x)

Lemma: sv-bag-only-append
[A:Type]. ∀[as,bs:bag(A)].
  (sv-bag-only(as bs) sv-bag-only(as) ∈ A) supposing 
     (similar-bags(A;as;bs) and 
     0 < #(as) and 
     single-valued-bag(as;A) and 
     single-valued-bag(bs;A))

Lemma: sv-bag-only-combine
[A,B:Type]. ∀[b:bag(A)]. ∀[f:A ⟶ bag(B)].
  (sv-bag-only(⋃x∈b.f[x]) sv-bag-only(f[sv-bag-only(b)]) ∈ B) supposing 
     ((∀a:A. 0 < #(f[a])) and 
     (∀a:A. single-valued-bag(f[a];B)) and 
     0 < #(b) and 
     single-valued-bag(b;A))

Lemma: sv-bag-only-map
[A,B:Type]. ∀[f:A ⟶ B]. ∀[b:bag(A)].
  (sv-bag-only(bag-map(f;b)) f[sv-bag-only(b)] ∈ B) supposing (0 < #(b) and single-valued-bag(b;A))

Lemma: sv-bag-only-map2
[A,B:Type]. ∀[f:A ⟶ B]. ∀[b:bag(A)].
  (sv-bag-only(bag-map(f;b)) (f sv-bag-only(b)) ∈ B) supposing (0 < #(b) and single-valued-bag(b;A))

Definition: bag-disjoint
bag-disjoint(T;as;bs) ==  ∀x:T. (x ↓∈ as ∧ x ↓∈ bs))

Lemma: bag-disjoint_wf
[T:Type]. ∀[as,bs:bag(T)].  (bag-disjoint(T;as;bs) ∈ ℙ)

Lemma: bag-combine-eq-right
[A,B:Type]. ∀[b:bag(A)]. ∀[f1,f2:A ⟶ bag(B)].
  ⋃x∈b.f1[x] = ⋃x∈b.f2[x] ∈ bag(B) supposing ∀x:{x:A| x ↓∈ b} (f1[x] f2[x] ∈ bag(B))

Lemma: bag-filter-empty
[T:Type]. ∀[P:T ⟶ 𝔹]. ∀[b:bag(T)].  ∀x:T. (x ↓∈  (¬↑P[x])) supposing ↑bag-null([x∈b|P[x]])

Lemma: bag-filter-empty-iff
[T:Type]. ∀[P:T ⟶ 𝔹]. ∀[b:bag(T)].  uiff(∀x:T. (x ↓∈  (¬↑P[x]));↑bag-null([x∈b|P[x]]))

Lemma: bag-filter-is-empty
[T:Type]. ∀[P:T ⟶ 𝔹]. ∀[b:bag(T)].  uiff(∀x:T. (x ↓∈  (¬↑P[x]));[x∈b|P[x]] {} ∈ bag(T))

Lemma: bag-filter-trivial2
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[bs:bag(T)].  [x∈bs|p[x]] bs ∈ bag(T) supposing ∀x:T. (x ↓∈ bs  (↑p[x]))

Lemma: bag-filter-equal
[T:Type]. ∀[p1,p2:T ⟶ 𝔹]. ∀[b:bag(T)].  uiff([x∈b|p1[x]] [x∈b|p2[x]] ∈ bag(T);∀x:T. (x ↓∈  (↑p1[x] ⇐⇒ ↑p2[x])))

Lemma: sub-bag-member
[T:Type]. ∀[b1,b2:bag(T)]. ∀[x:T].  (x ↓∈ b2) supposing (sub-bag(T;b1;b2) and x ↓∈ b1)

Lemma: sub-bag-filter
[T:Type]. ∀p:T ⟶ 𝔹. ∀b,c:bag(T).  (sub-bag(T;b;[x∈c|p[x]]) ⇐⇒ sub-bag(T;b;c) ∧ (∀x:T. (x ↓∈  (↑p[x]))))

Lemma: bag-filter-is-sub-bag
[T:Type]. ∀p:T ⟶ 𝔹. ∀b:bag(T).  sub-bag(T;[x∈b|p[x]];b)

Lemma: sub-bag-filter2
T:Type. ∀p1,p2:T ⟶ 𝔹. ∀b,c:bag(T).
  (sub-bag(T;b;[x∈c|p1[x]])  sub-bag(T;b;[x∈c|p2[x]])  sub-bag(T;b;[x∈c|p1[x] ∧b p2[x]]))

Lemma: sub-bag-filter3
T:Type. ∀p:T ⟶ 𝔹. ∀b,c:bag(T).  (sub-bag(T;b;c)  sub-bag(T;[x∈b|p[x]];[x∈c|p[x]]))

Lemma: single-valued-sub-bag
[T:Type]. ∀[as,bs:bag(T)].  (single-valued-bag(bs;T)  sub-bag(T;as;bs)  single-valued-bag(as;T))

Lemma: bag-subtype
[A:Type]. ∀b:bag(A). (b ∈ bag({x:A| x ↓∈ b} ))

Lemma: bag-subtype2
[A:Type]. ∀P:A ⟶ ℙ. ∀b:bag({x:A| P[x]} ). ∀x:{x:A| P[x]} .  (x ↓∈ ⇐⇒ x ↓∈ b)

Lemma: bag-member-subtype-2
[A:Type]. ∀b:bag(A). ∀x:A.  (x ↓∈  x ↓∈ b)

Lemma: strong-subtype-bag
[A,B:Type].  strong-subtype(bag(A);bag(B)) supposing strong-subtype(A;B)

Definition: bag-to-list
bag-to-list(cmp;b) ==  comparison-sort(cmp;b)

Lemma: bag-to-list_wf
[T:Type]
  ∀[b:bag(T)]. ∀[cmp:comparison({x:T| x ↓∈ b} )].
    bag-to-list(cmp;b) ∈ List supposing ∀x,y:{x:T| x ↓∈ b} .  (((cmp y) 0 ∈ ℤ (x y ∈ T)) 
  supposing valueall-type(T)

Lemma: sub-bag-of-bag-rep
[T:Type]. ∀x:T. ∀n:ℕ.  ∀[b:bag(T)]. bag-rep(#(b);x) ∈ bag(T) supposing sub-bag(T;b;bag-rep(n;x))

Lemma: bag-append-equal-bag-rep
[T:Type]. ∀[x:T]. ∀[n:ℕ]. ∀[a,b:bag(T)].
  uiff((a b) bag-rep(n;x) ∈ bag(T);(n (#(a) #(b)) ∈ ℤ)
  ∧ (a bag-rep(#(a);x) ∈ bag(T))
  ∧ (b bag-rep(#(b);x) ∈ bag(T)))

Lemma: bag-no-repeats-subtype
[T,A:Type]. ∀[bs:bag(A)].  (bag-no-repeats(A;bs)) supposing (bag-no-repeats(T;bs) and strong-subtype(A;T))

Lemma: bag-filter-no-repeats2
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[bs:bag(T)].  bag-no-repeats({x:T| ↑p[x]} ;[x∈bs|p[x]]) supposing bag-no-repeats(T;bs)

Lemma: bag-combine-eq-out
[A,B,C:Type]. ∀[as:bag(A)]. ∀[bs:bag(B)]. ∀[f:A ⟶ bag(C)]. ∀[g:B ⟶ bag(C)]. ∀[h:A ⟶ B].
  (⋃a∈as.f[a] = ⋃b∈bs.g[b] ∈ bag(C)) supposing 
     ((∀a:A. (a ↓∈ as  (g[h[a]] f[a] ∈ bag(C)))) and 
     (bs bag-map(h;as) ∈ bag(B)))

Lemma: bag-map-member-wf
[A,B:Type]. ∀[bs:bag(A)]. ∀[f:{a:A| a ↓∈ bs}  ⟶ B].  (bag-map(f;bs) ∈ bag(B))

Lemma: bag-combine-member-wf
[A,B:Type]. ∀[bs:bag(A)]. ∀[f:{a:A| a ↓∈ bs}  ⟶ bag(B)].  (⋃x∈bs.f[x] ∈ bag(B))

Lemma: bag-filter-wf2
[T:Type]. ∀[bs:bag(T)]. ∀[p:{b:T| b ↓∈ bs}  ⟶ 𝔹].  ([x∈bs|p[x]] ∈ bag({x:{b:T| b ↓∈ bs} | ↑p[x]} ))

Lemma: bag-mapfilter-wf2
[T,A:Type]. ∀[bs:bag(T)]. ∀[p:{b:T| b ↓∈ bs}  ⟶ 𝔹]. ∀[f:{x:{b:T| b ↓∈ bs} | ↑p[x]}  ⟶ A].
  (bag-mapfilter(f;p;bs) ∈ bag(A))

Lemma: bag-member-map2
[T,U:Type].  ∀x:U. ∀bs:bag(T). ∀f:{v:T| v ↓∈ bs}  ⟶ U.  uiff(x ↓∈ bag-map(f;bs);↓∃v:{v:T| v ↓∈ bs} (x (f v) ∈ U))

Lemma: bag-member-map3
[T,U:Type].  ∀x:U. ∀bs:bag(T). ∀f:{v:T| v ↓∈ bs}  ⟶ U.  uiff(x ↓∈ bag-map(f;bs);↓∃v:T. (v ↓∈ bs ∧ (x (f v) ∈ U)))

Lemma: bag-member-filter-implies1
[T:Type]. ∀[x:T]. ∀[bs:bag(T)]. ∀[P:{x:T| x ↓∈ bs}  ⟶ 𝔹].  x ↓∈ [x∈bs|P[x]] supposing x ↓∈ bs ∧ (↑P[x])

Lemma: bag-member-filter-implies2
[T:Type]. ∀[x:T]. ∀[bs:bag(T)]. ∀[P:{x:T| x ↓∈ bs}  ⟶ 𝔹].  x ↓∈ bs ∧ (↑P[x]) supposing x ↓∈ [x∈bs|P[x]]

Lemma: bag-member-filter2
[T:Type]. ∀[x:T]. ∀[bs:bag(T)]. ∀[P:{x:T| x ↓∈ bs}  ⟶ 𝔹].  uiff(x ↓∈ [x∈bs|P[x]];x ↓∈ bs ∧ (↑P[x]))

Lemma: single-valued-bag-filter
[A:Type]. ∀[b:bag(A)]. ∀[p:{x:A| x ↓∈ b}  ⟶ 𝔹].
  single-valued-bag([x∈b|p[x]];A) supposing ∀x,y:A.  (x ↓∈  y ↓∈  (↑p[x])  (↑p[y])  (x y ∈ A))

Lemma: bag-eq-subtype1
[A:Type]. ∀[B:A ⟶ ℙ]. ∀[d1,d2:bag({a:A| B[a]} )].  d1 d2 ∈ bag({a:A| B[a]} supposing d1 d2 ∈ bag(A)

Lemma: bag-eq-subtype
[A:Type]. ∀[d1,d2:bag(A)].  d1 d2 ∈ bag({a:A| a ↓∈ d1} supposing d1 d2 ∈ bag(A)

Lemma: sv-bag-only-filter
[A:Type]. ∀[b:bag(A)]. ∀[p:{x:A| x ↓∈ b}  ⟶ 𝔹].
  ∀x:A. (sv-bag-only([x∈b|p[x]]) x ∈ A) supposing ((↑p[x]) and x ↓∈ and (∀y:A. (y ↓∈  (↑p[y])  (y x ∈ A))))

Lemma: bag-member-map3-deq
[T,U:Type].
  ∀x:U. ∀bs:bag(T). ∀f:{v:T| v ↓∈ bs}  ⟶ U.
    (Inj({v:T| v ↓∈ bs} ;U;f)  (∀x,y:U.  Dec(x y ∈ U))  uiff(x ↓∈ bag-map(f;bs);∃v:T. (v ↓∈ bs ∧ (x (f v) ∈ U)))\000C)

Lemma: b_all-map2
[A,B:Type].
  ∀b:bag(A). ∀f:{a:A| a ↓∈ b}  ⟶ B. ∀P:B ⟶ ℙ.
    ((∀b:B. SqStable(P[b]))  (b_all(B;bag-map(f;b);x.P[x]) ⇐⇒ b_all(A;b;x.P[f x])))

Definition: bag-combine-restrict
bag-combine-restrict(b;x.f[x]) ==  ⋃x∈b.f[x]

Lemma: bag-combine-restrict_wf
[A,B:Type]. ∀[b:bag(A)]. ∀[f:{a:A| a ↓∈ b}  ⟶ bag(B)].  (bag-combine-restrict(b;x.f[x]) ∈ bag(B))

Lemma: bag-only_wf2
[T:Type]. ∀[b:bag(T)].  only(b) ∈ supposing single-valued-bag(b;T) ∧ 0 < #(b)

Lemma: bag-filter-combine
[T,U:Type]. ∀[P:T ⟶ 𝔹]. ∀[f:U ⟶ bag(T)]. ∀[b:bag(U)].  ([x∈⋃z∈b.f[z]|P[x]] = ⋃z∈b.[x∈f[z]|P[x]] ∈ bag(T))

Lemma: bag-filter-combine2
[T,U:Type]. ∀[P:T ⟶ 𝔹]. ∀[f:U ⟶ bag(T)]. ∀[b:bag(U)].  ([x∈⋃z∈b.f[z]|P[x]] = ⋃z∈b.[x∈f[z]|P[x]] ∈ bag({x:T| ↑P[x]} ))

Lemma: bag-mapfilter-combine
[A,B,C:Type]. ∀[b:bag(A)]. ∀[f:A ⟶ bag(B)]. ∀[P:B ⟶ 𝔹]. ∀[g:{x:B| ↑P[x]}  ⟶ C].
  (bag-mapfilter(g;P;⋃x∈b.f[x]) = ⋃x∈b.bag-mapfilter(g;P;f[x]) ∈ bag(C))

Definition: bag-mapfilter-fast
bag-mapfilter-fast(f;P;bs) ==  bag-accum(b,x.if P[x] then f[x].b else fi ;{};bs)

Lemma: bag-mapfilter-fast_wf
[A,B:Type]. ∀[bs:bag(A)]. ∀[P:A ⟶ 𝔹]. ∀[f:{x:A| ↑P[x]}  ⟶ B].  (bag-mapfilter-fast(f;P;bs) ∈ bag(B))

Lemma: bag-mapfilter-fast-eq
[A,B:Type]. ∀[bs:bag(A)]. ∀[P:A ⟶ 𝔹]. ∀[f:{x:A| ↑P[x]}  ⟶ B].
  (bag-mapfilter-fast(f;P;bs) bag-mapfilter(f;P;bs) ∈ bag(B))

Lemma: bag-mapfilter-fast-eq2
[A,B:Type]. ∀[bs:bag(A)]. ∀[P:A ⟶ 𝔹]. ∀[f:{x:A| ↑P[x]}  ⟶ B].
  (bag-mapfilter(f;P;bs) bag-mapfilter-fast(f;P;bs) ∈ bag(B))

Lemma: bag-mapfilter-fast-map
[bs:bag(Top)]. ∀[P,f,g:Top].  (bag-mapfilter-fast(f;P;bag-map(g;bs)) bag-mapfilter-fast(f g;P g;bs))

Lemma: bag-maximals-not-max
[T:Type]. ∀[b:bag(T)]. ∀[R:T ⟶ T ⟶ 𝔹]. ∀[x,y:T].
  (¬↑(R y)) supposing 
     (y ↓∈ bag-maximals(b;R) and 
     x ↓∈ bag-maximals(b;R) and 
     (∀x,y:T.  ((↑(R y))  (↑(R x))  (x y ∈ T))) and 
     (∀x:T. (¬↑(R x))))

Lemma: bag-maximal?-max
[T:Type]. ∀[b:bag(T)]. ∀[R:T ⟶ T ⟶ 𝔹]. ∀[x,y:T].  (↑(R y)) supposing ((↑bag-maximal?(b;x;R)) and y ↓∈ b)

Lemma: bag-maximal?-iff
[T:Type]. ∀[b:bag(T)]. ∀[R:T ⟶ T ⟶ 𝔹]. ∀[x:T].  uiff(↑bag-maximal?(b;x;R);∀y:T. (y ↓∈  (↑(R y))))

Lemma: bag-maximals-max
[T:Type]. ∀[b:bag(T)]. ∀[R:T ⟶ T ⟶ 𝔹]. ∀[x,y:T].  (↑(R y)) supposing (x ↓∈ bag-maximals(b;R) and y ↓∈ b)

Lemma: imax-bag-ub
[bs:bag(ℤ)]. ∀[x:ℤ].  (x ↓∈ bs  (x ≤ imax-bag(bs)))

Lemma: imax-bag-lb
[bs:bag(ℤ)]. (0 < #(bs)  imax-bag(bs) ↓∈ bs)

Definition: bag-max
bag-max(f;bs) ==  imax-bag(bag-map(f;bs))

Lemma: bag-max_wf
[A:Type]. ∀[f:A ⟶ ℤ]. ∀[bs:bag(A)].  bag-max(f;bs) ∈ ℤ supposing 0 < #(bs)

Lemma: bag-max-ub
[A:Type]. ∀[f:A ⟶ ℤ]. ∀[bs:bag(A)]. ∀[x:A].  (f x) ≤ bag-max(f;bs) supposing x ↓∈ bs

Lemma: bag-max-lb
[A:Type]. ∀[f:A ⟶ ℤ]. ∀[bs:bag(A)].  bag-max(f;bs) ↓∈ bag-map(f;bs) supposing 0 < #(bs)

Lemma: bag-append-no-repeats1
[T:Type]. ∀[as,bs:bag(T)].
  bag-no-repeats(T;as bs) supposing bag-no-repeats(T;as) ∧ bag-no-repeats(T;bs) ∧ (∀z:T. (z ↓∈ as  z ↓∈ bs)))

Lemma: bag-append-no-repeats
[T:Type]. ∀[as,bs:bag(T)].
  uiff(bag-no-repeats(T;as) ∧ bag-no-repeats(T;bs) ∧ (∀z:T. (z ↓∈ as  z ↓∈ bs)));bag-no-repeats(T;as bs))

Lemma: bag-product-no-repeats
[A,B:Type]. ∀[as:bag(A)]. ∀[bs:bag(B)].
  bag-no-repeats(A × B;as × bs) supposing bag-no-repeats(A;as) ∧ bag-no-repeats(B;bs)

Lemma: bag-no-repeats-implies-disjoint
[T:Type]. ∀[as,bs:bag(T)].  bag-disjoint(T;as;bs) supposing bag-no-repeats(T;as bs)

Lemma: bag-settype
[T:Type]. ∀[bs:bag(T)]. ∀[P:T ⟶ ℙ].  bs ∈ bag({x:T| P[x]} supposing ∀x:T. (x ↓∈ bs  P[x])

Lemma: bag-filter-same
[T:Type]. ∀[p:T ⟶ 𝔹]. ∀[bs:bag(T)].  [x∈bs|p[x]] bs ∈ bag(T) supposing ∀x:T. (x ↓∈ bs  (↑p[x]))

Lemma: bag-extensionality-no-repeats
[T:Type]
  ((∀x,y:T.  Dec(x y ∈ T))
   (∀[as,bs:bag(T)].
        uiff(as bs ∈ bag(T);∀x:T. uiff(x ↓∈ as;x ↓∈ bs)) supposing bag-no-repeats(T;as) ∧ bag-no-repeats(T;bs)))

Lemma: bag-extensionality1
[T:Type]. ∀[eq:T ⟶ T ⟶ 𝔹].
  ∀[as,bs:bag(T)].  uiff(as bs ∈ bag(T);∀x:T. (#([y∈as|eq y]) #([y∈bs|eq y]) ∈ ℤ)) 
  supposing ∀[x,y:T].  (↑(eq y) ⇐⇒ y ∈ T)

Lemma: bag-intersection
[A:Type]. ∀[as,as',bs,bs':bag(A)].
  (↓∃x:A. (x ↓∈ as ∧ x ↓∈ bs)) supposing (#(as') < #(as) and #(bs') < #(bs) and ((as as') (bs bs') ∈ bag(A)))

Definition: bag-splits
bag-splits(b) ==  rec-case(b) of [] => {<{}, {}>a::as => r.bag-map(λp.<{a} (fst(p)), snd(p)>;r) bag-map(λp.<fst(\000Cp), {a} (snd(p))>;r)

Lemma: bag-splits_wf_list
T:Type. ∀b:T List.  (bag-splits(b) ∈ (bag(T) × bag(T)) List)

Lemma: bag-splits-permutation1
T:Type. ∀L:T List. ∀a,b:T.  permutation(bag(T) × bag(T);bag-splits([a; [b L]]);bag-splits([b; [a L]]))

Lemma: bag-splits-permutation
T:Type. ∀L1,L2:T List.  (permutation(T;L1;L2)  permutation(bag(T) × bag(T);bag-splits(L1);bag-splits(L2)))

Lemma: bag-splits_wf
T:Type. ∀b:bag(T).  (bag-splits(b) ∈ bag(bag(T) × bag(T)))

Lemma: bag-member-splits
[T:Type]. ∀[as,bs,cs:bag(T)].  uiff(<as, bs> ↓∈ bag-splits(cs);(as bs) cs ∈ bag(T))

Definition: bag-decomp
bag-decomp(bs) ==  map(λn.remove-nth(n;bs);upto(||bs||))

Lemma: bag-decomp_wf
[T:Type]. ∀[bs:bag(T)].  (bag-decomp(bs) ∈ bag(T × bag(T)))

Lemma: bag-member-decomp
[T:Type]. ∀[bs:bag(T)]. ∀[x:T]. ∀[b:bag(T)].  uiff(<x, b> ↓∈ bag-decomp(bs);({x} b) bs ∈ bag(T))

Lemma: bag-decomp_wf2
[T:Type]. ∀[bs:bag(T)].  (bag-decomp(bs) ∈ bag({p:T × bag(T)| bs ({fst(p)} (snd(p))) ∈ bag(T)} ))

Lemma: no_repeats-bag
[T:Type]. ∀[as,bs:T List].  (no_repeats(T;as)) supposing (no_repeats(T;bs) and (as bs ∈ bag(T)))

Lemma: bag-no-repeats-settype
[T:Type]. ∀[bs:bag(T)].  uiff(bag-no-repeats({x:T| x ↓∈ bs} ;bs);bag-no-repeats(T;bs)) supposing ∀x,y:T.  Dec(x y ∈ T\000C)

Lemma: bag-no-repeats-le-bag-size
[T:Type]. ∀[locs,b:bag(T)].  #(b) ≤ #(locs) supposing bag-no-repeats(T;b) ∧ (∀x:T. (x ↓∈  x ↓∈ locs))

Lemma: bag-no-repeats-single
[T:Type]. ∀[x:T].  bag-no-repeats(T;{x})

Lemma: bag-no-repeats-append
[T:Type]. ∀[as,bs:bag(T)].
  uiff(bag-no-repeats(T;as bs);bag-no-repeats(T;as) ∧ bag-no-repeats(T;bs) ∧ (∀x:T. (x ↓∈ as  x ↓∈ bs))))

Lemma: bag-no-repeats-cons
[T:Type]. ∀[b:bag(T)]. ∀[x:T].  uiff(bag-no-repeats(T;x.b);bag-no-repeats(T;b) ∧ x ↓∈ b))

Lemma: bag-no-repeats-list
[T:Type]. ∀[L:T List].  uiff(bag-no-repeats(T;L);no_repeats(T;L))

Lemma: bag-no-repeats-filter
[T:Type]. ∀[b:bag(T)]. ∀[p:T ⟶ 𝔹].  bag-no-repeats(T;[x∈b|p[x]]) supposing bag-no-repeats(T;b)

Lemma: remove-repeats-wf-bag
[T:Type]. ∀eq:EqDecider(T). ∀bs:bag(T).  (remove-repeats(eq;bs) ∈ bag(T))

Lemma: bag-summation-equal
[T,R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)]. ∀[f,g:T ⟶ R].
  Σ(x∈b). f[x] = Σ(x∈b). g[x] ∈ supposing (∀x:T. (x ↓∈  (f[x] g[x] ∈ R))) ∧ IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-summation-equal2
[T:Type]. ∀[r:Rng]. ∀[f,g:T ⟶ |r|]. ∀[b,c:bag(T)].
  Σ(x∈b). f[x] = Σ(x∈c). g[x] ∈ |r| supposing (∀x:T. (x ↓∈  (f[x] g[x] ∈ |r|))) ∧ (b c ∈ bag(T))

Lemma: bag-summation-is-zero
[T,R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)]. ∀[f:T ⟶ R].
  Σ(x∈b). f[x] zero ∈ supposing (∀x:T. (x ↓∈  (f[x] zero ∈ R))) ∧ IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-summation-single-non-zero
[T,R:Type]. ∀[eq:EqDecider(T)]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)]. ∀[f:T ⟶ R].
  ∀z:T. Σ(x∈b). f[x] = Σ(x∈[x∈b|eq z]). f[x] ∈ supposing ∀x:T. (x ↓∈  ((x z ∈ T) ∨ (f[x] zero ∈ R))) 
  supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-summation-single-non-zero-no-repeats
[T,R:Type]. ∀[eq:EqDecider(T)]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)]. ∀[f:T ⟶ R].
  ∀z:T
    (x∈b). f[x] f[z] ∈ R) supposing 
       ((bag-no-repeats(T;b) ∧ z ↓∈ b) and 
       (∀x:T. (x ↓∈  ((x z ∈ T) ∨ (f[x] zero ∈ R))))) 
  supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-summation-filter
[T,R:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)]. ∀[p:T ⟶ 𝔹]. ∀[f:T ⟶ R].
  Σ(x∈[x∈b|p[x]]). f[x] = Σ(x∈b). if p[x] then f[x] else zero fi  ∈ supposing IsMonoid(R;add;zero) ∧ Comm(R;add)

Lemma: bag-summation-from-upto
[a,b:ℤ]. ∀[f:{a..b-} ⟶ ℤ].  (i∈[a, b)). f[i] = Σ(f[j a] j < a) ∈ ℤ)

Lemma: bag-summation-partition
[A:Type]
  ∀[R,T:Type]. ∀[add:R ⟶ R ⟶ R]. ∀[zero:R]. ∀[b:bag(T)]. ∀[case:T ⟶ A ⟶ 𝔹]. ∀[f:T ⟶ R]. ∀[c:bag(A)].
    Σ(x∈b). f[x] = Σ(z∈c). Σ(x∈[x∈b|case[x;z]]). f[x] ∈ 
    supposing (IsMonoid(R;add;zero) ∧ Comm(R;add))
    ∧ (∀x:{x:T| x ↓∈ b} (∃z:A [(z ↓∈ c ∧ (↑case[x;z]))]))
    ∧ bag-no-repeats(A;c)
    ∧ (∀z1,z2:A. ∀x:T.  ((↑case[x;z1])  (↑case[x;z2])  (z1 z2 ∈ A))) 
  supposing ∀x,y:A.  Dec(x y ∈ A)

Lemma: bag-summation_functionality_wrt_le_1
[T:Type]. ∀[b:bag(T)]. ∀[f,g:T ⟶ ℤ].  Σ(x∈b). f[x] ≤ Σ(x∈b). g[x] supposing ∀x:T. (f[x] ≤ g[x])

Lemma: bag-summation_functionality_wrt_le
[T:Type]. ∀[b:bag(T)]. ∀[f,g:{x:T| x ↓∈ b}  ⟶ ℤ].
  Σ(x∈b). f[x] ≤ Σ(x∈b). g[x] supposing ∀x:T. (x ↓∈  (f[x] ≤ g[x]))

Lemma: bag-summation-equal-implies-all-equal-1
[T:Type]. ∀[b:bag(T)]. ∀[f,g:T ⟶ ℤ].
  (∀x:T. (x ↓∈  (f[x] g[x] ∈ ℤ))) supposing ((Σ(x∈b). g[x] ≤ Σ(x∈b). f[x]) and (∀x:T. (x ↓∈  (f[x] ≤ g[x]))))

Lemma: bag-summation-equal-implies-all-equal
[T:Type]. ∀[b:bag(T)]. ∀[f,g:{x:T| x ↓∈ b}  ⟶ ℤ].
  (∀x:T. (x ↓∈  (f[x] g[x] ∈ ℤ))) supposing ((Σ(x∈b). g[x] ≤ Σ(x∈b). f[x]) and (∀x:T. (x ↓∈  (f[x] ≤ g[x]))))

Definition: strict-bag-function
strict-bag-function(G;L;B;S) ==  ∀x:tuple-type(map(λT.bag(T);L)). ((∀i∈S.x.i {} ∈ bag(L[i]))  ((G x) {} ∈ bag(B)))

Lemma: strict-bag-function_wf
[L:Type List]. ∀[B:Type]. ∀[G:tuple-type(map(λT.bag(T);L)) ⟶ bag(B)]. ∀[S:ℕ||L|| List].
  (strict-bag-function(G;L;B;S) ∈ ℙ)

Lemma: bag-from-member-function
[T:Type]
  ∀bs:bag(T). ∀P,Q:T ⟶ ℙ.
    ((∀i:T. Dec(Q[i]))
     (∀i:T. (i ↓∈ bs  Q[i]  P[i]))
     (∃b:bag(T). ((∀i:T. (i ↓∈ bs  Q[i]  i ↓∈ b)) ∧ (∀i:T. (i ↓∈  P[i])))))

Lemma: bag-from-member-function-exists
[T,A:Type].
  ∀bs:bag(T). ∀P:T ⟶ A ⟶ ℙ.
    ((∀x,y:A.  Dec(x y ∈ A))
     (∀x,y:T.  Dec(x y ∈ T))
     (∀i:T. (i ↓∈ bs  (∃a:A. P[i;a])))
     (∃b:bag(T × A). ((∀i:T. (i ↓∈ bs  i ↓∈ bag-map(λx.(fst(x));b))) ∧ (∀x:T × A. (x ↓∈  P[fst(x);snd(x)])))))

Definition: lifting-gen-list-rev
lifting-gen-list-rev(n;bags) ==
  fix((λlifting-gen-list-rev,m,g. if (n =z m) then {g} else ⋃x∈bags m.lifting-gen-list-rev (m 1) (g x) fi ))

Lemma: lifting-gen-list-rev_wf
[B:Type]. ∀[n:ℕ]. ∀[m:ℕ1]. ∀[A:ℕn ⟶ Type]. ∀[bags:k:ℕn ⟶ bag(A k)]. ∀[g:funtype(n m;λx.(A (x m));B)].
  (lifting-gen-list-rev(n;bags) g ∈ bag(B))

Lemma: temp-lifting-gen-list-rev_wf
[B:Type]. ∀[n:ℕ]. ∀[m:ℕ1]. ∀[A:ℕn ⟶ Type]. ∀[bags:k:ℕn ⟶ bag(A k)]. ∀[g:funtype(n m;λx.(A (x m));B)].
  (lifting-gen-list-rev(n;bags) g ∈ bag(B))

Definition: lifting-gen-rev
lifting-gen-rev(n;f;bags) ==  lifting-gen-list-rev(n;bags) f

Lemma: lifting-gen-rev_wf
[B:Type]. ∀[n:ℕ]. ∀[A:ℕn ⟶ Type]. ∀[bags:k:ℕn ⟶ bag(A k)]. ∀[f:funtype(n;A;B)].  (lifting-gen-rev(n;f;bags) ∈ bag(B))

Definition: lifting-gen
lifting-gen(n;f) ==  λbags.lifting-gen-rev(n;f;bags)

Lemma: lifting-gen_wf
[B:Type]. ∀[n:ℕ]. ∀[A:ℕn ⟶ Type]. ∀[f:funtype(n;A;B)].  (lifting-gen(n;f) ∈ (k:ℕn ⟶ bag(A k)) ⟶ bag(B))

Lemma: lifting-gen-strict
[n:ℕ]. ∀[f:Top]. ∀[a:k:ℕn ⟶ bag(Top)].  lifting-gen(n;f) {} supposing ∃k:ℕn. (↑bag-null(a k))

Definition: lifting1
lifting1(f;b) ==  lifting-gen-rev(1;f;λx.b)

Lemma: lifting1_wf
[A,B:Type]. ∀[f:A ⟶ B]. ∀[b:bag(A)].  (lifting1(f;b) ∈ bag(B))

Definition: lifting2
lifting2(f;abag;bbag) ==  lifting-gen-rev(2;f;λx.[abag; bbag][x])

Lemma: lifting2_wf
[A,B,C:Type]. ∀[f:A ⟶ B ⟶ C]. ∀[abag:bag(A)]. ∀[bbag:bag(B)].  (lifting2(f;abag;bbag) ∈ bag(C))

Definition: lifting-0
lifting-0(b) ==  lifting-gen-rev(0;b;λn.[][n])

Lemma: lifting-0_wf
[B:Type]. ∀[b:B].  (lifting-0(b) ∈ bag(B))

Definition: lifting-1
lifting-1(f) ==  λb.lifting1(f;b)

Lemma: lifting-1_wf
[A,B:Type]. ∀[f:A ⟶ B].  (lifting-1(f) ∈ bag(A) ⟶ bag(B))

Lemma: lifting-1-strict
[f:Top]. (lifting-1(f) {} {})

Definition: lifting-2
lifting-2(f) ==  λa,b. lifting2(f;a;b)

Lemma: lifting-2_wf
[C,B,A:Type]. ∀[f:A ⟶ B ⟶ C].  (lifting-2(f) ∈ bag(A) ⟶ bag(B) ⟶ bag(C))

Lemma: lifting-2-strict
[f:Top]. ∀[b:bag(Top)].  ((lifting-2(f) {} {}) ∧ (lifting-2(f) {} {}))

Definition: lifting-3
lifting-3(f) ==  λa,b,c. lifting-gen-rev(3;f;λn.[a; b; c][n])

Lemma: lifting-3_wf
[A,B,C,D:Type]. ∀[f:A ⟶ B ⟶ C ⟶ D].  (lifting-3(f) ∈ bag(A) ⟶ bag(B) ⟶ bag(C) ⟶ bag(D))

Lemma: lifting-3-strict
[f:Top]. ∀[b:bag(Top)].
  ∀b':bag(Top). ((lifting-3(f) {} b' {}) ∧ (lifting-3(f) {} b' {}) ∧ (lifting-3(f) b' {} {}))

Definition: uncurry-gen
uncurry-gen(n) ==  fix((λrec,m,g. if (m =z n) then else rec (m 1) x.(g (x m))) fi ))

Lemma: uncurry-gen_wf
[B:Type]. ∀[n:ℕ]. ∀[m:ℕ1]. ∀[A:ℕn ⟶ Type]. ∀[g:(k:ℕn ⟶ (A k)) ⟶ funtype(n m;λx.(A (x m));B)].
  (uncurry-gen(n) g ∈ (k:ℕn ⟶ (A k)) ⟶ B)

Lemma: uncurry-gen_wf2
[B:Type]. ∀[n:ℕ]. ∀[m:ℕ1]. ∀[q:ℕ1]. ∀[A:ℕn ⟶ Type].
[g:(k:{q..n-} ⟶ (A k)) ⟶ funtype(n m;λx.(A (x m));B)].
  (uncurry-gen(n) g ∈ (k:{q..n-} ⟶ (A k)) ⟶ B)

Definition: uncurry-rev
uncurry-rev(n;f) ==  uncurry-gen(n) x.f)

Lemma: uncurry-rev_wf
[B:Type]. ∀[n:ℕ]. ∀[A:ℕn ⟶ Type]. ∀[f:funtype(n;A;B)].  (uncurry-rev(n;f) ∈ (k:ℕn ⟶ (A k)) ⟶ B)

Definition: apply_gen
apply_gen(n;lst) ==  fix((λrec,m,g. if (m =z n) then else rec (m 1) (g (lst m)) fi ))

Lemma: apply_gen_wf
[B:Type]. ∀[n:ℕ]. ∀[m:ℕ1]. ∀[A:ℕn ⟶ Type]. ∀[f:funtype(n m;λx.(A (x m));B)]. ∀[lst:k:{m..n-} ⟶ (A k)].
  (apply_gen(n;lst) f ∈ B)

Lemma: apply_gen_wf2
[B:Type]. ∀[n:ℕ]. ∀[m:ℕ1]. ∀[q:ℕ1]. ∀[A:ℕn ⟶ Type]. ∀[f:funtype(n q;λx.(A (x q));B)].
[lst:k:{q..n-} ⟶ (A k)].
  (apply_gen(m;lst) f ∈ funtype(n m;λx.(A (x m));B))

Lemma: apply_uncurry
[B:Type]. ∀[n:ℕ]. ∀[m:ℕ1]. ∀[q:ℕ1]. ∀[A:ℕn ⟶ Type]. ∀[lst:k:{q..n-} ⟶ (A k)].
[f:(k:{q..n-} ⟶ (A k)) ⟶ funtype(n m;λx.(A (x m));B)].
  ((uncurry-gen(n) lst) (apply_gen(n;lst) (f lst)) ∈ B)

Lemma: apply_larger_list
[B:Type]. ∀[n:ℕ]. ∀[m:ℕ1]. ∀[q:ℕ1]. ∀[A:ℕn ⟶ Type]. ∀[lst:k:{q..n-} ⟶ (A k)]. ∀[r:ℕm]. ∀[a:A r].
[f:funtype(n m;λx.(A (x m));B)].
  ((apply_gen(n;λx.if (x =z r) then else lst fi f) (apply_gen(n;lst) f) ∈ B)

Lemma: lifting-member
[B:Type]. ∀[n:ℕ]. ∀[m:ℕ1]. ∀[A:ℕn ⟶ Type]. ∀[bags:k:ℕn ⟶ bag(A k)]. ∀[f:funtype(n m;λx.(A (x m));B)]. ∀[b:B].
  (b ↓∈ lifting-gen-list-rev(n;bags) f
  ⇐⇒ ↓∃lst:k:{m..n-} ⟶ (A k). ((∀[k:{m..n-}]. lst k ↓∈ bags k) ∧ ((uncurry-gen(n) x.f) lst) b ∈ B)))

Lemma: lifting-member-simple
[B:Type]. ∀[n:ℕ]. ∀[A:ℕn ⟶ Type]. ∀[bags:k:ℕn ⟶ bag(A k)]. ∀[f:funtype(n;A;B)]. ∀[b:B].
  (b ↓∈ lifting-gen-rev(n;f;bags)
  ⇐⇒ ↓∃lst:k:ℕn ⟶ (A k). ((∀[k:ℕn]. lst k ↓∈ bags k) ∧ ((uncurry-rev(n;f) lst) b ∈ B)))

Lemma: bag-member-lifting-2
[C,B,A:Type]. ∀[f:A ⟶ B ⟶ C]. ∀[as:bag(A)]. ∀[bs:bag(B)]. ∀[c:C].
  uiff(c ↓∈ lifting-2(f) as bs;↓∃a:A. ∃b:B. (a ↓∈ as ∧ b ↓∈ bs ∧ (c (f b) ∈ C)))

Definition: concat-lifting-list
concat-lifting-list(n;bags) ==  λm,g. bag-union(lifting-gen-list-rev(n;bags) g)

Lemma: concat-lifting-list_wf
[B:Type]. ∀[n:ℕ]. ∀[m:ℕ1]. ∀[A:ℕn ⟶ Type]. ∀[bags:k:ℕn ⟶ bag(A k)]. ∀[g:funtype(n m;λx.(A (x m));bag(B))].
  (concat-lifting-list(n;bags) g ∈ bag(B))

Lemma: concat-lifting-list-member
[B:Type]. ∀[n:ℕ]. ∀[m:ℕ1]. ∀[A:ℕn ⟶ Type]. ∀[bags:k:ℕn ⟶ bag(A k)]. ∀[f:funtype(n m;λx.(A (x m));bag(B))].
[b:B].
  (b ↓∈ concat-lifting-list(n;bags) f
  ⇐⇒ ↓∃lst:k:{m..n-} ⟶ (A k). ((∀[k:{m..n-}]. lst k ↓∈ bags k) ∧ b ↓∈ uncurry-gen(n) x.f) lst))

Definition: concat-lifting
concat-lifting(n;f;bags) ==  concat-lifting-list(n;bags) f

Lemma: concat-lifting_wf
[B:Type]. ∀[n:ℕ]. ∀[A:ℕn ⟶ Type]. ∀[bags:k:ℕn ⟶ bag(A k)]. ∀[f:funtype(n;A;bag(B))].
  (concat-lifting(n;f;bags) ∈ bag(B))

Lemma: concat-lifting-member
[B:Type]. ∀[n:ℕ]. ∀[A:ℕn ⟶ Type]. ∀[bags:k:ℕn ⟶ bag(A k)]. ∀[f:funtype(n;A;bag(B))]. ∀[b:B].
  (b ↓∈ concat-lifting(n;f;bags) ⇐⇒ ↓∃lst:k:ℕn ⟶ (A k). ((∀[k:ℕn]. lst k ↓∈ bags k) ∧ b ↓∈ uncurry-rev(n;f) lst))

Lemma: concat-lifting-strict
[n:ℕ]. ∀[bags:k:ℕn ⟶ bag(Top)]. ∀[f:Top].  concat-lifting(n;f;bags) {} supposing ∃k:ℕn. ((bags k) {} ∈ bag(Top))

Definition: concat-lifting-gen
concat-lifting-gen(n;f) ==  λbags.concat-lifting(n;f;bags)

Lemma: concat-lifting-gen_wf
[B:Type]. ∀[n:ℕ]. ∀[A:ℕn ⟶ Type]. ∀[f:funtype(n;A;bag(B))].  (concat-lifting-gen(n;f) ∈ (k:ℕn ⟶ bag(A k)) ⟶ bag(B))

Definition: concat-lifting1
concat-lifting1(f;bag) ==  concat-lifting(1;f;λx.bag)

Lemma: concat-lifting1_wf
[A,B:Type]. ∀[f:A ⟶ bag(B)]. ∀[b:bag(A)].  (concat-lifting1(f;b) ∈ bag(B))

Definition: concat-lifting2
concat-lifting2(f;abag;bbag) ==  concat-lifting(2;f;λn.[abag; bbag][n])

Lemma: concat-lifting2_wf
[A,B,C:Type]. ∀[f:A ⟶ B ⟶ bag(C)]. ∀[abag:bag(A)]. ∀[bbag:bag(B)].  (concat-lifting2(f;abag;bbag) ∈ bag(C))

Definition: concat-lifting-0
concat-lifting-0(f) ==  concat-lifting(0;f;λn.[][n])

Lemma: concat-lifting-0_wf
[B:Type]. ∀[f:bag(B)].  (concat-lifting-0(f) ∈ bag(B))

Definition: concat-lifting-1
f@ ==  λb.concat-lifting1(f;b)

Lemma: concat-lifting-1_wf
[B,A:Type]. ∀[f:A ⟶ bag(B)].  (f@ ∈ bag(A) ⟶ bag(B))

Lemma: concat-lifting-1-strict
[f:Top]. (f@ {} {})

Definition: concat-lifting-2
f@ ==  λa,b. concat-lifting2(f;a;b)

Lemma: concat-lifting-2_wf
[A,B,C:Type]. ∀[f:A ⟶ B ⟶ bag(C)].  (f@ ∈ bag(A) ⟶ bag(B) ⟶ bag(C))

Lemma: concat-lifting-2-strict
[f:Top]. ∀[b:bag(Top)].  ((f@ {} {}) ∧ (f@ {} {}))

Definition: concat-lifting-3
concat-lifting-3(f) ==  λa,b,c. concat-lifting(3;f;λn.[a; b; c][n])

Lemma: concat-lifting-3_wf
[A,B,C,D:Type]. ∀[f:A ⟶ B ⟶ C ⟶ bag(D)].  (concat-lifting-3(f) ∈ bag(A) ⟶ bag(B) ⟶ bag(C) ⟶ bag(D))

Lemma: concat-lifting-3-strict
[f:Top]. ∀[b:bag(Top)].
  ∀b':bag(Top)
    ((concat-lifting-3(f) {} b' {}) ∧ (concat-lifting-3(f) {} b' {}) ∧ (concat-lifting-3(f) b' {} {}))

Lemma: bag-map-append-empty
[f,b:Top].  (bag-map(f;b) {} bag-map(f;b))

Lemma: bag-combine-append-empty
[f,bs:Top].  (⋃x∈bs.f[x] [] ~ ⋃x∈bs.f[x])

Lemma: bag-combine-bag-append-empty
[f,bs:Top].  (⋃x∈bs.f[x] [] ~ ⋃x∈bs.f[x])

Definition: bag-monoid
bag-monoid(T) ==  <bag(T), λx,y. tt, λx,y. tt, λx,y. (x y), {}, λx.x>

Lemma: bag-monoid_wf
[T:Type]. (bag-monoid(T) ∈ AbMon)

Lemma: single-bag-append-nil
[a:Top]. ([a] [] [a])

Lemma: spread-bag-append
[x,F,L:Top].  (let a,b in F[a;b] let a,b in F[a;b] L)

Lemma: callbyvalueall-single-bag-combine1
[F,a,as:Top].  (let x ⟵ [a] in let y ⟵ ⋃z∈x.map(z;as) in F[y] let x ⟵ in let y ⟵ map(x;as) in F[y])

Lemma: callbyvalueall-single-bag-combine2
[F,G,a:Top].  (let x ⟵ [a] in let y ⟵ ⋃z∈x.G[z] in F[y] let x ⟵ in let y ⟵ G[x] [] in F[y])

Lemma: callbyvalueall-single-bag-combine3
[F,G,a,b:Top].
  (let x ⟵ [a]
   in let z ⟵ b
      in let y ⟵ ⋃v∈x.G[z;v]
         in F[z;y] let x ⟵ a
                     in let z ⟵ b
                        in let y ⟵ G[z;x] []
                           in F[z;y])

Lemma: callbyvalueall-single-bag-combine4
[F,a:Top].  (let x ⟵ [a] in F[x] let x ⟵ in F[[x]])

Lemma: lifting-bag-combine-decide
[a,F,G,f:Top].
  (⋃b∈case of inl(x) => F[x] inr(x) => G[x].f[b] case of inl(x) => ⋃b∈F[x].f[b] inr(x) => ⋃b∈G[x].f[b])

Lemma: lifting-bag-combine-decide-name_eq
[a,b,F,G,f:Top].
  (⋃b∈case name_eq(a;b) of inl(x) => F[x] inr(x) => G[x].f[b] case name_eq(a;b)
   of inl(x) =>
   ⋃b∈F[x].f[b]
   inr(x) =>
   ⋃b∈G[x].f[b])

Definition: bag-admissable
bag-admissable(T;as,bs.R[as; bs]) ==  (∀bs:bag(T). R[{}; bs]) ∧ (∀as,bs,cs:bag(T).  (R[as; bs]  R[as cs; bs cs]))

Lemma: bag-admissable_wf
[T:Type]. ∀[R:bag(T) ⟶ bag(T) ⟶ ℙ].  (bag-admissable(T;as,bs.R[as;bs]) ∈ ℙ)

Lemma: sub-bag-admissable
[T:Type]. ∀[R:bag(T) ⟶ bag(T) ⟶ ℙ].
  (bag-admissable(T;as,bs.R[as;bs])  (∀as,bs:bag(T).  (sub-bag(T;as;bs)  R[as;bs])))

Lemma: sub-bag-singleton-left
[T:Type]. ∀[b:bag(T)]. ∀[x:T].  x ↓∈ supposing sub-bag(T;{x};b)

Lemma: sub-bag-map-equal
[T,U:Type]. ∀[b1,b2:bag(T)]. ∀[f:T ⟶ U].
  (b1 b2 ∈ bag(T)) supposing (sub-bag(T;b2;b1) and sub-bag(U;bag-map(f;b1);bag-map(f;b2)))

Lemma: sub-bag-mapfilter-implies
[A,B:Type].
  ∀as:bag(A). ∀bs:bag(B). ∀f:A ⟶ B. ∀P:A ⟶ 𝔹.  (sub-bag(B;bag-map(f;as);bs)  sub-bag(B;bag-mapfilter(f;P;as);bs))

Lemma: sub-bag-size
[T:Type]. ∀[a,b:bag(T)].  #(a) ≤ #(b) supposing sub-bag(T;a;b)

Definition: bag-order
bag-order(T) ==
  {cmp:bag(T) ⟶ bag(T) ⟶ ℤ
   (∀as,bs:bag(T).  (((cmp as bs) 0 ∈ ℤ ⇐⇒ as bs ∈ bag(T)) ∧ (cmp as bs < ⇐⇒ (cmp bs as) > 0)))
   ∧ Linorder(bag(T);as,bs.(cmp as bs) ≤ 0)} 

Lemma: bag-order_wf
T:Type. (bag-order(T) ∈ Type)

Definition: unordered-combination
UnorderedCombination(n;T) ==  {b:bag(T)| bag-no-repeats(T;b) ∧ (#(b) n ∈ ℤ)} 

Lemma: unordered-combination_wf
[T:Type]. ∀[n:ℕ].  (UnorderedCombination(n;T) ∈ Type)

Lemma: unordered-combination_functionality
[A,B:Type].  ∀n,m:ℕ.  (A  UnorderedCombination(n;A) UnorderedCombination(m;B) supposing m ∈ ℤ)

Lemma: subtype_rel_unordered-combination
[A,B:Type].  ∀n:ℕUnorderedCombination(n;A) ⊆UnorderedCombination(n;B) supposing strong-subtype(A;B)

Definition: bag-incomparable
bag-incomparable(T;R;b) ==  ∀x,y:T.  (x ↓∈  y ↓∈  (x y)))

Lemma: bag-incomparable_wf
[T:Type]. ∀[R:T ⟶ T ⟶ ℙ]. ∀[b:bag(T)].  (bag-incomparable(T;R;b) ∈ ℙ)

Definition: bag-covers
bag-covers(T;R;cvr;b) ==  ∀x:T. (x ↓∈  (x ↓∈ cvr ∨ (∃y:T. (y ↓∈ cvr ∧ (x y)))))

Lemma: bag-covers_wf
[T:Type]. ∀[R:T ⟶ T ⟶ ℙ]. ∀[cvr,b:bag(T)].  (bag-covers(T;R;cvr;b) ∈ ℙ)

Definition: bag-cover
bag-cover(T;R;mx;b) ==  sub-bag(T;mx;b) ∧ bag-covers(T;R;mx;b) ∧ bag-incomparable(T;R;mx)

Lemma: bag-cover_wf
[T:Type]. ∀[R:T ⟶ T ⟶ ℙ]. ∀[cvr,b:bag(T)].  (bag-cover(T;R;cvr;b) ∈ ℙ)

Definition: monad-from
monad-from(Mnd) ==
  mk-monad(functor(ob(T) M-map(Mnd) T;
                   arrow(X,Y,f) = λz.(M-bind(Mnd) x.(M-return(Mnd) (f x)))));
           λx.M-return(Mnd);
           λx,z. (M-bind(Mnd) x.x)))

Lemma: monad-from_wf
[Mnd:Monad]. (monad-from(Mnd) ∈ Monad(TypeCat))

Definition: bag-cat-monad
bag-cat-monad() ==  mk-monad(functor(ob(x) bag(x);arrow(x,y,f) = λz.bag-map(f;z));x |→ λz.{z};x |→ λz.bag-union(z))

Lemma: bag-cat-monad_wf
bag-cat-monad() ∈ Monad(TypeCat)

Definition: bag-bind
bag-bind(bs;f) ==  bag-union(bag-map(f;bs))

Lemma: bag-bind_wf
[A,B:Type]. ∀[bs:bag(A)]. ∀[f:A ⟶ bag(B)].  (bag-bind(bs;f) ∈ bag(B))

Lemma: bag-bind-assoc
[A,B,C:Type]. ∀[f:A ⟶ bag(B)]. ∀[g:B ⟶ bag(C)]. ∀[bs:bag(A)].
  (bag-bind(bag-bind(bs;f);g) bag-bind(bs;λa.bag-bind(f a;g)) ∈ bag(C))

Lemma: bag-bind-empty-right
A:Type. ∀ba:bag(A).  (bag-bind(ba;λa.{}) {})

Lemma: bag-bind-append
[A,B:Type]. ∀[ba,bb:bag(A)]. ∀[f:A ⟶ bag(B)].  (bag-bind(ba bb;f) (bag-bind(ba;f) bag-bind(bb;f)) ∈ bag(B))

Lemma: bag-bind-append2
[A,B:Type]. ∀[F,G:A ⟶ bag(B)]. ∀[ba:bag(A)].
  (bag-bind(ba;λa.((F a) (G a))) (bag-bind(ba;F) bag-bind(ba;G)) ∈ bag(B))

Lemma: bag-bind-com
[A,B,C:Type]. ∀[f:A ⟶ B ⟶ bag(C)]. ∀[ba:bag(A)]. ∀[bb:bag(B)].
  (bag-bind(ba;λa.bag-bind(bb;λb.f[a;b])) bag-bind(bb;λb.bag-bind(ba;λa.f[a;b])) ∈ bag(C))

Lemma: bag-bind-filter
[A,B:Type]. ∀[p:A ⟶ 𝔹]. ∀[f:{a:A| ↑p[a]}  ⟶ bag(B)]. ∀[ba:bag(A)].
  (bag-bind([a∈ba|p[a]];λa.f[a]) bag-bind(ba;λa.if p[a] then f[a] else {} fi ) ∈ bag(B))



Home Index