Documentation

AlgebraicCombinatorics.FPS.WeightedSets

The Generating Function of a Weighted Set #

This file formalizes the theory of weighted sets and their weight generating functions, following Section sec.gf.weighted-set of the Algebraic Combinatorics notes.

A weighted set is a set equipped with a weight function to ℕ. When the set is "finite-type" (only finitely many elements of each weight), we can define its weight generating function as a formal power series.

Main Definitions #

Main Results #

Applications #

The file includes applications to:

Note: Height-3 domino tilings are handled in Details/DominoTilings.lean.

References #

Tags #

weighted set, generating function, combinatorial class, domino tiling

Weighted Sets #

structure WeightedSet (α : Type u_2) :
Type u_2

A weighted set is a type equipped with a weight function to ℕ. (Definition \ref{def.gf-ws.weighted-sets}(a))

  • weight : α

    The weight function assigning a natural number to each element

Instances For

    A weighted set is finite-type if for each n ∈ ℕ, there are only finitely many elements of weight n. (Definition \ref{def.gf-ws.weighted-sets}(b))

    Equations
    Instances For
      def WeightedSet.elementsOfWeight {α : Type u_2} (W : WeightedSet α) (n : ) :
      Set α

      The set of elements of a given weight in a weighted set

      Equations
      Instances For
        def WeightedSet.countOfWeight {α : Type u_2} (W : WeightedSet α) (hft : W.IsFiniteType) (n : ) :

        For a finite-type weighted set, the count of elements of weight n

        Equations
        Instances For

          Weight Generating Function #

          def WeightedSet.weightGenFun {R : Type u_1} [CommSemiring R] {α : Type u_2} (W : WeightedSet α) (hft : W.IsFiniteType) :

          The weight generating function of a finite-type weighted set is the FPS ∑_{n ∈ ℕ} (# of elements of weight n) · x^n. (Definition \ref{def.gf-ws.weighted-sets}(c))

          Equations
          Instances For
            theorem WeightedSet.weightGenFun_eq_sum {R : Type u_1} [CommSemiring R] {α : Type u_2} (W : WeightedSet α) (hft : W.IsFiniteType) :
            W.weightGenFun hft = PowerSeries.mk fun (n : ) => .toFinset.card

            Alternative characterization: weightGenFun = ∑_{a ∈ A} x^{|a|}

            Isomorphisms of Weighted Sets #

            structure WeightedSet.Isomorphism {α : Type u_2} {β : Type u_3} (W₁ : WeightedSet α) (W₂ : WeightedSet β) :
            Type (max u_2 u_3)

            An isomorphism between weighted sets is a weight-preserving bijection. (Definition \ref{def.gf-ws.weighted-sets}(d))

            • toEquiv : α β

              The underlying bijection

            • weight_eq (a : α) : W₂.weight (self.toEquiv a) = W₁.weight a

              The bijection preserves weights

            Instances For
              def WeightedSet.AreIsomorphic {α : Type u_2} {β : Type u_3} (W₁ : WeightedSet α) (W₂ : WeightedSet β) :

              Two weighted sets are isomorphic if there exists an isomorphism between them. (Definition \ref{def.gf-ws.weighted-sets}(e))

              Equations
              Instances For
                theorem WeightedSet.weightGenFun_eq_of_isomorphic {R : Type u_1} [CommSemiring R] {α : Type u_2} {β : Type u_3} (W₁ : WeightedSet α) (W₂ : WeightedSet β) (hft₁ : W₁.IsFiniteType) (hft₂ : W₂.IsFiniteType) (h : W₁ ≅ᵥ W₂) :
                W₁.weightGenFun hft₁ = W₂.weightGenFun hft₂

                Isomorphic finite-type weighted sets have equal weight generating functions. (Proposition \ref{prop.gf-ws.iso})

                Disjoint Union of Weighted Sets #

                def WeightedSet.disjointUnion {α : Type u_2} {β : Type u_3} (W₁ : WeightedSet α) (W₂ : WeightedSet β) :

                The disjoint union of two weighted sets, with weights inherited from each component. (Definition \ref{def.gf-ws.djun})

                Equations
                Instances For
                  @[simp]
                  theorem WeightedSet.disjointUnion_weight_inl {α : Type u_2} {β : Type u_3} (W₁ : WeightedSet α) (W₂ : WeightedSet β) (a : α) :
                  (W₁ +ᵥ W₂).weight (Sum.inl a) = W₁.weight a
                  @[simp]
                  theorem WeightedSet.disjointUnion_weight_inr {α : Type u_2} {β : Type u_3} (W₁ : WeightedSet α) (W₂ : WeightedSet β) (b : β) :
                  (W₁ +ᵥ W₂).weight (Sum.inr b) = W₂.weight b
                  theorem WeightedSet.disjointUnion_isFiniteType {α : Type u_2} {β : Type u_3} (W₁ : WeightedSet α) (W₂ : WeightedSet β) (hft₁ : W₁.IsFiniteType) (hft₂ : W₂.IsFiniteType) :
                  (W₁ +ᵥ W₂).IsFiniteType

                  The disjoint union of finite-type weighted sets is finite-type.

                  theorem WeightedSet.weightGenFun_disjointUnion {R : Type u_1} [CommSemiring R] {α : Type u_2} {β : Type u_3} (W₁ : WeightedSet α) (W₂ : WeightedSet β) (hft₁ : W₁.IsFiniteType) (hft₂ : W₂.IsFiniteType) :
                  (W₁ +ᵥ W₂).weightGenFun = W₁.weightGenFun hft₁ + W₂.weightGenFun hft₂

                  The weight generating function of a disjoint union is the sum of the generating functions. (Proposition \ref{prop.gf-ws.djun})

                  Product of Weighted Sets #

                  def WeightedSet.prod {α : Type u_2} {β : Type u_3} (W₁ : WeightedSet α) (W₂ : WeightedSet β) :
                  WeightedSet (α × β)

                  The product of two weighted sets, with weight defined as the sum of component weights. (Definition \ref{def.gf-ws.prod})

                  Equations
                  Instances For
                    @[simp]
                    theorem WeightedSet.prod_weight {α : Type u_2} {β : Type u_3} (W₁ : WeightedSet α) (W₂ : WeightedSet β) (p : α × β) :
                    (W₁ ×ᵥ W₂).weight p = W₁.weight p.1 + W₂.weight p.2
                    theorem WeightedSet.prod_isFiniteType {α : Type u_2} {β : Type u_3} (W₁ : WeightedSet α) (W₂ : WeightedSet β) (hft₁ : W₁.IsFiniteType) (hft₂ : W₂.IsFiniteType) :
                    (W₁ ×ᵥ W₂).IsFiniteType

                    The product of finite-type weighted sets is finite-type. (Proof of first part of Proposition \ref{prop.gf-ws.prod})

                    theorem WeightedSet.weightGenFun_prod {R : Type u_1} [CommSemiring R] {α : Type u_2} {β : Type u_3} [DecidableEq α] [DecidableEq β] (W₁ : WeightedSet α) (W₂ : WeightedSet β) (hft₁ : W₁.IsFiniteType) (hft₂ : W₂.IsFiniteType) :
                    (W₁ ×ᵥ W₂).weightGenFun = W₁.weightGenFun hft₁ * W₂.weightGenFun hft₂

                    The weight generating function of a product is the product of the generating functions. (Proposition \ref{prop.gf-ws.prod})

                    This is the key theorem showing that the weight generating function respects Cartesian products: ḡ(A × B) = ḡ(A) · ḡ(B). The proof partitions the pairs of total weight n by the weight of the first component, showing this equals the convolution sum that defines multiplication of power series.

                    Cartesian Powers #

                    def WeightedSet.pow {α : Type u_2} (W : WeightedSet α) (k : ) :
                    WeightedSet (Fin kα)

                    The k-th Cartesian power of a weighted set. Weight of (a₁, ..., aₖ) is |a₁| + ... + |aₖ|.

                    Equations
                    Instances For
                      theorem WeightedSet.pow_isFiniteType {α : Type u_2} (W : WeightedSet α) (hft : W.IsFiniteType) (k : ) :

                      The k-th power of a finite-type weighted set is finite-type.

                      def WeightedSet.pow_succ_equiv {α : Type u_2} (W : WeightedSet α) (n : ) :
                      (W.pow (n + 1)).Isomorphism (W ×ᵥ W.pow n)

                      Helper: pow (n+1) is isomorphic to W × pow n

                      Equations
                      Instances For
                        theorem WeightedSet.weightGenFun_pow {R : Type u_1} [CommSemiring R] {α : Type u_2} (W : WeightedSet α) (hft : W.IsFiniteType) (k : ) :
                        (W.pow k).weightGenFun = W.weightGenFun hft ^ k

                        The weight generating function of A^k is (ḡ(A))^k. (Proposition \ref{prop.gf-ws.pow})

                        Infinite Disjoint Union (Tuples) #

                        def WeightedSet.tuples {α : Type u_2} (W : WeightedSet α) :
                        WeightedSet ((n : ) × (Fin nα))

                        The infinite disjoint union W^0 + W^1 + W^2 + ... of all tuples of elements. This is the "Kleene star" construction on weighted sets. An element is a pair (k, f) where k ∈ ℕ and f : Fin k → α is a k-tuple. The weight of (k, f) is the sum of weights of the entries: ∑ᵢ |f(i)|.

                        Equations
                        Instances For
                          theorem WeightedSet.tuples_weight_eq_pow {α : Type u_2} (W : WeightedSet α) (n : ) (f : Fin nα) :
                          W.tuples.weight n, f = (W.pow n).weight f

                          The weight in the tuples weighted set equals the weight in the corresponding power

                          A weighted set has positive weights if every element has weight ≥ 1

                          Equations
                          Instances For

                            The tuples weighted set is finite-type if the original is finite-type and has positive weights.

                            Note: The hypothesis hpos : W.HasPositiveWeights is necessary. Without it, the theorem is false: if W has elements of weight 0, then for any weight m, there are infinitely many tuples of weight m (we can have arbitrarily many weight-0 elements in a tuple). For example, if W = ℕ with weight = id, then tuples of weight 2 include ⟨1, ![2]⟩, ⟨2, ![0, 2]⟩, ⟨3, ![0, 0, 2]⟩, etc.

                            The key insight is that with positive weights, a tuple of length n has weight ≥ n, so for weight m, we only need to consider tuples of length ≤ m.

                            Examples and Applications #

                            Binary Strings (Example \ref{exa.ws.bin-string1}) #

                            Binary strings (finite tuples of 0s and 1s) with weight = length

                            Equations
                            Instances For

                              The binary strings weighted set is finite-type

                              The generating function of binary strings is 1/(1-2x). Since (mk 1) represents 1 + x + x² + ... = 1/(1-x), we express 1/(1-2x) differently.

                              Positive Integers #

                              The positive integers with weight = value

                              Equations
                              Instances For

                                Positive integers form a finite-type weighted set

                                Compositions #

                                Compositions of length k are k-tuples of positive integers

                                Equations
                                Instances For

                                  Compositions form a finite-type weighted set

                                  The generating function of compositions of length k is (x/(1-x))^k

                                  Domino Tilings #

                                  Shapes and Dominos (Definition \ref{def.domino.shapes-and-tilings}) #

                                  @[reducible, inline]

                                  A shape is a subset of ℤ² (Definition \ref{def.domino.shapes-and-tilings}(a))

                                  Equations
                                  Instances For

                                    The n × m rectangle (Definition \ref{def.domino.shapes-and-tilings}(b))

                                    Equations
                                    Instances For
                                      theorem DominoTilingsZ.mem_rectangle_iff {n m : } {p : × } :
                                      p Rectangle n m 1 p.1 p.1 n 1 p.2 p.2 m

                                      Membership in a rectangle

                                      @[simp]

                                      The 0 × m rectangle is empty

                                      @[simp]

                                      The n × 0 rectangle is empty

                                      The rectangle has n * m cells

                                      A domino is either horizontal or vertical (Definition \ref{def.domino.shapes-and-tilings}(c))

                                      Instances For

                                        The cells covered by a domino

                                        Equations
                                        Instances For

                                          A domino covers exactly 2 cells

                                          @[simp]

                                          A horizontal domino covers the cells (i,j) and (i+1,j)

                                          @[simp]

                                          A vertical domino covers the cells (i,j) and (i,j+1)

                                          The shape of a domino is nonempty

                                          The shape of a domino is finite

                                          theorem DominoTilingsZ.Domino.eq_of_toShape_eq {d1 d2 : Domino} (h : d1.toShape = d2.toShape) :
                                          d1 = d2

                                          Two dominos with the same shape are equal. This follows from the fact that a domino's shape uniquely determines its type and position.

                                          A domino tiling of a shape S is a set partition of S into dominos (Definition \ref{def.domino.shapes-and-tilings}(d))

                                          Instances For
                                            theorem DominoTilingsZ.Tiling.ext {S : Shape} (T1 T2 : Tiling S) (h : T1.dominos = T2.dominos) :
                                            T1 = T2

                                            Two tilings are equal iff they have the same dominos

                                            theorem DominoTilingsZ.Tiling.ext_iff {S : Shape} {T1 T2 : Tiling S} :
                                            T1 = T2 T1.dominos = T2.dominos

                                            The empty tiling of an empty shape

                                            Equations
                                            Instances For

                                              The empty shape has exactly one tiling (the empty tiling)

                                              The number of domino tilings of the n × m rectangle (Definition \ref{def.domino.shapes-and-tilings}(e))

                                              This is defined as the cardinality of the type of all tilings. Note: For this to be meaningful, the set of tilings must be finite, which holds for any finite rectangle.

                                              Equations
                                              Instances For
                                                Equations
                                                • One or more equations did not get rendered due to their size.
                                                Instances For

                                                  Height-2 Rectangle Tilings #

                                                  Domino tilings of height-2 rectangles, with weight = width of rectangle

                                                  Equations
                                                  Instances For

                                                    TilingsHeight2 is a finite-type weighted set

                                                    def DominoTilingsZ.hasFault (n : ) (T : Tiling (Rectangle n 2)) (k : ) :

                                                    A fault in a domino tiling is a vertical line that no domino straddles

                                                    Equations
                                                    • One or more equations did not get rendered due to their size.
                                                    Instances For
                                                      theorem DominoTilingsZ.hasFault_eq_of_dominos_eq {n : } {T1 T2 : Tiling (Rectangle n 2)} (h : T1.dominos = T2.dominos) (k : ) :
                                                      hasFault n T1 k hasFault n T2 k

                                                      hasFault only depends on the dominos set

                                                      A tiling is faultfree if it is nonempty and has no fault

                                                      Equations
                                                      Instances For

                                                        isFaultfree only depends on the dominos set

                                                        Faultfree tilings of height-2 rectangles

                                                        Equations
                                                        • One or more equations did not get rendered due to their size.
                                                        Instances For
                                                          Helper lemmas for faultfree classification #
                                                          theorem DominoTilingsZ.exists_domino_covering_11 (n : ) (hn : n 1) (T : Tiling (Rectangle n 2)) :
                                                          dT.dominos, (1, 1) d.toShape
                                                          theorem DominoTilingsZ.fault_at_1_if_vertical (n : ) (hn : n 2) (T : Tiling (Rectangle n 2)) (hv : Domino.vertical 1 1 T.dominos) :
                                                          hasFault n T 1
                                                          theorem DominoTilingsZ.faultfree_height2_classification (n : ) (T : Tiling (Rectangle n 2)) (hff : isFaultfree n T) :
                                                          n = 1 n = 2

                                                          The only faultfree tilings of height-2 rectangles have width 1 or 2

                                                          The unique tiling of the 1×2 rectangle (one vertical domino)

                                                          Equations
                                                          Instances For

                                                            Every tiling of the 1×2 rectangle equals tiling_1_2

                                                            Every element of FaultfreeTilingsHeight2 with weight 1 equals faultfreeTiling_1_2

                                                            There is exactly one faultfree tiling of width 1 (one vertical domino)

                                                            The unique faultfree tiling of width 2: two horizontal dominos

                                                            Equations
                                                            • One or more equations did not get rendered due to their size.
                                                            Instances For

                                                              The two horizontal dominos tiling is faultfree

                                                              Any faultfree tiling of Rectangle 2 2 equals twoHorizontalDominos

                                                              There is exactly one faultfree tiling of width 2 (two horizontal dominos)

                                                              For n ≠ 1 and n ≠ 2, there are no faultfree tilings of width n

                                                              Decomposition Lemma (lem.gf.weighted-set.domino.fd) #

                                                              Helper definitions for tiling composition/decomposition #

                                                              Shift a domino horizontally by an offset

                                                              Equations
                                                              Instances For
                                                                theorem DominoTilingsZ.Domino.shift_toShape (d : Domino) (offset : ) :
                                                                (d.shift offset).toShape = (fun (p : × ) => (p.1 + offset, p.2)) '' d.toShape

                                                                Shifting preserves the shape structure

                                                                Shift a set of dominos

                                                                Equations
                                                                Instances For
                                                                  theorem DominoTilingsZ.Domino.shift_injective (offset : ) :
                                                                  Function.Injective fun (d : Domino) => d.shift offset

                                                                  Shifting is injective

                                                                  @[simp]

                                                                  Shifting by 0 is the identity

                                                                  theorem DominoTilingsZ.Domino.shift_shift (d : Domino) (a b : ) :
                                                                  (d.shift a).shift b = d.shift (a + b)

                                                                  Shifting twice is the same as shifting by the sum

                                                                  theorem DominoTilingsZ.Rectangle_shift (n m : ) (offset : ) :
                                                                  (fun (p : × ) => (p.1 + offset, p.2)) '' Rectangle n m = {p : × | 1 + offset p.1 p.1 n + offset 1 p.2 p.2 m}

                                                                  Rectangle shift lemma

                                                                  def DominoTilingsZ.Tiling.shift {n m : } (T : Tiling (Rectangle n m)) (offset : ) :
                                                                  Tiling {p : × | 1 + offset p.1 p.1 n + offset 1 p.2 p.2 m}

                                                                  Shift a tiling to a new position

                                                                  Equations
                                                                  Instances For
                                                                    def DominoTilingsZ.Tiling.cast {S S' : Shape} (h : S = S') (T : Tiling S) :

                                                                    Cast a tiling along rectangle equality

                                                                    Equations
                                                                    Instances For
                                                                      @[simp]
                                                                      theorem DominoTilingsZ.Tiling.cast_dominos {S S' : Shape} (h : S = S') (T : Tiling S) :

                                                                      Casting a tiling preserves its dominos

                                                                      @[simp]
                                                                      theorem DominoTilingsZ.Tiling.subst_dominos {n m : } (h : n = m) (T : Tiling (Rectangle n 2)) :

                                                                      Subst (▸) on a tiling preserves dominos

                                                                      Composition: Concatenating faultfree tilings #

                                                                      def DominoTilingsZ.partialWidthSum (k : ) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (i : Fin k) :

                                                                      The partial sum of widths up to (but not including) index i

                                                                      Equations
                                                                      Instances For
                                                                        @[simp]
                                                                        theorem DominoTilingsZ.partialWidthSum_zero (k : ) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (i : Fin k) (hi : i = 0) :

                                                                        The partial width sum at index with val = 0 is always 0

                                                                        Shift a domino by a natural number offset (for composition)

                                                                        Equations
                                                                        Instances For
                                                                          @[simp]

                                                                          Shifting by natural 0 is the identity

                                                                          theorem DominoTilingsZ.Domino.shiftNat_toShape (d : Domino) (offset : ) :
                                                                          (d.shiftNat offset).toShape = (fun (p : × ) => (p.1 + offset, p.2)) '' d.toShape

                                                                          Shifting by natural number preserves shape structure

                                                                          Shifting twice by natural numbers is the same as shifting by the sum

                                                                          def DominoTilingsZ.composeTilings_component_dominos (k : ) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (i : Fin k) :

                                                                          The set of dominos for the i-th component in the composition, shifted appropriately

                                                                          Equations
                                                                          Instances For
                                                                            def DominoTilingsZ.composeTilings_dominos (k : ) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) :

                                                                            The union of all shifted dominos for composition

                                                                            Equations
                                                                            Instances For
                                                                              theorem DominoTilingsZ.composeTilings_component_dominos_disjoint (k : ) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (i1 i2 : Fin k) (hi : i1 i2) (d1 : Domino) (hd1 : d1 composeTilings_component_dominos k ts i1) (d2 : Domino) (hd2 : d2 composeTilings_component_dominos k ts i2) :

                                                                              Helper: Dominos from different components have disjoint x-coordinate ranges

                                                                              def DominoTilingsZ.composeTilings (k : ) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) :
                                                                              (n : ) × Tiling (Rectangle n 2)

                                                                              The composition function: given a tuple of faultfree tilings, concatenate them horizontally to produce a single tiling.

                                                                              Each faultfree tiling is shifted by the cumulative width of the previous tilings, and the union of all shifted dominos forms the composed tiling.

                                                                              This is the inverse of decomposeTiling.

                                                                              Equations
                                                                              Instances For
                                                                                theorem DominoTilingsZ.composeTilings_dominos_one (ts : Fin 1(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) :

                                                                                For k = 1, the composed dominos equal the original dominos (shifted by 0)

                                                                                theorem DominoTilingsZ.composeTilings_one_dominos (ts : Fin 1(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) :
                                                                                (composeTilings 1 ts).snd.dominos = (↑(ts 0).snd).dominos

                                                                                For k = 1, the composed tiling has the same dominos as the original

                                                                                theorem DominoTilingsZ.composeTilings_one_width (ts : Fin 1(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) :
                                                                                (composeTilings 1 ts).fst = (ts 0).fst

                                                                                For k = 1, the width of the composed tiling equals the width of the single component

                                                                                theorem DominoTilingsZ.composeTilings_one_tiling (ts : Fin 1(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) :
                                                                                (composeTilings 1 ts).snd = (ts 0).snd

                                                                                For k = 1, the composed tiling equals the single component (as Tilings)

                                                                                For k = 1, the composed tiling is faultfree

                                                                                theorem DominoTilingsZ.composeTilings_prepend_width (m first_width : ) (first : { T' : Tiling (Rectangle first_width 2) // isFaultfree first_width T' }) (rest : Fin m(w : ) × { T' : Tiling (Rectangle w 2) // isFaultfree w T' }) (ts : Fin (m + 1)(w : ) × { T' : Tiling (Rectangle w 2) // isFaultfree w T' }) (hts : ts = fun (i : Fin (m + 1)) => if hi : i = 0 then first_width, first else rest i - 1, ) :
                                                                                (composeTilings (m + 1) ts).fst = first_width + j : Fin m, (rest j).fst

                                                                                Helper lemma: The width of composeTilings with a prepended element equals the first width plus the sum of the remaining widths. This is used in proving composeTilings_decomposeTiling.

                                                                                theorem DominoTilingsZ.composeTilings_prepend_width' (m first_width rest_width : ) (first : { T' : Tiling (Rectangle first_width 2) // isFaultfree first_width T' }) (rest : Fin m(w : ) × { T' : Tiling (Rectangle w 2) // isFaultfree w T' }) (hrest : (composeTilings m rest).fst = rest_width) (ts : Fin (m + 1)(w : ) × { T' : Tiling (Rectangle w 2) // isFaultfree w T' }) (hts : ts = fun (i : Fin (m + 1)) => if hi : i = 0 then first_width, first else rest i - 1, ) :
                                                                                (composeTilings (m + 1) ts).fst = first_width + rest_width

                                                                                Helper lemma: When we compose with a prepended element, if the rest composes to a specific width and tiling, then the total width equals first_width + rest_width.

                                                                                Decomposition: Cutting at faults #

                                                                                Infrastructure for restricting tilings at faults #

                                                                                Shift a domino by a negative offset (for decomposition)

                                                                                Equations
                                                                                Instances For
                                                                                  theorem DominoTilingsZ.Domino.shiftNeg_toShape (d : Domino) (offset : ) :
                                                                                  (d.shiftNeg offset).toShape = (fun (p : × ) => (p.1 - offset, p.2)) '' d.toShape

                                                                                  Shifting by negative offset preserves shape structure

                                                                                  Shifting by k then by -k returns the original domino

                                                                                  Shifting by -k then by k returns the original domino

                                                                                  A domino is in the left part (all x-coordinates ≤ k)

                                                                                  Equations
                                                                                  Instances For

                                                                                    A domino is in the right part (all x-coordinates ≥ k+1)

                                                                                    Equations
                                                                                    Instances For
                                                                                      theorem DominoTilingsZ.domino_left_or_right_at_fault {n : } {T : Tiling (Rectangle n 2)} {k : } (hk : hasFault n T k) (d : Domino) (hd : d T.dominos) :

                                                                                      At a fault, each domino is either entirely left or entirely right

                                                                                      def DominoTilingsZ.restrictTilingLeft (n : ) (T : Tiling (Rectangle n 2)) (k : ) (hk : hasFault n T k) :

                                                                                      Restrict a tiling to the left part at a fault position

                                                                                      Equations
                                                                                      Instances For
                                                                                        def DominoTilingsZ.restrictTilingRight (n : ) (T : Tiling (Rectangle n 2)) (k : ) (hk : hasFault n T k) :
                                                                                        Tiling (Rectangle (n - k) 2)

                                                                                        Restrict a tiling to the right part at a fault position, shifted to origin

                                                                                        Equations
                                                                                        • One or more equations did not get rendered due to their size.
                                                                                        Instances For
                                                                                          @[simp]
                                                                                          theorem DominoTilingsZ.restrictTilingLeft_proof_irrel (n : ) (T : Tiling (Rectangle n 2)) (k : ) (hk1 hk2 : hasFault n T k) :

                                                                                          restrictTilingLeft does not depend on the proof of hasFault

                                                                                          @[simp]
                                                                                          theorem DominoTilingsZ.restrictTilingRight_proof_irrel (n : ) (T : Tiling (Rectangle n 2)) (k : ) (hk1 hk2 : hasFault n T k) :

                                                                                          restrictTilingRight does not depend on the proof of hasFault

                                                                                          theorem DominoTilingsZ.restrictTilingLeft_isFaultfree (n : ) (T : Tiling (Rectangle n 2)) (k : ) (hk : hasFault n T k) (hmin : j < k, ¬hasFault n T j) :

                                                                                          The left restriction at a fault is faultfree if k is the smallest fault

                                                                                          At a fault position, the tiling's dominos split into left and right parts

                                                                                          The original dominos equal the union of left part and shifted right part

                                                                                          The set of fault positions in a tiling

                                                                                          Equations
                                                                                          Instances For

                                                                                            The fault positions form a finite set (bounded by n)

                                                                                            noncomputable def DominoTilingsZ.minFault (n : ) (T : Tiling (Rectangle n 2)) (hne : (faultPositions n T).Nonempty) :

                                                                                            The minimum fault position in a tiling (when faults exist)

                                                                                            Equations
                                                                                            Instances For

                                                                                              The minimum fault is indeed a fault

                                                                                              theorem DominoTilingsZ.minFault_hasFault (n : ) (T : Tiling (Rectangle n 2)) (hne : (faultPositions n T).Nonempty) :
                                                                                              hasFault n T (minFault n T hne)

                                                                                              The minimum fault is a hasFault

                                                                                              theorem DominoTilingsZ.minFault_le (n : ) (T : Tiling (Rectangle n 2)) (hne : (faultPositions n T).Nonempty) (j : ) (hj : j faultPositions n T) :
                                                                                              minFault n T hne j

                                                                                              The minimum fault is less than or equal to any other fault

                                                                                              Decidability instance for faultPositions.Nonempty

                                                                                              Equations

                                                                                              A faultfree tiling has no faults, so faultPositions is empty

                                                                                              A faultfree tiling has non-nonempty faultPositions

                                                                                              Helper lemmas for k >= 2 case of decomposeTiling_composeTilings #
                                                                                              theorem DominoTilingsZ.partialWidthSum_one (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) :
                                                                                              partialWidthSum k ts 1, = (ts 0, ).fst

                                                                                              The partial width sum at index 1 equals the width of the first component

                                                                                              theorem DominoTilingsZ.composeTilings_hasFault_at_boundary (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) :

                                                                                              For k >= 2, the composed tiling has a fault at position (ts 0).1

                                                                                              theorem DominoTilingsZ.composeTilings_no_fault_before_boundary (k : ) (hk : k 1) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (p : ) (hp : p < (ts 0, hk).fst) :

                                                                                              For k >= 1, there are no faults at positions less than (ts 0).1 in the composed tiling

                                                                                              theorem DominoTilingsZ.composeTilings_minFault_eq (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (hne : (faultPositions (composeTilings k ts).fst (composeTilings k ts).snd).Nonempty) :
                                                                                              minFault (composeTilings k ts).fst (composeTilings k ts).snd hne = (ts 0, ).fst

                                                                                              The minimum fault in a composed tiling with k >= 2 components is at (ts 0).1

                                                                                              Lemmas relating restrictTiling to composeTilings #
                                                                                              def DominoTilingsZ.faultfreeTilingsTail (k : ) (hk : k 1) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) :
                                                                                              Fin (k - 1)(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }

                                                                                              The tail of a tuple of faultfree tilings

                                                                                              Equations
                                                                                              Instances For
                                                                                                theorem DominoTilingsZ.composeTilings_tail_width (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) :
                                                                                                (composeTilings (k - 1) (faultfreeTilingsTail k ts)).fst = (composeTilings k ts).fst - (ts 0, ).fst

                                                                                                The width of composing the tail equals the total width minus the first component width

                                                                                                theorem DominoTilingsZ.composeTilings_component0_inLeftPart (k : ) (hk : k 1) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (d : Domino) (hd : d (↑(ts 0, hk).snd).dominos) :
                                                                                                d.inLeftPart (ts 0, hk).fst

                                                                                                Dominos from component 0 are in the left part at position (ts 0).1

                                                                                                theorem DominoTilingsZ.composeTilings_componentPos_inRightPart (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (i : Fin k) (hi : i 1) (d : Domino) (hd : d (↑(ts i).snd).dominos) :

                                                                                                Dominos from component i >= 1 are in the right part at position (ts 0).1

                                                                                                theorem DominoTilingsZ.restrictTilingLeft_composeTilings_dominos (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (hfault : hasFault (composeTilings k ts).fst (composeTilings k ts).snd (ts 0, ).fst) :
                                                                                                (restrictTilingLeft (composeTilings k ts).fst (composeTilings k ts).snd (ts 0, ).fst hfault).dominos = (↑(ts 0, ).snd).dominos

                                                                                                The left restriction of a composed tiling at the first boundary has the same dominos as the first component

                                                                                                theorem DominoTilingsZ.restrictTilingLeft_composeTilings_eq (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (hfault : hasFault (composeTilings k ts).fst (composeTilings k ts).snd (ts 0, ).fst) :
                                                                                                restrictTilingLeft (composeTilings k ts).fst (composeTilings k ts).snd (ts 0, ).fst hfault = (ts 0, ).snd

                                                                                                The left restriction of a composed tiling equals the first component's tiling. This follows from restrictTilingLeft_composeTilings_dominos via Tiling.ext.

                                                                                                theorem DominoTilingsZ.composeTilings_componentPos_dominos_unshift (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (i : Fin k) (hi : i 1) (d : Domino) (hd : d (↑(ts i).snd).dominos) :
                                                                                                (d.shiftNat (partialWidthSum k ts i)).shiftNeg (ts 0, ).fst = d.shiftNat (partialWidthSum k ts i - (ts 0, ).fst)

                                                                                                Dominos from component i shifted and then unshifted by k gives back the original

                                                                                                theorem DominoTilingsZ.partialWidthSum_tail (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (j : Fin (k - 1)) :
                                                                                                partialWidthSum (k - 1) (faultfreeTilingsTail k ts) j = partialWidthSum k ts j + 1, - (ts 0, ).fst

                                                                                                The partial width sum for the tail equals the original minus (ts 0).1

                                                                                                theorem DominoTilingsZ.restrictTilingRight_composeTilings_dominos (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (hfault : hasFault (composeTilings k ts).fst (composeTilings k ts).snd (ts 0, ).fst) :

                                                                                                The right restriction of a composed tiling at the first boundary has the same dominos as the composition of the tail

                                                                                                theorem DominoTilingsZ.restrictTilingRight_composeTilings_dominos_eq (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (hfault : hasFault (composeTilings k ts).fst (composeTilings k ts).snd (ts 0, ).fst) :

                                                                                                The right restriction of a composed tiling has the same dominos as the composition of the tail. Note: The tilings have different types (different width parameters), so we state this as a domino equality rather than a tiling equality. Use Tiling.ext with the width equality composeTilings_tail_width to convert to tiling equality when needed.

                                                                                                theorem DominoTilingsZ.restrictTilingRight_composeTilings_eq (k : ) (hk : k 2) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) (hfault : hasFault (composeTilings k ts).fst (composeTilings k ts).snd (ts 0, ).fst) :

                                                                                                The right restriction of a composed tiling equals the composition of the tail. This combines the width equality composeTilings_tail_width with the domino equality restrictTilingRight_composeTilings_dominos_eq to give a full tiling equality.

                                                                                                Note: The two tilings have the same type because:

                                                                                                • restrictTilingRight has width (composeTilings k ts).1 - (ts 0).1
                                                                                                • composeTilings (k-1) (tail ts) has width (composeTilings k ts).1 - (ts 0).1 (by composeTilings_tail_width)
                                                                                                @[irreducible]
                                                                                                noncomputable def DominoTilingsZ.decomposeTiling (n : ) (T : Tiling (Rectangle n 2)) :
                                                                                                (k : ) × (Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' })

                                                                                                The decomposition function: given a tiling of a height-2 rectangle, produce a tuple of faultfree tilings by cutting along all faults.

                                                                                                For example, a tiling with faults at positions k₁ < k₂ < ... < kₘ decomposes into m+1 faultfree tilings of widths k₁, k₂-k₁, ..., n-kₘ.

                                                                                                The empty tiling (n=0) decomposes into the empty tuple (k=0).

                                                                                                Implementation: We recursively find the minimum fault position, cut the tiling there, and decompose the right part. The left part at a minimum fault is always faultfree. If no faults exist, the entire tiling is faultfree and returned as a singleton.

                                                                                                Equations
                                                                                                Instances For
                                                                                                  theorem DominoTilingsZ.decomposeTiling_hasFault (n : ) (T : Tiling (Rectangle (n + 1) 2)) (hne : (faultPositions (n + 1) T).Nonempty) :
                                                                                                  let k := minFault (n + 1) T hne; have hk := ; have hk_min := ; let left := restrictTilingLeft (n + 1) T k hk; have left_ff := ; have right := restrictTilingRight (n + 1) T k hk; match decomposeTiling (n + 1 - k) right with | m, ts => decomposeTiling (n + 1) T = m + 1, fun (i : Fin (m + 1)) => if hi : i = 0 then k, left, left_ff else ts i - 1,

                                                                                                  Decomposing a tiling with faults at the minimum fault position. This characterizes the structure of decomposeTiling when faults exist.

                                                                                                  theorem DominoTilingsZ.decomposeTiling_hasFault_fst (n : ) (T : Tiling (Rectangle (n + 1) 2)) (hne : (faultPositions (n + 1) T).Nonempty) :
                                                                                                  let k := minFault (n + 1) T hne; have hk := ; have right := restrictTilingRight (n + 1) T k hk; (decomposeTiling (n + 1) T).fst = (decomposeTiling (n + 1 - k) right).fst + 1

                                                                                                  The width of decomposeTiling when faults exist equals m+1 where m is the count from decomposing the right part. This is useful for proving composeTilings_decomposeTiling.

                                                                                                  Decomposition followed by composition gives back the original tiling

                                                                                                  theorem DominoTilingsZ.decomposeTiling_faultfree (n : ) (T : Tiling (Rectangle (n + 1) 2)) (hff : isFaultfree (n + 1) T) :
                                                                                                  decomposeTiling (n + 1) T = 1, fun (x : Fin 1) => n + 1, T, hff

                                                                                                  Decomposing a faultfree tiling returns a singleton tuple containing the original tiling. This is a key helper for proving decomposeTiling_composeTilings.

                                                                                                  Decomposition is invariant under type cast (subst). This is key for handling dependent types in the inverse proofs.

                                                                                                  theorem DominoTilingsZ.decomposeTiling_eq_of_dominos_eq {n m : } (h : n = m) (T1 : Tiling (Rectangle n 2)) (T2 : Tiling (Rectangle m 2)) (hdom : T1.dominos = T2.dominos) :

                                                                                                  Decomposition depends only on width and dominos. If two tilings have the same width and dominos, their decompositions are equal.

                                                                                                  theorem DominoTilingsZ.restrictTilingLeft_subst {n m : } (h : n = m) (T : Tiling (Rectangle n 2)) (k : ) (hk : hasFault n T k) :

                                                                                                  The left restriction of a subst'd tiling equals the left restriction of the original.

                                                                                                  theorem DominoTilingsZ.restrictTilingRight_subst_dominos {n m : } (h : n = m) (T : Tiling (Rectangle n 2)) (k : ) (hk : hasFault n T k) :

                                                                                                  The right restriction of a subst'd tiling has the same dominos as the original.

                                                                                                  Composition followed by decomposition gives back the original tuple.

                                                                                                  This theorem proves that composing faultfree tilings and then decomposing recovers the original tuple of tilings.

                                                                                                  The proof handles two cases:

                                                                                                  1. If k = 0 (empty tuple), the composed tiling is empty (width 0), and decomposeTiling returns the empty tuple by definition.
                                                                                                  2. If k > 0, the composed tiling has positive width, and we need to show that the faults in the composed tiling occur exactly at the partial width sums, so decomposing at those faults recovers the original pieces.
                                                                                                  theorem DominoTilingsZ.composeTilings_width (k : ) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }) :
                                                                                                  (composeTilings k ts).fst = i : Fin k, (ts i).fst

                                                                                                  The width of the composed tiling equals the sum of widths of the components. This follows from the definition of composeTilings as horizontal concatenation.

                                                                                                  theorem DominoTilingsZ.decomposeTiling_weight_sum (n : ) (T : Tiling (Rectangle n 2)) :
                                                                                                  match decomposeTiling n T with | k, ts => i : Fin k, (ts i).fst = n

                                                                                                  The sum of widths of the faultfree tilings equals the width of the original. This is the key property that makes the decomposition weight-preserving.

                                                                                                  Main decomposition isomorphism (Lemma \ref{lem.gf.weighted-set.domino.fd}):

                                                                                                  Any domino tiling of a height-2 rectangle can be decomposed uniquely into a tuple of faultfree tilings of (usually smaller) height-2 rectangles, by cutting it along its faults.

                                                                                                  This gives an isomorphism of weighted sets: D ≅ F⁰ + F¹ + F² + F³ + ... where D = TilingsHeight2 and F = FaultfreeTilingsHeight2.

                                                                                                  The isomorphism preserves weights: the sum of the widths of the faultfree tilings in the tuple equals the width of the original tiling.

                                                                                                  Equations
                                                                                                  • One or more equations did not get rendered due to their size.
                                                                                                  Instances For
                                                                                                    theorem DominoTilingsZ.tiling_decomposition (n : ) (T : Tiling (Rectangle n 2)) :
                                                                                                    ∃ (k : ) (ts : Fin k(m : ) × { T' : Tiling (Rectangle m 2) // isFaultfree m T' }), i : Fin k, (ts i).fst = n

                                                                                                    Corollary: Any tiling decomposes into a tuple of faultfree tilings with matching total weight

                                                                                                    Helper definitions for the Fibonacci recurrence bijection #

                                                                                                    Prepend a vertical domino to a tiling of Rectangle m 2, giving a tiling of Rectangle (m+1) 2.

                                                                                                    The new tiling has dominos = {vertical 1 1} ∪ (T.dominos shifted right by 1). This is the inverse of restricting at fault 1 when a vertical domino is present.

                                                                                                    Equations
                                                                                                    Instances For

                                                                                                      The vertical domino is not in the image of shifted dominos from Rectangle m 2.

                                                                                                      Prepend a pair of horizontal dominos to a tiling of Rectangle m 2, giving a tiling of Rectangle (m+2) 2.

                                                                                                      The new tiling has dominos = {horizontal 1 1, horizontal 1 2} ∪ (T.dominos shifted right by 2). This is the inverse of restricting at fault 2 when horizontal dominos are present.

                                                                                                      Equations
                                                                                                      • One or more equations did not get rendered due to their size.
                                                                                                      Instances For

                                                                                                        The horizontal dominos are not in the image of shifted dominos from Rectangle m 2.

                                                                                                        The vertical domino at (1,1) is not in the image of dominos shifted by 2.

                                                                                                        @[simp]

                                                                                                        The empty rectangle has exactly one tiling

                                                                                                        @[simp]

                                                                                                        The 1×2 rectangle has exactly one tiling

                                                                                                        The Fibonacci recurrence for tiling counts: d_{n+2,2} = d_{n,2} + d_{n+1,2}.

                                                                                                        This follows from the bijection: Tiling (Rectangle (n+2) 2) ≃ Tiling (Rectangle n 2) ⊕ Tiling (Rectangle (n+1) 2)

                                                                                                        The bijection classifies tilings based on what covers the first column:

                                                                                                        • If a vertical domino covers (1,1)-(1,2): removing it and shifting gives a tiling of Rectangle (n+1) 2
                                                                                                        • If horizontal dominos cover (1,1)-(2,1) and (1,2)-(2,2): removing them and shifting gives a tiling of Rectangle n 2

                                                                                                        This is a classical result in combinatorics.

                                                                                                        The number of domino tilings of a 2×n rectangle equals the (n+1)-th Fibonacci number

                                                                                                        The count of tilings at weight n equals the number of tilings of R_{n,2}

                                                                                                        The generating function of height-2 tilings equals 1/(1-x-x²), which is the Fibonacci generating function

                                                                                                        Height-3 Rectangle Tilings #

                                                                                                        The set of dominos that fit within a rectangle

                                                                                                        Equations
                                                                                                        Instances For

                                                                                                          The set of dominos in a rectangle is finite

                                                                                                          A tiling's dominos are contained in DominosInRectangle

                                                                                                          The set of tilings of a rectangle is finite