Added documentation to Recursive multiplier and hopefully fixed some issues with popcount output generation.

This commit is contained in:
honzastor 2024-04-08 21:37:34 +02:00
parent 4e331f0525
commit 739d5fafce
9 changed files with 167 additions and 23 deletions

View File

@ -54,8 +54,9 @@ class GeneralCircuit():
self.out = Bus(outname, out_N, out_bus=True, signed=signed)
self.components = []
self.circuit_wires = []
self._prefixes = [] # TODO rename to fullname and add distinct attr for prefix, name, suffix
self.circuit_gates = []
self.circuit_wires = []
self.signed = signed
self.c_data_type = "int64_t" if self.signed is True else "uint64_t"
self.pyc = None # Python compiled function
@ -87,12 +88,26 @@ class GeneralCircuit():
def add_component(self, component):
"""Adds a component into list of circuit's inner subcomponents.
Additionally it adds all the gates of the component to the circuit's list of gates and all
sbcomponents prefixes to check for naming duplicates which could cause issues in the circuit generation.
Args:
component: Subcomponent to be added into list of components composing described circuit.
"""
prefixes = [c.prefix for c in self.components]
assert component.prefix not in prefixes, f"Component with prefix {component.prefix} already exists in the circuit."
# TODO will be redone in ArithsGen rework
# We should probably check also wire names for especially hierarchical generation
if isinstance(component, TwoInputLogicGate):
if component.disable_generation is False:
self.circuit_gates.append(component)
else:
self.circuit_gates.extend(component.get_circuit_gates())
for prefix in component._prefixes:
assert prefix not in self._prefixes, f"Component with prefix {prefix} already exists in the circuit."
self._prefixes.extend(component._prefixes)
assert component.prefix not in self._prefixes, f"Component with prefix {component.prefix} already exists in the circuit."
self._prefixes.append(component.prefix)
self.components.append(component)
return component
@ -120,7 +135,7 @@ class GeneralCircuit():
return sum(isinstance(c, cls) for c in self.components if isinstance(c, cls) and c.disable_generation is False)
else:
return sum(isinstance(c, cls) for c in self.components)
def get_circuit_gates(self, verilog_output: bool = False):
"""Gets a list of all the logic gates in circuit that should be generated.
@ -227,14 +242,13 @@ class GeneralCircuit():
else:
return len(self.circuit_wires)+2
def get_cgp_wires(self):
def get_circuit_wires(self):
"""Gets a list of all wires in circuit along with their index position for cgp chromosome generation and stores them inside `self.circuit_wires` list.
Constant wire with value 0 has constant index of 0.
Constant wire with value 1 has constant index of 1.
Other wires indexes start counting from 2 and up.
"""
self.circuit_wires = []
circuit_wires_names = []
for input in self.inputs:
@ -262,6 +276,7 @@ class GeneralCircuit():
self.circuit_wires.append(
(gate.out, gate.out.name, self.save_wire_id(wire=gate.out)))
circuit_wires_names.append(gate.out.name)
def get_circuit_wire_index(self, wire: Wire):
"""Searches for circuit's wire unique index position within the circuit. Used for cgp chromosome generation.
@ -773,7 +788,7 @@ class GeneralCircuit():
Returns:
str: CGP chromosome parameters of described arithmetic circuit.
"""
self.circuit_gates = self.get_circuit_gates()
# self.circuit_gates = self.get_circuit_gates() TODO delete
return f"{{{sum(input_bus.N for input_bus in self.inputs)},{self.out.N},1,{len(self.circuit_gates)},2,1,0}}"
def get_triplets_cgp(self):
@ -789,7 +804,7 @@ class GeneralCircuit():
Returns:
str: List of triplets each describing logic function of corresponding two input logic gate and as a whole describe the arithmetic circuit.
"""
self.get_cgp_wires()
self.get_circuit_wires()
return "".join([g.get_triplet_cgp(a_id=self.get_circuit_wire_index(g.a), out_id=self.get_circuit_wire_index(g.out)) if isinstance(g, OneInputLogicGate) else
g.get_triplet_cgp(a_id=self.get_circuit_wire_index(g.a), b_id=self.get_circuit_wire_index(g.b), out_id=self.get_circuit_wire_index(g.out)) for g in self.circuit_gates])

View File

