Dual-rail normalization for AC0 circuits #
This module implements the local compiler underlying input-negation normal form. Every Boolean value is represented by two wires carrying the value and its complement. A source NOT swaps the two rails without adding a gate. A source AND or OR produces both its ordinary output and its De Morgan dual, using exactly two target gates.
The construction is semantic rather than syntactic: the same block translation simulates both Boolean evaluation and the logical-depth interpretation. Thus compilation preserves logical depth exactly and doubles the charged AND/OR cost, including at fan-in zero.
Duplicate a logical depth across both rails.
Equations
- Algebraic.AC0.DualRail.duplicateDepth depth = ![depth, depth]
Instances For
A NOT gate swaps the two rails without adding a gate.
Equations
- Algebraic.AC0.DualRail.notCircuit = { size := 0, program := Cslib.Circuits.Program.empty, outputs := ![Algebraic.Block.inputWire 0 1, Algebraic.Block.inputWire 0 0] }
Instances For
The dual-rail NOT only swaps the rails: it has no gates.
The dual-rail AND gadget has exactly two gates: an AND for the positive rail and an OR for its complement.
Number of gates in a dual-rail operation gadget.
Equations
Instances For
Dual-rail compilation of arbitrary AC0 gates.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Each dual-rail gadget has gateCount gates.
Logical-depth dual-rail simulation.
Equations
Instances For
Whole-circuit normalization #
The first g input-negation gates over an n-input namespace.
Equations
- One or more equations did not get rendered due to their size.
- Algebraic.AC0.DualRail.inputNegationProgram n 0 x_2 = Cslib.Circuits.Program.empty
Instances For
Generate the positive and negative literal rails for every input. The encoder has one NOT gate per input, and each such gate reads that input directly.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The input encoder computes each input together with its complement.
Input encoding adds no logical depth: both rails inherit their input's arrival time.
Input encoding has zero charged AND/OR cost.
Every NOT in the input encoder reads an original input.
Project the positive rail of every compiled output.
Equations
- Algebraic.AC0.DualRail.positiveOutputs circuit = circuit.mapOutputs fun (output : Fin m) => finProdFinEquiv (output, 0)
Instances For
Keeping only the positive rails adds no gates.
Eliminate every internal negation by dual-rail compilation. The resulting
circuit contains n input-literal NOT gates followed by a negation-free
compiled program.
Equations
Instances For
The normalized circuit satisfies the checked input-negation invariant.
Normalization preserves the logical depth of every designated output.
Normalization preserves maximum logical depth exactly.
Family-level normalization #
Normalize every member of a circuit family.
Equations
- Algebraic.AC0.DualRail.normalizeFamily family = { circuit := fun (n : ℕ) => Algebraic.AC0.DualRail.normalize (family.circuit n) }
Instances For
The member at width n is the normalization of the source member.
Family normalization doubles charged cost pointwise.
Family normalization has one input-literal gate per input and two gates per charged source gate.
Family normalization preserves logical depth pointwise.
Family normalization preserves the computed target.
Every normalized family member has only input-level negations.
Polynomial AND/OR cost is preserved by family normalization.
Normalization turns polynomial charged cost into polynomial total gate
count, with the explicit bound
(2 * coefficient + 1) * (n + 1) ^ (degree + 1).
Constant logical depth is preserved by family normalization.
Every raw small-depth family has an equivalent checked family.
Raw and input-negation-normalized presentations define the same nonuniform AC0 class.