def computeConstantFormat(self, c): if c == 0: # default to double precision return self.get_format_from_accuracy(53, eps_target=0, interval=Interval(c), exact=True) else: accuracy = 0 cN = c limb_num = 0 while cN != 0 and limb_num < self.LIMB_NUM_THRESHOLD: cR = sollya.round(cN, sollya.binary64, sollya.RN) cN = cN - cR accuracy += 53 limb_num += 1 if accuracy > 159 or limb_num > self.LIMB_NUM_THRESHOLD: eps_target = S2**--accuracy accuracy = 159 else: eps_target = 0 if cN == 0 else S2**-accuracy return self.get_format_from_accuracy(accuracy, eps_target=eps_target, interval=Interval(c), exact=True)
class DefaultArgTemplate: base_name = "unknown_function" function_name = "undef_function" output_file = "undef.c" # metalim engine settings display_after_opt = False display_after_gen = False verbose_enable = False # arity = 1 # output/intermediate format Specification precision = ML_Binary32 input_precisions = None # list of input precisions # None <=> [self.precision] * self.get_arity() abs_accuracy = None accuracy = ML_Faithful libm_compliant = False input_interval = Interval(0, 1) # Optimization parameters target = GenericProcessor() fuse_fma = False fast_path_extract = True dot_product_enabled = False # Debug verbosity debug = False # Vector related parameters vector_size = 1 sub_vector_size = None language = C_Code # auto-test properties auto_test = False auto_test_range = Interval(0, 1) auto_test_std = False # enable max error computation compute_max_error = False break_error = False # bench properties bench_test_number = 0 bench_test_range = Interval(0, 1) bench_function_name = "undefined" headers = [] libraries = [] # emulation numeric function emulate = lambda x: x # list of pre-code generation opt passe names (string tag) pre_gen_passes = [] check_processor_support = True # source elaboration build_enable = False # passes = [] # built binary execution execute_trigger = False def __init__(self, **kw): for key in kw: setattr(self, key, kw[key])
def misc(self): print("Gappa script generation") cg = CCodeGenerator(processor, declare_cst=False, disable_debug=not debug_flag, libm_compliant=libm_compliant) self.result = exp_implementation.get_definition(cg, C_Code, static_cst=True) self.result.add_header("math.h") self.result.add_header("stdio.h") self.result.add_header("inttypes.h") self.result.add_header("support_lib/ml_special_values.h") output_stream = open(output_file, "w") output_stream.write(self.result.get(cg)) output_stream.close() seed_var = Variable("seed", precision=self.precision, interval=Interval(0.5, 1)) cg_eval_error_copy_map = { gappa_init_approx.get_handle().get_node(): seed_var, gappa_vx.get_handle().get_node(): Variable("x", precision=self.precision, interval=Interval(1, 2)), gappa_vy.get_handle().get_node(): Variable("y", precision=self.precision, interval=Interval(1, 2)), } G1 = Constant(1, precision=ML_Exact) exact = G1 / gappa_vy exact.set_precision(ML_Exact) exact.set_tag("div_exact") gappa_goal = gappa_current_approx.get_handle().get_node() - exact gappa_goal.set_precision(ML_Exact) gappacg = GappaCodeGenerator(target, declare_cst=False, disable_debug=True) gappa_code = gappacg.get_interval_code(gappa_goal, cg_eval_error_copy_map) new_exact_node = exact.get_handle().get_node() for nr in inv_iteration_list: nr.get_hint_rules(gappacg, gappa_code, new_exact_node) seed_wrt_exact = seed_var - new_exact_node seed_wrt_exact.set_precision(ML_Exact) gappacg.add_hypothesis(gappa_code, seed_wrt_exact, Interval(-S2**-7, S2**-7)) try: eval_error = execute_gappa_script_extract( gappa_code.get(gappacg))["goal"] print("eval_error: "), eval_error except: print("error during gappa run")
def __init__(self, interval=None, lhs=None, rhs=None): if not interval is None: self.interval = interval elif not lhs is None: if not rhs is None: self.interval = Interval(lhs, rhs) else: self.interval = Interval(lhs) else: # empty interval self.interval = None
def get_default_args(**kw): """ Return a structure containing the arguments for MetaFMOD, builtin from a default argument mapping overloaded with @p kw """ default_args_exp = { "output_file": "ml_fmod.c", "function_name": "ml_fmod", "input_intervals": (Interval(-100, 100), Interval(-100, 100)), "precision": ML_Binary32, "accuracy": ML_Faithful, "target": GenericProcessor.get_target_instance(), } default_args_exp.update(kw) return DefaultArgTemplate(**default_args_exp)
def get_default_args(**kw): """ Return a structure containing the arguments for ML_Exponential, builtin from a default argument mapping overloaded with @p kw """ default_args_mmk = { "output_file": "mm_kernel.c", "function_name": "mm_kernel", "test_index_range": [[16, 32], [16, 32], [16, 32]], "auto_test_range": [Interval(-1, 1), Interval(-1, 1)], "vectorize": False, "precision": ML_Binary32, "target": GenericProcessor.get_target_instance() } default_args_mmk.update(kw) return DefaultArgTemplate(**default_args_mmk)
def rootn_option_specialization(opt_dict): """ Option specilization callback for FunctionTest dedicated to rootn meta-function """ precision = opt_dict["precision"] input_precisions = { ML_Binary32: [ML_Binary32, ML_Int32], ML_Binary64: [ML_Binary64, ML_Int64], }[precision] auto_test_range = { ML_Binary32: [Interval(-2.0**126, 2.0**126), Interval(0, 255)], ML_Binary64: [Interval(-2.0**1022, 2.0**1022), Interval(0, 255)], }[precision] opt_dict["auto_test_range"] = auto_test_range opt_dict["input_precisions"] = input_precisions return opt_dict
def get_default_args(**kw): """ Return a structure containing the arguments for MetaAtan, builtin from a default argument mapping overloaded with @p kw """ default_args_pow = { "output_file": "ml_pow.c", "function_name": "ml_pow", "input_precisions": [ML_Binary32, ML_Binary32], "accuracy": ML_Faithful, "input_intervals": [None, Interval(-2**24, 2**24)], # sollya.Interval(-2.0**126, 2.0**126), sollya.Interval(0, 2**31-1)], "auto_test_range": [None, Interval(-2**24, 2**24)], # sollya.Interval(-2.0**126, 2.0**126), sollya.Interval(0, 47)], "target": GenericProcessor.get_target_instance() } default_args_pow.update(kw) return DefaultArgTemplate(**default_args_pow)
def generate_approx_poly_near_zero(self, function, high_bound, error_bound, variable): """ Generate polynomial approximation scheme """ error_function = lambda p, f, ai, mod, t: sollya.dirtyinfnorm( p - f, ai) # Some issues encountered when 0 is one of the interval bound # so we use a symetric interval around it approx_interval = Interval(2**-100, high_bound) local_function = function / sollya.x degree = sollya.sup( sollya.guessdegree(local_function, approx_interval, error_bound)) degree_list = range(0, int(degree) + 4, 2) poly_object, approx_error = Polynomial.build_from_approximation_with_error( function / sollya.x, degree_list, [1] + [self.precision] * (len(degree_list) - 1), approx_interval, sollya.absolute, error_function=error_function) Log.report( Log.Info, "approximation poly: {}\n with error {}".format( poly_object, approx_error)) poly_scheme = Multiplication( variable, PolynomialSchemeEvaluator.generate_horner_scheme( poly_object, variable, self.precision)) return poly_scheme, approx_error
def generate_test_case(self, input_signals, io_map, index, test_range=Interval(-1.0, 1.0)): """ generic test case generation: generate a random input with index @p index Args: index (int): integer index of the test case Returns: dict: mapping (input tag -> numeric value) """ # extracting test interval boundaries low_input = sollya.inf(test_range) high_input = sollya.sup(test_range) input_values = {} for input_tag in input_signals: input_signal = io_map[input_tag] # FIXME: correct value generation depending on signal precision input_precision = input_signal.get_precision().get_base_format() if isinstance(input_precision, ML_FP_Format): input_value = generate_random_fp_value(input_precision, low_input, high_input) elif isinstance(input_precision, ML_Fixed_Format): # TODO: does not depend on low and high range bounds input_value = generate_random_fixed_value(input_precision) else: input_value = random.randrange( 2**input_precision.get_bit_size()) # registering input value input_values[input_tag] = input_value return input_values
class DefaultEntityArgTemplate(DefaultArgTemplate): base_name = "unknown_entity" entity_name = "unknown_entity" output_file = "entity.vhd" debug_file = None # Specification, precision = HdlVirtualFormat(ML_Binary32) io_precisions = None io_formats = None accuracy = ML_Faithful # Optimization parameters, backend = VHDLBackend() # Debug verbosity, debug = False language = VHDL_Code # functional test related parameters auto_test = False auto_test_range = Interval(0, 1) auto_test_std = False embedded_test = True externalized_test_data = False # exit after test exit_after_test = True # RTL elaboration build_enable = False # RTL elaboration & simulation tool simulator = "vsim" # pipelined deisgn pipelined = False # pipeline register control (reset, synchronous) reset_pipeline = (False, True) negate_reset = False reset_name = "reset" recirculate_pipeline = False recirculate_signal_map = {}
def generate_function_list(self): # declaring function input variable vx = self.implementation.add_input_variable("x", self.precision) vy = self.implementation.add_input_variable("y", self.precision) # declaring specific interval for input variable <x> vx.set_interval(Interval(-1, 1)) vec = Variable("vec", precision = v2float32, var_type = Variable.Local) vec2 = Multiplication(vec, vec, precision = v2float32) vec3 = Addition(vec, vec2, precision = v2float32) large_vector = VectorAssembling(vec2, vec3, precision=v4float32) sub_vector = SubVectorExtract(large_vector, 0, 3, precision=v2float32) result = Addition(sub_vector[0], sub_vector[1], precision = ML_Binary32) scheme = Statement( ReferenceAssign(vec[0], vx), ReferenceAssign(vec[1], vy), Return(result) ) # dummy scheme to make functionnal code generation self.implementation.set_scheme(scheme) return FunctionGroup([self.implementation])
def generate_function_list(self): vector_size = 2 # declaring function input variable #vx = self.implementation.add_input_variable("x", self.precision) vx = Variable("x", precision = self.precision) # declaring specific interval for input variable <x> vx.set_interval(Interval(-1, 1)) cond0 = Test(vx, specifier = Test.IsInfOrNaN, likely = False) cond1 = Comparison(vx, 0, specifier = Comparison.GreaterOrEqual, likely = True) exp0 = vx exp1 = vx + vx * vx + Constant(1, precision = self.precision) exp2 = vx * vx * vx scheme = Statement( ConditionBlock(cond0, Return(exp0), ConditionBlock(cond1, Return(exp1), Return(exp2) ) ) ) return self.generate_vector_implementation(scheme, [vx], vector_size)
def generate_scheme(self): vx = self.implementation.add_input_variable("x", FIXED_FORMAT) # declaring specific interval for input variable <x> vx.set_interval(Interval(-1, 1)) acc_format = ML_Custom_FixedPoint_Format(6, 58, False) c = Constant(2, precision=acc_format, tag="C2") ivx = vx add_ivx = Addition( c, Multiplication(ivx, ivx, precision=acc_format, tag="mul"), precision=acc_format, tag="add" ) result = add_ivx input_mapping = {ivx: ivx.get_precision().round_sollya_object(0.125)} error_eval_map = runtime_error_eval.generate_error_eval_graph(result, input_mapping) # dummy scheme to make functionnal code generation scheme = Statement() for node in error_eval_map: scheme.add(error_eval_map[node]) scheme.add(Return(result)) return scheme
class DefaultEntityArgTemplate(DefaultArgTemplate): base_name = "unknown_entity" entity_name = "unknown_entity" output_file = "entity.vhd" debug_file = None # Specification, precision = ML_Binary32 io_precisions = None accuracy = ML_Faithful libm_compliant = False # Optimization parameters, backend = VHDLBackend() fuse_fma = None fast_path_extract = False # Debug verbosity, debug = False language = VHDL_Code # functional test related parameters auto_test = False auto_test_range = Interval(0, 1) auto_test_std = False # exit after test exit_after_test = True # RTL elaboration build_enable = False # pipelined deisgn pipelined = False # pipeline register control reset_pipeline = False recirculate_pipeline = False
def __init__(self, precision=ML_Binary32, accuracy=ML_Faithful, libm_compliant=True, debug_flag=False, fuse_fma=True, fast_path_extract=True, processor=GenericProcessor(), output_file="cosf.c", function_name="cosf", input_interval=Interval(0, 1), result_precision=ML_Binary32, table_size_log=8, cos_output=True): # initializing I/O precision io_precisions = [result_precision, precision] # initializing base class ML_FunctionBasis.__init__(self, base_name="cos", function_name=function_name, output_file=output_file, io_precisions=io_precisions, abs_accuracy=None, libm_compliant=libm_compliant, processor=processor, fuse_fma=fuse_fma, fast_path_extract=fast_path_extract, debug_flag=debug_flag) self.precision = precision self.cos_output = cos_output self.accuracy = accuracy self.input_interval = input_interval self.table_size_log = table_size_log
def __truediv__(lhs, rhs): if isinstance(rhs, MetaIntervalList): MetaIntervalList.__div__(MetaIntervalList([lhs.interval]), rhs) elif isinstance(rhs, (int, float)): rhs = MetaInterval(Interval(rhs)) elif lhs.interval is None or rhs.interval is None: return MetaInterval(None) lhs = convert_to_MetaInterval(lhs) rhs = convert_to_MetaInterval(rhs) return MetaInterval(interval=lhs.interval / rhs.interval)
def get_subset_interval(self, index_function, range_set): # init bound values low_bound = None high_bound = None # going through the selected valued list # to build the range interval for indexes in range_set: value = index_function(self, indexes) if low_bound is None or low_bound > value: low_bound = value if high_bound is None or high_bound < value: high_bound = value return Interval(low_bound, high_bound)
def get_default_args(cls, **kw): """ Return a structure containing the arguments for MetaAtan, builtin from a default argument mapping overloaded with @p kw """ arg_dict = cls.default_args_atan.copy() arg_dict.update({ "output_file": "my_atan2.c", "function_name": "my_atan2", "input_intervals": [Interval(-5, 5)] * 2, }) arg_dict.update(kw) return DefaultArgTemplate(**arg_dict)
def generate_scheme(self): """ main scheme generation """ input_precision = self.precision output_precision = self.precision # declaring main input variable x_interval = Interval(-10.3, 10.7) var_x = self.implementation.add_input_variable("x", input_precision, interval=x_interval) y_interval = Interval(-17.9, 17.2) var_y = self.implementation.add_input_variable("y", input_precision, interval=y_interval) z_interval = Interval(-70.3, -57.7) var_z = self.implementation.add_input_variable("z", input_precision, interval=z_interval) min_yz = Min(var_z, var_y) cst0 = Constant(42.5, tag="cst0", precision=self.precision) cst1 = Constant(2.5, tag="cst1", precision=self.precision) cst2 = Constant(12.5, tag="cst2", precision=self.precision) new_cst = cst0 + cst1 * cst2 result = min_yz + new_cst scheme = ConditionBlock( LogicalAnd( LogicalOr(cst0 > cst1, LogicalNot(cst1 > cst0)), var_x > var_y, ), Return(result), Return(cst2)) return scheme
def __init__(self, op_class, bench_name, op_arity=2, init_interval=Interval(-0.5, 0.5), renorm_function=lambda x: x, output_precision=ML_Binary32, input_precisions=[ML_Binary32, ML_Binary32]): """ OpUnitBench ctor """ self.op_class = op_class self.op_arity = op_arity self.init_interval = init_interval self.renorm_function = renorm_function self.output_precision = output_precision self.input_precisions = input_precisions self.bench_name = bench_name
def get_default_args(**kw): """ Return a structure containing the arguments for current class, builtin from a default argument mapping overloaded with @p kw """ default_args = { "output_file": "ut_eval_error.c", "function_name": "ut_eval_error", "precision": FIXED_FORMAT, "target": GenericProcessor.get_target_instance(), "fast_path_extract": True, "fuse_fma": True, "debug": True, "libm_compliant": True, "test_range": Interval(S2**-8, S2**8), "accuracy": dar(S2**-6), } default_args.update(kw) return DefaultArgTemplate(**default_args)
def get_default_args(**kw): """ Return a structure containing the arguments for current class, builtin from a default argument mapping overloaded with @p kw """ default_args = { "output_file": "ut_legalize_sqrt.c", "function_name": "ut_legalize_sqrt", "precision": ML_Binary32, "target": GenericProcessor(), "fast_path_extract": True, "fuse_fma": True, "debug": True, "libm_compliant": True, "test_range": Interval(S2**-8, S2**8), "accuracy": dar(S2**-7), } default_args.update(kw) return DefaultArgTemplate(**default_args)
def generate_scheme(self, skip_interface_gen=False): # retrieving I/Os if skip_interface_gen: vx = self.input_vx else: vx = self.generate_interfaces() lzc_width = ML_LeadingZeroCounter.get_lzc_output_width(self.width) precision = ML_StdLogicVectorFormat(lzc_width) vr_out = Signal("lzc", precision=precision, var_type=Variable.Local) tmp_lzc = Variable("tmp_lzc", precision=precision, var_type=Variable.Local) iterator = Variable("i", precision=ML_Integer, var_type=Variable.Local) lzc_loop = RangeLoop( iterator, Interval(0, self.width - 1), ConditionBlock( Comparison(VectorElementSelection(vx, iterator, precision=ML_StdLogic), Constant(1, precision=ML_StdLogic), specifier=Comparison.Equal, precision=ML_Bool), ReferenceAssign( tmp_lzc, Conversion(Subtraction(Constant(self.width - 1, precision=ML_Integer), iterator, precision=ML_Integer), precision=precision), )), specifier=RangeLoop.Increasing, ) lzc_process = Process(Statement( ReferenceAssign(tmp_lzc, Constant(self.width, precision=precision)), lzc_loop, ReferenceAssign(vr_out, tmp_lzc)), sensibility_list=[vx]) self.implementation.add_process(lzc_process) self.implementation.set_output_signal("vr_out", vr_out) return [self.implementation]
def piecewise_approximation_degree_generator(function, bound_low=-1.0, bound_high=1.0, num_intervals=16, max_degree=2, error_threshold=S2**-24): """ """ interval_size = (bound_high - bound_low) / num_intervals for i in range(num_intervals): subint_low = bound_low + i * interval_size subint_high = bound_low + (i + 1) * interval_size local_function = function(sollya.x + subint_low) local_interval = Interval(-interval_size, interval_size) local_degree = sollya.guessdegree(local_function, local_interval, error_threshold) yield int(sollya.sup(local_degree))
def get_default_args(**kw): """ Return a structure containing the arguments for current class, builtin from a default argument mapping overloaded with @p kw """ default_args = { "output_file": "ut_bfloat16.c", "function_name": "ut_bfloat16", "precision": ML_Binary32, "input_precisions": [ML_UInt32], "target": GenericProcessor.get_target_instance(), "fast_path_extract": True, "fuse_fma": True, "debug": True, "libm_compliant": True, "table_size": 16, "auto_test_range": Interval(0, 16), "accuracy": dar(S2**-7), } default_args.update(kw) return DefaultArgTemplate(**default_args)
def generate_scheme(self): lzc_width = int(floor(log2(self.width))) + 1 Log.report(Log.Info, "width of lzc out is {}".format(lzc_width)) input_precision = ML_StdLogicVectorFormat(self.width) precision = ML_StdLogicVectorFormat(lzc_width) # declaring main input variable vx = self.implementation.add_input_signal("x", input_precision) vr_out = Signal("lzc", precision=precision, var_type=Variable.Local) tmp_lzc = Variable("tmp_lzc", precision=precision, var_type=Variable.Local) iterator = Variable("i", precision=ML_Integer, var_type=Variable.Local) lzc_loop = RangeLoop( iterator, Interval(0, self.width - 1), ConditionBlock( Comparison(VectorElementSelection(vx, iterator, precision=ML_StdLogic), Constant(1, precision=ML_StdLogic), specifier=Comparison.Equal, precision=ML_Bool), ReferenceAssign( tmp_lzc, Conversion(Subtraction(Constant(self.width - 1, precision=ML_Integer), iterator, precision=ML_Integer), precision=precision), )), specifier=RangeLoop.Increasing, ) lzc_process = Process(Statement( ReferenceAssign(tmp_lzc, Constant(self.width, precision=precision)), lzc_loop, ReferenceAssign(vr_out, tmp_lzc)), sensibility_list=[vx]) self.implementation.add_process(lzc_process) self.implementation.add_output_signal("vr_out", vr_out) return [self.implementation]
def generate_auto_test(self, test_num = 10, test_range = Interval(-1.0, 1.0), debug = False, time_step = 10): """ time_step: duration of a stage (in ns) """ # instanciating tested component # map of input_tag -> input_signal and output_tag -> output_signal io_map = {} # map of input_tag -> input_signal, excludind commodity signals # (e.g. clock and reset) input_signals = self.get_input_signal_map(io_map) # map of output_tag -> output_signal output_signals = self.get_output_signal_map(io_map) # building list of test cases tc_list = [] # initializing random test case generator self.init_test_generator() # Appending standard test cases if required if self.auto_test_std: tc_list += self.standard_test_cases for i in range(test_num): input_values = self.generate_test_case(input_signals, io_map, i, test_range) tc_list.append((input_values,None)) def compute_results(tc): """ update test case with output values if required """ input_values, output_values = tc if output_values is None: return input_values, self.numeric_emulate(input_values) else: return tc # filling output values tc_list = [compute_results(tc) for tc in tc_list] if self.externalized_test_data: return self.generate_datafile_testbench(tc_list, io_map, input_signals, output_signals, time_step, test_fname=self.externalized_test_data) else: return self.generate_embedded_testbench(tc_list, io_map, input_signals, output_signals, time_step)
def get_default_args(**kw): """ generate default argument structure for BipartiteApprox """ default_dict = { "target": FixedPointBackend(), "output_file": "my_bipartite_approx.c", "entity_name": "my_bipartie_approx", "language": C_Code, "function": lambda x: 1.0 / x, "interval": Interval(1, 2), "pipelined": False, "precision": fixed_point(1, 15, signed=False), "disable_sub_testing": False, "disable_sv_testing": False, "alpha": 6, "beta": 5, "gamma": 5, "guard_bits": 3, "passes": ["start:size_datapath"], } default_dict.update(kw) return DefaultArgTemplate(**default_dict)
def generate_function_list(self): # declaring function input variable vx = self.implementation.add_input_variable("x", self.precision) vy = self.implementation.add_input_variable("y", self.precision) # declaring specific interval for input variable <x> vx.set_interval(Interval(-1, 1)) vec = Variable("vec", precision=ML_Float2, var_type=Variable.Local) vec2 = Multiplication(vec, vec, precision=ML_Float2) vec3 = Addition(vec, vec2, precision=ML_Float2) result = Addition(vec3[0], vec3[1], precision=ML_Binary32) scheme = Statement(ReferenceAssign(vec[0], vx), ReferenceAssign(vec[1], vy), Return(result)) # dummy scheme to make functionnal code generation self.implementation.set_scheme(scheme) return [self.implementation]