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.out = Bus(outname, out_N, out_bus=True, signed=signed)
self.components = [] self.components = []
self.circuit_wires = [] self._prefixes = [] # TODO rename to fullname and add distinct attr for prefix, name, suffix
self.circuit_gates = [] self.circuit_gates = []
self.circuit_wires = []
self.signed = signed self.signed = signed
self.c_data_type = "int64_t" if self.signed is True else "uint64_t" self.c_data_type = "int64_t" if self.signed is True else "uint64_t"
self.pyc = None # Python compiled function self.pyc = None # Python compiled function
@ -87,12 +88,26 @@ class GeneralCircuit():
def add_component(self, component): def add_component(self, component):
"""Adds a component into list of circuit's inner subcomponents. """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: Args:
component: Subcomponent to be added into list of components composing described circuit. component: Subcomponent to be added into list of components composing described circuit.
""" """
prefixes = [c.prefix for c in self.components] # TODO will be redone in ArithsGen rework
assert component.prefix not in prefixes, f"Component with prefix {component.prefix} already exists in the circuit." # 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) self.components.append(component)
return 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) return sum(isinstance(c, cls) for c in self.components if isinstance(c, cls) and c.disable_generation is False)
else: else:
return sum(isinstance(c, cls) for c in self.components) return sum(isinstance(c, cls) for c in self.components)
def get_circuit_gates(self, verilog_output: bool = False): def get_circuit_gates(self, verilog_output: bool = False):
"""Gets a list of all the logic gates in circuit that should be generated. """Gets a list of all the logic gates in circuit that should be generated.
@ -227,14 +242,13 @@ class GeneralCircuit():
else: else:
return len(self.circuit_wires)+2 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. """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 0 has constant index of 0.
Constant wire with value 1 has constant index of 1. Constant wire with value 1 has constant index of 1.
Other wires indexes start counting from 2 and up. Other wires indexes start counting from 2 and up.
""" """
self.circuit_wires = []
circuit_wires_names = [] circuit_wires_names = []
for input in self.inputs: for input in self.inputs:
@ -262,6 +276,7 @@ class GeneralCircuit():
self.circuit_wires.append( self.circuit_wires.append(
(gate.out, gate.out.name, self.save_wire_id(wire=gate.out))) (gate.out, gate.out.name, self.save_wire_id(wire=gate.out)))
circuit_wires_names.append(gate.out.name) circuit_wires_names.append(gate.out.name)
def get_circuit_wire_index(self, wire: Wire): def get_circuit_wire_index(self, wire: Wire):
"""Searches for circuit's wire unique index position within the circuit. Used for cgp chromosome generation. """Searches for circuit's wire unique index position within the circuit. Used for cgp chromosome generation.
@ -773,7 +788,7 @@ class GeneralCircuit():
Returns: Returns:
str: CGP chromosome parameters of described arithmetic circuit. 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}}" 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): def get_triplets_cgp(self):
@ -789,7 +804,7 @@ class GeneralCircuit():
Returns: Returns:
str: List of triplets each describing logic function of corresponding two input logic gate and as a whole describe the arithmetic circuit. 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 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]) 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 UnsignedAccurateTwoBitMultiplier(MultiplierCircuit):
"""Class representing unsigned two-bit accurate multiplier. """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. Description of the __init__ method.
Args: Args:
@ -76,6 +98,22 @@ class UnsignedApproximateTwoBitMultiplierM1(MultiplierCircuit):
"""Class representing unsigned two-bit approximate multiplier variant M1. """Class representing unsigned two-bit approximate multiplier variant M1.
M1 ax variant defined here: https://ieeexplore.ieee.org/document/8727537 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. Description of the __init__ method.
@ -127,6 +165,29 @@ class UnsignedApproximateTwoBitMultiplierM2(MultiplierCircuit):
"""Class representing unsigned two-bit approximate multiplier variant M2. """Class representing unsigned two-bit approximate multiplier variant M2.
M2 ax variant defined here: https://ieeexplore.ieee.org/document/8727537 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. Description of the __init__ method.
@ -180,6 +241,33 @@ class UnsignedApproximateTwoBitMultiplierM3(MultiplierCircuit):
"""Class representing unsigned two-bit approximate multiplier variant M3. """Class representing unsigned two-bit approximate multiplier variant M3.
M3 ax variant defined here: https://ieeexplore.ieee.org/document/8727537 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. Description of the __init__ method.
@ -236,6 +324,22 @@ class UnsignedApproximateTwoBitMultiplierM4(MultiplierCircuit):
M4 ax variant defined here: https://ieeexplore.ieee.org/document/8727537 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. Description of the __init__ method.
Args: Args:
@ -285,7 +389,13 @@ class SignedApproximateTwoBitMultiplierM4(MultiplierCircuit):
class UnsignedRecursiveMultiplier(MultiplierCircuit): class UnsignedRecursiveMultiplier(MultiplierCircuit):
"""Class representing unsigned recursive multiplier. """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. Description of the __init__ method.
Args: 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 ( 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 ( 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): 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) super().__init__(a=a, gate=OrGate, prefix=prefix, name=name, **kwargs)
class AndReduce(BitReduce): class AndReduce(BitReduce):
def __init__(self, a: Bus, prefix : str = "", name : str = "orreduce", **kwargs): def __init__(self, a: Bus, prefix: str = "", name: str = "andreduce", **kwargs):
super().__init__(a=a, gate=AndGate, prefix=prefix, name=name, **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 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.a = a
self.b = b self.b = b
self.N = max(a.N, b.N) self.N = max(a.N, b.N)
@ -177,7 +177,7 @@ class UnsignedCompareGTE(GeneralCircuit):
for i in reversed(range(self.N)): for i in reversed(range(self.N)):
iA = self.a[i] if i < self.a.N else ConstantWireValue0() iA = self.a[i] if i < self.a.N else ConstantWireValue0()
iB = self.b[i] if i < self.b.N else ConstantWireValue0() iB = self.b[i] if i < self.b.N else ConstantWireValue0()
i1 = iA i1 = iA
i2 = self.add_component(NotGate(iB, f"{self.prefix}_i1_{i}", parent_component=self)).out 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 psum = self.add_component(AndGate(pi, psum, f"{self.prefix}_psum_{i}", parent_component=self)).out
res[self.N] = psum # or all equal (xor) res[self.N] = psum # or all equal (xor)
red = self.add_component(OrReduce(res, prefix=f"{self.prefix}_orred", inner_component=True)) 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 return a
else: else:
half = a.N // 2 half = a.N // 2
b_in = Bus(N=half, prefix=f"b_inn{depth}A") b_in = Bus(N=half, prefix=f"b_inn_{branch}_{depth}A")
c_in = Bus(N=a.N - half, prefix=f"b_inn{depth}B") c_in = Bus(N=a.N - half, prefix=f"b_inn_{branch}_{depth}B")
#print(a, half, a.N) #print(a, half, a.N)
@ -87,4 +87,4 @@ class UnsignedPopCount(GeneralCircuit):
sumbus = create_tree(self.a,0, "X") sumbus = create_tree(self.a,0, "X")
#print(sumbus) #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.a = a
self.b = b 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 io import StringIO
from ariths_gen.core.cgp_circuit import UnsignedCGPCircuit from ariths_gen.core.cgp_circuit import UnsignedCGPCircuit
from ariths_gen.wire_components import ( 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 ( from ariths_gen.wire_components import (
Wire, Wire,
ConstantWireValue0, ConstantWireValue0,