Imports
Fixed binary adder: controller and word semantics
The public codec is big-endian. The controller first reverses the two input words onto separate work stacks, so the addition phase sees least-significant bits first. Each produced bit is prepended to the output stack; consequently the final result is big-endian again.
noncomputable sectionopen StateTransitionnamespace CLRS.Chapter34.Turing.BinaryNat.Adderopen PolyBuilder
One full-adder cell, returning (sum bit, carry bit).
def addCell (left right carry : Bool) : Bool × Bool :=
let parity := left != right
(parity != carry, (left && right) || (carry && parity))Add two little-endian bit lists and return a big-endian word.
The recursive result contains the more significant suffix. Appending the current sum bit therefore agrees with the prepend-only output stack used by the concrete controller.
def addLittle : List Bool → List Bool → Bool → List Bool
| [], [], false => []
| [], [], true => [true]
| left :: lefts, [], carry =>
let cell := addCell left false carry
addLittle lefts [] cell.2 ++ [cell.1]
| [], right :: rights, carry =>
let cell := addCell false right carry
addLittle [] rights cell.2 ++ [cell.1]
| left :: lefts, right :: rights, carry =>
let cell := addCell left right carry
addLittle lefts rights cell.2 ++ [cell.1]Total word-level semantics of the fixed adder.
def addWords (left right : List Bool) : List Bool :=
addLittle left.reverse right.reverse falseinductive Label
| loadLeft
| storeLeft (bit : Bool)
| loadRight
| storeRight (bit : Bool)
| addLeft (carry : Bool)
| addRight (carry : Bool) (left : Option Bool)
| emit (carry bit : Bool)
| finish (carry : Bool)
| halt
deriving DecidableEq, FintypeFixed two-work-stack binary addition controller.
def program : Program (Option Bool) Bool where
Label := Label
main := .loadLeft
op
| .loadLeft => .popInput (.finish false) fun
| none => .loadRight
| some bit => .storeLeft bit
| .storeLeft bit => .pushWork₁ (some bit) .loadLeft
| .loadRight => .popInput (.addLeft false) fun
| none => .loadRight
| some bit => .storeRight bit
| .storeRight bit => .pushWork₂ (some bit) .loadRight
| .addLeft carry => .popWork₁ (.addRight carry none) fun
| none => .addRight carry none
| some bit => .addRight carry (some bit)
| .addRight carry left => .popWork₂
(match left with
| none => .finish carry
| some leftBit =>
let cell := addCell leftBit false carry
.emit cell.2 cell.1)
fun
| none =>
match left with
| none => .finish carry
| some leftBit =>
let cell := addCell leftBit false carry
.emit cell.2 cell.1
| some rightBit =>
let cell := addCell (left.getD false) rightBit carry
.emit cell.2 cell.1
| .emit carry bit => .pushOutput bit (.addLeft carry)
| .finish false => .halt
| .finish true => .pushOutput true .halt
| .halt => .haltUniform proof-facing controller configuration.
def cfg (label : Label) (buffer₁ buffer₂ : Option (Option Bool))
(input : List (Option Bool)) (output : List Bool)
(work₁ work₂ : List (Option Bool)) : BuilderCfg program :=
{ initialCfg program input with
label := some label
buffer₁ := buffer₁
buffer₂ := buffer₂
output := output
work₁ := work₁
work₂ := work₂ }end CLRS.Chapter34.Turing.BinaryNat.Adder