Ejemplo n.º 1
0
 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)
Ejemplo n.º 2
0
        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)
Ejemplo n.º 3
0
	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)}
Ejemplo n.º 4
0
 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))))
Ejemplo n.º 5
0
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))
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
        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
Ejemplo n.º 8
0
        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
Ejemplo n.º 9
0
    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
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
    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
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
 def get_exponent_interval(self):
     low_bound  = self.get_emin_normal()
     high_bound = self.get_emax()
     return sollya.Interval(low_bound, high_bound)
Ejemplo n.º 14
0
    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)
Ejemplo n.º 15
0
    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)
Ejemplo n.º 16
0
    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
Ejemplo n.º 17
0
    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
Ejemplo n.º 18
0
        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