def popcount(w): """ Create a population count circuit. Parameters ---------- w: the width of the adder. Returns ------- a `CircuitGraph` addder. """ c = Circuit(name="popcount") ps = [[c.add(f"in_{i}", "input")] for i in range(w)] i = 0 while len(ps) > 1: # get values ns = ps.pop(0) ms = ps.pop(0) # pad aw = max(len(ns), len(ms)) while len(ms) < aw: ms += ["null"] while len(ns) < aw: ns += ["null"] # instantiate and connect adder a = adder(aw).strip_io() c.extend(a.relabel({n: f"add_{i}_{n}" for n in a.nodes()})) for j, (n, m) in enumerate(zip(ns, ms)): c.connect(n, f"add_{i}_a_{j}") c.connect(m, f"add_{i}_b_{j}") # add adder outputs ps.append([f"add_{i}_out_{j}" for j in range(aw + 1)]) i += 1 # connect outputs for i, o in enumerate(ps[0]): c.add(f"out_{i}", "buf", fanin=o, output=True) if "null" in c: c.set_type("null", "0") c.set_output("null", False) return c
def sensitivity_transform(c, n): """ Creates a circuit to compute sensitivity. Parameters ---------- c : Circuit Sequential circuit to unroll. n : str Node to compute sensitivity at. Returns ------- Circuit Sensitivity circuit. """ # check for blackboxes if c.blackboxes: raise ValueError(f"{c.name} contains a blackbox") # check for startpoints startpoints = c.startpoints(n) if len(startpoints) < 1: raise ValueError(f"{n} has no startpoints") # get input cone fi_nodes = c.transitive_fanin(n) | set([n]) sub_c = Circuit(graph=c.graph.subgraph(fi_nodes).copy()) # create sensitivity circuit sen = Circuit() sen.add_subcircuit(sub_c, "orig") for s in startpoints: sen.add(s, "input", fanout=f"orig_{s}") # add popcount sen.add_subcircuit(popcount(len(startpoints)), "pc") # add inverted input copies for i, s0 in enumerate(startpoints): sen.add_subcircuit(sub_c, f"inv_{s0}") # connect inputs for s1 in startpoints: if s0 != s1: sen.connect(s1, f"inv_{s0}_{s1}") else: # connect inverted input sen.set_type(f"inv_{s0}_{s1}", "not") sen.connect(s0, f"inv_{s0}_{s1}") # compare to orig sen.add( f"dif_{s0}", "xor", fanin=[f"orig_{n}", f"inv_{s0}_{n}"], fanout=f"pc_in_{i}", ) sen.add(f"dif_out_{s0}", "output", fanin=f"dif_{s0}") # instantiate population count for o in range(clog2(len(startpoints) + 1)): sen.add(f"sen_out_{o}", "output", fanin=f"pc_out_{o}") return sen