1-- Inclusion–exclusion for finite sets: differences, unions of two and three2-- sets, the subtraction forms, and the symmetric difference3-- Part of Cumulus, the Grace17 mathematics library.4-- Copyright (c) 2026 Grant Passmore.5-- Released under the Apache License 2.0. See LICENSE in the repository root.6-- Authors: Grant Passmore78module Grace.Cumulus.Combinatorics.InclusionExclusion9import Basics1011theorem Finite.intersection_left (A B : Set)12requires finite : Finite(A)13shows Finite(A ∩ B)14proof15exact Finite.subset with finite, (intersection.subset_left at A, B)1617theorem Finite.intersection_right (A B : Set)18requires finite : Finite(B)19shows Finite(A ∩ B)20proof21exact Finite.subset with finite, (intersection.subset_right at A, B)2223theorem Finite.symmetricDifference (A B : Set)24requires finiteA : Finite(A)25requires finiteB : Finite(B)26shows Finite(A △ B)27proof28unfold symmetricDifference29exact Finite.union with (Finite.difference at A, B with finiteA),30 (Finite.difference at B, A with finiteB)3132-- A finite set splits into the part inside B and the part outside B.33theorem cardinality.difference_add_intersection (A B : Set)34requires finite : Finite(A)35shows cardinality(A ∖ B) + cardinality(A ∩ B) = cardinality(A)36proof37have finiteRest := Finite.difference at A, B with finite38have finiteMeet := Finite.intersection_left at A, B with finite39have disjoint : Disjoint(A ∖ B, A ∩ B)40unfold Disjoint41ext x42simp43havesplit : (A ∖ B) ∪ (A ∩ B) = A44ext x45simp46have count := cardinality.union_disjoint with finiteRest, finiteMeet, disjoint47rwsplitat count48 symm49exact count5051theorem cardinality.difference_count (A B : Set)52requires finite : Finite(A)53shows cardinality(A ∖ B) = cardinality(A) - cardinality(A ∩ B)54proof55havesplit:= cardinality.difference_add_intersection at A, B with finite56have natRest := cardinality.nat with (Finite.difference at A, B with finite)57have natMeet := cardinality.nat with (Finite.intersection_left at A, B with58 finite)59rw←split60 symm61exact sub.add_right at cardinality(A ∖ B), cardinality(A ∩ B)6263theorem cardinality.intersection_le_left (A B : Set)64requires finite : Finite(A)65shows cardinality(A ∩ B) ≤ cardinality(A)66proof67exact cardinality.monotone with finite, (intersection.subset_left at A, B)6869theorem cardinality.intersection_le_right (A B : Set)70requires finite : Finite(B)71shows cardinality(A ∩ B) ≤ cardinality(B)72proof73exact cardinality.monotone with finite, (intersection.subset_right at A, B)7475theorem cardinality.difference_le (A B : Set)76requires finite : Finite(A)77shows cardinality(A ∖ B) ≤ cardinality(A)78proof79exact cardinality.monotone with finite, (difference.subset_left at A, B)8081theorem cardinality.difference_add_of_subset (A B : Set)82requires finite : Finite(A)83requires subset : B ⊆ A84shows cardinality(A ∖ B) + cardinality(B) = cardinality(A)85proof86havesplit:= cardinality.difference_add_intersection at A, B with finite87have meet : A ∩ B = B88ext x89simp90rw meet atsplit91exactsplit9293theorem cardinality.difference_of_subset (A B : Set)94requires finite : Finite(A)95requires subset : B ⊆ A96shows cardinality(A ∖ B) = cardinality(A) - cardinality(B)97proof98havesplit:= cardinality.difference_add_of_subset with finite, subset99have natRest := cardinality.nat with (Finite.difference at A, B with finite)100have natB := cardinality.nat with (Finite.subset with finite, subset)101rw←split102 symm103exact sub.add_right at cardinality(A ∖ B), cardinality(B)104105theorem cardinality.union_sub (A B : Set)106requires finiteA : Finite(A)107requires finiteB : Finite(B)108shows109 cardinality(A ∪ B) = cardinality(A) + cardinality(B) - cardinality(A ∩ B)110proof111have both := cardinality.inclusion_exclusion with finiteA, finiteB112have natUnion := cardinality.nat with (Finite.union with finiteA, finiteB)113have natMeet := cardinality.nat with (Finite.intersection_left at A, B with114 finiteA)115rw← both116 symm117exact sub.add_right at cardinality(A ∪ B), cardinality(A ∩ B)118119theorem cardinality.union_le (A B : Set)120requires finiteA : Finite(A)121requires finiteB : Finite(B)122shows cardinality(A ∪ B) ≤ cardinality(A) + cardinality(B)123proof124have both := cardinality.inclusion_exclusion with finiteA, finiteB125have natUnion := cardinality.nat with (Finite.union with finiteA, finiteB)126have natMeet := cardinality.nat with (Finite.intersection_left at A, B with127 finiteA)128have natA := cardinality.nat with finiteA129have natB := cardinality.nat with finiteB130arith131132theorem cardinality.union_ge_left (A B : Set)133requires finiteA : Finite(A)134requires finiteB : Finite(B)135shows cardinality(A) ≤ cardinality(A ∪ B)136proof137have finiteUnion := Finite.union with finiteA, finiteB138exact cardinality.monotone with finiteUnion, (union2.subset_left at A, B)139140theorem cardinality.union_ge_right (A B : Set)141requires finiteA : Finite(A)142requires finiteB : Finite(B)143shows cardinality(B) ≤ cardinality(A ∪ B)144proof145have finiteUnion := Finite.union with finiteA, finiteB146exact cardinality.monotone with finiteUnion, (union2.subset_right at A, B)147148theorem cardinality.le_add_of_cover (S A B : Set)149requires finiteA : Finite(A)150requires finiteB : Finite(B)151requires cover : S ⊆ A ∪ B152shows cardinality(S) ≤ cardinality(A) + cardinality(B)153proof154have finiteUnion := Finite.union with finiteA, finiteB155have inside := cardinality.monotone with finiteUnion, cover156have bound := cardinality.union_le with finiteA, finiteB157have natS := cardinality.nat with (Finite.subset with finiteUnion, cover)158have natUnion := cardinality.nat with finiteUnion159have natA := cardinality.nat with finiteA160have natB := cardinality.nat with finiteB161exact LessEqual.transitive with inside, bound162163-- The union has the full count exactly when the sets are disjoint.164theorem cardinality.union_eq_add_iff_disjoint (A B : Set)165requires finiteA : Finite(A)166requires finiteB : Finite(B)167shows cardinality(A ∪ B) = cardinality(A) + cardinality(B) ↔ Disjoint(A, B)168proof169constructor170 . intro full171have both := cardinality.inclusion_exclusion with finiteA, finiteB172rw full at both173have finiteMeet := Finite.intersection_left at A, B with finiteA174have natMeet := cardinality.nat with finiteMeet175have natA := cardinality.nat with finiteA176have natB := cardinality.nat with finiteB177have zero : cardinality(A ∩ B) =0178have le : cardinality(A ∩ B) ≤0byarith179have ge : 0≤ cardinality(A ∩ B) byarith180exact LessEqual.antisymmetric with le, ge181have iff := cardinality.eq_zero_iff with finiteMeet182unfold Disjoint183exact iff.forward with zero184 . intro disjoint185exact cardinality.union_disjoint with finiteA, finiteB, disjoint186187-- Inclusion–exclusion for three sets.188theorem cardinality.union_three (A B C : Set)189requires finiteA : Finite(A)190requires finiteB : Finite(B)191requires finiteC : Finite(C)192shows cardinality(A ∪ B ∪ C) + cardinality(A ∩ B) + cardinality(A ∩ C) +193 cardinality(B ∩ C) =194 cardinality(A) + cardinality(B) + cardinality(C) + cardinality(A ∩ B ∩ C)195proof196have finiteAB := Finite.union with finiteA, finiteB197have finiteAC := Finite.intersection_left at A, C with finiteA198have finiteBC := Finite.intersection_left at B, C with finiteB199have outer := cardinality.inclusion_exclusion with finiteAB, finiteC200have inner := cardinality.inclusion_exclusion with finiteA, finiteB201have meetSplit : (A ∪ B) ∩ C = (A ∩ C) ∪ (B ∩ C)202ext x203simp204have meetMeet : (A ∩ C) ∩ (B ∩ C) = A ∩ B ∩ C205ext x206simp207have meets := cardinality.inclusion_exclusion with finiteAC, finiteBC208rw meetSplit at outer209rw meetMeet at meets210have natUnion := cardinality.nat with (Finite.union with finiteAB, finiteC)211have natAB := cardinality.nat with finiteAB212have natMeetAB := cardinality.nat with (Finite.intersection_left at A, B with213 finiteA)214have natAC := cardinality.nat with finiteAC215have natBC := cardinality.nat with finiteBC216have natACBC := cardinality.nat with (Finite.union with finiteAC, finiteBC)217have natABC := cardinality.nat with (Finite.intersection_left at A ∩ B, C with (Finite.intersection_left at A, B with finiteA))218have natA := cardinality.nat with finiteA219have natB := cardinality.nat with finiteB220have natC := cardinality.nat with finiteC221have le : cardinality(A ∪ B ∪ C) + cardinality(A ∩ B) + cardinality(A ∩ C) + cardinality(B ∩ C) ≤ cardinality(A) + cardinality(B) + cardinality(C) + cardinality(A ∩ B ∩ C) byarith222have ge : cardinality(A) + cardinality(B) + cardinality(C) + cardinality(A ∩ B ∩ C) ≤ cardinality(A ∪ B ∪ C) + cardinality(A ∩ B) + cardinality(A ∩ C) + cardinality(B ∩ C) byarith223exact LessEqual.antisymmetric with le, ge224225theorem cardinality.union_three_le (A B C : Set)226requires finiteA : Finite(A)227requires finiteB : Finite(B)228requires finiteC : Finite(C)229shows230 cardinality(A ∪ B ∪ C) ≤ cardinality(A) + cardinality(B) + cardinality(C)231proof232have finiteAB := Finite.union with finiteA, finiteB233have first := cardinality.union_le with finiteAB, finiteC234have second := cardinality.union_le with finiteA, finiteB235have natABC := cardinality.nat with (Finite.union with finiteAB, finiteC)236have natAB := cardinality.nat with finiteAB237have natA := cardinality.nat with finiteA238have natB := cardinality.nat with finiteB239have natC := cardinality.nat with finiteC240arith241242theorem cardinality.union_three_disjoint (A B C : Set)243requires finiteA : Finite(A)244requires finiteB : Finite(B)245requires finiteC : Finite(C)246requires disjointAB : Disjoint(A, B)247requires disjointAC : Disjoint(A, C)248requires disjointBC : Disjoint(B, C)249shows250 cardinality(A ∪ B ∪ C) = cardinality(A) + cardinality(B) + cardinality(C)251proof252have finiteAB := Finite.union with finiteA, finiteB253have disjoint : Disjoint(A ∪ B, C)254have leftFree := Disjoint.iff.forward with disjointAC255have rightFree := Disjoint.iff.forward with disjointBC256apply Disjoint.iff.backward257intros x hx258havesplit:= union2.membership.forward with hx259casessplitwith inA | inB260 . exact leftFree with x, inA261 . exact rightFree with x, inB262have outer := cardinality.union_disjoint with finiteAB, finiteC, disjoint263have inner := cardinality.union_disjoint with finiteA, finiteB, disjointAB264rw [outer, inner]265rfl266267-- The symmetric difference counts each set once and the overlap twice less.268theorem cardinality.symmetricDifference_add (A B : Set)269requires finiteA : Finite(A)270requires finiteB : Finite(B)271shows cardinality(A △ B) +2* cardinality(A ∩ B) =272 cardinality(A) + cardinality(B)273proof274have finiteAB := Finite.difference at A, B with finiteA275have finiteBA := Finite.difference at B, A with finiteB276have disjoint : Disjoint(A ∖ B, B ∖ A)277unfold Disjoint278ext x279simp280havesplit:= cardinality.union_disjoint with finiteAB, finiteBA, disjoint281haveleft:= cardinality.difference_add_intersection at A, B with finiteA282haveright:= cardinality.difference_add_intersection at B, A with finiteB283have commute := intersection.commutative at B, A284rw commute atright285have natAB := cardinality.nat with finiteAB286have natBA := cardinality.nat with finiteBA287have natMeet := cardinality.nat with (Finite.intersection_left at A, B with288 finiteA)289have natA := cardinality.nat with finiteA290have natB := cardinality.nat with finiteB291unfold symmetricDifference292rwsplit293have le : cardinality(A ∖ B) + cardinality(B ∖ A) +2* cardinality(A ∩ B) ≤ cardinality(A) + cardinality(B) byarith294have ge : cardinality(A) + cardinality(B) ≤ cardinality(A ∖ B) + cardinality(B ∖ A) +2* cardinality(A ∩ B) byarith295exact LessEqual.antisymmetric with le, ge296297theorem cardinality.symmetricDifference_sub (A B : Set)298requires finiteA : Finite(A)299requires finiteB : Finite(B)300shows cardinality(A △ B) =301 cardinality(A) + cardinality(B) - 2* cardinality(A ∩ B)302proof303havesplit:= cardinality.symmetricDifference_add with finiteA, finiteB304have natSym := cardinality.nat with (Finite.symmetricDifference with305 finiteA, finiteB)306have natMeet := cardinality.nat with (Finite.intersection_left at A, B with307 finiteA)308rw←split309 symm310exact sub.add_right at cardinality(A △ B), 2* cardinality(A ∩ B)311312theorem cardinality.symmetricDifference_le (A B : Set)313requires finiteA : Finite(A)314requires finiteB : Finite(B)315shows cardinality(A △ B) ≤ cardinality(A) + cardinality(B)316proof317havesplit:= cardinality.symmetricDifference_add with finiteA, finiteB318have natSym := cardinality.nat with (Finite.symmetricDifference with319 finiteA, finiteB)320have natMeet := cardinality.nat with (Finite.intersection_left at A, B with321 finiteA)322have natA := cardinality.nat with finiteA323have natB := cardinality.nat with finiteB324arith325326theorem cardinality.symmetricDifference_of_disjoint (A B : Set)327requires finiteA : Finite(A)328requires finiteB : Finite(B)329requires disjoint : Disjoint(A, B)330shows cardinality(A △ B) = cardinality(A) + cardinality(B)331proof332havesplit:= cardinality.symmetricDifference_add with finiteA, finiteB333unfold Disjoint at disjoint334rw [disjoint, cardinality.empty] atsplit335have natSym := cardinality.nat with (Finite.symmetricDifference with336 finiteA, finiteB)337have zero : 2*0=0bycompute338rw zero atsplit339have natA := cardinality.nat with finiteA340have natB := cardinality.nat with finiteB341have shape : cardinality(A △ B) +0= cardinality(A △ B) byring342rw shape atsplit343exactsplit344345-- Removing a subset of known size.346theorem cardinality.difference_lt_of_member (A B b : Set)347requires finite : Finite(A)348requires inA : b ∈ A349requires inB : b ∈ B350shows cardinality(A ∖ B) < cardinality(A)351proof352have absent : ¬b ∈ A ∖ B353intro h354have parts := difference.membership.forward with h355exact parts.right with inB356exact cardinality.strict with finite, (difference.subset_left at A, B), inA, absent357358theorem cardinality.difference_eq_iff_disjoint (A B : Set)359requires finite : Finite(A)360shows cardinality(A ∖ B) = cardinality(A) ↔ Disjoint(A, B)361proof362constructor363 . intro same364have equal := cardinality.eq_subset with finite,365 (difference.subset_left at A, B), same366apply Disjoint.iff.backward367intros x hx inB368rw← equal at hx369have parts := difference.membership.forward with hx370exact parts.right with inB371 . intro disjoint372have same : A ∖ B = A373have free := Disjoint.iff.forward with disjoint374ext x375constructor376 . intro hx377exact difference.subset_left at A, B with x, hx378 . intro hx379apply difference.membership.backward380exact⟨hx, (free with x, hx)⟩381rw same382rfl383