Carry-save addition trees and logarithmic-depth bit counting #
A 3-to-2 carry-save adder (csa3to2 w) reduces three w-bit words x, y, z to a bitwise
exclusive-or word csaSum x y z and a shifted carry word csaCarry x y z in constant depth (≤ 6)
and linear size (≤ 20 w), preserving the sum of their unsigned values modulo 2 ^ w
(val_csaSum_add_val_csaCarry_mod). Two carry-save layers form a 4-to-2 reducer (csa4to2 w) that
combines two redundant carry-save pairs (a₁, b₁) and (a₂, b₂) into one pair (s, c) in depth
at most 12 and size at most 40 w.
Combining k one-bit inputs along a balanced binary tree (Circuit.balanced) of 4-to-2 reducers
produces a carry-save pair whose sum modulo 2 ^ w is the Hamming weight BitString.weight x, in
depth O(log k) and size O(k w). Iterating csa3to2 w with a zero third word w times
(finishCircuit w w) clears a further carry bit at every step
(sndBits_eval_finishCircuit_eq_false), collapsing the carry-save pair to a single w-bit binary
numeral in depth O(w) and size O(w²).
Taking w = ⌈log₂ (k + 1)⌉ gives a De Morgan circuit (weightCircuit k) of depth O(log k) and
size O(k log k) that outputs the exact binary representation of BitString.weight x
(val_eval_weightCircuit) Chandra, Stockmeyer and Vishkin,
Vollmer, Chapter 1.
Main definitions #
Cslib.Circuits.Boolean.pairVal,Cslib.Circuits.Boolean.maj3,Cslib.Circuits.Boolean.csaSum,Cslib.Circuits.Boolean.csaCarry: carry-save pair value, 3-bit majority carry, and bitwise sum and shifted carry words onw-bit words.Cslib.Circuits.Boolean.csaSumFormula,Cslib.Circuits.Boolean.maj3Formula,Cslib.Circuits.Boolean.csaCarryFormula,Cslib.Circuits.Boolean.csa4to2FirstIn: coordinate formulas and input wiring for 3-to-2 and 4-to-2 carry-save reduction.Cslib.Circuits.Boolean.csa3to2,Cslib.Circuits.Boolean.csa4to2: 3-to-2 and 4-to-2 carry-save reduction circuits onw-bit words.Cslib.Circuits.Boolean.finishStepIn,Cslib.Circuits.Boolean.finishStep,Cslib.Circuits.Boolean.finishCircuit: carry-clearing step and iteration reducing a carry-save pair to a singlew-bit word.Cslib.Circuits.Boolean.zeroPairCircuit,Cslib.Circuits.Boolean.bitPairCircuit,Cslib.Circuits.Boolean.weightPairCircuit,Cslib.Circuits.Boolean.weightCircuit: leaf circuits, balanced carry-save reduction tree, and De Morgan circuit computing the binary numeral of the Hamming weight ofkinput bits.
Main results #
Cslib.Circuits.Boolean.val_csaSum_add_val_csaCarry_mod: 3-to-2 carry-save reduction preserves the sum modulo2 ^ w.Cslib.Circuits.Boolean.val_eval_weightCircuit:weightCircuit kcomputes the exact binary numeral ofBitString.weight xin⌈log₂ (k + 1)⌉bits.Cslib.Circuits.Boolean.size_weightCircuit_le,Cslib.Circuits.Boolean.depth_weightCircuit_le: sizeO(k log k)and depthO(log k).
References #
- [A. K. Chandra, L. Stockmeyer, U. Vishkin, Constant depth reducibility] [CSV84]
- H. Vollmer, Introduction to Circuit Complexity
Unsigned word values and carry-save arithmetic #
The carry-save value of an appended pair (x, y) is the sum of the unsigned values of x and
y.
The carry of a 1-bit full adder: whether at least two of the three bits are true.
Instances For
The bitwise exclusive-or word of a 3-to-2 carry-save adder on w-bit words.
Instances For
The shifted carry word of a 3-to-2 carry-save adder on w-bit words: bit 0 is false and
bit i + 1 is the full-adder carry from bit i.
Instances For
Carry-save 3-to-2 invariant: the sum and shifted carry words have the same sum of unsigned
values modulo 2 ^ w as the three input words.
3-to-2 and 4-to-2 carry-save circuits #
csaSumFormula w i evaluates to bit i of csaSum on the three w-bit words of u.
csaSumFormula w i has size 15.
csaSumFormula w i has depth at most 6.
maj3Formula a b c evaluates to maj3 (u a) (u b) (u c).
maj3Formula a b c has size 5.
maj3Formula a b c has depth at most 3.
csaCarryFormula w i evaluates to bit i of csaCarry on the three w-bit words of u.
csaCarryFormula w i has size at most 5.
csaCarryFormula w i has depth at most 3.
Carry-clearing iteration #
finishStep w evaluates to (csaSum a b 0, csaCarry a b 0) on the carry-save pair
p = (a, b).
finishStep w preserves the carry-save value modulo 2 ^ w.
finishStep w has size at most 20 * w + 1.
finishStep w has depth at most 7.
finishCircuit w t preserves the carry-save value modulo 2 ^ w.
After w carry-clearing steps, the carry word is identically zero, so the first w-bit word
has unsigned value congruent to pairVal p modulo 2 ^ w.
finishCircuit w t has size at most t * (20 * w + 1).
finishCircuit w t has depth at most 7 * t.
Balanced carry-save tree for Hamming weight #
zeroPairCircuit k w outputs false on every wire.
zeroPairCircuit k w has size 1.
zeroPairCircuit k w has depth at most 1.
bitPairCircuit k w j outputs a carry-save pair with value congruent to (x j).toNat modulo
2 ^ w.
bitPairCircuit k w j has size 1.
bitPairCircuit k w j has depth at most 1.
weightPairCircuit k w outputs a carry-save pair whose value is congruent to the Hamming
weight BitString.weight x modulo 2 ^ w.
weightPairCircuit k w has size at most max 1 k + k * (40 * w).
weightPairCircuit k w has depth at most 1 + 12 * Nat.clog 2 k.
weightCircuit k computes the exact binary numeral of BitString.weight x.
weightCircuit k has depth O(log k).