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_rootn = { "output_file": "rootn.c", "function_name": "rootn", "input_precisions": [ML_Binary32, ML_Int32], "accuracy": ML_Faithful, "input_intervals": [ sollya.Interval(-2.0**126, 2.0**126), sollya.Interval(-2**24, 2**24) ], "auto_test_range": [ sollya.Interval(-2.0**126, 2.0**126), sollya.Interval(-2**24, 2**24) ], "target": GenericProcessor.get_target_instance(), "expand_div": False, } default_args_rootn.update(kw) return DefaultArgTemplate(**default_args_rootn)
def sollya_gamma_fct(x, diff_order, prec): """ wrapper to use bigfloat implementation of exponential rather than sollya's implementation directly. This wrapper implements sollya's function API. :param x: numerical input value (may be an Interval) :param diff_order: differential order :param prec: numerical precision expected (min) """ fct = None if diff_order == 0: fct = sollya_gamma elif diff_order == 1: fct = sollya_gamma_d0 elif diff_order == 2: fct = sollya_gamma_d1 else: raise NotImplementedError with bigfloat.precision(prec): if x.is_range(): lo = sollya.inf(x) hi = sollya.sup(x) return sollya.Interval(fct(lo), fct(hi)) else: return fct(x)
def sollyaConstraint(self, margin): """ Parameter: - margin: margin we add to the band (not in dB) margin is negative when the band is reduced Returns a dictonary for sollya checkModulusFilterInSpecification """ # deal with Sollya Gabarit.readyToRunWithSollya() w1 = 2*sollya.SollyaObject(self._F1)/self._Fs w2 = 2*sollya.SollyaObject(self._F2)/self._Fs if self._F2 else 1 # F2==None -> F2=Fs/2, so w2=1 margin = sollya.SollyaObject(margin) if self.isPassBand: # pass band betaInf = 10 ** (sollya.SollyaObject(self._passGains[0]) / 20) - margin betaSup = 10 ** (sollya.SollyaObject(self._passGains[1]) / 20) + margin else: # stop band betaInf = 0 betaSup = 10 ** (sollya.SollyaObject(self._stopGain) / 20) + margin assert(betaInf < betaSup) return {"Omega": sollya.Interval(w1, w2), "omegaFactor": sollya.pi, "betaInf": sollya.round(betaInf, 53, sollya.RU), "betaSup": sollya.round(betaSup, 53, sollya.RD)}
def __init__(self, inf_bound, sup_bound): self.inf_bound = inf_bound self.sup_bound = sup_bound self.zero_in_interval = 0 in sollya.Interval( inf_bound, sup_bound) self.min_exp = None if self.zero_in_interval else min( sollya.ceil(sollya.log2(abs(inf_bound))), sollya.ceil(sollya.log2(abs(sup_bound)))) self.max_exp = max(sollya.ceil(sollya.log2(abs(inf_bound))), sollya.ceil(sollya.log2(abs(sup_bound))))
def parse_gappa_interval(interval_value): # search for middle "," end_index = len(interval_value) tmp_str = re.sub("[ \[\]]", lambda _: "", interval_value) while "{" in tmp_str: start = tmp_str.index("{") end = tmp_str.index("}") tmp_str = tmp_str[:start] + tmp_str[end + 1:] v0, v1 = tmp_str.split(",") return sollya.Interval(sollya.parse(v0), sollya.parse(v1))
def generate_scheme(self): x = self.implementation.add_input_variable("x", self.precision) n_log2 = self.precision.round_sollya_object(sollya.log(2), sollya.RN) if not self.skip_reduction: n_invlog2 = self.precision.round_sollya_object( 1 / sollya.log(2), sollya.RN) invlog2 = Constant(n_invlog2, tag="invlog2") unround_k = Multiplication(x, invlog2, tag="unround_k") k = Floor(unround_k, precision=self.precision, tag="k") log2 = Constant(n_log2, tag="log2") whole = Multiplication(k, log2, tag="whole") r = Subtraction(x, whole, tag="r") else: r = x approx_interval = sollya.Interval(-2**-10, n_log2 + 2**-10) approx_func = sollya.exp(sollya.x) builder = Polynomial.build_from_approximation sollya.settings.prec = 2**10 poly_object = builder(approx_func, self.poly_degree, [self.precision] * (self.poly_degree + 1), approx_interval, sollya.relative) self.poly_object = poly_object schemer = PolynomialSchemeEvaluator.generate_horner_scheme poly = schemer(poly_object, r) if not self.skip_reduction: ik = Conversion(k, precision=ML_Binary32.get_integer_format(), tag="ik") twok = ExponentInsertion(ik, precision=self.precision, tag="twok") retval = Multiplication(poly, twok, tag="retval") else: retval = poly scheme = Return(retval) return scheme
def split_domain(starting_domain, slivers): in_domains = [starting_domain] # abs out_domains = list() for I in in_domains: if sollya.inf(I) < 0 and sollya.sup(I) > 0: out_domains.append(sollya.Interval(sollya.inf(I), 0)) out_domains.append(sollya.Interval(0, sollya.sup(I))) else: out_domains.append(I) in_domains = out_domains # k out_domains = list() while len(in_domains) > 0: I = in_domains.pop() #print("in: [{}, {}]".format(float(sollya.inf(I)), float(sollya.sup(I)))) unround_mult = I * n_invpi mult_low = sollya.floor(sollya.inf(unround_mult)) mult_high = sollya.floor(sollya.sup(unround_mult)) if mult_low == mult_high or (mult_low == -1 and mult_high == 0): #print(" accepted") out_domains.append(I) continue if sollya.sup(I) <= 0: divider_low = (mult_low + 1) * n_pi divider_high = divider_low - divider_low * 2**-53 else: divider_high = (mult_low + 1) * n_pi divider_low = divider_high - divider_high * 2**-53 lower_part = sollya.Interval(sollya.inf(I), divider_low) upper_part = sollya.Interval(divider_high, sollya.sup(I)) #print(" -> [{}, {}]".format(float(sollya.inf(lower_part)), float(sollya.sup(lower_part)))) #print(" -> [{}, {}]".format(float(sollya.inf(upper_part)), float(sollya.sup(upper_part)))) in_domains.append(lower_part) in_domains.append(upper_part) in_domains = out_domains # subdivide each section into 2**subd sections for _ in range(slivers): out_domains = list() for I in in_domains: mid = sollya.mid(I) out_domains.append(sollya.Interval(sollya.inf(I), mid)) out_domains.append(sollya.Interval(mid, sollya.sup(I))) in_domains = out_domains in_domains = set(in_domains) in_domains = sorted(in_domains, key=lambda x: float(sollya.inf(x))) in_domains = [ d for d in in_domains if sollya.inf(d) != sollya.sup(d) ] return in_domains
def split_domain(starting_domain, slivers): in_domains = [starting_domain] out_domains = list() while len(in_domains) > 0: I = in_domains.pop() unround_e = sollya.log2(I) e_low = sollya.floor(sollya.inf(unround_e)) e_high = sollya.floor(sollya.sup(unround_e)) #print("in: [{}, {}] ({}, {})".format(float(sollya.inf(I)), float(sollya.sup(I)), int(e_low), int(e_high))) if e_low == e_high: #print(" accepted") out_domains.append(I) continue e_range = sollya.Interval(e_low, e_low+1) I_range = 2**e_range for _ in range(100): mid = sollya.mid(I_range) e = sollya.floor(sollya.log2(mid)) if e == e_low: I_range = sollya.Interval(mid, sollya.sup(I_range)) else: I_range = sollya.Interval(sollya.inf(I_range), mid) divider_high = sollya.sup(I_range) divider_low = sollya.inf(I_range) lower_part = sollya.Interval(sollya.inf(I), divider_low) upper_part = sollya.Interval(divider_high, sollya.sup(I)) #print(" -> [{}, {}]".format(float(sollya.inf(lower_part)), float(sollya.sup(lower_part)))) #print(" -> [{}, {}]".format(float(sollya.inf(upper_part)), float(sollya.sup(upper_part)))) in_domains.append(upper_part) in_domains.append(lower_part) in_domains = out_domains # subdivide each section into 2**subd sections for _ in range(slivers): out_domains = list() for I in in_domains: mid = sollya.mid(I) out_domains.append(sollya.Interval(sollya.inf(I), mid)) out_domains.append(sollya.Interval(mid, sollya.sup(I))) in_domains = out_domains in_domains = set(in_domains) in_domains = sorted(in_domains, key=lambda x:float(sollya.inf(x))) in_domains = [d for d in in_domains if sollya.inf(d) != sollya.sup(d)] return in_domains
def generate_scheme(self): x = self.implementation.add_input_variable("x", self.precision) if not self.skip_reduction: x_exp_int = ExponentExtraction(x, tag="x_exp_int") x_exp = Conversion(x_exp_int, precision=self.precision, tag="x_exp") x_man = MantissaExtraction(x, tag="x_man") r = Multiplication(x_man, 0.5, tag="r") else: r = x approx_interval = sollya.Interval(0.5-2**-10, 1+2**-10) approx_func = sollya.log(sollya.x) builder = Polynomial.build_from_approximation sollya.settings.prec = 2**10 poly_object = builder(approx_func, self.poly_degree, [self.precision]*(self.poly_degree+1), approx_interval, sollya.relative) self.poly_object = poly_object schemer = PolynomialSchemeEvaluator.generate_horner_scheme poly = schemer(poly_object, r, unified_precision=self.precision) if not self.skip_reduction: n_log2 = self.precision.round_sollya_object(sollya.log(2), sollya.RN) log2 = Constant(n_log2, tag="log2") x_mul = Addition(x_exp, 1, tag="x_mul") offset = Multiplication(x_mul, log2, tag="offset") retval = Addition(offset, poly, tag="retval") else: retval = poly scheme = Return(retval) return scheme
def generate_scheme(self): x = self.implementation.add_input_variable("x", self.precision) n_hpi = self.precision.round_sollya_object(sollya.pi / 2, sollya.RN) if not self.skip_reduction: abs_x = Abs(x, tag="abs_x") n_invhpi = self.precision.round_sollya_object( 2 / sollya.pi, sollya.RN) invhpi = Constant(n_invhpi, tag="invhpi") unround_k = Multiplication(abs_x, invhpi, tag="unround_k") k = Floor(unround_k, precision=self.precision, tag="k") hpi = Constant(n_hpi, tag="hpi") whole = Multiplication(k, hpi, tag="whole") r = Subtraction(abs_x, whole, tag="r") ik = Conversion(k, precision=ML_Binary32.get_integer_format(), tag="ik") part = Modulo(ik, 4, precision=ML_Binary32.get_integer_format(), tag="part") pre_part = Modulo(part, 2, precision=ML_Binary32.get_integer_format(), tag="pre_part") flip = Subtraction(hpi, r, tag="flip") do_flip = Equal(pre_part, 0, tag="do_flip") z = Select(do_flip, r, flip) else: z = x approx_interval = sollya.Interval(-2**-10, n_hpi + 2**-10) approx_func = sollya.cos(sollya.x) builder = Polynomial.build_from_approximation sollya.settings.prec = 2**10 poly_object = builder(approx_func, range(0, self.poly_degree + 1, 2), [self.precision] * (self.poly_degree + 1), approx_interval, sollya.relative) self.poly_object = poly_object schemer = PolynomialSchemeEvaluator.generate_horner_scheme poly = schemer(poly_object, z) self.poly = poly if not self.skip_reduction: post_bool = LogicalOr(Equal(part, 1, tag="part_eq_1"), Equal(part, 2, tag="part_eq_2")) flipped_poly = Select(post_bool, -poly, poly) retval = flipped_poly else: retval = poly scheme = Return(retval, precision=self.precision) return scheme
def generate_scheme(self): x = self.implementation.add_input_variable("x", self.precision) n_pi = self.precision.round_sollya_object(sollya.pi, sollya.RN) if not self.skip_reduction: abs_x = Abs(x, tag="abs_x") n_one = self.precision.round_sollya_object(1, sollya.RN) one = Constant(n_one, precision=self.precision, tag="one") sign_x = CopySign(one, x, tag="sign_x") n_invpi = self.precision.round_sollya_object( 1 / sollya.pi, sollya.RN) invpi = Constant(n_invpi, tag="invpi") unround_k = Multiplication(abs_x, invpi, tag="unround_k") k = Floor(unround_k, precision=self.precision, tag="k") pi = Constant(n_pi, tag="pi") whole = Multiplication(k, pi, tag="whole") r = Subtraction(abs_x, whole, tag="r") ik = Conversion(k, precision=ML_Binary32.get_integer_format(), tag="ik") part = Modulo(ik, 2, precision=ML_Binary32.get_integer_format(), tag="part") z = r else: z = x approx_interval = sollya.Interval(-2**-7, n_pi + 2**-7) approx_func = sollya.sin(sollya.x) builder = Polynomial.build_from_approximation poly_object = builder(approx_func, range(1, self.poly_degree + 1, 2), [self.precision] * (self.poly_degree + 1), approx_interval, sollya.relative) self.poly_object = poly_object schemer = PolynomialSchemeEvaluator.generate_horner_scheme poly = schemer(poly_object, z) self.poly = poly if not self.skip_reduction: post_bool = Equal(part, 1, tag="part_eq_1") flipped_poly = Select(post_bool, -poly, poly) retval = flipped_poly * sign_x else: retval = poly scheme = Return(retval, precision=self.precision) return scheme
def determine_error(self): sollya.settings.display = sollya.hexadecimal n_pi = self.precision.round_sollya_object(sollya.pi, sollya.RN) n_invpi = self.precision.round_sollya_object(1 / sollya.pi, sollya.RN) poly_expr = str(sollya.horner(self.poly_object.get_sollya_object())) poly_expr = poly_expr.replace("_x_", "z") poly_expr = poly_expr.replace("z^0x1p1", "z*z") config = fptaylor.CHECK_CONFIG.copy() del config["--abs-error"] config["--opt"] = "bb-eval" config["--rel-error-threshold"] = "0.0" config["--intermediate-opt"] = "false" config["--uncertainty"] = "false" def generate_fptaylor(x): x_low = sollya.inf(x) x_high = sollya.sup(x) query = "\n".join([ "Variables", " real z in [{},{}];".format(x_low, x_high), "Definitions", " retval rnd64= {};".format(poly_expr), "Expressions", " retval;" ]) rnd_rel_err = None rnd_abs_err = None try: res = fptaylor.Result(query, { **config, "--rel-error": "true", "--abs-error": "true" }) rnd_rel_err = float( res.result["relative_errors"]["final_total"]["value"]) rnd_abs_err = float( res.result["absolute_errors"]["final_total"]["value"]) except AssertionError: pass except KeyError: try: rnd_abs_err = float( res.result["absolute_errors"]["final_total"]["value"]) except KeyError: pass if rnd_abs_err is None: try: res = fptaylor.Result(query, { **config, "--rel-error": "false", "--abs-error": "true" }) rnd_abs_err = float( res.result["absolute_errors"]["final_total"]["value"]) except AssertionError: pass err_int = sollya.supnorm(self.poly_object.get_sollya_object(), sollya.sin(sollya.x), x, sollya.relative, 2**-100) algo_rel_err = sollya.sup(err_int) err_int = sollya.supnorm(self.poly_object.get_sollya_object(), sollya.sin(sollya.x), x, sollya.absolute, 2**-100) algo_abs_err = sollya.sup(err_int) if rnd_rel_err is None or str(algo_rel_err) == "error": rel_err = float("inf") else: rel_err = rnd_rel_err + algo_rel_err abs_err = rnd_abs_err + algo_abs_err return rel_err, abs_err def generate_reduction_fptaylor(x): # get sign and abs_x, must be the same at endpoints if sollya.sup(x) <= 0: sign_x_expr = "-1.0" abs_x_expr = "-x" abs_x = -x elif sollya.inf(x) >= 0: sign_x_expr = "1.0" abs_x_expr = "x" abs_x = x else: assert False, "Interval must not straddle 0" # get k, must be the same at endpoints unround_k = abs_x * n_invpi k_low = sollya.floor(sollya.inf(unround_k)) k_high = sollya.floor(sollya.sup(unround_k)) if k_low != k_high: assert False, "Interval must not straddle multples of pi" k = int(k_low) part = k % 2 r_expr = "abs_x - whole" r = abs_x - k * n_pi z_expr = "r" z = r if part == 1: flipped_poly_expr = "-poly" else: flipped_poly_expr = "poly" x_low = sollya.inf(x) x_high = sollya.sup(x) query = "\n".join([ "Variables", " real x in [{},{}];".format(x_low, x_high), "Definitions", " abs_x rnd64= {};".format(abs_x_expr), " whole rnd64= {} * {};".format(k, n_pi), " r rnd64= abs_x - whole;", " z rnd64= {};".format(z_expr), " poly rnd64= {};".format(poly_expr), " flipped_poly rnd64= {};".format(flipped_poly_expr), " retval rnd64= flipped_poly*{};".format(sign_x_expr), "Expressions", " retval;" ]) rnd_rel_err = None rnd_abs_err = None try: res = fptaylor.Result(query, { **config, "--rel-error": "true", "--abs-error": "true" }) rnd_rel_err = float( res.result["relative_errors"]["final_total"]["value"]) rnd_abs_err = float( res.result["absolute_errors"]["final_total"]["value"]) except AssertionError: pass except KeyError: try: rnd_abs_err = float( res.result["absolute_errors"]["final_total"]["value"]) except KeyError: pass if rnd_abs_err is None: try: res = fptaylor.Result(query, { **config, "--rel-error": "false", "--abs-error": "true" }) rnd_abs_err = float( res.result["absolute_errors"]["final_total"]["value"]) except AssertionError: pass err_int = sollya.supnorm(self.poly_object.get_sollya_object(), sollya.sin(sollya.x), z, sollya.relative, 2**-100) algo_rel_err = sollya.sup(err_int) err_int = sollya.supnorm(self.poly_object.get_sollya_object(), sollya.sin(sollya.x), z, sollya.absolute, 2**-100) algo_abs_err = sollya.sup(err_int) if rnd_rel_err is None or str(algo_rel_err) == "error": rel_err = float("inf") else: rel_err = rnd_rel_err + algo_rel_err abs_err = rnd_abs_err + algo_abs_err return rel_err, abs_err def split_domain(starting_domain, slivers): in_domains = [starting_domain] # abs out_domains = list() for I in in_domains: if sollya.inf(I) < 0 and sollya.sup(I) > 0: out_domains.append(sollya.Interval(sollya.inf(I), 0)) out_domains.append(sollya.Interval(0, sollya.sup(I))) else: out_domains.append(I) in_domains = out_domains # k out_domains = list() while len(in_domains) > 0: I = in_domains.pop() #print("in: [{}, {}]".format(float(sollya.inf(I)), float(sollya.sup(I)))) unround_mult = I * n_invpi mult_low = sollya.floor(sollya.inf(unround_mult)) mult_high = sollya.floor(sollya.sup(unround_mult)) if mult_low == mult_high or (mult_low == -1 and mult_high == 0): #print(" accepted") out_domains.append(I) continue if sollya.sup(I) <= 0: divider_low = (mult_low + 1) * n_pi divider_high = divider_low - divider_low * 2**-53 else: divider_high = (mult_low + 1) * n_pi divider_low = divider_high - divider_high * 2**-53 lower_part = sollya.Interval(sollya.inf(I), divider_low) upper_part = sollya.Interval(divider_high, sollya.sup(I)) #print(" -> [{}, {}]".format(float(sollya.inf(lower_part)), float(sollya.sup(lower_part)))) #print(" -> [{}, {}]".format(float(sollya.inf(upper_part)), float(sollya.sup(upper_part)))) in_domains.append(lower_part) in_domains.append(upper_part) in_domains = out_domains # subdivide each section into 2**subd sections for _ in range(slivers): out_domains = list() for I in in_domains: mid = sollya.mid(I) out_domains.append(sollya.Interval(sollya.inf(I), mid)) out_domains.append(sollya.Interval(mid, sollya.sup(I))) in_domains = out_domains in_domains = set(in_domains) in_domains = sorted(in_domains, key=lambda x: float(sollya.inf(x))) in_domains = [ d for d in in_domains if sollya.inf(d) != sollya.sup(d) ] return in_domains if self.skip_reduction: starting_domain = sollya.Interval(-n_pi - 2**-7, n_pi + 2**-7) else: reduction_k = 20 starting_domain = sollya.Interval(-reduction_k * n_pi, reduction_k * n_pi) # analyse each piece in_domains = split_domain(starting_domain, self.slivers) errors = list() for I in in_domains: if self.skip_reduction: rel_err, abs_err = generate_fptaylor(I) else: rel_err, abs_err = generate_reduction_fptaylor(I) print("{}\t{}\t{}\t{}".format(float(sollya.inf(I)), float(sollya.sup(I)), float(abs_err), float(rel_err))) errors.append((I, abs_err, rel_err)) def generate_json(errors, domain): errors = [err for err in errors if err[0] in domain] errors.sort(key=lambda err: err[2]) epsilon = errors[0][2] delta = max(err[1] for err in errors) d = { "cname": self.function_name, "delta": float(delta), "domain": [ float(sollya.inf(domain)), float(sollya.sup(domain)), ], "epsilon": float(epsilon), "operation": "sin" } return d if self.skip_reduction: d = generate_json(errors, sollya.Interval(-n_pi - 2**-7, n_pi + 2**-7)) json_str = json.dumps(d, sort_keys=True, indent=4) json_str = "spec: " + json_str.replace("\n", "\nspec: ") print(json_str) else: specs = list() for k in range(1, reduction_k): d = generate_json(errors, sollya.Interval(-k * n_pi, k * n_pi)) specs.append(d) for i in range(len(specs)): d = specs[i] if i == len(specs) - 1: json_str = json.dumps(d, sort_keys=True, indent=4) json_str = "spec: " + json_str.replace("\n", "\nspec: ") print(json_str) break nd = specs[i + 1] if d["epsilon"] == nd["epsilon"] and d["delta"] == nd["delta"]: continue json_str = json.dumps(d, sort_keys=True, indent=4) json_str = "spec: " + json_str.replace("\n", "\nspec: ") print(json_str)
def get_exponent_interval(self): low_bound = self.get_emin_normal() high_bound = self.get_emax() return sollya.Interval(low_bound, high_bound)
def determine_error(self): sollya.settings.display = sollya.hexadecimal n_log2 = self.precision.round_sollya_object(sollya.log(2), sollya.RN) poly_expr = str(sollya.horner(self.poly_object.get_sollya_object())) poly_expr = poly_expr.replace("_x_", "z") poly_expr = poly_expr.replace("z^0x1p1", "z*z") config = fptaylor.CHECK_CONFIG.copy() del config["--abs-error"] config["--opt"] = "gelpia" config["--rel-error-threshold"] = "0.0" config["--intermediate-opt"] = "false" config["--uncertainty"] = "false" config["--opt-timeout"] = 100000 # log is returning inf config["--opt-f-rel-tol"] = "1e0" config["--opt-f-abs-tol"] = "0.0" config["--opt-x-rel-tol"] = "0.0" config["--opt-x-abs-tol"] = "0.0" def generate_fptaylor(x): x_low = sollya.inf(x) x_high = sollya.sup(x) query = "\n".join( ["Variables", " real z in [{},{}];".format(x_low, x_high), "Definitions", " retval rnd64= {};".format(poly_expr), "Expressions", " retval;"]) rnd_rel_err = None rnd_abs_err = None try: res = fptaylor.Result(query, {**config, "--rel-error": "true", "--abs-error": "true"}) rnd_rel_err = float(res.result["relative_errors"]["final_total"]["value"]) rnd_abs_err = float(res.result["absolute_errors"]["final_total"]["value"]) except AssertionError: pass except KeyError: try: rnd_abs_err = float(res.result["absolute_errors"]["final_total"]["value"]) except KeyError: pass if rnd_abs_err is None: try: res = fptaylor.Result(query, {**config, "--rel-error": "false", "--abs-error": "true"}) rnd_abs_err = float(res.result["absolute_errors"]["final_total"]["value"]) except AssertionError: pass err_int = sollya.supnorm(self.poly_object.get_sollya_object(), sollya.log(sollya.x), x, sollya.relative, 2**-100) algo_rel_err = sollya.sup(err_int) err_int = sollya.supnorm(self.poly_object.get_sollya_object(), sollya.log(sollya.x), x, sollya.absolute, 2**-100) algo_abs_err = sollya.sup(err_int) if rnd_rel_err is None or str(algo_rel_err) == "error": rel_err = float("inf") else: rel_err = rnd_rel_err + algo_rel_err abs_err = rnd_abs_err + algo_abs_err return rel_err, abs_err def generate_reduction_fptaylor(x): unround_e = sollya.log2(I) e_low = sollya.floor(sollya.inf(unround_e)) e_high = sollya.floor(sollya.sup(unround_e)) if e_low != e_high: assert False, "Interval must not stradle a binade" e = int(e_low) + 1 z = x / (2**e) * 0.5 query = "\n".join( ["Variables", " real z in [{},{}];".format(sollya.inf(z), sollya.sup(z)), "Definitions", " poly rnd64= {};".format(poly_expr), " retval rnd64= {}*{} + poly;".format(e, n_log2), "Expressions", " retval;"]) rnd_rel_err = None rnd_abs_err = None try: res = fptaylor.Result(query, {**config, "--rel-error": "true", "--abs-error": "true"}) rnd_rel_err = float(res.result["relative_errors"]["final_total"]["value"]) rnd_abs_err = float(res.result["absolute_errors"]["final_total"]["value"]) except AssertionError: pass except KeyError: try: rnd_abs_err = float(res.result["absolute_errors"]["final_total"]["value"]) except KeyError: pass if rnd_abs_err is None: try: res = fptaylor.Result(query, {**config, "--rel-error": "false", "--abs-error": "true"}) rnd_abs_err = float(res.result["absolute_errors"]["final_total"]["value"]) except AssertionError: pass err_int = sollya.supnorm(self.poly_object.get_sollya_object(), sollya.log(sollya.x), z, sollya.relative, 2**-100) algo_rel_err = sollya.sup(err_int) err_int = sollya.supnorm(self.poly_object.get_sollya_object(), sollya.log(sollya.x), z, sollya.absolute, 2**-100) algo_abs_err = sollya.sup(err_int) if rnd_rel_err is None or str(algo_rel_err) == "error": rel_err = float("inf") else: rel_err = rnd_rel_err + algo_rel_err abs_err = rnd_abs_err + algo_abs_err return rel_err, abs_err def split_domain(starting_domain, slivers): in_domains = [starting_domain] out_domains = list() while len(in_domains) > 0: I = in_domains.pop() unround_e = sollya.log2(I) e_low = sollya.floor(sollya.inf(unround_e)) e_high = sollya.floor(sollya.sup(unround_e)) #print("in: [{}, {}] ({}, {})".format(float(sollya.inf(I)), float(sollya.sup(I)), int(e_low), int(e_high))) if e_low == e_high: #print(" accepted") out_domains.append(I) continue e_range = sollya.Interval(e_low, e_low+1) I_range = 2**e_range for _ in range(100): mid = sollya.mid(I_range) e = sollya.floor(sollya.log2(mid)) if e == e_low: I_range = sollya.Interval(mid, sollya.sup(I_range)) else: I_range = sollya.Interval(sollya.inf(I_range), mid) divider_high = sollya.sup(I_range) divider_low = sollya.inf(I_range) lower_part = sollya.Interval(sollya.inf(I), divider_low) upper_part = sollya.Interval(divider_high, sollya.sup(I)) #print(" -> [{}, {}]".format(float(sollya.inf(lower_part)), float(sollya.sup(lower_part)))) #print(" -> [{}, {}]".format(float(sollya.inf(upper_part)), float(sollya.sup(upper_part)))) in_domains.append(upper_part) in_domains.append(lower_part) in_domains = out_domains # subdivide each section into 2**subd sections for _ in range(slivers): out_domains = list() for I in in_domains: mid = sollya.mid(I) out_domains.append(sollya.Interval(sollya.inf(I), mid)) out_domains.append(sollya.Interval(mid, sollya.sup(I))) in_domains = out_domains in_domains = set(in_domains) in_domains = sorted(in_domains, key=lambda x:float(sollya.inf(x))) in_domains = [d for d in in_domains if sollya.inf(d) != sollya.sup(d)] return in_domains if self.skip_reduction: starting_domain = sollya.Interval(0.5, 1.0) else: reduction_e = 12 starting_domain = sollya.Interval(2**(-reduction_e), 2**reduction_e) # analyse each piece in_domains = split_domain(starting_domain, self.slivers) errors = list() for I in in_domains: if self.skip_reduction: rel_err, abs_err = generate_fptaylor(I) else: rel_err, abs_err = generate_reduction_fptaylor(I) print("{}\t{}\t{}\t{}".format(float(sollya.inf(I)), float(sollya.sup(I)), float(abs_err), float(rel_err))) errors.append((I, abs_err, rel_err)) def generate_json(errors, domain): errors = [err for err in errors if err[0] in domain] errors.sort(key=lambda err: err[2]) epsilon = errors[0][2] delta = max(err[1] for err in errors) d = { "cname": self.function_name, "delta": float(delta), "domain": [float(sollya.inf(domain)), float(sollya.sup(domain)),], "epsilon": float(epsilon), "operation": "log" } return d if self.skip_reduction: d = generate_json(errors, sollya.Interval(0.5, 1.0)) json_str = json.dumps(d, sort_keys=True, indent=4) json_str = "spec: " + json_str.replace("\n", "\nspec: ") print(json_str) else: specs = list() for e in range(1, reduction_e): d = generate_json(errors, sollya.Interval(2**(-e), 2**e)) specs.append(d) for i in range(len(specs)): d = specs[i] if i == len(specs)-1: json_str = json.dumps(d, sort_keys=True, indent=4) json_str = "spec: " + json_str.replace("\n", "\nspec: ") print(json_str) break nd = specs[i+1] if d["epsilon"] == nd["epsilon"] and d["delta"] == nd["delta"]: continue json_str = json.dumps(d, sort_keys=True, indent=4) json_str = "spec: " + json_str.replace("\n", "\nspec: ") print(json_str)
def function(self, fct_expr="exp(x)", io_format="binary32", vector_size=1, target="generic", registered_pass_list="", sub_vector_size="default", debug=False, language="c", range_nan="false", range_lo="-infty", range_hi="+infty", bench="false", eval_error="false"): total_time = None input_url = ("{localhost}/function?fct_expr={fct_expr}&io_format={io_format}&" +\ "vector_size={vector_size}&target={target}&" +\ "registered_pass_list={registered_pass_list}&" + \ "debug={debug}&language={language}&eval_error={eval_error}").format( localhost=self.mwa.LOCALHOST, fct_expr=fct_expr, io_format=io_format, vector_size=vector_size, target=target, registered_pass_list=registered_pass_list, sub_vector_size=sub_vector_size, debug=debug, language=language, eval_error=eval_error) # generate git commentary (indicating which version of metalibm was # used to generate code) ml_code_configuration.GLOBAL_GET_GIT_COMMENT = custom_get_common_git_comment( self.mwa.LOCALHOST, lambda: input_url) registered_pass_list = [ tag for tag in registered_pass_list.split(",") if tag != "" ] error = None source_code = "" build_cmd = "" report_issue_url = "" # function results max_error = None # checking inputs class KnownError(Exception): """ known error exception which can are raised when a manageable error is detected """ pass try: no_error = False if not ml_function_expr.check_fct_expr(fct_expr): source_code = "invalid function expression \"{}\"".format( fct_expr) elif not all((pass_tag in self.mwa.ALLOWED_PASS_LIST) for pass_tag in registered_pass_list): source_code = "unknown pass in {}".format([ pass_tag for pass_tag in registered_pass_list if not pass_tag in self.mwa.ALLOWED_PASS_LIST ]) print(source_code) # no allowed target list for now elif not io_format in self.mwa.format_list: source_code = ("forbidden format {}".format(io_format)) print(source_code) elif not int(vector_size) in self.mwa.vector_size_list: source_code = ("forbidden vector_size {}".format(vector_size)) print(source_code) elif sub_vector_size != "default" and not int( sub_vector_size) in self.mwa.sub_vector_size_list: source_code = ( "forbidden sub_vector_size {}".format(sub_vector_size)) print(source_code) elif not language in self.mwa.LANGUAGE_MAP: source_code = ("forbidden language {}".format(language)) print(source_code) elif not range_nan.lower() in ["true", "false"]: source_code = ("invalid range NaN flag {}".format(range_nan)) print(source_code) elif not bench.lower() in ["true", "false"]: source_code = ("invalid bench flag {}".format(bench)) print(source_code) elif not eval_error.lower() in ["true", "false"]: source_code = ("invalid eval_error flag {}".format(bench)) print(source_code) else: no_error = True if not no_error: raise KnownError(source_code) except KnownError as e: # stat counter self.stats.num_known_errors += 1 error = e self.log_msg(e, tag="error") except: # stat counter self.stats.num_unknwon_errors += 1 e = sys.exc_info() error = "Exception:\n {}".format("".join( traceback.format_exception(*e))).replace('\n', '<br/>') source_code = "" self.log_msg(error, tag="error") else: # clearing logs ml_log_report.Log.log_stream.log_output = "" try: start_time = time.perf_counter() fct_ctor = ml_function_expr.FunctionExpression arity = ml_function_expr.count_expr_arity(fct_expr) fct_extra_args = {} language_object = self.mwa.LANGUAGE_MAP[language] precision = precision_parser(io_format) vector_size = int(vector_size) sub_vector_size = None if sub_vector_size == "default" else int( sub_vector_size) range_nan = range_nan.lower() in ["true"] eval_error = eval_error.lower() in ["true"] bench = bench.lower() in ["true"] if range_nan: input_interval = None else: input_interval = sollya.Interval(sollya.parse(range_lo), sollya.parse(range_hi)) debug = bool(debug) target_class = target_parser(target) target_inst = target_class() passes = [ "beforecodegen:{}".format(pass_tag) for pass_tag in registered_pass_list if pass_tag in self.mwa.ALLOWED_PASS_LIST ] args = fct_ctor.get_default_args( function_expr_str=[fct_expr], precision=precision, input_precisions=(precision, ) * arity, input_intervals=(input_interval, ) * arity, vector_size=vector_size, sub_vector_size=sub_vector_size, passes=passes, language=language_object, debug=debug, bench_test_number=100 if bench else None, compute_max_error=eval_error, execute_trigger=eval_error, bench_test_range=input_interval, target=target_inst, **fct_extra_args) # function instance object fct_instance = fct_ctor(args=args) # principal scheme function_only_group = fct_instance.generate_function_list() function_only_group = fct_instance.transform_function_group( function_only_group) function_only_code_obj = fct_instance.get_new_main_code_object( ) function_only_code_obj = fct_instance.generate_code( function_only_code_obj, function_only_group, language=fct_instance.language) # actual source code source_code = function_only_code_obj.get( fct_instance.main_code_generator) with open("source_code.dump.c", "w") as output_stream: output_stream.write(source_code) if eval_error: fct_instance.main_code_generator.clear_memoization_map() main_pre_statement, main_statement, function_group = fct_instance.instrument_function_group( function_only_group, enable_subexpr_sharing=True) EMBEDDING_BINARY = True fct_instance.main_code_object = fct_instance.get_new_main_code_object( ) bench_source_code_obj = fct_instance.generate_output( EMBEDDING_BINARY, main_pre_statement, main_statement, function_group) execute_result = fct_instance.build_and_execute_source_code( function_group, bench_source_code_obj) max_error = execute_result["max_error"] # constructing build command build_cmd = SourceFile.get_build_command("<source_path>", target_inst, bin_name="ml_bench", shared_object=False, link=True, expand_env_var=False) total_time = time.perf_counter() - start_time except: self.stats.num_gen_errors += 1 e = sys.exc_info() error = "Output: \n{}\nException:\n {}".format( ml_log_report.Log.log_stream.log_output, "".join(traceback.format_exception(*e))).replace( '\n', '<br/>') source_code = "" self.log_msg(error, tag="error") report_issue_url = gen_report_issue_url( MetalibmWebApp.REPORT_ISSUE_BASE_URL, precision=io_format, fct_expr=fct_expr, target=target, vector_size=vector_size, debug=debug, language=language, sub_vector_size=sub_vector_size, registered_pass_list=registered_pass_list, ) else: self.stats.num_generated_function += 1 self.log_msg(input_url, tag="info") return dict(code=source_code, build_cmd=build_cmd, precision=io_format, fct_expr=fct_expr, target=target, vector_size=vector_size, debug=debug, language=language, sub_vector_size=sub_vector_size, registered_pass_list=registered_pass_list, report_issue_url=report_issue_url, error=error, range_lo=range_lo, range_hi=range_hi, range_nan=range_nan, total_time=total_time, max_error=max_error, eval_error=eval_error, **self.mwa.option_dict)
def generate_scheme(self): x = self.implementation.add_input_variable("x", self.precision) n_pi = self.precision.round_sollya_object(sollya.pi, sollya.RN) if not self.skip_reduction: abs_x = Abs(x, tag="abs_x") n_invpi = self.precision.round_sollya_object( 1 / sollya.pi, sollya.RN) invpi = Constant(n_invpi, tag="invpi") unround_k = Multiplication(abs_x, invpi, tag="unround_k") k = Floor(unround_k, precision=self.precision, tag="k") pi = Constant(n_pi, tag="pi") whole = Multiplication(k, pi, tag="whole") r = Subtraction(abs_x, whole, tag="r") ik = Conversion(k, precision=ML_Binary32.get_integer_format(), tag="ik") part = Modulo(ik, 2, precision=ML_Binary32.get_integer_format(), tag="part") z = r else: z = x approx_interval = sollya.Interval(-2**-7, n_pi + 2**-7) approx_func = sollya.cos(sollya.x) builder = Polynomial.build_from_approximation for p in range(10, 20): try: sollya.settings.prec = 2**p poly_object = builder(approx_func, range(0, self.poly_degree + 1, 2), [self.precision] * (self.poly_degree + 1), approx_interval, sollya.relative) except SollyaError: continue if str(poly_object.get_sollya_object()) == "0": continue break self.poly_object = poly_object schemer = PolynomialSchemeEvaluator.generate_horner_scheme poly = schemer(poly_object, z) print("LSKDFKLJK", poly_object.get_sollya_object()) self.poly = poly if not self.skip_reduction: post_bool = Equal(part, 1, tag="part_eq_1") flipped_poly = Select(post_bool, -poly, poly) retval = flipped_poly else: retval = poly scheme = Return(retval, precision=self.precision) return scheme
def generate_scheme(self): x = self.implementation.add_input_variable("x", self.precision) n_qpi = self.precision.round_sollya_object(sollya.pi / 4, sollya.RN) if not self.skip_reduction: abs_x = Abs(x, precision=self.precision, tag="abs_x") n_one = self.precision.round_sollya_object(1, sollya.RN) one = Constant(n_one, precision=self.precision, tag="one") sign_x = CopySign(one, x, precision=self.precision, tag="sign_x") n_invqpi = self.precision.round_sollya_object( 4 / sollya.pi, sollya.RN) invqpi = Constant(n_invqpi, tag="invqpi") unround_k = Multiplication(abs_x, invqpi, tag="unround_k") k = Floor(unround_k, precision=self.precision, tag="k") qpi = Constant(n_qpi, tag="qpi") whole = Multiplication(k, qpi, tag="whole") r = Subtraction(abs_x, whole, tag="r") ik = Conversion(k, precision=ML_Binary32.get_integer_format(), tag="ik") part = Modulo(ik, 4, precision=ML_Binary32.get_integer_format(), tag="part") eq_1 = Equal(part, 1) eq_2 = Equal(part, 2) eq_3 = Equal(part, 3) r_1 = Select(eq_1, qpi - r, r) r_2 = Select(eq_2, -r, r_1) r_3 = Select(eq_3, r - qpi, r_2) else: r_3 = x approx_interval = sollya.Interval(-2**-10, n_qpi + 2**-10) approx_func = sollya.tan(sollya.x) builder = Polynomial.build_from_approximation sollya.settings.prec = 2**10 poly_object = builder(approx_func, range(1, self.poly_degree + 1, 2), [self.precision] * (self.poly_degree + 1), approx_interval, sollya.relative) self.poly_object = poly_object schemer = PolynomialSchemeEvaluator.generate_horner_scheme poly = schemer(poly_object, r_3) if not self.skip_reduction: post_bool = LogicalOr(eq_1, eq_2) inv_poly = Select(post_bool, 1 / poly, poly) retval = Multiplication(inv_poly, sign_x, tag="retval") else: retval = poly scheme = Return(retval, precision=self.precision) return scheme
def split_domain(starting_domain, slivers): in_domains = [starting_domain] # abs out_domains = list() for I in in_domains: if sollya.inf(I) < 0 and sollya.sup(I) > 0: out_domains.append(sollya.Interval(sollya.inf(I), 0)) out_domains.append(sollya.Interval(0, sollya.sup(I))) else: out_domains.append(I) in_domains = out_domains # k out_domains = list() while len(in_domains) > 0: I = in_domains.pop() unround_mult = I * n_invlog2 mult_low = sollya.floor(sollya.inf(unround_mult)) mult_high = sollya.floor(sollya.sup(unround_mult)) #print("in: [{}, {}] ({}, {})".format(float(sollya.inf(I)), float(sollya.sup(I)), int(mult_low), int(mult_high))) if mult_low == mult_high or (mult_low == -1 and mult_high == 0): #print(" accepted") out_domains.append(I) continue k_range = sollya.Interval(mult_low, mult_low + 1.5) I_range = k_range * n_log2 for _ in range(100): mid = sollya.mid(I_range) k = sollya.floor(mid * n_invlog2) if k == mult_low: I_range = sollya.Interval(mid, sollya.sup(I_range)) else: I_range = sollya.Interval(sollya.inf(I_range), mid) divider_high = sollya.sup(I_range) divider_low = sollya.inf(I_range) lower_part = sollya.Interval(sollya.inf(I), divider_low) upper_part = sollya.Interval(divider_high, sollya.sup(I)) #print(" -> [{}, {}]".format(float(sollya.inf(lower_part)), float(sollya.sup(lower_part)))) #print(" -> [{}, {}]".format(float(sollya.inf(upper_part)), float(sollya.sup(upper_part)))) in_domains.append(upper_part) in_domains.append(lower_part) in_domains = out_domains # subdivide each section into 2**subd sections for _ in range(slivers): out_domains = list() for I in in_domains: mid = sollya.mid(I) out_domains.append(sollya.Interval(sollya.inf(I), mid)) out_domains.append(sollya.Interval(mid, sollya.sup(I))) in_domains = out_domains in_domains = set(in_domains) in_domains = sorted(in_domains, key=lambda x: float(sollya.inf(x))) in_domains = [ d for d in in_domains if sollya.inf(d) != sollya.sup(d) ] return in_domains