def to_Sollya(self): """ Convert transfer function into two Sollya polynomials (numerator and denomitator) The result is cached in self._sollya Returns - num, den: (sollya object) numerator and denominator of the transfer function """ if not self._sollya: try: import sollya except ImportError: raise ImportError( "Sollya and SollyaPython are required (but not installed) !" ) num = sollya.horner( sum( sollya.SollyaObject(x) * sollya._x_**i for i, x in enumerate(array(self.num)[0, :]))) den = sollya.horner( sum( sollya.SollyaObject(x) * sollya._x_**i for i, x in enumerate(array(self.den)[0, :]))) self._sollya = (num, den) return self._sollya
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 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)