Documentation

DescriptiveComplexity.Problems.Wide.LowFile

A register file on a stretch of consecutive addresses #

The register file the input channel marks (DescriptiveComplexity.wmSegFile) is free, but it is a geometric ruler: the cell of the j-th element sits at address 2 ^ m − 2 ^ (m − j − 1), so the file lies entirely in the top half of the tape and reaching its upper registers costs almost the whole tape. A machine with no clock does not care. A machine whose clock counts the addresses can walk that file once and never again.

This file builds the other one:

the registers are n consecutive addresses, the register of the j-th element being the address of rank base + j.

Everything a walk asks for follows at once, since DescriptiveComplexity.RegFile asks only for strict monotonicity: ranks are monotone, so the cells are (DescriptiveComplexity.segFile). What indexes the registers plays no part in that, so the construction is made at an arbitrary ordered index (DescriptiveComplexity.ixSegFile) and the elementwise file is its diagonal – which is what a program too tightly clocked to afford one register per element will build its own file with. What the geometry buys is the cost: consecutive registers are consecutive addresses (DescriptiveComplexity.segFile_gap), so a move of the walk is one step and a pass over the whole file costs n, against the whole tape for the ruler.

Where the stretch sits is the caller's choice, and it is not a free one. The subroutines written for the input channel's file assume it lies above the addresses the program computes with, since that is where the ruler is (DescriptiveComplexity.Problems.Wide.Marks): a scan looking for a register scans upwards, and the bound it is given is a register. A program that builds its own file and wants those subroutines unchanged puts it above its data as well; one that wants it out of the way takes base = 1, DescriptiveComplexity.lowFile, whose registers are the first n nonempty addresses and which therefore lies below everything (DescriptiveComplexity.wideRank_lowCell_le).

There is nothing to arrange for the addresses to exist: the cell of an element uses no marked symbol, so a program with this file writes its own names into those cells – one per cell, as it walks the bottom of the tape in its first n steps – and the two ends are recognized like any other register. The one fact that has to be proved is that there is room, and there is, with room to spare: there are 2 ^ n addresses for n elements (DescriptiveComplexity.card_wideAddr, the clock of the model read as a count).

Comparing addresses by rank #

An address is below another exactly when its rank is smaller. The rank determines the address, so a family of addresses is strictly monotone as soon as its ranks are.

Dependency graph

There is room at the bottom #

There are strictly more addresses than elements, which is the room the construction below needs: one address per element, and one more for the empty address it starts above.

Dependency graph

The addresses from the bottom, one by one #

The j-th address from the bottom: the empty address, then increments. Beyond the last address the sequence stands still, which never happens below the number of addresses.

