Documentation

DescriptiveComplexity.LogTime.Bits

The bit layer of a finite ordered universe #

An element of a finite linearly ordered universe is a number, its rank; this file gives access to that number one bit at a time, in the two ways a bit position can be named, and relates them.

Two namings, and what each is for #

A bit position can be named by its index i, or by its place value, the element p whose rank is 2 ^ i. Both appear here, and neither is a variant of the other:

DescriptiveComplexity.bitIx_iff_bitAt is the bridge, and it is one existential: BitIx i x is BitAt p x at the p of rank 2 ^ i. What that existential costs is the definability of the graph of i ↦ 2 ^ i (DescriptiveComplexity.PowArithDef) – Immerman 1999 Thm 1.17(2), and the single lemma on which the translation of the machine's logic into FO(≤, +, ×) rests. It is a named statement rather than an assumption, and it is proved: DescriptiveComplexity.powArithDef (LogTime/Pow.lean); see DescriptiveComplexity.LogTime.

The number of positions is Nat.clog 2 (Nat.card A) (DescriptiveComplexity.posCount), and the ranks are exactly the numbers whose bits live in that range; the top index is DescriptiveComplexity.IsTopIx, read off the bits of the greatest element and so needing no arithmetic on exponents.

What a bit vector can hold #

A single element holds one bit per position, so it can carry a whole Bool-valued function of the positions – provided the value stays below the size of the universe. That is the reason for DescriptiveComplexity.exists_orank_testBit, stated with an explicit bit budget: below posCount A a bit vector is not in general a rank (the universe need not have a power of two elements), below posCount A - 1 it always is. That one-position gap is what forces the sweep simulation of DescriptiveComplexity.LogTime to carry the state of its last step separately, and it is the only place the arithmetic of the layer is not uniform.

Bits of a natural number #

A bit is a comparison of the remainder: the bit of x at place value 2 ^ i is set exactly when x is at least 2 ^ i modulo 2 ^ (i + 1).

Dependency graph
theorem DescriptiveComplexity.testBit_iff_exists_split (x i : ) :
x.testBit i = true ∃ (u : ) (v : ), u + v = x 2 ^ i v v < 2 ^ (i + 1) 2 ^ (i + 1) u

A bit is a splitting: the bit of x at place value 2 ^ i is set exactly when x splits as a multiple of 2 ^ (i + 1) plus a remainder between 2 ^ i and 2 ^ (i + 1). Every witness is at most x, which is what makes the statement survive the truncation of a finite universe.

Dependency graph
theorem DescriptiveComplexity.testBit_iff_le_of_lt {x i : } (h : x < 2 ^ (i + 1)) :
x.testBit i = true 2 ^ i x

Below 2 ^ (i + 1) a bit is just a comparison: the truncated case, where the doubling of the place value has overflowed the universe.

Dependency graph
theorem DescriptiveComplexity.eq_two_pow_of_forall_dvd (p : ) :
p 0(∀ (d : ), d pd = 1 2 d)∃ (i : ), p = 2 ^ i

Powers of two, by their divisors: a nonzero number all of whose divisors are 1 or even is a power of two. This is the first-order reading of “p is a position”, and it needs no primality.

Dependency graph
theorem DescriptiveComplexity.forall_dvd_of_eq_two_pow {p i : } (hp : p = 2 ^ i) (d : ) :
d pd = 1 2 d

The converse: every divisor of a power of two is 1 or even.

Dependency graph
noncomputable def DescriptiveComplexity.bitsVal (b : Bool) (m : ) :

The value of a finite bit vector, as a sum of place values.