@ -22,6 +22,28 @@ import math
class UnsignedAccurateTwoBitMultiplier(MultiplierCircuit):
"""Class representing unsigned two-bit accurate multiplier.
```
A1B1 A1B0 A0B1 A0B0
AND AND AND AND
AND
AND XOR XOR
O3 O2 O1 O0
```
Description of the __init__ method.
Args:
@ -76,6 +98,22 @@ class UnsignedApproximateTwoBitMultiplierM1(MultiplierCircuit):
"""Class representing unsigned two-bit approximate multiplier variant M1.
M1 ax variant defined here: https://ieeexplore.ieee.org/document/8727537
```
A1B1 A1B0 A0B1 A0B0
AND AND AND AND
OR
O3=0 O2 O1 O0
```
Description of the __init__ method.
@ -127,6 +165,29 @@ class UnsignedApproximateTwoBitMultiplierM2(MultiplierCircuit):
"""Class representing unsigned two-bit approximate multiplier variant M2.
M2 ax variant defined here: https://ieeexplore.ieee.org/document/8727537
```
A1B1 A1B0 A0B1
AND AND AND
XOR AND
XOR
O3 O2 O1 O0
```
Description of the __init__ method.
@ -180,6 +241,33 @@ class UnsignedApproximateTwoBitMultiplierM3(MultiplierCircuit):
"""Class representing unsigned two-bit approximate multiplier variant M3.
M3 ax variant defined here: https://ieeexplore.ieee.org/document/8727537
```
A1B1 A1B0 A0B1 A0B0
AND AND AND AND
OR
NOT
AND AND
O3 O2 O1 O0
```
Description of the __init__ method.
@ -236,6 +324,22 @@ class UnsignedApproximateTwoBitMultiplierM4(MultiplierCircuit):
M4 ax variant defined here: https://ieeexplore.ieee.org/document/8727537
```
A1B1 A1B0 A0B1 A0B0
AND AND AND AND
XOR
O3=0 O2 O1 O0
```
Description of the __init__ method.
Args:
@ -285,7 +389,13 @@ class SignedApproximateTwoBitMultiplierM4(MultiplierCircuit):
class UnsignedRecursiveMultiplier(MultiplierCircuit):
"""Class representing unsigned recursive multiplier.
TODO
Input bit-vector length N can be any power of two greater than 1 (e.g. 2, 4, 8, ...).
The internal structure of the recursive multiplier is composed of subsequent two-bit submultipliers provided in the input `submultipliers` list.
The `submultipliers` list should contain the classes of the two-bit submultipliers that will be used for instantiation. If None are provided, accurate two-bit submultipliers are assumed.
The number of submultipliers required is equal to (N/2)² for N > 2. For N = 2, only one two-bit submultiplier is required.
Description of the __init__ method.
Args:

View File

@ -4,11 +4,18 @@ from ariths_gen.multi_bit_circuits.others.popcount import (
)
from ariths_gen.multi_bit_circuits.others.bit_reduce import (
BitReduce, AndReduce, OrReduce
BitReduce,
AndReduce,
OrReduce
)
from ariths_gen.multi_bit_circuits.others.compare import (
UnsignedCompareLT, UnsignedCompareLTE, UnsignedCompareGT, UnsignedCompareGTE
UnsignedCompareLT,
UnsignedCompareLTE,
UnsignedCompareGT,
UnsignedCompareGTE
)
from ariths_gen.multi_bit_circuits.others.popcount_compare import PopCountCompare
from ariths_gen.multi_bit_circuits.others.popcount_compare import (
PopCountCompare
)

View File

@ -80,10 +80,10 @@ class BitReduce(GeneralCircuit):
class OrReduce(BitReduce):
def __init__(self, a: Bus, prefix : str = "", name : str = "orreduce", **kwargs):
def __init__(self, a: Bus, prefix: str = "", name: str = "orreduce", **kwargs):
super().__init__(a=a, gate=OrGate, prefix=prefix, name=name, **kwargs)
class AndReduce(BitReduce):
def __init__(self, a: Bus, prefix : str = "", name : str = "orreduce", **kwargs):
super().__init__(a=a, gate=AndGate, prefix=prefix, name=name, **kwargs)
def __init__(self, a: Bus, prefix: str = "", name: str = "andreduce", **kwargs):
super().__init__(a=a, gate=AndGate, prefix=prefix, name=name, **kwargs)

View File

@ -83,7 +83,7 @@ class UnsignedCompareLTE(GeneralCircuit):
Returns true if a <= b
"""
def __init__(self, a: Bus, b: Bus, prefix : str = "", name : str = "cmp_lt", **kwargs):
def __init__(self, a: Bus, b: Bus, prefix : str = "", name : str = "cmp_lte", **kwargs):
self.a = a
self.b = b
self.N = max(a.N, b.N)
@ -177,7 +177,7 @@ class UnsignedCompareGTE(GeneralCircuit):
for i in reversed(range(self.N)):
iA = self.a[i] if i < self.a.N else ConstantWireValue0()
iB = self.b[i] if i < self.b.N else ConstantWireValue0()
i1 = iA
i2 = self.add_component(NotGate(iB, f"{self.prefix}_i1_{i}", parent_component=self)).out
@ -188,7 +188,7 @@ class UnsignedCompareGTE(GeneralCircuit):
psum = self.add_component(AndGate(pi, psum, f"{self.prefix}_psum_{i}", parent_component=self)).out
res[self.N] = psum # or all equal (xor)
red = self.add_component(OrReduce(res, prefix=f"{self.prefix}_orred", inner_component=True))
self.out.connect_bus(red.out)
self.out.connect_bus(red.out)

View File

@ -68,8 +68,8 @@ class UnsignedPopCount(GeneralCircuit):
return a
else:
half = a.N // 2
b_in = Bus(N=half, prefix=f"b_inn{depth}A")
c_in = Bus(N=a.N - half, prefix=f"b_inn{depth}B")
b_in = Bus(N=half, prefix=f"b_inn_{branch}_{depth}A")
c_in = Bus(N=a.N - half, prefix=f"b_inn_{branch}_{depth}B")
#print(a, half, a.N)
@ -87,4 +87,4 @@ class UnsignedPopCount(GeneralCircuit):
sumbus = create_tree(self.a,0, "X")
#print(sumbus)
self.out.connect_bus(sumbus )
self.out.connect_bus(sumbus)

View File

@ -59,7 +59,7 @@ class PopCountCompare(GeneralCircuit):
"""
def __init__(self, a: Bus, b: Bus, prefix : str = "", name : str = "cmp_lt", **kwargs):
def __init__(self, a: Bus, b: Bus, prefix : str = "", name : str = "popcnt_cmp", **kwargs):
self.a = a
self.b = b

View File

@ -1,3 +1,9 @@
import os
import sys
# Add the parent directory to the system path
DIR_PATH = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(DIR_PATH, '..'))
from io import StringIO
from ariths_gen.core.cgp_circuit import UnsignedCGPCircuit
from ariths_gen.wire_components import (

View File

@ -1,3 +1,9 @@
import os
import sys
# Add the parent directory to the system path
DIR_PATH = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(DIR_PATH, '..'))
from ariths_gen.wire_components import (
Wire,
ConstantWireValue0,