Equations
Instances For
    Dependency graph
    theorem DescriptiveComplexity.wmIncr_addrSeq {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] (h : IsLinOrd WMLe) {j : } (hex : ∃ (x : A), ¬addrSeq h j x) :
    WMIncr WMLe (addrSeq h j) (addrSeq h (j + 1))

    Where the sequence advances, it advances by an increment.

    Dependency graph

    The j-th address has rank j, as long as there is a j-th address at all. This is the whole content of the construction: the ranks are the numbers 0, 1, 2, …, so the addresses are the tape read from its bottom end.

    Dependency graph

    The file, and where it sits #

    Which stretch of the tape the registers occupy is the caller's choice, and it is not a free one. The file the input channel marks lies above every address a program computes with (DescriptiveComplexity.Problems.Wide.Marks), and the subroutines written for it are stated that way – a scan looking for a register scans upwards, and the bound it is given is a register. A program that builds its own file and wants those subroutines unchanged must therefore put it above its data as well, which here means high in its working region; one that wants the file out of the way puts it at the bottom. Both are the same construction at a different base.

    The file, at an arbitrary index #

    noncomputable def DescriptiveComplexity.ixSegCell {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} (ile : IIProp) (h : IsLinOrd WMLe) (base : ) (u : I) :
    AProp

    The register of an index in the file based at base: the address whose rank is base above the index's, so the file is the stretch of consecutive addresses whose ranks start at base.

    Equations
    Instances For
      Dependency graph
      theorem DescriptiveComplexity.wideRank_ixSegCell {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (ile : IIProp) (h : IsLinOrd WMLe) {base : } (hbase : base + Nat.card I Nat.card { p : WPoint A // (wideData A).Posn p }) (u : I) :
      wideRank (ixSegCell ile h base u) = base + ixRank ile u

      The rank of a register is its index's, shifted by the base.

      Dependency graph
      noncomputable def DescriptiveComplexity.ixSegFile {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (ile : IIProp) (h : IsLinOrd WMLe) (hi : IsLinOrd ile) {base : } (hpos : 0 < base) (hbase : base + Nat.card I Nat.card { p : WPoint A // (wideData A).Posn p }) :
      IxFile A I ile

      A register file on a stretch of consecutive addresses, one register per index. The base says where the stretch starts; it must be positive, so that no register is the empty address the head starts on, and the stretch must fit below the top of the tape.

      Equations
      Instances For
        Dependency graph
        @[simp]
        theorem DescriptiveComplexity.cell_ixSegFile {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (ile : IIProp) (h : IsLinOrd WMLe) (hi : IsLinOrd ile) {base : } (hpos : 0 < base) (hbase : base + Nat.card I Nat.card { p : WPoint A // (wideData A).Posn p }) :
        (ixSegFile ile h hi hpos hbase).cell = ixSegCell ile h base
        Dependency graph
        theorem DescriptiveComplexity.wmIncr_ixSegCell {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (ile : IIProp) (h : IsLinOrd WMLe) (hi : IsLinOrd ile) {base : } (hbase : base + Nat.card I Nat.card { p : WPoint A // (wideData A).Posn p }) {u u' : I} (hs : IxSucc ile u u') :
        WMIncr WMLe (ixSegCell ile h base u) (ixSegCell ile h base u')

        The successor of a register's address is the next register's, so a sweep of the file's stretch and a walk of the file step together: the address the sweep moves to is the cell of the index the pointer moves to. This is what lets the file-laying phase name every cell it writes.

        Dependency graph
        theorem DescriptiveComplexity.ixSegFile_gap {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (ile : IIProp) (h : IsLinOrd WMLe) (hi : IsLinOrd ile) {base : } (hpos : 0 < base) (hbase : base + Nat.card I Nat.card { p : WPoint A // (wideData A).Posn p }) {u u' : I} (hs : IxSucc ile u u') :
        wideRank ((ixSegFile ile h hi hpos hbase).cell u') - wideRank ((ixSegFile ile h hi hpos hbase).cell u) 1

        Consecutive registers are consecutive addresses, wherever the file sits, so a move of a walk over it is a single step and a pass over the whole file costs one step per index.

        Dependency graph
        noncomputable def DescriptiveComplexity.segCell {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] (h : IsLinOrd WMLe) (base : ) (u : A) :
        AProp

        The register of an element in the file based at base: the address whose rank is base above the element's, so the file is the stretch of n consecutive addresses whose ranks start at base.

        Equations
        Instances For
          Dependency graph
          theorem DescriptiveComplexity.wideRank_segCell {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] (h : IsLinOrd WMLe) {base : } (hbase : base + Nat.card A Nat.card { p : WPoint A // (wideData A).Posn p }) (u : A) :
          wideRank (segCell h base u) = base + wmRank u

          The rank of a register is its element's, shifted by the base.

          Dependency graph
          noncomputable def DescriptiveComplexity.segFile {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] (h : IsLinOrd WMLe) {base : } (hpos : 0 < base) (hbase : base + Nat.card A Nat.card { p : WPoint A // (wideData A).Posn p }) :

          A register file on a stretch of consecutive addresses. The base says where the stretch starts; it must be positive, so that no register is the empty address the head starts on, and the stretch must fit below the top of the tape.

          Equations
          Instances For
            Dependency graph
            @[simp]
            theorem DescriptiveComplexity.cell_segFile {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] (h : IsLinOrd WMLe) {base : } (hpos : 0 < base) (hbase : base + Nat.card A Nat.card { p : WPoint A // (wideData A).Posn p }) :
            (segFile h hpos hbase).cell = segCell h base
            Dependency graph
            theorem DescriptiveComplexity.segFile_gap {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] (h : IsLinOrd WMLe) {base : } (hpos : 0 < base) (hbase : base + Nat.card A Nat.card { p : WPoint A // (wideData A).Posn p }) {u u' : A} (hs : WMSucc A u u') :
            wideRank ((segFile h hpos hbase).cell u') - wideRank ((segFile h hpos hbase).cell u) 1

            Consecutive registers are consecutive addresses, wherever the file sits, so a move of a walk over it is a single step and a pass over the whole file costs one step per element. This is the hypothesis the budgeted walks ask for, with w = 1.

            Dependency graph

            The file at the bottom #

            The base-1 case: the registers are the first n nonempty addresses, so the machine builds the file in its first n steps and everything above it is free.

            noncomputable def DescriptiveComplexity.lowCell {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] (h : IsLinOrd WMLe) (u : A) :
            AProp

            The register of an element in the file at the bottom of the tape.

            Equations
            Instances For
              Dependency graph

              There is room for the file at the bottom: there are strictly more addresses than elements.

              Dependency graph

              The rank of a register is one above the rank of the element naming it.

              Dependency graph

              The register file at the bottom of the tape.

              Equations
              Instances For
                Dependency graph
                Dependency graph

                Which addresses the registers are #

                A program does not merely need its file to exist: the phase that builds it walks the bottom of the tape writing one name per cell, so it needs to know that the cells it passes are exactly the registers, and which element each belongs to. Both are read off the ranks.

                An address is determined by its rank, ranks being a strictly monotone map of a linear order.

                Dependency graph

                Every rank below the number of elements is taken. The rank map is injective into as many numbers as there are elements, so it is onto them; this is what says the file has a register for each of the first n nonempty addresses.

                Dependency graph
                theorem DescriptiveComplexity.exists_ixRank_eq {I : Type} [Finite I] {ile : IIProp} (hi : IsLinOrd ile) {k : } (hk : k < Nat.card I) :
                ∃ (u : I), ixRank ile u = k

                Every rank below the number of indices is taken. The index rank map is injective into as many numbers as there are indices, so it is onto them – the index-level sibling of DescriptiveComplexity.exists_wmRank_eq, and what says a file on a stretch has a register for every address of that stretch.

                Dependency graph
                noncomputable def DescriptiveComplexity.ixSegTop {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] (I : Type) [Finite I] (h : IsLinOrd WMLe) (base : ) :
                AProp

                The address just above a file's stretch: where a sweep of the file stops, one past its last register.

                Equations
                Instances For
                  Dependency graph
                  theorem DescriptiveComplexity.wideRank_ixSegTop {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (h : IsLinOrd WMLe) {base : } (hbase : base + Nat.card I < Nat.card { p : WPoint A // (wideData A).Posn p }) :
                  wideRank (ixSegTop I h base) = base + Nat.card I

                  The rank of that address is the stretch's length above the base.

                  Dependency graph
                  theorem DescriptiveComplexity.wmSetLt_ixSegTop {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (ile : IIProp) (h : IsLinOrd WMLe) {base : } (hbase : base + Nat.card I < Nat.card { p : WPoint A // (wideData A).Posn p }) (u : I) :
                  WMSetLt WMLe (ixSegCell ile h base u) (ixSegTop I h base)

                  Every register is below the stretch's end, which is the upper bound a file-laying sweep is run against.

                  Dependency graph
                  theorem DescriptiveComplexity.ixRank_of_top {I : Type} [Finite I] {ile : IIProp} (hi : IsLinOrd ile) {utop : I} (htop : ∀ (y : I), ile y utop) :
                  ixRank ile utop + 1 = Nat.card I

                  The greatest index has the greatest rank: every index below it, and the ranks running over 0 … card − 1, leave it the last. So a walk that stops at the top register has crossed every one of them.

                  Dependency graph

                  The last address the sequence of a stretch reaches is taken: below the tape's top, some cell is outside the address, which is what lets the sequence advance.

                  Dependency graph
                  theorem DescriptiveComplexity.ixRank_of_bot {I : Type} [Finite I] {ile : IIProp} (hi : IsLinOrd ile) {ubot : I} (hbot : ∀ (y : I), ile ubot y) :
                  ixRank ile ubot = 0

                  The least index has rank zero: nothing lies below it, so a walk that starts at the first register has crossed none.

                  Dependency graph
                  theorem DescriptiveComplexity.ixSegTop_ne_ixSegCell {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (ile : IIProp) (h : IsLinOrd WMLe) {base : } (hbase : base + Nat.card I < Nat.card { p : WPoint A // (wideData A).Posn p }) (w : I) :
                  ixSegTop I h base ixSegCell ile h base w

                  The address past a stretch is no register's, which is what tells the sweep's last landing from every cell it wrote.

                  Dependency graph
                  theorem DescriptiveComplexity.wmIncr_ixSegCell_top {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (ile : IIProp) (h : IsLinOrd WMLe) (hi : IsLinOrd ile) {base : } (hbase : base + Nat.card I < Nat.card { p : WPoint A // (wideData A).Posn p }) {utop : I} (htop : ∀ (y : I), ile y utop) :
                  WMIncr WMLe (ixSegCell ile h base utop) (ixSegTop I h base)

                  The step off the last register: the address the sweep moves to when it writes the file's last register is the one just past the stretch.

                  Dependency graph

                  What a file's stretch costs #

                  A sweep of the stretch costs the difference of the two ranks, and these are what that difference is: the stretch is exactly as long as the file has registers, and the last register sits one short of its end. Every budget of the opening phases is one of these two numbers.

                  theorem DescriptiveComplexity.wideRank_ixSegTop_sub_bot {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (ile : IIProp) (h : IsLinOrd WMLe) (hi : IsLinOrd ile) {base : } (hbase : base + Nat.card I < Nat.card { p : WPoint A // (wideData A).Posn p }) {ubot : I} (hbot : ∀ (y : I), ile ubot y) :
                  wideRank (ixSegTop I h base) - wideRank (ixSegCell ile h base ubot) = Nat.card I

                  A sweep of the stretch costs one step per register.

                  Dependency graph
                  theorem DescriptiveComplexity.wideRank_ixSegCell_top {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (ile : IIProp) (h : IsLinOrd WMLe) (hi : IsLinOrd ile) {base : } (hbase : base + Nat.card I Nat.card { p : WPoint A // (wideData A).Posn p }) {utop : I} (htop : ∀ (y : I), ile y utop) :
                  wideRank (ixSegCell ile h base utop) + 1 = base + Nat.card I

                  The last register sits one short of the stretch's end, so a walk home from it costs the stretch and the file's base together, less one.

                  Dependency graph
                  theorem DescriptiveComplexity.exists_ixSegCell_eq {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] {I : Type} [Finite I] (ile : IIProp) (h : IsLinOrd WMLe) (hi : IsLinOrd ile) {base : } (hbase : base + Nat.card I Nat.card { p : WPoint A // (wideData A).Posn p }) {s : AProp} (h1 : base wideRank s) (h2 : wideRank s < base + Nat.card I) :
                  ∃ (u : I), ixSegCell ile h base u = s

                  The registers of a file on a stretch are exactly the addresses of that stretch. So a sweep of the stretch is a walk of the file: every cell it stops at is some register's, which is what lets the sweep's pointer name the cell it is writing.

                  Dependency graph
                  theorem DescriptiveComplexity.exists_lowCell_eq {A : Type} [FirstOrder.Language.wide.Structure A] [Finite A] (h : IsLinOrd WMLe) {s : AProp} (h1 : 1 wideRank s) (h2 : wideRank s Nat.card A) :
                  ∃ (u : A), lowCell h u = s

                  The registers of the bottom file are exactly the addresses of rank between 1 and n. So the phase that builds the file walks the first n cells above the empty address, writing at each the name of the element whose rank is one below the cell's.

                  Dependency graph

                  The file at the bottom lies in the initial stretch of n + 1 addresses: everything the machine keeps above that stretch is out of its way.

                  Dependency graph