Equations
Instances For
    Dependency graph
    theorem DescriptiveComplexity.bitsVal_succ (b : Bool) (m : ) :
    bitsVal b (m + 1) = bitsVal b m + if b m = true then 2 ^ m else 0

    Peeling the top bit of a finite bit vector.

    Dependency graph
    theorem DescriptiveComplexity.bitsVal_lt (b : Bool) (m : ) :
    bitsVal b m < 2 ^ m
    Dependency graph
    theorem DescriptiveComplexity.testBit_bitsVal (b : Bool) (m : ) {i : } (hi : i < m) :
    (bitsVal b m).testBit i = b i
    Dependency graph

    Positions of a finite ordered universe #

    noncomputable def DescriptiveComplexity.posCount (A : Type) [LinearOrder A] [Finite A] :

    The number of bit positions of the ranks of A: the ranks are the numbers below Nat.card A, so they are exactly the numbers whose bits live below Nat.clog 2 (Nat.card A).

    Equations
    Instances For
      Dependency graph

      A place value is that of a position exactly when it is a rank.

      Dependency graph

      Above the positions, every rank has a zero bit.

      Dependency graph

      p is a position: its rank is a place value 2 ^ i. The element is the place value; the exponent never appears in a formula.

      Equations
      Instances For
        Dependency graph
        noncomputable def DescriptiveComplexity.posExp {A : Type} [LinearOrder A] (p : A) :

        The exponent of a position.

        Equations
        Instances For
          Dependency graph
          theorem DescriptiveComplexity.posExp_eq {A : Type} [LinearOrder A] {p : A} {i : } (h : orank p = 2 ^ i) :
          posExp p = i
          Dependency graph
          Dependency graph
          theorem DescriptiveComplexity.exists_isPos {A : Type} [LinearOrder A] [Finite A] {i : } (hi : i < posCount A) :
          ∃ (p : A), orank p = 2 ^ i

          Every exponent in range is the exponent of a position.

          Dependency graph
          theorem DescriptiveComplexity.isPos_iff_forall_dvd {A : Type} [LinearOrder A] [Finite A] (p : A) :
          IsPos p orank p 0 ∀ (d : A), (∃ (w : A), orank w * orank d = orank p)orank d = 1 ∃ (e : A), orank e + orank e = orank d

          Being a position is first-order: a nonzero rank all of whose divisors are 1 or even, with every divisor and cofactor a rank of the universe – which they are, being at most orank p.

          Dependency graph
          theorem DescriptiveComplexity.exists_orank_testBit {A : Type} [LinearOrder A] [Finite A] [Nonempty A] (b : Bool) :
          ∃ (t : A), ∀ (i : ), i + 1 < posCount A(orank t).testBit i = b i

          The bit budget of a trace: a bit vector supported below the top position is a rank, whatever the size of the universe.

          Dependency graph
          theorem DescriptiveComplexity.exists_orank_testBit' {A : Type} [LinearOrder A] [Finite A] [Nonempty A] (b : Bool) :
          ∃ (t : A), (∀ (i : ), i + 1 < posCount A(orank t).testBit i = b i) ∀ (i : ), posCount A i + 1(orank t).testBit i = false

          The same, with the top positions pinned to zero: the element a bit vector names carries no bit at the top position, which is what a construction needs when it also has to say that nothing outside its layout is set.

          Dependency graph

          The bit of an element at a position #

          The bit of x at the place value p, first-order in , + and ×: either the doubling q = p + p exists, and then x splits as a multiple u of q plus a remainder v with p ≤ v < q; or it does not, and then x is below 2 p already and the bit is the comparison p ≤ x.

          Equations
          • One or more equations did not get rendered due to their size.
          Instances For
            Dependency graph
            theorem DescriptiveComplexity.bitAt_iff {A : Type} [LinearOrder A] [Finite A] {p x : A} {i : } (hp : orank p = 2 ^ i) :

            BitAt is BIT: at a position of place value 2 ^ i, it is the i-th bit of the rank.

            Dependency graph

            The bit of an element at an index #

            The bit of x at the index i: the BIT of the classical vocabulary FO(≤, BIT), the position being named by the element whose rank is the exponent. Total, and with no guard – above the bit positions of the universe every bit is simply clear.

            Equations
            Instances For
              Dependency graph
              Dependency graph

              A bit that is set is at a position of the universe.

              Dependency graph
              theorem DescriptiveComplexity.exists_isMax (A : Type) [LinearOrder A] [Finite A] [Nonempty A] :
              ∃ (m : A), ∀ (k : A), k m

              A finite nonempty order has a greatest element – the one a formula reads the top index off.

              Dependency graph
              theorem DescriptiveComplexity.bitIx_iff_bitAt {A : Type} [LinearOrder A] [Finite A] {i x : A} :
              BitIx i x ∃ (p : A), orank p = 2 ^ orank i BitAt p x

              The two namings agree: the bit at the index i is the bit at the place value 2 ^ i. The existential is the whole of the difference between the two readings of BIT, and DescriptiveComplexity.PowArithDef is what it costs.

              Dependency graph

              i is the top index: the highest bit position of the universe.

              Equations
              Instances For
                Dependency graph

                i is a low index: a bit position with a further one above it. What separates the two is the budget of DescriptiveComplexity.exists_orank_testBit: a guessed trace carries a bit at every low index, and the top one has to be carried apart.

                Equations
                Instances For
                  Dependency graph
                  theorem DescriptiveComplexity.bitIx_max_of_isTopIx {A : Type} [LinearOrder A] [Finite A] {i m : A} (hm : ∀ (k : A), k m) (h : IsTopIx i) :
                  BitIx i m

                  The greatest element has its highest bit at the top index: orank of it is Nat.card A - 1, which lies between 2 ^ (posCount A - 1) and 2 ^ posCount A. This is what lets a formula find the end of the tape without any arithmetic on exponents – it reads it off the bits of an element it already has.

                  Dependency graph

                  Every index below the count is the rank of an element.

                  Dependency graph

                  The count of positions is itself a rank: there are never more bit positions than elements, so a formula may quantify over an index one above the top – which is what pins the absence of a carry out of the last position.

                  Dependency graph
                  theorem DescriptiveComplexity.isTopIx_iff_bits {A : Type} [LinearOrder A] [Finite A] {i m : A} (hm : ∀ (k : A), k m) :
                  IsTopIx i BitIx i m ∀ (k : A), i < k¬BitIx k m

                  The top index, read from the bits of the greatest element: it is the highest index carrying a bit there.

                  Dependency graph
                  theorem DescriptiveComplexity.isLowIx_iff_bits {A : Type} [LinearOrder A] [Finite A] {i m : A} (hm : ∀ (k : A), k m) :
                  IsLowIx i ∃ (k : A), i < k BitIx k m

                  A low index, read from the same bits: one with a bit of the greatest element strictly above it.

                  Dependency graph

                  Definability of the bit layer #

                  theorem DescriptiveComplexity.arithDef_lt {L : FirstOrder.Language} {α : Type} (x y : α) :
                  ArithDef fun (x_1 : Type) (x_2 : L.Structure x_1) (x_3 : LinearOrder x_1) (x_4 : Finite x_1) (x_5 : Nonempty x_1) (v : αx_1) => v x < v y

                  The strict order between two variables is definable.

                  Dependency graph
                  theorem DescriptiveComplexity.arithDef_isZero {L : FirstOrder.Language} {α : Type} (x : α) :
                  ArithDef fun (x_1 : Type) (x_2 : L.Structure x_1) (x_3 : LinearOrder x_1) (x_4 : Finite x_1) (x_5 : Nonempty x_1) (v : αx_1) => orank (v x) = 0

                  A rank being zero is definable: x + x = x holds of the least element only.

                  Dependency graph
                  theorem DescriptiveComplexity.arithDef_isOne {L : FirstOrder.Language} {α : Type} (x : α) :
                  ArithDef fun (x_1 : Type) (x_2 : L.Structure x_1) (x_3 : LinearOrder x_1) (x_4 : Finite x_1) (x_5 : Nonempty x_1) (v : αx_1) => orank (v x) = 1

                  A rank being one is definable: an idempotent nonzero rank.

                  Dependency graph
                  theorem DescriptiveComplexity.arithDef_isPos {L : FirstOrder.Language} {α : Type} (x : α) :
                  ArithDef fun (x_1 : Type) (x_2 : L.Structure x_1) (x_3 : LinearOrder x_1) (x_4 : Finite x_1) (x_5 : Nonempty x_1) (v : αx_1) => IsPos (v x)

                  Being a position is definable, by DescriptiveComplexity.isPos_iff_forall_dvd.

                  Dependency graph
                  theorem DescriptiveComplexity.arithDef_bit {L : FirstOrder.Language} {α : Type} (p x : α) :
                  ArithDef fun (x_1 : Type) (x_2 : L.Structure x_1) (x_3 : LinearOrder x_1) (x_4 : Finite x_1) (x_5 : Nonempty x_1) (v : αx_1) => BitAt (v p) (v x)

                  The bit relation is definable: DescriptiveComplexity.BitAt is a formula of FO(≤, +, ×), so the bit layer costs the logic nothing.

                  Dependency graph

                  The naming bridge #

                  The one thing the place-value naming does not hand over. Everything above is a formula of FO(≤, +, ×) outright; the index naming needs, on top of it, the graph of i ↦ 2 ^ i, and that is a theorem rather than a construction – the half of Immerman 1999 Thm 1.17 that goes from +, × to BIT at an exponent. It is named here, where its consumers are, and proved in DescriptiveComplexity.LogTime.Pow, which is where the certificate it is proved by can be stated.

                  The naming bridge: the graph of i ↦ 2 ^ i is a formula of FO(≤, +, ×), uniformly in the variable layout.

                  This is Immerman 1999 Thm 1.17(2), and it is proved: DescriptiveComplexity.powArithDef, by the packing argument that guesses the doubling chain of i. It is a def rather than a plain statement because every consumer needs it at its own variable layout; DescriptiveComplexity.BitDefinable is a logic over the index naming, and this is what turns its bit atom back into the place-value one.

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    Dependency graph
                    theorem DescriptiveComplexity.PowArithDef.arithDef_bitIx {L : FirstOrder.Language} {α : Type} (h : PowArithDef L) (i x : α) :
                    ArithDef fun (x_1 : Type) (x_2 : L.Structure x_1) (x_3 : LinearOrder x_1) (x_4 : Finite x_1) (x_5 : Nonempty x_1) (v : αx_1) => BitIx (v i) (v x)

                    The bit at an index is first-order, given the bridge: guess the place value, and read the place-value bit there.

                    Dependency graph