Source file prefix_sum.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
open Base
open! Hardcaml
module Config = struct
type t =
| Serial
| Sklansky
| Brent_kung
| Kogge_stone
[@@deriving enumerate, sexp_of]
end
open Config
let serial ( +: ) l =
match l with
| [] -> assert false
| h :: t ->
let o =
List.fold t ~init:[ h ] ~f:(fun accum a -> (List.hd_exn accum +: a) :: accum)
in
List.rev o
;;
let split_pow2 l =
match List.length l with
| 0 -> #([], [])
| 1 -> #(l, [])
| w -> List.split_n l (Int.floor_pow2 (w - 1))
;;
let rec sklansky ( +: ) l =
match l with
| [] -> failwith "sklansky"
| [ a ] -> [ a ]
| _ ->
let #(s, t) = split_pow2 l in
let s = sklansky ( +: ) s in
let t = sklansky ( +: ) t in
let s_last = List.last_exn s in
s @ List.map t ~f:(fun t -> s_last +: t)
;;
let rec pairs = function
| [] -> []
| a :: b :: tl -> (a, b) :: pairs tl
| _ -> failwith "pairs"
;;
let rec brent_kung ( +: ) l =
match l with
| [] -> failwith "brent_kung"
| [ a ] -> [ a ]
| _ ->
let p = pairs l in
let l = List.map p ~f:(fun (a, b) -> a +: b) in
let l = brent_kung ( +: ) l in
let p = List.map p ~f:fst in
(match p with
| [] -> assert false
| ph :: pt ->
let lt, lh =
match List.rev l with
| [] -> assert false
| h :: t -> List.rev t, h
in
let o = List.concat (List.map2_exn lt pt ~f:(fun a b -> [ a; a +: b ])) in
ph :: (o @ [ lh ]))
;;
let kogge_stone ( +: ) l =
let length = List.length l in
if not (Int.is_pow2 length)
then
raise_s
[%message
"Kogge_stone adder requires input list's length to be a power of two"
(length : int)];
let rec loop n =
if n = 0
then l
else (
let l = loop (n / 2) in
let l0, l1, l2 = List.take l n, List.drop l n, List.take l (length - n) in
l0 @ List.map2_exn l2 l1 ~f:( +: ))
in
loop (length / 2)
;;
let network = function
| Serial -> serial
| Sklansky -> sklansky
| Brent_kung -> brent_kung
| Kogge_stone -> kogge_stone
;;
let eval ~config ~operator inputs = network config operator inputs
let create
(type t)
(module Bits : Hardcaml.Comb.S with type t = t)
~config
~input1
~input2
~carry_in
=
let open Bits in
let module A = Add.Make (Bits) in
let open A.Add_result in
let module Gp = struct
type t =
{
g : Bits.t
; p : Bits.t
}
let ( + ) t1 t2 = { g = t2.g |: (t1.g &: t2.p); p = t1.p &: t2.p }
end
in
let open Gp in
let input_bits = List.rev (List.zip_exn (bits_msb input1) (bits_msb input2)) in
let half_adders = List.map input_bits ~f:(fun (a, b) -> A.half_adder a b) in
let prefix_sums =
network
config
( + )
(List.map half_adders ~f:(fun { A.Add_result.carry; sum } -> { g = carry; p = sum }))
in
let input_bit_sums = List.map half_adders ~f:(fun { sum; _ } -> sum) @ [ gnd ] in
let carry_ins =
carry_in :: List.map prefix_sums ~f:(fun { g; p } -> g |: (p &: carry_in))
in
let sums =
List.map2_exn input_bit_sums carry_ins ~f:(fun input_bit_sum carry_in ->
input_bit_sum ^: carry_in)
in
concat_lsb sums
;;