def get_expr(self, block, rel): if self == ProfileOpType.INPUT_OUTPUT: return rel elif self == ProfileOpType.INTEG_INITIAL_COND: integ_expr = genoplib.unpack_integ(rel) return integ_expr.init_cond elif self == ProfileOpType.INTEG_DERIVATIVE_GAIN: integ_expr = genoplib.unpack_integ(rel) coeff, offset, exprs = genoplib.unpack_linear_operator( integ_expr.deriv) assert (all(map(lambda expr: expr.op == oplib.OpType.VAR, exprs))) all_vars = list(map(lambda e: e.name, exprs)) block_vars = list(map(lambda inp: inp.name, block.inputs)) + \ list(map(lambda dat: dat.name, block.data)) model_terms = list(filter(lambda v: not v in block_vars, all_vars)) block_terms = list(filter(lambda v: v in block_vars, all_vars)) rel = genoplib.product([genoplib.Const(coeff)] + \ list(map(lambda v: genoplib.Var(v), \ model_terms))) return rel elif self == ProfileOpType.INTEG_DERIVATIVE_BIAS: integ_expr = genoplib.unpack_integ(rel) coeff, offset, exprs = genoplib.unpack_linear_operator( integ_expr.deriv) return genoplib.Const(offset) else: return genoplib.Const(0.0)
def get_expr_coefficient(expr): if expr.op == baseoplib.OpType.INTEG: return 1.0, expr elif expr.op == baseoplib.OpType.MULT: c1, e1 = get_expr_coefficient(expr.arg(0)) c2, e2 = get_expr_coefficient(expr.arg(1)) if e1 is None and e2 is None: return c1 * c2, genoplib.Const(1.0) elif e1 is None: return c1 * c2, e2 elif e2 is None: return c1 * c2, e1 else: return c1 * c2, genoplib.Mult(e1, e2) elif expr.op == baseoplib.OpType.ADD: c1, _e1 = get_expr_coefficient(expr.arg(0)) c2, _e2 = get_expr_coefficient(expr.arg(1)) e1 = genoplib.Const(1) if _e1 is None else _e1 e2 = genoplib.Const(1) if _e2 is None else _e2 if c1 == c2: return c1, genoplib.Add(e1, e2) else: return c1, genoplib.Add(e1, genoplib.Mult(genoplib.Const(c2 / c1), e2)) elif expr.op == baseoplib.OpType.CONST: return expr.value, None elif expr.op == baseoplib.OpType.VAR: return 1.0, expr elif expr.op == baseoplib.OpType.EMIT: c1, _e1 = get_expr_coefficient(expr.arg(0)) return c1, genoplib.Emit(_e1, expr.loc) else: raise Exception("unhandled: %s" % expr)
def get_calibration_objective_scores(all_models): #assert(models_are_homogenous(all_models,enable_outputs=False)) block, loc, _, config = models_get_block_info(all_models, use_output=False) phys_models = {} models = {} for model in all_models: calib_obj = model.output.deltas[model.config.mode].objective if not model.hidden_cfg in phys_models: phys_models[model.hidden_cfg] = exp_phys_model_lib.ExpPhysModel(block, \ config) models[model.hidden_cfg] = [] phys_model = phys_models[model.hidden_cfg] models[model.hidden_cfg].append(model) for varname, val in model.variables().items(): node = dectreelib.RegressionLeafNode(genoplib.Const(val)) phys_model.set_variable(model.output, varname, node) for hidden_cfg, model in phys_models.items(): variables = dict(map(lambda tup: (tup[0],tup[1].expr.compute()), \ model.variables().items())) print(variables) calib_expr = model.calib_obj() if not all(map(lambda v: v in variables, calib_expr.vars())): continue yield models[hidden_cfg], calib_expr.compute(variables)
def canonicalize_integration_operation(expr): has_integ_op = any( map(lambda n: n.op == baseoplib.OpType.INTEG, expr.nodes())) if has_integ_op: if expr.op == baseoplib.OpType.MULT: c, e = get_expr_coefficient(expr) if (e.op == baseoplib.OpType.INTEG): return genoplib.Integ( genoplib.Mult(genoplib.Const(c), e.deriv), genoplib.Mult(genoplib.Const(c), e.init_cond)) elif expr.op == baseoplib.OpType.INTEG: return expr else: raise Exception("unhandled: %s" % expr) else: return expr
def _prepare_minimize_model(variables,expr,params,bounds={}): n_inputs = len(variables) #if phys.model.complete: # return False repl = {} dataset = [None]*n_inputs for idx,bound_var in enumerate(variables): repl[bound_var] = genoplib.Var("x[%d]" % idx) for par,value in params.items(): repl[par] = genoplib.Const(value) bounds_arr = [(None,None)]*n_inputs for var,(lower,upper) in bounds.items(): if not var in variables: continue idx = variables.index(var) bounds_arr[idx] = (lower,upper) conc_expr = expr.substitute(repl) _,pyexpr = lambdoplib.to_python(conc_expr) return { 'expr':pyexpr, 'bounds':bounds_arr, 'variable_array':variables }
def apply_fuse_lut(goal,rule,unif): law_var = tablib.LawVar(rule.law,rule.ident,tablib.LawVar.APPLY) stmts = [] if isinstance(goal.variable, tablib.DSVar): var_name = goal.variable.var stmts.append(tablib.VADPSource(law_var,genoplib.Var(var_name))) else: stmts.append(tablib.VADPConn(law_var,goal.variable)) inpexpr = unif.get_by_name('a') coeff,base_expr = genoplib.factor_coefficient(inpexpr) assert(not base_expr is None) expr = unif.get_by_name('e') repl = {'T': genoplib.Mult(genoplib.Const(1.0/coeff), \ genoplib.Var("y")) \ } rule_var = vadplib.LawVar(rule.law,rule.ident) cfg = tablib.VADPConfig(rule_var,rule.mode) cfg.bind('e',expr.substitute(repl)) stmts.append(cfg) new_unif = unifylib.Unification() new_unif.set_by_name('a', base_expr) return new_unif,stmts
def _concretize(self, expr): sub_dict = {} for var, val in self.get_digital_config(): sub_dict[var] = genoplib.Const(val) for stmt in self.cfg.stmts: if stmt.type == adplib.ConfigStmtType.EXPR: sub_dict[stmt.name] = stmt.concrete_expr conc_expr = expr.substitute(sub_dict) return conc_expr
def fit(self): for (out, var), model in self.variables.items(): codes, values = self.data.get_dataset(self.block.outputs[out], var) npts = len(values) if len(values) == 0: raise Exception( "no data for fitting variable <%s> at output <%s>" % (var, out)) try: result = modelfitlib.fit_model(model.params, model.expr, { 'inputs': codes, 'meas_mean': values }) except Exception as e: print( "[WARN] failed to predict <%s> for output <%s> of block <%s>" % (var, out, self.block.name)) print(" %s.%s deltavar=%s expr=%s" % (self.block.name, out, var, model.expr)) print(" EXCEPTION=%s" % e) continue self.values[(out, var)] = {} for par in model.params: self.values[(out, var)][par] = result['params'][par] subst = dict(map(lambda tup: (tup[0],genoplib.Const(tup[1])), \ self.values[(out,var)].items())) conc_expr = model.expr.substitute(subst) self.concrete_variables[(out, var)] = conc_expr error = 0.0 all_errors = [] for idx in range(npts): pred = conc_expr.compute( dict( map(lambda hc: (hc, codes[hc][idx]), self.data.hidden_codes))) all_errors.append(values[idx] - pred) error += (values[idx] - pred)**2 self.errors[(out, var)] = math.sqrt(error) / npts print("%s.%s npts=%d deltavar=%s error=%s expr=%s" \ % (self.block.name,out,npts, var,self.errors[(out,var)], conc_expr)) for idx, (v, e) in enumerate(zip(values, all_errors)): ci = dict(map(lambda c: (c, codes[c][idx]), codes.keys())) #print(" codes=%s value=%s error=%s" % (ci,v,e)) for (out, var), model in self.variables.items(): if not (out, var) in self.concrete_variables: raise Exception( "could not infer parametres for <%s> in output <%s>" % (var, out))
def validate_model(model, expr, surf, dataset): variables = list(dataset.inputs.keys()) inputs = dataset.inputs npts = len(dataset.meas_mean) deviations = [] # the moutiplier is fine # "mult_0_3_2_0" -> okay # "integ_0_3_1_0" -> not okay ## "integ_0_3_2_0" -> okay ''' if str(model.cfg.inst) == "integ_0_3_1_0": surf.zero() ''' n_failures = 0 for idx in range(npts): inps = {} for var, val in dataset.get_input(idx).items(): inps[var] = genoplib.Const(val) expr_val = val = expr.substitute(inps).compute() dev_val = surf.get( dict(map(lambda tup: (tup[0], tup[1].value), inps.items()))) val = expr_val + dev_val err = val - dataset.meas_mean[idx] if abs(err) > 1e-6: print("fail delta=%f dev=%f pred=%f meas=%f err=%f noise=%f" \ % (expr_val, dev_val, val, \ dataset.meas_mean[idx], \ err, \ dataset.meas_stdev[idx])) n_failures += 1 deviations.append(val - expr_val) ''' print("pred=%f pred2=%f meas=%f err=%f noise=%f" \ % (val, expr_val, \ dataset.meas_mean[idx], \ err, \ dataset.meas_stdev[idx])) ''' if n_failures > 0: print("[warn] model validation failed: %d/%d datapoints." % (n_failures, npts)) #raise Exception("model validation failed: %d/%d datapoints." % (n_failures,npts)) print("DEVIATION %s %s dev=%f +- %f" \ % (model.cfg.inst, model.cfg.mode, \ np.mean(deviations), np.std(deviations)))
def simplify_flip(dev,vadp_stmts,rule): sink_stmt = None for stmt in vadp_stmts: # identify a connection or source flip is used if isinstance(stmt, tablib.VADPConn) and \ isinstance(stmt.source, tablib.LawVar) and \ stmt.source.law == rule.law: sink_stmt = stmt sink_var = stmt.sink target_var = stmt.source break elif isinstance(stmt,tablib.VADPSource) and \ isinstance(stmt.target, tablib.LawVar) and \ stmt.target.law == rule.law: sink_stmt = stmt sink_var = VirtualSourceVar(stmt.dsexpr.name) target_var = stmt.port break # is there is no statement with rule variables if sink_stmt is None: return False,vadp_stmts # identify sink statement connected to law variable new_stmt = [] replaced_stmts = [sink_stmt] for stmt in vadp_stmts: if isinstance(stmt,tablib.VADPSink) and \ isinstance(stmt.port, tablib.LawVar) and \ stmt.port.same_usage(target_var): new_stmt.append(tablib.VADPSink(sink_var, \ genoplib.Mult(genoplib.Const(-1), \ stmt.dsexpr) \ )) replaced_stmts.append(stmt) new_vadp = [] for stmt in vadp_stmts: if not stmt in replaced_stmts: new_vadp.append(stmt) return True,new_vadp
def _compute(self, expr, values): vdict = dict(values) for inp, blks in self.inputs.items(): val = 0.0 for blk in blks: val += blk.compute(values) port = self.block.inputs[inp] if self.enable_intervals: val = port.interval[self.cfg.mode].clip(val) vdict[inp] = val #print("") #print(self.cfg) if self.user_defined is None: vdict_sym = dict(map(lambda tup: (tup[0], \ genoplib.Const(tup[1])), \ vdict.items())) #print(expr) val = expr.substitute(vdict_sym).compute() else: input_port, inputs, outputs = self.user_defined inp_val = vdict[input_port] idx = util.nearest_value(inputs, inp_val, index=True) val = outputs[idx] #print(vdict) #print("orig-val: %f" % val) val += self.get_model_error(self.error_model, vdict) #print("err-val: %f" % val) port = self.block.outputs[self.port.name] if self.enable_intervals: val = port.interval[self.cfg.mode].clip(val) #print("clip-val: %f" % val) return val
def canonicalize_call(expr): call_expr = None if expr.op == oplib.OpType.MULT: args_const, args_exprs = separate(oplib.OpType.CONST, get_assoc(oplib.OpType.MULT, expr)) const_val = 1.0 for arg in args_const: const_val *= arg.value if len(args_exprs) == 1 and \ args_exprs[0].op == oplib.OpType.CALL: call_expr = args_exprs[0] func_expr = call_expr.func new_impl = genoplib.Mult(genoplib.Const(const_val), \ func_expr.expr) return genoplib.Call(call_expr.values, \ lambdoplib.Func(func_expr.func_args, \ new_impl)) else: return None
def sympy_unify_const(pat_expr, targ_expr): assert (len(pat_expr.vars()) <= 1) assert (len(targ_expr.vars()) == 0) targ_syms = {} targ_symexpr = lambdoplib.to_sympy(targ_expr, targ_syms) pat_syms = dict(targ_syms) pat_symexpr = lambdoplib.to_sympy(pat_expr, pat_syms) symbols = list(targ_syms.values()) + list(pat_syms.values()) try: result = sympy_solve(targ_symexpr - pat_symexpr, \ symbols,dict=True) except Exception as e: return False, None, None assign = result[0] if len(pat_expr.vars()) == 1: pat_var = pat_expr.vars()[0] const_val = genoplib.Const(assign[pat_syms[pat_var]]) return True, genoplib.Var(pat_var), const_val else: print(assign) raise NotImplementedError
def render_config_info(board,graph,cfg): blk = board.get_block(cfg.inst.block) st = [] st.append("\modes: %s" % (cfg.modes)) for data in cfg.stmts_of_type(adplib \ .ConfigStmtType \ .CONSTANT): st.append("%s=%.2f scf=%.2e" % (data.name, \ data.value, \ data.scf)) for data in cfg.stmts_of_type(adplib \ .ConfigStmtType \ .EXPR): inj_args = dict(map(lambda tup: (tup[0], \ genoplib.Mult(genoplib.Var(tup[0]), \ genoplib.Const(tup[1]))), \ data.injs.items())) subexpr = data.expr.substitute(inj_args) st.append("%s=%s injs=%s scfs=%s" \ % (data.name,data.expr,data.injs,data.scfs)) ident = "%s-config" % cfg.inst graph.node(ident, "%s" % "\n".join(st), \ shape="note", \ style="filled", \ fillcolor=Colors.LIGHTYELLOW) port_id = "%s:block" % (cfg.inst) graph.edge(ident,port_id, \ penwidth="2", \ style="dashed", \ arrowhead="tee", arrowtail="normal", \ color=Colors.ORANGE) return st
def get_model(self, params): repls = dict(map(lambda tup: (tup[0],oplib.Const(tup[1])), \ params.items())) return self.relation.substitute(repls)
def compute_expression_fields(board,adp,cfg,compensate=True, debug=False): #print(cfg) blk = board.get_block(cfg.inst.block) if(len(blk.data) < 1): return data = list(filter(lambda d: d.type == blocklib.BlockDataType.EXPR, \ blk.data)) if(len(data) < 1): return assert(len(data) == 1) # only allowed to have one output. output_port = blk.outputs.singleton() calib_obj = llenums.CalibrateObjective(adp.metadata[adplib.ADPMetadata.Keys.RUNTIME_CALIB_OBJ]) rel = output_port.relation[cfg.mode] fn_call= util.singleton(filter(lambda n: n.op == oplib.OpType.CALL, rel.nodes())) fn_spec=fn_call.func fn_params = fn_call.values data_expr_field_name = util.singleton(fn_spec.expr.vars()) data_expr_field = cfg.get(data_expr_field_name) # build offset map repls = {} for input_port, func_arg in zip(fn_call.values,fn_spec.func_args): if compensate: assert(input_port.op == oplib.OpType.VAR) conn = util.singleton(adp.incoming_conns(blk.name, cfg.inst.loc, input_port.name)) src_block = board.get_block(conn.source_inst.block) src_cfg = adp.configs.get(conn.source_inst.block, conn.source_inst.loc) model = get_experimental_model(board, \ src_block, \ conn.source_inst.loc, \ src_cfg, \ calib_obj=calib_obj) gain,offset = get_compensation_parameters(model,init_cond=False) else: gain,offset = 1.0,0.0 inj = data_expr_field.injs[func_arg] repls[func_arg] = genoplib.Mult(genoplib.Const(inj), \ genoplib.Add( \ genoplib.Var(func_arg), \ genoplib.Const(-offset) )) if debug: print("inp-var %s inj=%f offset=%f" % (func_arg,inj,offset)) # compute model of output block if compensate: conn = util.singleton(adp.outgoing_conns(blk.name, cfg.inst.loc, output_port.name)) dest_block = board.get_block(conn.dest_inst.block) dest_cfg = adp.configs.get(conn.dest_inst.block, conn.dest_inst.loc) model = get_experimental_model(board, \ dest_block, \ dest_cfg.inst.loc, \ dest_cfg, \ calib_obj=calib_obj) gain,offset = get_compensation_parameters(model,False) else: gain,offset = 1.0,0.0 inj = data_expr_field.injs[data_expr_field.name] if debug: print("out-var %s inj=%f gain=%f offset=%f" % (data_expr_field.name, \ inj,gain,offset)) func_impl = genoplib.Mult(genoplib.Const(inj), \ data_expr_field.expr.substitute(repls)) if debug: print("func-expr: %s" % func_impl) rel_impl = genoplib.Add( \ rel.substitute({data_expr_field.name:func_impl}), \ genoplib.Const(-offset/gain) \ ) output_port = blk.outputs.singleton() input_port = blk.inputs.singleton() final_expr = rel_impl.concretize() if debug: print("rel-expr: %s" % rel_impl) print("--- building lookup table ---") print(final_expr) input_values = input_port.quantize[cfg.mode] \ .get_values(input_port \ .interval[cfg.mode]) cfg[data_expr_field.name].set_input(input_port,input_values) lut_outs = [] for val in input_values: out = final_expr.compute({input_port.name:val}) out = max(min(1.0-1.0/128.0,out),-1.0) cfg[data_expr_field.name].set_output({input_port.name:val},out) cfg[data_expr_field.name].concrete_expr = final_expr
def Sqrt(a): return Pow(a, genop.Const(0.5))
def Div(a, b): return genop.Mult(a, Pow(b, genop.Const(-1)))
def from_sympy(symexpr, no_aliasing=False): if isinstance(symexpr, sympy.Function): if isinstance(symexpr, sympy.sin): e0 = from_sympy(symexpr.args[0], no_aliasing) return Sin(e0) elif symexpr.func.name == "integ": assert (len(symexpr.args) == 2) e1 = from_sympy(symexpr.args[0], no_aliasing) e2 = from_sympy(symexpr.args[1], no_aliasing) return genop.Integ(e1, e2) elif symexpr.func.name == "max": assert (len(symexpr.args) == 2) e1 = from_sympy(symexpr.args[0], no_aliasing) e2 = from_sympy(symexpr.args[1], no_aliasing) return Max(e1, e2) elif symexpr.func.name == "abs": e1 = from_sympy(symexpr.args[-1], no_aliasing) return Abs(e1) elif symexpr.func.name == "sgn": e1 = from_sympy(symexpr.args[-1], no_aliasing) return Sgn(e1) elif symexpr.func.name == "call": efn = from_sympy(symexpr.args[0], no_aliasing) args = list(map(lambda e : from_sympy(e,no_aliasing), \ symexpr.args[1:])) return genop.Call(args, efn) elif symexpr.func.name == "func": ebody = from_sympy(symexpr.args[-1], no_aliasing) pars = list(map(lambda e: from_sympy(e,no_aliasing).name, \ symexpr.args[:-1])) return Func(pars, ebody) elif symexpr.func.name == "extvar": e1 = from_sympy(symexpr.args[-1], no_aliasing) assert (isinstance(e1, genop.Var)) return genop.ExtVar(e1.name) elif symexpr.func.name == "emit": e1 = from_sympy(symexpr.args[-1], no_aliasing) return genop.Emit(e1) elif symexpr.func.name == "map": raise FromSympyFailed("cannot convert mapping %s back to expr" % symexpr) else: raise Exception("unhandled func: %s" % (symexpr.func)) elif isinstance(symexpr, sympy.Pow): e1 = from_sympy(symexpr.args[0], no_aliasing) e2 = from_sympy(symexpr.args[1], no_aliasing) return Pow(e1, e2) elif isinstance(symexpr, sympy.Symbol): if no_aliasing: name = symexpr.name.split(".")[0] else: name = symexpr.name return genop.Var(name) elif isinstance(symexpr, sympy.Float) or \ isinstance(symexpr, sympy.Integer): return genop.Const(float(symexpr)) elif isinstance(symexpr, sympy.Mul): args = list(map(lambda a: from_sympy(a,no_aliasing), \ symexpr.args)) return genop.product(args) elif isinstance(symexpr, sympy.Add): args = list(map(lambda a: from_sympy(a,no_aliasing), \ symexpr.args)) return genop.sum(args) elif isinstance(symexpr, sympy.Rational): return genop.Const(float(symexpr)) else: print(symexpr.func) raise Exception(sympy.srepr(symexpr))