Documentation

Complexity.Computability.Circuit.Boolean.Sorting

Batcher sorting circuits #

Records occupy consecutive blocks of input wires. The key selects coordinates in lexicographic order, with coordinate zero most significant. Each comparison moves whole records and shares its comparison flag across the record bits. Descending layers reverse ascending pairs, including ties; the complete sorter is not stable. Traced outputs prepend each comparison decision and its complement to the record blocks, sharing the original negation. Ordinary sorting selects the record outputs by free wiring. Empty records bypass the traced construction and use identity wiring; traced sorting still computes its control pairs. At depth d there are 2^d records and d * (d + 1) * 2^d / 4 comparisons. The circuit constructor is executable; the gate-count theorems do not certify its running time.

Main definitions #

Main results #

References #

def Cslib.Circuits.Boolean.bitonicLayerCircuit.pairInput {n r : ℕ} (j : Fin n) :
Fin (r + r) → Fin ((n + n) * r)

Read a comparison's two records from the two halves.

Instances For
    def Cslib.Circuits.Boolean.bitonicLayerCircuit.gather (n r : ℕ) :
    Fin (n * (r + r)) → Fin ((n + n) * r)

    Gather corresponding records into adjacent pairs.

    Instances For
      def Cslib.Circuits.Boolean.bitonicLayerCircuit.scatter (n r : ℕ) :
      Fin ((n + n) * r) → Fin (n * (r + r))

      Scatter the compared pairs back into the two record halves.

      Instances For

        Gather reads corresponding records from the two halves without changing their bits.

        Select the first half of a flat record array.

        Instances For

          Select the second half of a flat record array.

          Instances For

            The first flat input block is the first half of the record array.

            The second flat input block is the second half of the record array.

            Flatten a finite array of equal-width records.

            Instances For

              The controls retain both a decision and its complement.

              Instances For

                The payload records following the controls.

                Instances For
                  def Cslib.Circuits.Boolean.bitonicSortTraceCircuit.pack {t n r : ℕ} (c : Fin t → BitString 2) (x : Fin n → BitString r) :
                  BitString (t * 2 + n * r)

                  Encode control pairs followed by records.

                  Instances For
                    @[simp]
                    @[simp]

                    Flattening the record view recovers the original wire assignment.

                    Apply a circuit to the payload while retaining every control pair by free wiring.

                    theorem Cslib.Circuits.Boolean.bitonicSortTraceCircuit.ext {t n r : ℕ} {x y : BitString (t * 2 + n * r)} (hc : controls x = controls y) (hd : records x = records y) :
                    x = y

                    Control pairs and payload records determine the complete wire assignment.

                    The explicit numbering of control-pair and record coordinates.

                    Instances For
                      def Cslib.Circuits.Boolean.bitonicSortTraceCircuit.collect {input a b n m r : ℕ} (left : Circuit signature input (a * 2 + n * r)) (right : Circuit signature input (b * 2 + m * r)) :
                      Circuit signature input ((a + b) * 2 + (n + m) * r)

                      Collect two circuits' controls before their concatenated record outputs.

                      Instances For
                        def Cslib.Circuits.Boolean.bitonicSortTraceCircuit.chain {input a b n m r : ℕ} (first : Circuit signature input (a * 2 + n * r)) (second : Circuit signature (n * r) (b * 2 + m * r)) :
                        Circuit signature input ((a + b) * 2 + m * r)

                        Preserve the first controls while executing the second circuit on its payload.

                        Instances For

                          Pair each decision with its complement.

                          Instances For
                            def Cslib.Circuits.Boolean.bitonicSortTraceCircuit.pair {r : ℕ} (flag : Circuit signature (r + r) 1) (ascending : Bool) :
                            Circuit signature (r + r) (2 + (r + r))

                            Descending compare-exchange reverses both the payload and the two control wires.

                            Instances For
                              def Cslib.Circuits.Boolean.bitonicSortTraceCircuit.layer {k r : ℕ} (key : Fin k → Fin r) (n : ℕ) (ascending : Bool) :
                              Circuit signature ((n + n) * r) (n * 2 + (n + n) * r)

                              Compare a layer and retain all of its controls before the payload.

                              Instances For
                                def Cslib.Circuits.Boolean.bitonicSortTraceCircuit.halves {a b n r : ℕ} (left : Circuit signature (n * r) (a * 2 + n * r)) (right : Circuit signature (n * r) (b * 2 + n * r)) :
                                Circuit signature ((n + n) * r) ((a + b) * 2 + (n + n) * r)

                                Run one traced circuit on each half of a record array.

                                Instances For

                                  Bitonic merge, retaining comparison decisions before the merged records.

                                  Instances For

                                    Bitonic sorting, retaining comparison decisions before the sorted records.

                                    Instances For
                                      theorem Cslib.Circuits.Boolean.eval_bitonicMergeTraceCircuit {k r : ℕ} (key : Fin k → Fin r) (d : ℕ) (ascending : Bool) (x : BitString (BitonicSort.arity d * r)) :

                                      The forward merge exposes exactly the semantic trace and merged records.

                                      theorem Cslib.Circuits.Boolean.eval_bitonicSortTraceCircuit {k r : ℕ} (key : Fin k → Fin r) (d : ℕ) (ascending : Bool) (x : BitString (BitonicSort.arity d * r)) :

                                      The forward sorter exposes exactly the semantic trace and sorted records.

                                      A traced merge computes each comparator once, retaining its existing control pair.

                                      A traced sort computes each comparator once, retaining its existing control pair.

                                      def Cslib.Circuits.Boolean.bitonicLayerCircuit {k r : ℕ} (key : Fin k → Fin r) (n : ℕ) (ascending : Bool) :
                                      Circuit signature ((n + n) * r) ((n + n) * r)

                                      Compare corresponding records, discarding the saved controls. Empty records use no gates.

                                      Instances For
                                        def Cslib.Circuits.Boolean.bitonicMergeCircuit {k r : ℕ} (key : Fin k → Fin r) (depth : ℕ) (ascending : Bool) :

                                        Merge a bitonic array by selecting its traced merge's record outputs.

                                        Instances For
                                          def Cslib.Circuits.Boolean.bitonicSortCircuit {k r : ℕ} (key : Fin k → Fin r) (depth : ℕ) (ascending : Bool) :

                                          Sort complete records, retaining the traced construction's sharing internally.

                                          Instances For
                                            theorem Cslib.Circuits.Boolean.eval_bitonicLayerCircuit {k r : ℕ} (key : Fin k → Fin r) (n : ℕ) (ascending : Bool) (x : BitString ((n + n) * r)) :
                                            directProductInput ((bitonicLayerCircuit key n ascending).eval interpretation x) = BitonicSort.compareLayer (fun (record : BitString r) => toLex (record ∘ key)) ascending (directProductInput x)

                                            Reading complete output records agrees with the generic bitonic comparison layer.

                                            theorem Cslib.Circuits.Boolean.eval_bitonicMergeCircuit {k r : ℕ} (key : Fin k → Fin r) (depth : ℕ) (ascending : Bool) (x : BitString (BitonicSort.arity depth * r)) :
                                            directProductInput ((bitonicMergeCircuit key depth ascending).eval interpretation x) = BitonicSort.merge (fun (record : BitString r) => toLex (record ∘ key)) depth ascending (directProductInput x)

                                            The native circuit realizes bitonic merge on complete records.

                                            theorem Cslib.Circuits.Boolean.eval_bitonicSortCircuit {k r : ℕ} (key : Fin k → Fin r) (depth : ℕ) (ascending : Bool) (x : BitString (BitonicSort.arity depth * r)) :
                                            directProductInput ((bitonicSortCircuit key depth ascending).eval interpretation x) = BitonicSort.sort (fun (record : BitString r) => toLex (record ∘ key)) depth ascending (directProductInput x)

                                            The native circuit realizes Batcher sorting on complete records.

                                            The output keys of ascending sorting are nondecreasing.

                                            The output keys of descending sorting are nonincreasing.

                                            theorem Cslib.Circuits.Boolean.bitonicSortCircuit_perm {k r : ℕ} (key : Fin k → Fin r) (depth : ℕ) (ascending : Bool) (x : BitString (BitonicSort.arity depth * r)) :

                                            Sorting preserves the multiset of complete input records, including payload and duplicates.

                                            theorem Cslib.Circuits.Boolean.cost_program_bitonicLayerCircuit {k r : ℕ} (key : Fin k → Fin r) (n : ℕ) (ascending : Bool) (cost : signature.Op → ℕ) :
                                            (bitonicLayerCircuit key n ascending).program.cost cost = n * (compareSwapCircuit key).program.cost cost

                                            A layer uses n copies of the comparator under any assignment of gate costs.

                                            theorem Cslib.Circuits.Boolean.two_mul_cost_program_bitonicMergeCircuit {k r : ℕ} (key : Fin k → Fin r) (depth : ℕ) (ascending : Bool) (cost : signature.Op → ℕ) :
                                            2 * (bitonicMergeCircuit key depth ascending).program.cost cost = depth * 2 ^ depth * (compareSwapCircuit key).program.cost cost

                                            Exact merge cost: depth * 2^depth / 2 comparisons, stated without natural division.

                                            theorem Cslib.Circuits.Boolean.four_mul_cost_program_bitonicSortCircuit {k r : ℕ} (key : Fin k → Fin r) (depth : ℕ) (ascending : Bool) (cost : signature.Op → ℕ) :
                                            4 * (bitonicSortCircuit key depth ascending).program.cost cost = depth * (depth + 1) * 2 ^ depth * (compareSwapCircuit key).program.cost cost

                                            Exact sorting cost: depth * (depth + 1) * 2^depth / 4 comparisons. The identity includes depth zero, empty keys, empty records, and arbitrary gate costs.

                                            @[simp]
                                            theorem Cslib.Circuits.Boolean.size_bitonicLayerCircuit {k r : ℕ} (key : Fin k → Fin r) (n : ℕ) (ascending : Bool) :

                                            Each of the n comparisons is charged once, including constants and negations.

                                            theorem Cslib.Circuits.Boolean.four_mul_size_bitonicSortCircuit {k r : ℕ} (key : Fin k → Fin r) (depth : ℕ) (ascending : Bool) :
                                            4 * (bitonicSortCircuit key depth ascending).size = depth * (depth + 1) * 2 ^ depth * if r = 0 then 0 else 6 * k + 6 * r + 2

                                            Exact total gate count, including constants and negations.

                                            theorem Cslib.Circuits.Boolean.cost_program_bitonicSortTraceCircuit_eq {k r : ℕ} (key : Fin k → Fin r) (d : ℕ) (ascending : Bool) (hr : r ≠ 0) (cost : signature.Op → ℕ) :
                                            (bitonicSortTraceCircuit key d ascending).program.cost cost = (bitonicSortCircuit key d ascending).program.cost cost

                                            Retaining the trace adds no gates to ordinary sorting when records are nonempty.

                                            theorem Cslib.Circuits.Boolean.size_bitonicSortTraceCircuit {k r : ℕ} (key : Fin k → Fin r) (d : ℕ) (ascending : Bool) :
                                            (bitonicSortTraceCircuit key d ascending).size = BitonicSort.sortTraceSize d * (6 * k + 6 * r + 2)

                                            Exact gate count, including the comparison constant and shared negation at empty width.