def computeConstBinaryExpr(op, opd0, opd1): assert (isinstance(op, EXPR.BinaryOp)) assert (isinstance(opd0, EXPR.ConstantExpr)) assert (isinstance(opd1, EXPR.ConstantExpr)) v0 = opd0.value() v1 = opd1.value() assert ((type(v0) is int) or (type(v0) is float) or isinstance(v0, Fraction)) assert ((type(v1) is int) or (type(v1) is float) or isinstance(v1, Fraction)) if (op.label == "+"): return EXPR.ConstantExpr(v0 + v1) elif (op.label == "-"): return EXPR.ConstantExpr(v0 - v1) elif (op.label == "*"): return EXPR.ConstantExpr(v0 * v1) elif (op.label == "/"): return EXPR.ConstantExpr(v0 / v1) elif (op.label == "^"): return EXPR.ConstantExpr(v0**v1) else: assert (False)
def scalingUpFactor (self): if (IR.PREC_CANDIDATES == ["e32", "e64"]): return tft_expr.ConstantExpr(math.pow(2, 21)) elif (IR.PREC_CANDIDATES == ["e64", "e128"]): return tft_expr.ConstantExpr(math.pow(2, 50)) elif (IR.PREC_CANDIDATES == ["e32", "e64", "e128"]): return tft_expr.ConstantExpr(math.pow(2, 48)) else: sys.exit("Error: invalid setting of IR.PREC_CANDIDATES: " + str(IR.PREC_CANDIDATES)) # scaling_eps = Fraction(0.0) scaling_eps = Fraction(1.0) for gid,epss in self.gid2epsilons.items(): for eps in epss: assert(eps.value() >= 0.0) if (eps.value() == 0.0): continue # if (scaling_eps < eps.value()): if (scaling_eps > eps.value()): scaling_eps = eps.value() up_fac = Fraction(scaling_eps.denominator, scaling_eps.numerator) # return tft_expr.ConstantExpr(up_fac) # return tft_expr.ConstantExpr(up_fac * 512.0) return tft_expr.ConstantExpr(up_fac / 8.0 ) # It is just a heuristic to divide by 8.0
def TCastErrorVar (gid, select, cgid, cselect): evar = tft_expr.VariableExpr(TCastErrorVarName(gid, select, cgid, cselect), int, -1, False) evar.setLB(tft_expr.ConstantExpr(int(0))) evar.setUB(tft_expr.ConstantExpr(int(1))) assert(tft_expr.isPseudoBooleanVar(evar)) return evar
def FindExprBound (optimizer, obj_expr, direction, constraints = []): assert(direction in ["max", "min"]) assert(optimizer in ALL_OPTIMIZERS) assert(isinstance(obj_expr, tft_expr.Expr)) if (isinstance(obj_expr, tft_expr.ConstantExpr)): assert(obj_expr.lb().value() == obj_expr.ub().value()) return obj_expr.lb().value() value_bound = None if (optimizer == "gelpia"): assert(len(constraints) == 0) if (direction == "min"): obj_expr = IR.MakeBinaryExpr("*", -1, tft_expr.ConstantExpr(Fraction(-1, 1)), obj_expr, True) glob_solver = None assert(optimizer == "gelpia") glob_solver = tft_ask_gelpia.GelpiaSolver() max_retries = 3 n_retries = 0 value_bound = None while (True): value_bound = glob_solver.maxObj(obj_expr) if (value_bound is not None): break else: n_retries = n_retries + 1 if (n_retries >= max_retries): break assert((value_bound is None) or (isinstance(value_bound, Fraction))) if ((value_bound is not None) and (direction == "min")): value_bound = value_bound * Fraction(-1, 1) else: sys.exit("ERROR: unknown optimizer: " + optimizer) if (value_bound is None): return None # check and set expr_min assert(isinstance(value_bound, Fraction)) if (direction == "max"): obj_expr.setUB(tft_expr.ConstantExpr(value_bound)) elif (direction == "min"): obj_expr.setLB(tft_expr.ConstantExpr(value_bound)) else: sys.exit("ERROR: invalid opt. direction for FindExprBound") # return assert(type(value_bound) is Fraction) return value_bound
def CastingNumExprTemplate (func_compare, casting_map = {}, gid2epsilons = {}): # generate the casting num. expr. cnum_expr = None for p,c in casting_map.items(): assert(len(p) == 2) assert((type(p[0]) is int) and (type(p[1]) is int)) gid_from = p[0] gid_to = p[1] assert(gid_to != tft_expr.PRESERVED_CONST_GID) if (gid_from == tft_expr.PRESERVED_CONST_GID): continue assert(0 <= gid_from) assert(gid_from in gid2epsilons.keys()) assert(0 <= gid_to) assert(gid_to in gid2epsilons.keys()) epss_from = gid2epsilons[gid_from] epss_to = gid2epsilons[gid_to] this_expr = None for f in range(0, len(epss_from)): sum_expr = None var_from = GroupErrorVar(gid_from, f) for t in range(0, len(epss_to)): if (func_compare(epss_from[f], epss_to[t])): tc_expr = None if (tft_utils.LINEAR_TYPE_CASTING_CONSTRAINTS): tc_expr = TCastErrorVar(gid_from, f, gid_to, t) else: tc_expr = IR.BE("*", -1, var_from, GroupErrorVar(gid_to, t), True) if (sum_expr is None): sum_expr = tc_expr else: sum_expr = IR.BE("+", -1, sum_expr, tc_expr, True) if (sum_expr is None): continue if (this_expr is None): this_expr = sum_expr else: this_expr = IR.BE("+", -1, this_expr, sum_expr, True) if (this_expr is None): continue this_expr = IR.BE("*", -1, tft_expr.ConstantExpr(c), this_expr, True) if (cnum_expr is None): cnum_expr = this_expr else: cnum_expr = IR.BE("+", -1, cnum_expr, this_expr, True) return cnum_expr
def EList2BinaryExpr(elist=[]): assert (len(elist) > 0) if ((len(elist) == 2) and isinstance(elist[0], EXPR.BinaryOp) and (elist[0].label == "-") and isinstance(elist[1], EXPR.Expr)): revised_bop = String2BinaryOp("*") return EList2BinaryExpr( [EXPR.ConstantExpr(-1.0), revised_bop, elist[1]]) if (len(elist) != 3): return None else: if (not isinstance(elist[0], EXPR.ArithmeticExpr)): return None if (not isinstance(elist[1], EXPR.BinaryOp)): return None if (not isinstance(elist[2], EXPR.ArithmeticExpr)): return None if (coalesceConstBinaryExpr(elist[0], elist[2])): return computeConstBinaryExpr(elist[1], elist[0], elist[2]) else: if (elist[1].label == "^"): assert (isinstance(elist[2], EXPR.ConstantExpr)) return ExpandConstPowerExpression(elist[1], elist[0], elist[2].value()) else: return EXPR.BinaryExpr(elist[1], elist[0], elist[2])
def String2ConstantExpr(s): s = sstrip(s) if ((s.find(".") >= 0) or (s.find("e") > 0)): try: v = float(s) return EXPR.ConstantExpr(v) except: return None else: try: v = int(s) if (not BIAS_FLOAT_CONST): v = float(s) return EXPR.ConstantExpr(v) except: return None
def SolveErrorForms(eforms=[], optimizers={}): assert (len(eforms) > 0) assert (all([isinstance(ef, tft_error_form.ErrorForm) for ef in eforms])) assert ("vrange" in optimizers.keys()) assert ("alloc" in optimizers.keys()) alloc = None err_M2 = 0.0 while (True): # -- solve the problem -- alloc = tft_solver.FirstLevelAllocSolver(optimizers, eforms) if (alloc is None): break if (tft_utils.NO_M2_CHECK): break # -- check the effect of M2 -- time_m2 = time.time() err_exc = EnsureM2(alloc) tft_utils.TIME_CHECK_M2 = tft_utils.TIME_CHECK_M2 + (time.time() - time_m2) if (type(err_exc) is bool): if (err_exc): break else: sys.exit("Error: invalid return value of boolean EnsureM2") elif (type(err_exc) is float): assert (err_exc > 0.0) alloc = None err_M2 = err_M2 + (err_exc / 2.0) tft_utils.VerboseMessage( "For the actual error is " + str(err_exc) + " higher than the threshold, retune with M2 = " + str(err_M2)) # -- adjust the M2 -- for ef in eforms: ef.M2 = tft_expr.ConstantExpr(err_M2) else: sys.exit("Error: invalid return value type of EnsureM2") # assert(alloc is not None) return eforms, alloc
def FConst(fpn): global CONST_ID assert ((type(fpn) is float) or (isinstance(fpn, Fraction))) # return tft_expr.ConstantExpr(fpn) const_value = tft_expr.ConstantExpr(fpn) const_name = tft_expr.PRESERVED_CONST_VPREFIX + "_" + str(CONST_ID) CONST_ID = CONST_ID + 1 return DeclareBoundedVar(const_name, Fraction, tft_expr.PRESERVED_CONST_GID, const_value, const_value, True)
def DeclareBoundedVar(label, vtype, gid, lb, ub, check_prefix=True): global EXTERNAL_GIDS global INPUT_VARS if (TUNE_FOR_ALL): gid = 0 CountGID(gid) assert (type(gid) is int) assert (0 <= gid) if (gid not in EXTERNAL_GIDS): EXTERNAL_GIDS.append(gid) if ((type(lb) is float) or (type(lb) is int)): lb = tft_expr.ConstantExpr(lb) elif (isinstance(lb, tft_expr.ConstantExpr)): pass else: sys.exit("ERROR: invalid type of var's lower bound") if ((type(ub) is float) or (type(ub) is int)): ub = tft_expr.ConstantExpr(ub) elif (isinstance(ub, tft_expr.ConstantExpr)): pass else: sys.exit("ERROR: invalid type of var's upper bound") assert (lb <= ub) var = tft_expr.VariableExpr(label, vtype, gid, check_prefix) var.setBounds(lb, ub) if (var not in INPUT_VARS): INPUT_VARS.append(var) AppendCppInst(var) return var
def copy (self, specific_alloc=None): ef_ret = ErrorForm(self.upper_bound) ef_ret.M2 = self.M2 for et in self.terms: epss = None if (specific_alloc is not None): assert(specific_alloc.isAssigned(et)) epss = [tft_expr.ConstantExpr(specific_alloc[et])] ef_ret.add(et.copy(epss)) ef_ret.gid2epsilons = self.gid2epsilons.copy() ef_ret.gid_counts = self.gid_counts.copy() ef_ret.casting_map = self.casting_map.copy() return ef_ret
def String2BoundedVariableExpr(s): tokens = tft_utils.String2Tokens(s, "in") assert (len(tokens) == 2) assert (tokens[1].startswith("[") and tokens[1].endswith("]")) var = String2Expr(tokens[0], True) assert (isinstance(var, EXPR.VariableExpr)) ran = tft_utils.String2Tokens(tokens[1][1:len(tokens[1]) - 1], ",") assert (len(ran) == 2) vlb = EXPR.ConstantExpr(var.type()(ran[0])) vub = EXPR.ConstantExpr(var.type()(ran[1])) assert (isinstance(vlb, EXPR.ConstantExpr)) assert (isinstance(vub, EXPR.ConstantExpr)) if (not var.hasBounds()): var.setBounds(vlb, vub) else: # assert(var.lb() == vlb) # assert(var.ub() == vub) assert (abs(var.lb().value() - vlb.value()) <= float(1e-07)) assert (abs(var.ub().value() - vub.value()) <= float(1e-07)) return var
def ExpandConstPowerExpression(op, e_base, c_power): assert ((isinstance(op, EXPR.BinaryOp)) and (op.label == "^")) assert (isinstance(e_base, EXPR.Expr)) assert (float(c_power) == int(c_power)) c_power = int(c_power) assert (c_power >= 0) if (c_power == 0): return EXPR.ConstantExpr(1.0) elif (c_power == 1): return e_base else: return EXPR.BinaryExpr( EXPR.BinaryOp(op.gid, "*"), ExpandConstPowerExpression(op, e_base, (c_power - 1)), e_base)
def overApproxExpr (self, error_expr): assert(isinstance(error_expr, tft_expr.ArithmeticExpr)) if (self.stored_overapprox_expr is not None): return self.stored_overapprox_expr expr_abs_expr = self.absexpr() if ((not expr_abs_expr.hasLB()) or (not expr_abs_expr.hasUB())): sys.exit("ERROR: cannot over-approximate expr. without both LB and UB...") value_lb = expr_abs_expr.lb().value() value_ub = expr_abs_expr.ub().value() assert(Fraction(0, 1) <= value_lb) assert(value_lb <= value_ub) self.stored_overapprox_expr = IR.MakeBinaryExpr("*", -1, tft_expr.ConstantExpr(value_ub), error_expr, True) return self.stored_overapprox_expr
def MakeBinaryExpr(op_label, op_gid, opd0, opd1, internal=False): global EXTERNAL_GIDS if ((not internal) and (TUNE_FOR_ALL)): op_gid = 0 assert (type(op_label) is str) assert (type(op_gid) is int) assert (isinstance(opd0, tft_expr.Expr)) assert (isinstance(opd1, tft_expr.Expr)) if (COALESCE_CONST): # if (isinstance(opd0, tft_expr.ConstantExpr) and isinstance(opd1, tft_expr.ConstantExpr)): if (isinstance(opd0, tft_expr.ConstantExpr) and isinstance(opd1, tft_expr.ConstantExpr) and tft_expr.isPreciseConstantExpr(opd0) and tft_expr.isPreciseConstantExpr(opd1)): v0 = opd0.value() v1 = opd1.value() if (op_label == "+"): eret = tft_expr.ConstantExpr(v0 + v1) AppendCppInst(eret) return eret elif (op_label == "-"): eret = tft_expr.ConstantExpr(v0 - v1) AppendCppInst(eret) return eret elif (op_label == "*"): eret = tft_expr.ConstantExpr(v0 * v1) AppendCppInst(eret) return eret elif (op_label == "/"): eret = tft_expr.ConstantExpr(v0 / v1) AppendCppInst(eret) return eret else: sys.exit("ERROR: unknown Binary Operator: " + op_label) # possibly bind the constant type if ((not tft_utils.FIX_CONST_TYPE) and tft_expr.isConstVar(opd0)): if (opd0.getGid() == tft_expr.PRESERVED_CONST_GID): CountGID(tft_expr.PRESERVED_CONST_GID, -1) opd0.gid = op_gid else: if (opd0.getGid() != op_gid): print("Warning: conflicting constant type...") if ((not tft_utils.FIX_CONST_TYPE) and tft_expr.isConstVar(opd1)): if (opd1.getGid() == tft_expr.PRESERVED_CONST_GID): CountGID(tft_expr.PRESERVED_CONST_GID, -1) opd1.gid = op_gid else: if (opd1.getGid() != op_gid): print("Warning: conflicting constant type...") if (not internal): CountGID(op_gid) CountCasting(opd0, op_gid) CountCasting(opd1, op_gid) if (internal): assert (-1 == op_gid) else: assert (0 <= op_gid) if (op_gid not in EXTERNAL_GIDS): EXTERNAL_GIDS.append(op_gid) ret_expr = tft_expr.BinaryExpr(tft_expr.BinaryOp(op_gid, op_label), opd0.copy((not internal)), opd1.copy((not internal))) AppendCppInst(ret_expr) return ret_expr
def Testing (): print ("==== testing in small-scale ====") # turn off tft_solver.LIMIT_N_CASTINGS tft_solver.LIMIT_N_CASTINGS = False # load CID_Training_Counts if (DEF.CID_Training_Counts is None): DEF.CID_Training_Counts = {} assert(os.path.isfile(DEF.FNAME_CID_Training_Counts)) file_ctc = open(DEF.FNAME_CID_Training_Counts, "r") for aline in file_ctc: aline = aline.strip() if (aline == ""): continue tokens = tft_utils.String2Tokens(aline, " ") assert(len(tokens) == 2) cid = int(tokens[0]) tcounts = int(tokens[1]) print ("CID Counts : " + str(cid) + " : " + str(tcounts)) assert(cid not in DEF.CID_Training_Counts.keys()) DEF.CID_Training_Counts[cid] = tcounts # assert(sum(DEF.CID_Training_Counts.values()) == DEF.N_Samples) file_ctc.close() # load HDLID_GID if (DEF.HDLID_GID is None): DEF.HDLID_GID = {} assert(os.path.isfile(DEF.FNAME_HDLID_GID)) fild_hdlid_gid = open(DEF.FNAME_HDLID_GID, "r") for aline in fild_hdlid_gid: aline = aline.strip() if (aline == ""): continue tokens = tft_utils.String2Tokens(aline, " ") assert(len(tokens) == 2) hdlid = int(tokens[0]) gid = int(tokens[1]) print ("HDLID: " + str(hdlid) + " : GID: " + str(gid)) assert(hdlid not in DEF.HDLID_GID.keys()) DEF.HDLID_GID[hdlid] = gid fild_hdlid_gid.close() # load CID_HDLabel if (DEF.CID_HDLabel is None): DEF.CID_HDLabel = {} assert(DEF.DIM_HDL == 0) DEF.DIM_HDL = None assert(os.path.isfile(DEF.FNAME_CID_HDLabel)) file_cid_hdlabel = open(DEF.FNAME_CID_HDLabel, "r") for aline in file_cid_hdlabel: aline = aline.strip() if (aline == ""): continue tokens = tft_utils.String2Tokens(aline, ":") assert(len(tokens) == 2) cid = int(tokens[0]) str_hdlabel = tokens[1] assert((0 <= cid) and (cid < DEF.N_Clusters)) assert(cid not in DEF.CID_HDLabel.keys()) assert(str_hdlabel.startswith("[") and str_hdlabel.endswith("]")) str_hdlabel = str_hdlabel[1:len(str_hdlabel)-1] tokens = tft_utils.String2Tokens(str_hdlabel, ",") hdlabel = [int(tokens[i]) for i in range(0, len(tokens))] print ("CID: " + str(cid) + " : " + str(hdlabel)) if (DEF.DIM_HDL is None): DEF.DIM_HDL = len(hdlabel) else: assert(DEF.DIM_HDL == len(hdlabel)) DEF.CID_HDLabel[cid] = hdlabel[:] file_cid_hdlabel.close() # count DEF.N_CTT_Samples if (DEF.N_CTT_Samples is None): DEF.N_CTT_Samples = 0 file_fc = open(DEF.FNAME_SVM_TRAIN_FEATURE_CLUSTER, "r") for aline in file_fc: aline = aline.strip() if (aline == ""): continue DEF.N_CTT_Samples = DEF.N_CTT_Samples + 1 file_fc.close() file_fc = open(DEF.FNAME_SVM_TEST_FEATURE_CLUSTER, "r") for aline in file_fc: aline = aline.strip() if (aline == ""): continue DEF.N_CTT_Samples = DEF.N_CTT_Samples + 1 file_fc.close() # load testing partitions assert((type(DEF.N_CTT_Samples) is int) and (DEF.N_CTT_Samples > 0)) file_parts = open(DEF.FNAME_Partitions, "r") String_Partitions = [] for aline in file_parts: aline = aline.strip() if (aline == ""): continue assert(len(String_Partitions) <= DEF.N_CTT_Samples) if (len(String_Partitions) == DEF.N_CTT_Samples): break String_Partitions.append(aline) file_parts.close() assert(len(String_Partitions) == DEF.N_CTT_Samples) Testing_Partitions = [] pid = -1 for i in range(0, DEF.N_CTT_Samples): aline = String_Partitions[i] pid = pid + 1 if (DEF.isTrainingID(pid, DEF.N_CTT_Samples)): continue tokens = tft_utils.String2Tokens(aline, " ") this_part = [] for i in range(0, len(tokens)): bs = tft_utils.String2Tokens(tokens[i], "~") assert(len(bs) == 2) lb = float(bs[0]) ub = float(bs[1]) this_part.append((lb, ub)) Testing_Partitions.append(this_part) String_Partitions = [] # release the space ... # load testing feature -> CID Testing_Features = [] Testing_CIDs = [] assert(os.path.isfile(DEF.FNAME_SVM_TEST_FEATURE_CLUSTER)) file_fc = open(DEF.FNAME_SVM_TEST_FEATURE_CLUSTER, "r") for aline in file_fc: aline = aline.strip() if (aline == ""): continue tokens = tft_utils.String2Tokens(aline, " ") cid = int(tokens[0]) assert(cid in DEF.CID_HDLabel.keys()) this_feature = [] for i in range(1, len(tokens)): fv = tft_utils.String2Tokens(tokens[i], ":") assert(len(fv) == 2) assert(i == int(fv[0])) this_feature.append(float(fv[1])) Testing_CIDs.append(cid) Testing_Features.append(this_feature) file_fc.close() # check the validity of the data n_tests = len(Testing_Partitions) assert(n_tests == len(Testing_Features)) assert(n_tests == len(Testing_CIDs)) # go testing n_test_success = 0 n_exact_allocs = 0 CID_Testing_Counts = {} # [0 for i in range(0, DEF.N_Clusters)] while (len(Testing_Partitions) > 0): assert(len(Testing_Partitions) == len(Testing_Features)) assert(len(Testing_Features) == len(Testing_CIDs)) # print out the testing progress sys.stdout.write("\rTest [" + str(n_tests - len(Testing_Partitions)) + "] : ") # get this partition, feature, and the cid this_part = Testing_Partitions[0] this_dvec = DEF.InverseSampleInputPartitionFromVec(this_part) this_feature = Testing_Features[0] exact_cid = Testing_CIDs[0] # sanitation check this_feature_2 = DEF.InputPartition2Feature([DEF.Feature_Option, []], this_dvec) assert(len(this_feature) == len(this_feature_2)) for i in range(0, len(this_feature)): f = this_feature[i] f2 = this_feature_2[i] assert(abs(f - f2) < 0.00000001) # predict the alloc this_cid = CIDPredict(this_feature) assert(this_cid in DEF.CID_HDLabel.keys()) if (this_cid not in CID_Testing_Counts.keys()): CID_Testing_Counts[this_cid] = 0 sys.stdout.write("predicted/exact CID : [" + str(this_cid) + " / " + str(exact_cid) + "] ") sys.stdout.flush() CID_Testing_Counts[this_cid] = CID_Testing_Counts[this_cid] + 1 predicted_alloc = DEF.HDLabel2Alloc(DEF.CID_HDLabel[this_cid]) assert(predicted_alloc is not None) # count exact prediction if (this_cid == exact_cid): n_exact_allocs = n_exact_allocs + 1 # solve the alloc this_eforms = None this_alloc = None if (DEF.REUSE_EFORMS): assert(DEF.BASE_EFORMS is not None) original_gid_epss = None new_gid_epss = {} # record and overwrite epsilons for ef in DEF.BASE_EFORMS: if (original_gid_epss is None): original_gid_epss = ef.gid2epsilons.copy() else: assert(original_gid_epss.keys() == ef.gid2epsilons.keys()) for gid,epss in original_gid_epss.items(): assert(ef.gid2epsilons[gid] == epss) for et in ef.terms: et.stored_overapprox_expr = None etgid = et.getGid() assert(etgid >= 0) assert(predicted_alloc.isAssigned(etgid)) assert(etgid in original_gid_epss.keys()) ow_epss = [tft_expr.ConstantExpr(predicted_alloc[etgid])] if (etgid in new_gid_epss.keys()): assert(new_gid_epss[etgid] == ow_epss) else: new_gid_epss[etgid] = ow_epss for gid in original_gid_epss.keys(): assert(predicted_alloc.isAssigned(gid)) new_gid_epss[gid] = [tft_expr.ConstantExpr(predicted_alloc[gid])] assert(new_gid_epss.keys() == original_gid_epss.keys()) for ef in DEF.BASE_EFORMS: ef.gid2epsilons = new_gid_epss.copy() # solve alloc. tft_tuning.TFTSystemReset() DEF.RewriteVarBounds(this_part) this_eforms, this_alloc = tft_sol_exprs.SolveErrorForms(DEF.BASE_EFORMS, tft_tuning.OPTIMIZERS) # restore the original epsilons for ef in DEF.BASE_EFORMS: ef.gid2epsilons = original_gid_epss.copy() else: # create the exprs file fname_part = tft_dat_sampling.FNameExprs(tft_dat_sampling.FNAME_EXPRS, id_feat) # solve alloc. tft_dat_sampling.WriteExprsFile(fname_part, this_part, predicted_alloc) tft_tuning.TFTSystemReset() this_eforms, this_alloc = tft_sol_exprs.SolveExprs(fname_part, tft_tuning.OPTIMIZERS) os.system("rm " + fname_part) # count the correct prediction if (this_alloc is not None): assert(this_alloc == predicted_alloc) n_test_success = n_test_success + 1 if (VERBOSE): sys.stdout.write(" ---- prediction successed!!") sys.stdout.flush() else: if (VERBOSE): print (" ---- prediction failed...") # finalizing del Testing_Partitions[0] del Testing_Features[0] del Testing_CIDs[0] print ("") print ("Small-scale Testing Result: " + str(n_test_success) + " / " + str(n_tests) + " (" + str(float(n_test_success)/float(n_tests)) + ")") print (" Exact Result : " + str(n_exact_allocs) + " / " + str(n_tests) + " (" + str(float(n_exact_allocs)/float(n_tests)) + ")") # show CID_Testing_Counts assert(sum(CID_Testing_Counts.values()) == n_tests) if (VERBOSE): print ("---- cid to # of training partitions ----") for cid in range(0, DEF.N_Clusters): if (cid in CID_Testing_Counts.keys()): print ("CID: " + str(cid) + " : " + str(CID_Testing_Counts[cid]))
def errorExpr (self, context_gid, gid): assert(False) assert(type(context_gid) is int) assert(type(gid) is int) assert(context_gid in self.gid2epsilons.keys()) assert(gid in self.gid2epsilons.keys()) assert((gid == context_gid) or ((gid, context_gid) in self.casting_map.keys())) temp_epss = self.gid2epsilons[gid] temp_context_epss = self.gid2epsilons[context_gid] epss = [] context_epss = [] checkValidEpsilonList(temp_epss) checkValidEpsilonList(temp_context_epss) # scaling up the epsilons scaling_expr = self.scalingUpFactor() for i in range(0, len(temp_epss)): epss.append( tft_expr.ConstantExpr(temp_epss[i].value() * scaling_expr.value()) ) for j in range(0, len(temp_context_epss)): context_epss.append( tft_expr.ConstantExpr(temp_context_epss[j].value() * scaling_expr.value()) ) error_expr = IR.BE("*", -1, GroupErrorVar(gid, 0), epss[0], True) for i in range(1, len(epss)): error_expr = IR.BE("+", -1, error_expr, IR.BE("*", -1, GroupErrorVar(gid, i), epss[i], True), True) tc_error = None if (gid != context_gid): for i in range(0, len(epss)): for j in range(0, len(context_epss)): if (epss[i] < context_epss[j]): temp_error = IR.BE("*", -1, GroupErrorVar(gid, i), GroupErrorVar(context_gid, j), True) temp_error = IR.BE("*", -1, temp_error, context_epss[j], # tft_expr.ConstantExpr(context_epss[j].value() + # (context_epss[j].value() * epss[i].value())), True) if (tc_error is None): tc_error = temp_error else: tc_error = IR.BE("+", -1, tc_error, temp_error, True) if (tc_error is None): return error_expr else: return IR.BE("+", -1, error_expr, tc_error, True)
def ExportExpr2ExprsFile(expr_or_exprs, upper_bound, ifname): tft_ir_api.STAT = False if (tft_ir_api.TUNE_FOR_ALL): assert (len(tft_ir_api.EXTERNAL_GIDS) <= 1) if (tft_ir_api.PREC_CANDIDATES == ["e32", "e64"]): tft_ir_api.GID_EPSS[tft_expr.PRESERVED_CONST_GID] = ["e64"] elif (tft_ir_api.PREC_CANDIDATES == ["e64", "e128"] or tft_ir_api.PREC_CANDIDATES == ["e32", "e64", "e128"]): tft_ir_api.GID_EPSS[tft_expr.PRESERVED_CONST_GID] = ["e128"] else: sys.exit("ERROR: invalid setting of tft_ir_api.PREC_CANDIDATES: " + str(tft_ir_api.PREC_CANDIDATES)) exprs = None if (isinstance(expr_or_exprs, tft_expr.Expr)): exprs = [expr_or_exprs] else: assert (len(expr_or_exprs) > 0) for expr in expr_or_exprs: assert (isinstance(expr, tft_expr.Expr)) exprs = expr_or_exprs # -- check the # of gangs and the # of error terms in the original error form) if (isinstance(upper_bound, tft_expr.ConstantExpr)): pass elif (isinstance(upper_bound, Fraction) or (type(upper_bound) is float)): upper_bound = tft_expr.ConstantExpr(upper_bound) else: sys.exit("ERROR: unsupported type of upper_bound...") assert (isinstance(upper_bound, tft_expr.ConstantExpr)) for v in tft_ir_api.INPUT_VARS: assert (isinstance(v, tft_expr.VariableExpr)) assert (v.hasBounds()) if (os.path.isfile(ifname)): print("WARNING: delete file : " + ifname) os.system("rm " + ifname) ifile = open(ifname, "w") # write options ifile.write("options:\n") ifile.write("opt-error-form : " + str(tft_ir_api.OPT_ERROR_FORM) + "\n") ifile.write("\n") # write upper-bound ifile.write("upper-bound:\n") ifile.write(upper_bound.toCString() + "\n") ifile.write("\n") # write var-ranges ifile.write("var-ranges:\n") for i in range(0, len(tft_ir_api.INPUT_VARS)): v = tft_ir_api.INPUT_VARS[i] ir_var = v.toIRString() assert (ir_var.startswith("(") and ir_var.endswith(")")) ir_var = ir_var[1:len(ir_var) - 1] ifile.write(ir_var + " in [" + v.lb().toCString() + ", " + v.ub().toCString() + "]\n") ifile.write("\n") # write group-epsilons ifile.write("group-epsilons:\n") for gid in tft_ir_api.EXTERNAL_GIDS: ifile.write(str(gid) + " : ") g_epss = None if (gid in tft_ir_api.GID_EPSS.keys()): g_epss = tft_ir_api.GID_EPSS[gid] else: g_epss = tft_ir_api.PREC_CANDIDATES for i in range(0, len(g_epss)): str_eps = g_epss[i] if (type(str_eps) is str): pass elif (type(str_eps) is float): str_eps = "(" + str(str_eps) + ")" else: sys.exit("ERROR: invalid type of group epsilon...") if (i == 0): ifile.write("[" + str_eps) else: ifile.write(", " + str_eps) ifile.write("]\n") ifile.write("\n") # write equal bit-width gids ifile.write("eq-gids:\n") for gp in tft_ir_api.EQ_GIDS: assert (len(gp) == 2) ifile.write(str(gp[0]) + " = " + str(gp[1]) + "\n") ifile.write("\n") # write gid counts ifile.write("gid-counts:\n") for gid, c in tft_ir_api.GID_COUNTS.items(): ifile.write(str(gid) + " : " + str(c) + "\n") ifile.write("\n") # write casting counts ifile.write("casting-counts:\n") for p, c in tft_ir_api.CAST_COUNTS.items(): ifile.write(str(p) + " : " + str(c) + "\n") ifile.write("\n") # write gid weight ifile.write("gid-weight:\n") for g, w in tft_ir_api.GID_WEIGHT.items(): ifile.write(str(g) + " : " + str(w) + "\n") ifile.write("\n") # write exprs ifile.write("exprs:\n") for i in range(0, len(tft_ir_api.INTERVAR_EXPR)): var_expr = tft_ir_api.INTERVAR_EXPR[i] assert (len(var_expr) == 2) assert (isinstance(var_expr[0], tft_expr.VariableExpr)) assert (isinstance(var_expr[1], tft_expr.Expr)) ir_var = var_expr[0].toIRString() assert (ir_var.startswith("(") and ir_var.endswith(")")) ir_var = ir_var[1:len(ir_var) - 1] ifile.write(ir_var + " = " + var_expr[1].toIRString() + "\n") for expr in exprs: ifile.write(expr.toIRString() + "\n") ifile.write("\n") # write constraints ifile.write("constraints:\n") for cons in tft_ir_api.CONSTRAINTS: ifile.write(cons.toIRString() + "\n") # finalize ifile.close()
def errorExpr (self, scaling_expr, gid2epsilons={}, casting_map={}): assert(isinstance(scaling_expr, tft_expr.ConstantExpr)) assert(type(self.context_gid) is int) assert(type(self.gid) is int) assert(self.context_gid in gid2epsilons.keys()) assert(self.gid in gid2epsilons.keys()) assert((self.gid == self.context_gid) or ((self.gid, self.context_gid) in casting_map.keys())) temp_epss = gid2epsilons[self.gid] temp_context_epss = gid2epsilons[self.context_gid] epss = [] context_epss = [] checkValidEpsilonList(temp_epss) checkValidEpsilonList(temp_context_epss) # scaling up the epsilons for i in range(0, len(temp_epss)): epss.append( tft_expr.ConstantExpr(temp_epss[i].value() * scaling_expr.value()) ) for j in range(0, len(temp_context_epss)): context_epss.append( tft_expr.ConstantExpr(temp_context_epss[j].value() * scaling_expr.value()) ) error_expr = None if (not self.is_precise_opt): error_expr = IR.BE("*", -1, GroupErrorVar(self.gid, 0), epss[0], True) for i in range(1, len(epss)): error_expr = IR.BE("+", -1, error_expr, IR.BE("*", -1, GroupErrorVar(self.gid, i), epss[i], True), True) tc_error = None if (self.gid != self.context_gid): for i in range(0, len(epss)): for j in range(0, len(context_epss)): if (epss[i] < context_epss[j]): temp_error = self.tcastExpr(i, j) temp_error = IR.BE("*", -1, temp_error, context_epss[j], # tft_expr.ConstantExpr(context_epss[j].value() + # (context_epss[j].value() * epss[i].value())), True) if (tc_error is None): tc_error = temp_error else: tc_error = IR.BE("+", -1, tc_error, temp_error, True) if (error_expr is None and tc_error is None): return tft_expr.ConstantExpr(0.0) elif (tc_error is None): return error_expr elif (error_expr is None): return tc_error else: return IR.BE("+", -1, error_expr, tc_error, True)
def GenerateErrorTermsFromExpr(context_expr, expr, error_exprs=[], program_exprs=[]): assert (len(error_exprs) == len(program_exprs)) if (isinstance(expr, tft_expr.ConstantExpr)): return [] elif (isinstance(expr, tft_expr.VariableExpr) or isinstance(expr, tft_expr.BinaryExpr) or isinstance(expr, tft_expr.UnaryExpr)): my_et = None gid = expr.getGid() assert (gid in GID_EPSS.keys()) epss = GID_EPSS[gid] prog_expr = None error_expr = None if (False): # if (tft_expr.isPreciseOperation(expr)): error_expr = tft_expr.ConstantExpr(0.0) else: for i in range(0, len(program_exprs)): pe = program_exprs[i] if (expr.identical(pe)): prog_expr = pe error_expr = error_exprs[i] if (error_expr is None): print("<<<< expr >>>>") print(expr.toIRString()) print(expr.toASTString()) print(">>>> program exprs <<<<") for pe in program_exprs: print(pe.toIRString()) print(pe.toASTString()) print("------------") assert (error_expr is not None) # get my ErrorTerm my_et = tft_error_form.ErrorTerm(error_expr, context_expr.getGid(), gid, tft_expr.isPreciseOperation(expr)) # get my operands' ErrorTerms and do some more book keeping if (isinstance(expr, tft_expr.VariableExpr)): return [my_et] elif (isinstance(expr, tft_expr.UnaryExpr)): ets_opd = GenerateErrorTermsFromExpr(expr, expr.opd(), error_exprs, program_exprs) return [my_et] + ets_opd elif (isinstance(expr, tft_expr.BinaryExpr)): ets_lhs = GenerateErrorTermsFromExpr(expr, expr.lhs(), error_exprs, program_exprs) ets_rhs = GenerateErrorTermsFromExpr(expr, expr.rhs(), error_exprs, program_exprs) return [my_et] + ets_lhs + ets_rhs else: sys.exit( "ERROR: broken control flow in GenerateErrorTermsFromExpr...") else: sys.exit("ERROR: invlaid expr. type...")
def SolveExprs(fname_exprs, optimizers={}): global EFORMS global E_UPPER_BOUND global M2 global GID_EPSS global GID_COUNTS global GID_WEIGHT global CASTING_MAP global EQ_GIDS global CONSTRAINT_EXPRS global OPT_ERROR_FORM global TARGET_EXPRS EFORMS = None E_UPPER_BOUND = None M2 = None time_parsing = time.time() tft_utils.VerboseMessage("parsing input expression...") tft_utils.DebugMessage("reading .exprs file...") assert (os.path.isfile(fname_exprs)) assert (ERROR_TYPE in ["abs", "rel"]) # variables input_vars = [] E_UPPER_BOUND = None ilines = [] efile = open(fname_exprs, "r") for aline in efile: aline = aline.strip() if (aline == ""): continue if (aline.startswith("#")): continue ilines.append(aline) efile.close() # options assert (ilines[0] == "options:") ilines = ilines[1:] while True: if (ilines[0] == "upper-bound:"): break tokens = tft_utils.String2Tokens(ilines[0], ":") assert (len(tokens) == 2) if (tokens[0] == "opt-error-form"): OPT_ERROR_FORM = tft_utils.String2Bool(tokens[1]) else: sys.exit("ERROR: unknown option setting: " + ilines[0]) ilines = ilines[1:] # read error bound assert (ilines[0] == "upper-bound:") ilines = ilines[1:] E_UPPER_BOUND = tft_expr.ConstantExpr(float(ilines[0])) ilines = ilines[1:] # M2 M2 = tft_expr.ConstantExpr(0.0) # read variable ranges assert (ilines[0] == "var-ranges:") ilines = ilines[1:] while True: if (ilines[0] == "group-epsilons:"): break var = tft_parser.String2BoundedVariableExpr(ilines[0]) assert (var not in input_vars) input_vars.append(var) ilines = ilines[1:] # get groups' epsilons assert (ilines[0] == "group-epsilons:") ilines = ilines[1:] while True: if (ilines[0] == "eq-gids:"): break tokens = tft_utils.String2Tokens(ilines[0], ":") assert (len(tokens) == 2) gid = int(tokens[0]) str_epss = tokens[1] assert (str_epss.startswith("[") and str_epss.endswith("]")) str_epss = str_epss[1:len(str_epss) - 1] str_eps_list = tft_utils.String2Tokens(str_epss, ",") eps_list = [] for i in range(0, len(str_eps_list)): try: i = tft_alloc.EpsLabels_String().index(str_eps_list[i]) eps_list.append( tft_expr.ConstantExpr(tft_alloc.EPSILONS[i].value)) except ValueError: expr_eps = tft_parser.String2Expr(str_eps_list[i], True) assert (isinstance(expr_eps, tft_expr.ConstantExpr)) eps_list.append(expr_eps) assert (gid not in GID_EPSS.keys()) GID_EPSS[gid] = eps_list ilines = ilines[1:] # get equal bit-width groups assert (len(ilines) > 0) assert (ilines[0] == "eq-gids:") ilines = ilines[1:] while True: assert (len(ilines) > 0) if (ilines[0] == "gid-counts:"): break tokens = tft_utils.String2Tokens(ilines[0], "=") assert (len(tokens) == 2) gid_1 = int(tokens[0]) gid_2 = int(tokens[1]) if (gid_1 == gid_2): ilines = ilines[1:] continue assert (gid_1 in GID_EPSS.keys()) assert (gid_2 in GID_EPSS.keys()) assert (GID_EPSS[gid_1] == GID_EPSS[gid_2]) gp12 = (gid_1, gid_2) gp21 = (gid_2, gid_1) if ((gp12 not in EQ_GIDS) and (gp21 not in EQ_GIDS)): EQ_GIDS.append(gp12) ilines = ilines[1:] # get GID_COUNTS assert (len(ilines) > 0) assert (ilines[0] == "gid-counts:") ilines = ilines[1:] while True: assert (len(ilines) > 0) if (ilines[0] == "casting-counts:"): break tokens = tft_utils.String2Tokens(ilines[0], ":") assert (len(tokens) == 2) gid = int(tokens[0]) c = int(tokens[1]) assert (gid >= 0) assert (c >= 0) assert (gid not in GID_COUNTS.keys()) if (c > 0): GID_COUNTS[gid] = c ilines = ilines[1:] # get CASTING_MAP assert (len(ilines) > 0) assert (ilines[0] == "casting-counts:") ilines = ilines[1:] while True: assert (len(ilines) > 0) if (ilines[0] == "gid-weight:"): break tokens = tft_utils.String2Tokens(ilines[0], ":") assert (len(tokens) == 2) p = tokens[0] c = int(tokens[1]) assert (c > 0) assert (p.startswith("(") and p.endswith(")")) p = p[1:len(p) - 1] tokens = tft_utils.String2Tokens(p, ",") assert (len(tokens) == 2) gid_from = int(tokens[0]) gid_to = int(tokens[1]) p = (gid_from, gid_to) assert (p not in CASTING_MAP.keys()) CASTING_MAP[p] = c ilines = ilines[1:] # get gid-weight mapping assert (len(ilines) > 0) assert (ilines[0] == "gid-weight:") ilines = ilines[1:] while True: assert (len(ilines) > 0) if (ilines[0] == "exprs:"): break tokens = tft_utils.String2Tokens(ilines[0], ":") assert (len(tokens) == 2) gid = int(tokens[0]) weight = float(tokens[1]) assert (0 <= gid) assert (0 <= weight) GID_WEIGHT[gid] = weight ilines = ilines[1:] # get expressions assert (len(ilines) > 0) assert (ilines[0] == "exprs:") ilines = ilines[1:] while True: assert (len(ilines) > 0) if (ilines[0] == "constraints:"): break target_expr = tft_parser.String2Expr(ilines[0], False) assert (isinstance(target_expr, tft_expr.ArithmeticExpr)) TARGET_EXPRS.append(target_expr) ilines = ilines[1:] assert (len(TARGET_EXPRS) > 0) assert (all([isinstance(te, tft_expr.Expr) for te in TARGET_EXPRS])) # get constraints assert (len(ilines) > 0) assert (ilines[0] == "constraints:") ilines = ilines[1:] while True: if (len(ilines) == 0): break pred_expr = tft_parser.String2Expr(ilines[0], False) assert (isinstance(pred_expr, tft_expr.Predicate)) CONSTRAINT_EXPRS.append(pred_expr) ilines = ilines[1:] # ---- generate the Error Forms ---- tft_utils.DebugMessage(".exprs file read") tft_utils.DebugMessage("generating ErrorForms...") target_alloc = None irstrings = None EFORMS = [] for te in TARGET_EXPRS: ef = GenerateErrorFormFromExpr(te, ERROR_TYPE, E_UPPER_BOUND, M2, EQ_GIDS, CONSTRAINT_EXPRS) EFORMS.append(ef) assert (len(EFORMS) == len(TARGET_EXPRS)) # ---- solve from the ErrorForms ---- tft_utils.DebugMessage("ErrorForms generated") tft_utils.TIME_PARSING = tft_utils.TIME_PARSING + (time.time() - time_parsing) EFORMS, target_alloc = SolveErrorForms(EFORMS, optimizers) if (VERBOSE): print("---- Error Forms after solving ----") for ef in EFORMS: print(str(ef)) print("------------") if (target_alloc is None): print("TFT: no available allocation for the main expr...") return EFORMS, None # ---- some finalize before return ---- if (VERBOSE): stat = {} for te in TARGET_EXPRS: tft_expr.ExprStatistics(te, stat) assert ("# constants" in stat.keys()) assert ("# variables" in stat.keys()) assert ("# operations" in stat.keys()) assert ("groups" in stat.keys()) stat["groups"].sort() print("---- # constants: " + str(stat["# constants"]) + " (# of appearances)") print("---- # variables: " + str(stat["# variables"]) + " (# of appearances)") print("---- # operations: " + str(stat["# operations"])) print("---- groups: " + str(stat["groups"])) # n_opts,n_insts = tft_error_form.countOptsInsts(EFORMS) # print ("---- # of (static) operations: " + str(n_opts) + " ----") # print ("---- # of (dynamic) instances: " + str(n_insts) + " ----") # ---- return ---- return EFORMS, target_alloc
def main(): # ==== get parameters ==== parser = argparse.ArgumentParser() parser.add_argument("expr_spec", help="Expression Specification") parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Verbose mode") parser.add_argument("-d", "--debug", action="store_true", default=False, help="Debug mode") parser.add_argument("-n", "--no-m2-check", action="store_true", default=False, help="Skip m2 check") parser.add_argument("-m", "--maxc", type=int, help="Maximum number of type casts") parser.add_argument("--linear-tc", action="store_true", default=False, help="Use linear type casting constraints") parser.add_argument( "--aopt", type=str, default="gurobi", help= "Allocation optimization solver: \"gurobi\" for Gurobi and \"glpk\" for GLPK (must work with --linear-tc)" ) parser.add_argument("--gopt-timeout", type=int, default=120, help="Timeout of the global optimization") parser.add_argument("--gopt-tolerance", type=float, default=5e-02, help="Tolerance of the global optimization") parser.add_argument("--optm", type=str, default="max-benefit", choices=tft_utils.OPT_METHODS, help="Optimization method") parser.add_argument("-e", "--error-bounds", type=str, required=True, help="Error bounds") parser.add_argument("-b", "--bitwidths", type=str, default="32 64", help="Bit-width candidates") parser.add_argument("--fix-const-type", action="store_true", default=False, help="Fix the constant type to the highest bit-width") args = parser.parse_args() INPUT_FILE = args.expr_spec if not os.path.isfile(INPUT_FILE): error("Input expression file doesn't exist: {}".format(INPUT_FILE)) tft_utils.FPTUNER_VERBOSE = args.verbose or args.debug tft_utils.FPTUNER_DEBUG = args.debug tft_utils.NO_M2_CHECK = args.no_m2_check if args.maxc != None: if args.maxc < 0: error("maxc must be >= 0") tft_utils.N_MAX_CASTINGS = args.maxc if args.gopt_timeout <= 0: error("gopt-timeout must be > 0") tft_utils.GOPT_TIMEOUT = args.gopt_timeout if args.gopt_tolerance < 0.0: error("gopt-tolerance must be >= 0.0") tft_utils.GOPT_TOLERANCE = args.gopt_tolerance tft_utils.OPT_METHOD = args.optm err_list = args.error_bounds.split() try: err_list = [float(e) for e in err_list] if len(err_list) == 0 or not all([e > 0.0 for e in err_list]): raise ValueError except ValueError: error("The error bounds must all be non-negative floats.") tft_tuning.ERROR_BOUNDS = err_list bit_widths = args.bitwidths.replace(',', ' ').split() try: bit_widths = [int(b) for b in bit_widths] bit_widths = list(set(bit_widths)) bit_widths.sort() if bit_widths not in ([32, 64, 128], [32, 64], [64, 128]): raise ValueError except ValueError: error( "Accepted bitwidth candidates are: '32 64', '64 128', '32 64 128'") IR.PREC_CANDIDATES = ["e{}".format(b) for b in bit_widths] tft_utils.FIX_CONST_TYPE = args.fix_const_type tft_utils.LINEAR_TYPE_CASTING_CONSTRAINTS = args.linear_tc tft_tuning.OPTIMIZERS["alloc"] = args.aopt if (tft_tuning.OPTIMIZERS['alloc'] == 'glpk'): assert (tft_utils.LINEAR_TYPE_CASTING_CONSTRAINTS ), "Solver GLPK must work with --linear-tc" # ==== load the input file as a module ==== if INPUT_FILE.endswith(".py"): tokens = tft_utils.String2Tokens(INPUT_FILE, "/") assert (len(tokens) >= 1) module_name = tokens[-1] assert (module_name.endswith(".py")) module_name = module_name[0:len(module_name) - 3] IR.LOAD_CPP_INSTS = True module_in = imp.load_source(module_name, INPUT_FILE) if (IR.TARGET_EXPR is None): error("no tuning target expression was specified.") IR.LOAD_CPP_INSTS = False else: # New frontend with open(INPUT_FILE, 'r') as f: data = f.read() processed_data = get_runmain_input(data) py_source = translate(processed_data) code_obj = compile(py_source, '<string>', 'exec') IR.LOAD_CPP_INSTS = True exec(code_obj) if (IR.TARGET_EXPR is None): error("No tuning target expression was specified.") IR.LOAD_CPP_INSTS = False # ==== tune the targeted expression ==== # reset the timers tft_utils.TIME_PARSING = 0 tft_utils.TIME_FIRST_DERIVATIVES = 0 tft_utils.TIME_GLOBAL_OPT = 0 tft_utils.TIME_ALLOCATION = 0 tft_utils.TIME_CHECK_M2 = 0 # possibly remove the .exprs file EXPRS_NAME = INPUT_FILE + ".exprs" if (os.path.isfile(EXPRS_NAME)): tft_utils.VerboseMessage("Warning: overwriting existing file: " + EXPRS_NAME) os.system("rm " + EXPRS_NAME) # go tuning for i in range(0, len(tft_tuning.ERROR_BOUNDS)): eforms = None alloc = None # Tune for the first error bound. # Need to generate the .exprs file first. if (i == 0): tft_ir_backend.ExportExpr2ExprsFile(IR.TARGET_EXPR, tft_tuning.ERROR_BOUNDS[0], EXPRS_NAME) # tune! eforms, alloc = tft_tuning.TFTRun(EXPRS_NAME) # otherwise, do some reset tasks else: tft_sol_exprs.ReadyToTune() new_eup = tft_expr.ConstantExpr(tft_tuning.ERROR_BOUNDS[i]) for ef in tft_sol_exprs.EFORMS: ef.upper_bound = new_eup # solve the error form eforms, alloc = tft_sol_exprs.SolveErrorForms( tft_sol_exprs.EFORMS, tft_tuning.OPTIMIZERS) # show the allocation print("==== error bound : " + str(tft_tuning.ERROR_BOUNDS[i]) + " ====") tft_tuning.PrintAlloc(alloc, eforms) print("") tft_ir_backend.ExportColorInsts(alloc) print("") # -- synthesize the mixed precision cpp file -- if (alloc is None): print( "Warning: no allocation was generated... Thus no .cpp file will be generated..." ) else: assert (isinstance(alloc, tft_alloc.Alloc)) assert (eforms is not None) str_error_bound = str(float(tft_tuning.ERROR_BOUNDS[i])) base = os.path.basename(INPUT_FILE) base = os.path.splitext(base)[0] fname_cpp = base + "." + str_error_bound + ".cpp" if (os.path.isfile(fname_cpp)): tft_utils.VerboseMessage( "Warning: overwrite the existed .cpp file: " + fname_cpp) tft_ir_backend.ExportCppInsts(alloc, fname_cpp) # show the timers timer_fname = base + ".timers.csv" write_header = (not os.path.isfile(timer_fname)) timer_file = None if (write_header): timer_file = open(timer_fname, "w") timer_file.write( "Total Parsing Time,First Derivatives,Global Optimization,QCQP,Check Higher-order Errors\n" ) else: timer_file = open(timer_fname, "a") timer_file.write( str(float(tft_utils.TIME_PARSING)) + "," + str(float(tft_utils.TIME_FIRST_DERIVATIVES)) + "," + str(float(tft_utils.TIME_GLOBAL_OPT)) + "," + str(float(tft_utils.TIME_ALLOCATION)) + "," + str(float(tft_utils.TIME_CHECK_M2)) + "\n") tft_utils.VerboseMessage("Total Parsing time : " + str(float(tft_utils.TIME_PARSING))) tft_utils.VerboseMessage(" First Dev. : " + str(float(tft_utils.TIME_FIRST_DERIVATIVES))) tft_utils.VerboseMessage("Time for global optimization: " + str(float(tft_utils.TIME_GLOBAL_OPT))) tft_utils.VerboseMessage("Time for solving QCQP : " + str(float(tft_utils.TIME_ALLOCATION))) tft_utils.VerboseMessage("Time for checking M2 : " + str(float(tft_utils.TIME_CHECK_M2))) timer_file.close()
"WARNING: no additional tuning when the \"base\" allocation is None..." ) exit(1) assert (tft_sol_exprs.EFORMS is not None) assert (len(tft_sol_exprs.EFORMS) > 0) assert (all( [isinstance(ef, tft_error_form.ErrorForm) for ef in tft_sol_exprs.EFORMS])) assert (len(tft_tuning.OPTIMIZERS) > 0) for ai in range(3, len(sys.argv)): af = None try: af = float(sys.argv[ai]) except: print("ERROR: invalid additional error threshold: " + str(sys.argv[ai])) new_eup = tft_expr.ConstantExpr(af) for ef in tft_sol_exprs.EFORMS: ef.upper_bound = new_eup # solve the error form eforms, alloc = tft_sol_exprs.SolveErrorForms(tft_sol_exprs.EFORMS, tft_tuning.OPTIMIZERS) print("==== Additional Allocation with Error Threshold: " + str(new_eup) + " ====") FinalizeAlloc(FNAME_ATEXT + "-" + sys.argv[ai], alloc, eforms)
def scoreExpr (self): global EPS_SCORE ret_se = None if (len(IR.PREC_CANDIDATES) == 2): for gid,c in self.gid_counts.items(): if (gid == tft_expr.PRESERVED_CONST_GID): continue checkValidEpsilonList(self.gid2epsilons[gid]) group_evar = None assert(tft_utils.OPT_METHOD in tft_utils.OPT_METHODS) if (tft_utils.OPT_METHOD == "max-benefit"): group_evar = GroupErrorVar(gid, 0) elif (tft_utils.OPT_METHOD == "min-penalty"): group_evar = GroupErrorVar(gid, 1) else: assert(False), "No such optimization method: " + str(tft_utils.OPT_METHOD) assert(group_evar is not None) expr_score = IR.BE("*", -1, group_evar, tft_expr.ConstantExpr(int(c)), True) assert(group_evar.hasBounds()) if gid in self.gid_weight.keys(): weight = self.gid_weight[gid] assert((type(weight) is float) and (0 <= weight)) expr_score = IR.BE("*", -1, expr_score, tft_expr.ConstantExpr(weight), True) if (ret_se is None): ret_se = expr_score else: ret_se = IR.BE("+", -1, ret_se, expr_score, True) assert(ret_se is not None) return ret_se elif (len(IR.PREC_CANDIDATES) >= 3): assert(tft_utils.OPT_METHOD in tft_utils.OPT_METHODS) if (tft_utils.OPT_METHOD == "max-benefit"): EPS_SCORE[tft_alloc.EPSILON_32] = 100.0 EPS_SCORE[tft_alloc.EPSILON_64] = 1.0 EPS_SCORE[tft_alloc.EPSILON_128] = 0.0 elif (tft_utils.OPT_METHOD == "min-penalty"): EPS_SCORE[tft_alloc.EPSILON_32] = 0.0 EPS_SCORE[tft_alloc.EPSILON_64] = 1.0 EPS_SCORE[tft_alloc.EPSILON_128] = 100.0 else: assert(False), "No such optimization method: " + str(tft_utils.OPT_METHOD) for gid,c in self.gid_counts.items(): if (gid == tft_expr.PRESERVED_CONST_GID): continue checkValidEpsilonList(self.gid2epsilons[gid]) for ei in range(0, len(self.gid2epsilons[gid])): expr_score = None group_evar = GroupErrorVar(gid, ei) assert(group_evar.hasBounds()) eps = self.gid2epsilons[gid][ei].value() assert(eps in EPS_SCORE.keys()) weight = EPS_SCORE[eps] assert(type(weight) is float) weight = weight * float(c) if gid in self.gid_weight.keys(): ext_weight = self.gid_weight[gid] assert((type(ext_weight) is float) and (0 <= ext_weight)) weight = weight * ext_weight assert(0 <= weight) if (weight > 0.0): expr_score = IR.BE("*", -1, group_evar, tft_expr.ConstantExpr(weight), True) if (ret_se is None): ret_se = expr_score else: ret_se = IR.BE("+", -1, ret_se, expr_score, True) else: pass assert(ret_se is not None) return ret_se else: sys.exit("Error: invalid # of bit-width candidates...")
def MakeUnaryExpr(op_label, op_gid, opd0, internal=False): global EXTERNAL_GIDS if ((not internal) and (TUNE_FOR_ALL)): op_gid = 0 assert (type(op_label) is str) assert (type(op_gid) is int) assert (isinstance(opd0, tft_expr.Expr)) if (COALESCE_CONST): if (isinstance(opd0, tft_expr.ConstantExpr)): if (op_label == "abs"): eret = tft_expr.ConstantExpr(abs(opd0.value())) AppendCppInst(eret) return eret elif (op_label == "-"): eret = tft_expr.ConstantExpr(-1.0 * opd0.value()) AppendCppInst(eret) return eret elif (op_label == "sqrt"): cv = opd0.value() assert (cv >= 0.0) eret = tft_expr.ConstantExpr(math.sqrt(cv)) AppendCppInst(eret) return eret else: sys.exit("ERROR: unknown Unary Operator: " + op_label) # possibly bind the constant type if ((not tft_utils.FIX_CONST_TYPE) and tft_expr.isConstVar(opd0)): if (opd0.getGid() == tft_expr.PRESERVED_CONST_GID): CountGID(tft_expr.PRESERVED_CONST_GID, -1) opd0.gid = op_gid else: if (opd0.getGId() != op_gid): print("Warning: conflicting constant type...") if (not internal): CountGID(op_gid) CountCasting(opd0, op_gid) if (internal): assert (-1 == op_gid) else: assert (0 <= op_gid) if (op_gid not in EXTERNAL_GIDS): EXTERNAL_GIDS.append(op_gid) ret_expr = None if (op_label == "-"): ret_expr = BE("*", op_gid, FConst(-1.0), opd0) else: ret_expr = tft_expr.UnaryExpr(tft_expr.UnaryOp(op_gid, op_label), opd0.copy((not internal))) AppendCppInst(ret_expr) return ret_expr
def FirstLevelAllocSolver (optimizers, error_forms = []): assert(len(error_forms) > 0) assert(("vrange" in optimizers.keys()) and ("alloc" in optimizers.keys())) assert(optimizers["vrange"] in ALL_OPTIMIZERS) assert(optimizers["alloc"] in ALL_OPTIMIZERS) assert(all([isinstance(error_forms[i], tft_error_form.ErrorForm) for i in range(0, len(error_forms))])) time_global_opt = time.time() tft_utils.VerboseMessage("invoking global optimization to bound first derivatives...") # ==== solve expressions' ranges ==== if (VERBOSE): print ("---- val. range opt. in FirstLevelAllocSolver [" + optimizers["vrange"] + "] ----") # unbounded_range = False for eform in error_forms: # len(error_forms) == 1 for et in eform.terms: assert(isinstance(et, tft_error_form.ErrorTerm)) value_max = None value_min = None # an optimization here: if the only epsilon for the ErrorTerm is 0.0, # set arbitrary bounds for the Term's expression since it will contribute 0.0 error anyway if (OPTIMIZATION_SKIP_PRECISE_OPTS and (len(et.epsilons) == 1) and (et.epsilons[0].value() == 0.0)): et.expr.setBounds(tft_expr.ConstantExpr(0.0), tft_expr.ConstantExpr(0.0)) et.absexpr().setBounds(tft_expr.ConstantExpr(0.0), tft_expr.ConstantExpr(0.0)) if (VERBOSE): print ("ErrorTerm[" + str(et.index) + "] which has expression \n" + str(et.expr) + "\nhas an only epsilon 0.0. Therefore, set arbitrary expression bounds for it.") print ("--------------------------------------------------") continue # find the obj_expr obj_expr = et.absexpr() obj_expr.setLB(tft_expr.ConstantExpr(Fraction(0, 1))) # ---- go solve the expression's range ---- if (optimizers["vrange"] in ["samplers"]): # parallel solvers SAMPLERS.addTask(obj_expr) else: # sequential solvers if (VERBOSE): print (str(obj_expr) + " IN...") if (obj_expr.hasUB()): value_max = obj_expr.ub().value() else: value_max = FindExprBound(optimizers["vrange"], obj_expr, "max", eform.constraints) if (value_max is None): return None obj_expr.setUB(tft_expr.ConstantExpr(value_max)) assert(value_max is not None) if (VERBOSE): print (" UB: " + str(float(value_max))) if (obj_expr.hasLB()): value_min = obj_expr.lb().value() else: value_min = FindExprBound(optimizers["vrange"], obj_expr, "min", eform.constraints) if (value_min is None): return None obj_expr.setLB(tft_expr.ConstantExpr(value_min)) assert(value_min is not None) if (VERBOSE): print (" LB: " + str(float(value_min))) if (VERBOSE): print ("--------------------------------------------------") # ---- for paralllel solvers, solve the expressions' ranges now ---- if (optimizers["vrange"] in ["samplers"]): SAMPLERS.goSample(eform.constraints) for et in eform.terms: if (OPTIMIZATION_SKIP_PRECISE_OPTS and (len(et.epsilons) == 1) and (et.epsilons[0].value() == 0.0)): continue obj_expr = et.absexpr() lb, ub = SAMPLERS.getRange(obj_expr) if ((lb is None) and (ub is None)): return None assert((lb is not None) and (ub is not None)) assert(lb <= ub) obj_expr.setLB(tft_expr.ConstantExpr(lb)) obj_expr.setUB(tft_expr.ConstantExpr(ub)) if (VERBOSE): print (str(obj_expr) + " IN [", str(float(lb)) + ", " + str(float(ub)) + "]") if (VERBOSE): print ("--------------------------------------------------") tft_utils.TIME_GLOBAL_OPT = tft_utils.TIME_GLOBAL_OPT + (time.time() - time_global_opt) time_allocation = time.time() # ==== dump the bounds of the first derivative expressions ==== # for et in eform.terms: # print ("GID: " + str(et.gid) + " (context: " + str(et.context_gid) + " ) : [" + str(et.absexpr().lb().value()) + ", " + str(float(et.absexpr().ub().value())) + "]") tft_utils.VerboseMessage("allocating bit-widths...") # ==== solve the allocation problem ==== mprog_back = tft_mathprog_backend.MathProg_Backend() # ---- solve the alloc. problem by using gurobi ---- alloc_solver = None if (optimizers["alloc"] == "gurobi"): alloc_solver = tft_ask_gurobi.GurobiSolver() elif (optimizers["alloc"] == "glpk"): alloc_solver = tft_ask_glpk.GLPKSolver("__mathprog_glpk.mp") else: sys.exit("ERROR: unknown alloc. optimizer: " + optimizers["alloc"]) # ---- solve ---- for eform in error_forms: # -- declare error variables and their range constraints -- # declare ref. variables for et in eform.terms: assert(isinstance(et, tft_error_form.ErrorTerm)) assert(not et.refVar().hasBounds()) alloc_solver.addVar(et.refVar()) for gid,epss in eform.gid2epsilons.items(): for ei in range(0, len(epss)): evar = tft_error_form.GroupErrorVar(gid, ei) alloc_solver.addVar(evar) # add constraints for error variables if (optimizers['alloc'] == 'gurobi'): alloc_solver.addConstraint("linear", "==", tft_expr.ConstantExpr(1), tft_error_form.GroupErrorVarSum(gid, epss)) elif (optimizers['alloc'] == 'glpk'): alloc_solver.addConstraint('==', tft_expr.ConstantExpr(1), tft_error_form.GroupErrorVarSum(gid, epss)) else: assert(False) if (VERBOSE): print ("Error Var Constraint: " + tft_error_form.GroupErrorVarSum(gid, epss).toCString() + " == 1") # add the optional type casting variables and constraints if (tft_utils.LINEAR_TYPE_CASTING_CONSTRAINTS): for gid,epss in eform.gid2epsilons.items(): for cgid, cepss in eform.gid2epsilons.items(): for ei in range(0, len(epss)): gvar = tft_error_form.GroupErrorVar(gid, ei) for cei in range(0, len(cepss)): cgvar = tft_error_form.GroupErrorVar(cgid, cei) evar = tft_error_form.TCastErrorVar(gid, ei, cgid, cei) ubv = IR.BE("+", -1, tft_expr.ConstantExpr(1), evar, True) lbv = IR.BE("+", -1, gvar, cgvar, True) alloc_solver.addVar(evar) if (optimizers['alloc'] == 'gurobi'): alloc_solver.addConstraint("linear", ">=", gvar, evar) alloc_solver.addConstraint("linear", ">=", cgvar, evar) alloc_solver.addConstraint("linear", ">=", ubv, lbv) elif (optimizers['alloc'] == 'glpk'): alloc_solver.addConstraint('<=', evar, gvar) alloc_solver.addConstraint('<=', evar, cgvar) alloc_solver.addConstraint('<=', lbv, ubv) else: assert(False) score_expr = eform.scoreExpr() for v in score_expr.vars(): assert(tft_expr.isPseudoBooleanVar(v)) alloc_solver.addVar(v) if (VERBOSE): print ("Score Expr: " + score_expr.toCString()) # add constraints for ref. variables ref_sum = None expr_up_scaling = eform.scalingUpFactor() assert(isinstance(expr_up_scaling, tft_expr.ConstantExpr)) if (VERBOSE): print ("Scaling up Expr: " + str(expr_up_scaling)) for et in eform.terms: # ref. variable rvar = et.refVar() error_expr = et.errorExpr(eform.scalingUpFactor(), eform.gid2epsilons, eform.casting_map) term_expr = et.overApproxExpr(error_expr) assert(all([pvar.isPreservedVar() for pvar in term_expr.vars()])) if (optimizers['alloc'] == 'gurobi'): alloc_solver.addConstraint("quadratic", "==", rvar, term_expr) elif (optimizers['alloc'] == 'glpk'): alloc_solver.addConstraint('==', rvar, term_expr) else: assert(False) if (VERBOSE): print ("Ref. Expr.: " + rvar.toCString() + " == " + term_expr.toCString()) if (ref_sum is None): ref_sum = rvar else: ref_sum = IR.BE("+", -1, ref_sum, rvar, True) # add M2 to ref_sum M2 = eform.M2 assert(isinstance(M2, tft_expr.ConstantExpr)) assert(isinstance(expr_up_scaling, tft_expr.ConstantExpr)) expr_scaled_M2 = tft_expr.ConstantExpr(M2.value() * expr_up_scaling.value()) # expr_scaled_M2 = IR.BE("*", -1, M2, expr_up_scaling, True) ref_sum = IR.BE("+", -1, ref_sum, expr_scaled_M2, True) # write error form upper found assert(isinstance(eform.upper_bound, tft_expr.ConstantExpr)) assert(eform.upper_bound > tft_expr.ConstantExpr(0)) assert(isinstance(ref_sum, tft_expr.Expr)) expr_scaled_upper_bound = IR.BE("*", -1, eform.upper_bound, expr_up_scaling, True) if (optimizers['alloc'] == 'gurobi'): alloc_solver.addConstraint("linear", "<=", ref_sum, expr_scaled_upper_bound) elif (optimizers['alloc'] == 'glpk'): alloc_solver.addConstraint('<=', ref_sum, expr_scaled_upper_bound) else: assert(False) if (VERBOSE): print ("expr_scaled_upper_bound: " + str(expr_scaled_upper_bound)) if (VERBOSE): print ("Reference Constraint: " + ref_sum.toCString() + " <= " + expr_scaled_upper_bound.toCString()) # write the constraints for equal bit-width groups for gp in eform.eq_gids: assert(len(gp) == 2) gid_1 = gp[0] gid_2 = gp[1] assert(gid_1 != gid_2) assert(gid_1 in eform.gid2epsilons.keys()) assert(gid_2 in eform.gid2epsilons.keys()) assert(eform.gid2epsilons[gid_1] == eform.gid2epsilons[gid_2]) len_epss = len(eform.gid2epsilons[gid_1]) for j in range(0, len_epss): ev_1 = tft_error_form.GroupErrorVar(gid_1, j) ev_2 = tft_error_form.GroupErrorVar(gid_2, j) if (optimizers['alloc'] == 'gurobi'): alloc_solver.addConstraint("linear", "==", ev_1, ev_2) elif (optimizers['alloc'] == 'glpk'): alloc_solver.addConstraint('==', ev_1, ev_2) # ---- generate the constraint for the number of castings ---- if (tft_utils.N_MAX_CASTINGS is not None): assert(type(tft_utils.N_MAX_CASTINGS) is int) assert(tft_utils.N_MAX_CASTINGS >= 0) cnum_expr = UnifiedCastingNumExpr(error_forms) if (cnum_expr is not None): assert(isinstance(cnum_expr, tft_expr.Expr)) cnum_var = tft_expr.VariableExpr(tft_expr.CNUM_PREFIX+"_var", int, -1, False) alloc_solver.addVar(cnum_var) if (optimizers['alloc'] == 'gurobi'): alloc_solver.addConstraint("quadratic", "==", cnum_expr, cnum_var) alloc_solver.addConstraint("linear", "<=", cnum_var, tft_expr.ConstantExpr(tft_utils.N_MAX_CASTINGS)) elif (optimizers['alloc'] == 'glpk'): alloc_solver.addConstraint('==', cnum_expr, cnum_var) alloc_solver.addConstraint('<=', cnum_var, tft_expr.ConstantExpr(tft_utils.N_MAX_CASTINGS)) else: assert(False) if (VERBOSE): print ("Casting Constraint: " + cnum_expr.toCString() + " <= " + str(tft_utils.N_MAX_CASTINGS)) # ---- add optimization obj. ---- score_sum = None for eform in error_forms: if (score_sum is None): score_sum = eform.scoreExpr() else: assert(score_sum == eform.scoreExpr()) # score_sum = IR.BE("+", -1, score_sum, eform.scoreExpr(), True) assert(tft_utils.OPT_METHOD in tft_utils.OPT_METHODS) if (tft_utils.OPT_METHOD == "max-benefit"): alloc_solver.setOptObj(score_sum, "max") elif (tft_utils.OPT_METHOD == "min-penalty"): alloc_solver.setOptObj(score_sum, "min") else: assert(False), "No such optimization method: " + str(tft_utils.OPT_METHOD) if (VERBOSE): print ("Tuning Objective: ") print (str(score_sum)) # go opt. levar_sum_max = alloc_solver.goOpt() alloc = tft_alloc.Alloc() if (levar_sum_max is None): return None else: alloc.score = float(levar_sum_max) if (VERBOSE): print ("==== solver: the optimal score is : " + str(float(levar_sum_max))) for eform in error_forms: for gid,c in eform.gid_counts.items(): evvs = [] assert(gid in eform.gid2epsilons.keys()) for ei in range(0, len(eform.gid2epsilons[gid])): evv = alloc_solver.getOptVarValue(tft_error_form.GroupErrorVar(gid, ei)) assert(evv is not None) assert(isinstance(evv, Fraction)) # adjust value tolerance = 0.01 if (((1 - tolerance) <= evv) and (evv <= (1 + tolerance))): evv = Fraction(1, 1) if (((0 - tolerance) <= evv) and (evv <= (0 + tolerance))): evv = Fraction(0, 1) evvs.append(evv) if (sum(evvs) != Fraction(1, 1)): print ("ERROR:[ " + str(gid) + "] : " + str(evvs) + " : " + str(sum(evvs))) assert(sum(evvs) == Fraction(1, 1)) assert(len(evvs) == len(eform.gid2epsilons[gid])) for ei in range(0, len(evvs)): if (evvs[ei] == Fraction(1, 1)): eps = eform.gid2epsilons[gid][ei] assert(isinstance(eps, tft_expr.ConstantExpr)) alloc[gid] = eps.value() break tft_utils.TIME_ALLOCATION = tft_utils.TIME_ALLOCATION + (time.time() - time_allocation) return alloc