def __lshift__(self, d): """Apply a left shift of d bits onto integer values and FxPF of a copy of self.""" SELF = self.copy() SELF._integer_inf <<= d SELF._integer_sup <<= d wl, m, lsb = SELF.FPF.wml() lsb = lsb - d SELF._FPF = FPF(wl=wl, lsb=lsb, signed=self.FPF._signed) return SELF
def copy(self): v_inf, v_sup = self.values N_inf, N_sup = self.integers w, m, l = self.FPF.wml() fpf = FPF(wl=w, msb=m, signed=self.FPF._signed) return Variable(value_inf=v_inf, value_sup=v_sup, fpf=fpf, integer_inf=N_inf, integer_sup=N_sup)
def mult(self, cst, wl=None, lsb=None): """Multiplication between constant and variable on wl_op bits (for the wordlength)""" # if cst is not a Constant object, then return an AssertionError assert ( isinstance(cst, Constant) ), "Constant type expected for 'cst', not %s" % type(cst).__name__ # compute real values X = (cst.value * self.values[0], cst.value * self.values[1]) inf = min(X) sup = max(X) # compute msb if not Variable.formatting: # constant shift is computed as the difference between optimal wordlength (wl_cst + wl_var) and operator wordlength (wl_op) rshift = cst.FPF.wl + self.FPF.wl - wl # if rshift < 0 then rshift equals 0 (only positive shift is considered) rshift = max(rshift, 0) # compute integer values with a positive (or zero) shift onto the constant #NX = ((cst.integer >> cst_rshift)*self.integers[0] , (cst.integer >> cst_rshift)*self.integers[1]) NX = ((cst.mantissa * self.integers[0]) >> rshift, (cst.mantissa * self.integers[1]) >> rshift) # if cst.value > 0 then Ninf <-- NX[0], else Ninf <-- NX[1]. In both cases Ninf <-- min(NX) Ninf = min(NX) # same reasoning for Nsup, Nsup <-- max(NX) Nsup = max(NX) fpf = FPF(wl=wl, msb=cst.FPF.msb + self.FPF.msb + 1) V = Variable(value_inf=inf, value_sup=sup, fpf=fpf, integer_inf=int(Ninf), integer_sup=int(Nsup)) else: lsb_prod = cst.FPF._lsb + self.FPF._lsb rshift = max(lsb - lsb_prod, 0) Cx = Constant(max(abs(inf), abs(sup)), wl=16) wl = Cx.FPF._msb + 1 - lsb V = Variable(value_inf=inf, value_sup=sup, wl=wl) return V, rshift
def add(self, other, wl_op, msb_final=None, fpf_add=None): # if other is not a Variable object, then return an AssertionError assert ( isinstance(other, Variable) ), "Variable type expected for 'other', not %s" % type(other).__name__ # the function computes sum between two variables where other variable has the smaller lsb, # then if it's not the case, addition is re-called with arguments interchanged if other.lsb < self.lsb: V, var1, var2, rshift = other.add(self, wl_op, msb_final=msb_final, fpf_add=fpf_add) return V, var2, var1, [rshift[1], rshift[0]] rshift = [0, 0] SELF = self.copy() OTHER = other.copy() # 1. FxPF of addition if fpf_add: msb_add = min(max(SELF.FPF.msb, OTHER.FPF.msb), fpf_add.msb) if Variable.formatting is True: l_add = fpf_add.lsb else: l_add = msb_add - fpf_add.wl + 1 fpf_add = FPF(msb=msb_add, lsb=l_add, signed=fpf_add._signed) else: #normally never happens msb_add = max(SELF.FPF.msb, OTHER.FPF.msb) l_add = msb_add + 1 - wl_op # 2. Formatting of the two operands into the format of the addition # rshift is computed by this formatting SELF, rshift[0] = SELF.Formatting(fpf_add) OTHER, rshift[1] = OTHER.Formatting(fpf_add) # 3. Addition inf = SELF._integer_inf + OTHER._integer_inf sup = SELF._integer_sup + OTHER._integer_sup # 4. Overflow # in case of overflow for inf or sup, sums are recomputed with one bit shifted integers if ((inf < -2**(wl_op - 1)) or (sup > 2**(wl_op - 1) - 1)): if (msb_add == msb_final): inf = -2**(wl_op - 1) sup = 2**(wl_op - 1) - 1 else: SELF = SELF >> 1 if OTHER != SELF: OTHER = OTHER >> 1 inf = SELF.integers[0] + OTHER.integers[0] sup = SELF.integers[1] + OTHER.integers[1] l_add -= 1 # the result Variable is created with real values, integer values and computed fpf (from wl_op and l_add) V = Variable(value_inf=SELF.values[0] + OTHER.values[0], value_sup=SELF.values[1] + OTHER.values[1], fpf=fpf_add, integer_inf=inf, integer_sup=sup) # operands rshifts are computed as the difference between operand lsb and l_add if positive, 0 else return V, SELF, OTHER, rshift
def best_oSoP_gen_from_dict(D): if isinstance(D, list): Osop = [] for i, d in enumerate(D): Osop.append(best_oSoP_gen_from_dict(d)) return Osop else: variables = D["list_var"] constants = D["list_cst"] constants_wordlength = D["wl_cst"] multipliers_wordlength = D["wl_mult"] adders_wordlength = D["wl_add"] fpf_final = D["fpf_final"] formatting = D["formatting"] RndOff = "RAM" # args N = len(constants) delta = 0 if formatting: Variable.formatting = True Adder.formatting = True Multiplier.formatting = True if N == 1: delta = 0 else: delta = int(floor(log(N - 1, 2))) + 1 Adder.wl = adders_wordlength + delta multipliers_wordlength += delta lsb_final = fpf_final.lsb - delta else: Variable.formatting = False Adder.formatting = False Multiplier.formatting = False lsb_final = 0 Adder.wl = adders_wordlength if not isinstance(constants_wordlength, list): constants_wordlength = [constants_wordlength] * N if not isinstance(multipliers_wordlength, list): multipliers_wordlength = [multipliers_wordlength] * N var_final = Variable(fpf=fpf_final) # Multipliers creation from args #Q&D multipliers = [] for i in range(N): M = None if constants_wordlength[i] > 0: try: M= Multiplier(constants[i], constants_wordlength[i], variables[i], variables[i]._name,\ multipliers_wordlength[i], i, RndOff=RndOff, lsb_final=lsb_final) except: print("Erreur création multiplieur") if M: multipliers.append(M) #multipliers = [Multiplier(constants[i], constants_wordlength[i], variables[i], variables[i]._name,\ # multipliers_wordlength[i], i, RndOff=RndOff, lsb_final=lsb_final) for i in range(N) if constants_wordlength[i] >0] multipliers.sort(Multiplier.cmp_lsb) # for m in multipliers: # print m._name,m._cst.integer, m.result.FxPF, m.result.values # Heuristic for non-exhaustive generation # Computation of max_lsb, the maximum difference of lsb between two consecutive multipliers (in the sorted list) max_lsb = 0 N = len(multipliers) for i in range(N - 1): max_lsb = max( max_lsb, abs(multipliers[i + 1].result.lsb - multipliers[i].result.lsb)) best_osop = None h = N # formatting is the bits cleaning option if formatting == True: # Computation of fpf_add, ie fpf_final 'plus' delta bits considered for additions fpf_add = FPF(wl=fpf_final.wl + delta, msb=fpf_final.msb, lsb=fpf_final.lsb - delta, signed=fpf_final._signed) if N == 1: best_osop = oSoP(multipliers[0]) # print best_osop._var_final elif N < 10: best_osop = oSoP_Generator2(multipliers, max_lsb, fpf_add, var_final, formatting=formatting) else: osop = multipliers[0] for m in multipliers[1:]: osop = osop.add(m, (False, False, fpf_add)) best_osop = oSoP(osop, var_final) best_osop.Calc_var_result((False, False, fpf_add)) # if formatting == False we use default parameters elif formatting == False: fpf_add = FPF(wl=adders_wordlength, msb=fpf_final.msb) LT = [] best_mean = 10000 # if 7>N >1: # best_osop = oSoP_Generator2(multipliers, max_lsb, fpf_add, var_final, formatting=formatting) if N == 1: best_osop = oSoP(multipliers[0]) else: osop = multipliers[0] for m in multipliers[1:]: osop = osop.add(m, (False, False, fpf_add)) best_osop = oSoP(osop, var_final) best_osop.Calc_var_result((False, False, fpf_add)) #for L in oSoP_Generator2(multipliers, max_lsb, fpf_add, var_final): # #if L.height() == ceil(log(N,2)): # # return L # if L._Top._total_error.mean <= best_mean: # if L._Top._total_error.mean < best_mean: # LT=[] # LT.append(L) # best_mean = L._Top._total_error.mean # best_osop = L # else: # L._Top.kill() # h = LT[0].height() # for L in LT: # if L.height() <=h: # h=L.height() # best_osop = L return best_osop
def best_oSoP_gen(variables_name, variables, constants, constants_wordlength, multipliers_wordlength,\ adders_wordlength, fpf_final, alfix = False,plus = False, RndOff = "RAM", formatting = True): # args N = len(constants) delta = 0 if formatting: Variable.formatting = True Adder.formatting = True Multiplier.formatting = True delta = int(ceil(log(N, 2))) Adder.wl = adders_wordlength + delta multipliers_wordlength += delta lsb_final = fpf_final.lsb - delta else: Variable.formatting = False Adder.formatting = False Multiplier.formatting = False lsb_final = 0 if not isinstance(constants_wordlength, list): constants_wordlength = [constants_wordlength] * N if not isinstance(multipliers_wordlength, list): multipliers_wordlength = [multipliers_wordlength] * N if RndOff and (not isinstance(RndOff, list)): RndOff = [RndOff] * N if not isinstance(variables_name, list): variables_name = [variables_name + repr(i) for i in range(N)] Adder.wl_add = adders_wordlength var_final = Variable(fpf=fpf_final) # Multipliers creation from args multipliers = [Multiplier(constants[i], constants_wordlength[i], variables[i], variables_name[i],\ multipliers_wordlength[i], i, RndOff=RndOff[i], lsb_final=lsb_final) for i in range(N)] multipliers.sort(Multiplier.cmp_lsb) # Heuristic for non-exhaustive generation # Computation of max_lsb, the maximum difference of lsb between two consecutive multipliers (in the sorted list) max_lsb = 0 for i in range(N - 1): max_lsb = max( max_lsb, abs(multipliers[i + 1].result.lsb - multipliers[i].result.lsb)) best_osop = None h = N # formatting is the bits cleaning option if formatting: # Computation of fpf_add, ie fpf_final 'plus' delta bits considered for additions fpf_add = FPF(wl=fpf_final.wl + delta, msb=fpf_final.msb, lsb=fpf_final.lsb - delta, signed=fpf_final._signed) for L in oSoP_Generator2(multipliers, max_lsb, fpf_add, var_final, alfix=False, plus=False, formatting=formatting): if L.height() == ceil(log(N, 2)): h = L.height() best_osop = L break # if formatting == False we use default parameters else: fpf_add = FPF(wl=adders_wordlength, msb=fpf_final.msb) nb = 0 LT = [] best_mean = 10000 for L in oSoP_Generator2(multipliers, max_lsb, fpf_add, var_final, alfix=False, plus=False, formatting=formatting): nb += 1 if nb % 10000 == 0: print(nb) #LT.append(L) #break if L._Top._total_error.mean <= best_mean: if L._Top._total_error.mean < best_mean: LT = [] LT.append(L) best_mean = L._Top._total_error.mean best_osop = L h = LT[0].height() for L in LT: if L.height() <= h: h = L.height() best_osop = L return best_osop