Пример #1
0
def ToFPCore(expr, ofname="fpcore.fpcore"):
    vs = expr.vars()
    vs = [v for v in vs if (not tft_expr.isConstVar(v))]

    assert (all([(v.hasLB() and v.hasUB()) for v in vs]))

    ofile = open(ofname, "w")

    str_paras = "("
    for v in vs:
        str_paras += v.label() + " "
    str_paras = str_paras.strip()
    str_paras += ")"

    str_pre = ":pre (and"
    for v in vs:
        str_pre += " (>= " + v.label() + " " + str(float(v.lb().value())) + ")"
        str_pre += " (>= " + str(float(v.ub().value())) + " " + v.label() + ")"
    str_pre += ")"

    ofile.write("(FPCore " + str_paras + "\n")
    ofile.write("  " + str_pre + "\n")
    ofile.write("  " + expr.toFPCoreString() + ")")

    ofile.close()
Пример #2
0
def ExportCppInsts(alloc, ifname):
    assert ((type(N_CPP_REPEATS) is int) and (1 <= N_CPP_REPEATS))
    assert (isinstance(alloc, tft_alloc.Alloc))
    assert (all(
        [isinstance(expr, tft_expr.Expr) for expr in tft_ir_api.CPP_INSTS]))

    type_def_map = {}
    for gid, eps in alloc.gid2eps.items():
        assert (TypeExpr(gid) not in type_def_map.keys())

        type_def_map[TypeExpr(gid)] = Eps2CtypeString(eps)

    # -- write .cpp file --
    ifile = open(ifname, "w")

    ifile.write("#include <iostream>\n")
    ifile.write("#include <math.h>\n")
    if (Eps2CtypeString(tft_alloc.EPSILON_128) in type_def_map.values()):
        ifile.write("extern \"C\" { \n#include \"quadmath.h\"\n}\n")

    ifile.write("\n")

    ifile.write("using namespace std;\n")

    ifile.write("\n")

    for tr, tv in type_def_map.items():
        ifile.write("#define " + tr + " " + tv + "\n")

    ifile.write("\n")

    #    ifile.write("void computation () {\n")
    #
    #    for expr in tft_ir_api.CPP_INSTS:
    #        if (isinstance(expr, tft_expr.VariableExpr) and
    #            tft_expr.isConstVar(expr)):
    #            continue
    #
    #        ifile.write("\t" + Expr2CStatement(expr, alloc) + "\n")
    #
    #    ifile.write("}\n")
    #
    #    ifile.write("\n")

    ifile.write("int main (int argc, char **argv) {\n")

    ifile.write("\n\tfor(int __r = 0 ; __r < " + str(N_CPP_REPEATS) +
                " ; __r++) {\n")

    #    ifile.write("\t\tcomputation();\n")
    for expr in tft_ir_api.CPP_INSTS:
        if (isinstance(expr, tft_expr.VariableExpr)
                and tft_expr.isConstVar(expr)):
            continue

        ifile.write("\t\t" + Expr2CStatement(expr, alloc) + "\n")

    ifile.write("\t}\n")

    ifile.write("\n\treturn 0;\n}")
Пример #3
0
def ExportExpr4FPTaylorSanitation(expr, alloc, qfname):
    assert (isinstance(expr, tft_expr.Expr))
    assert (isinstance(alloc, tft_alloc.Alloc))

    vs_all = expr.vars()

    vs = [v for v in vs_all if (not tft_expr.isConstVar(v))]

    qfile = open(qfname, "w")

    # write variables
    qfile.write("Variables\n")
    for i in range(0, len(vs)):
        v = vs[i]

        qfile.write("  " + v.label() + " in [" + v.lb().toCString() + ", " +
                    v.ub().toCString() + "]")
        if (i < (len(vs) - 1)):
            qfile.write(",")
        qfile.write("\n")
    qfile.write(";\n\n")

    # write expressions
    qfile.write("Expressions\n")
    qfile.write("  __final_result = " + FPTaylorExpr(expr, alloc) + "\n")
    qfile.write(";\n\n")

    qfile.close()
Пример #4
0
    def _ColorExpr(expr, alloc):
        assert (isinstance(expr, tft_expr.Expr))
        assert (isinstance(alloc, tft_alloc.Alloc))

        if (isinstance(expr, tft_expr.ConstantExpr)):
            return color(plain, tft_alloc.EPSILON_128,
                         str(float(expr.value())))

        bw_mine = alloc[expr.getGid()]
        if (isinstance(expr, tft_expr.VariableExpr)):
            if (tft_expr.isConstVar(expr)):
                assert (expr.lb() == expr.ub())
                return color(plain, bw_mine, expr.ub().toCString())
            else:
                return color(plain, bw_mine, expr.label())

        if (isinstance(expr, tft_expr.UnaryExpr)):
            str_opd = _ColorExpr(expr.opd(), alloc)
            str_opd = color(plain, bw_mine, "(") + str_opd + color(
                plain, bw_mine, ")")
            return color(plain, bw_mine, expr.operator.label + " ") + str_opd

        if (isinstance(expr, tft_expr.BinaryExpr)):
            str_lhs = _ColorExpr(expr.lhs(), alloc)
            str_rhs = _ColorExpr(expr.rhs(), alloc)
            str_lhs = color(plain, bw_mine, "(") + str_lhs + color(
                plain, bw_mine, ")")
            str_rhs = color(plain, bw_mine, "(") + str_rhs + color(
                plain, bw_mine, ")")
            return color(plain, bw_mine,
                         expr.operator.label + " ") + str_lhs + " \n" + str_rhs

        sys.exit("Error: not supported expr 4 ColorExpr...")
Пример #5
0
def Expr2Ref(expr, alloc):
    global NEW_EREF
    global EREF_LIST

    assert (isinstance(alloc, tft_alloc.Alloc))

    if (isinstance(expr, tft_expr.ConstantExpr)):
        return expr.toCString()

    elif (isinstance(expr, tft_expr.VariableExpr)
          and tft_expr.isConstVar(expr)):
        assert (expr.lb().value() == expr.ub().value())

        vstr = str(float(expr.lb().value()))

        my_bw = alloc[expr.getGid()]

        if (my_bw == tft_alloc.EPSILON_32):
            vstr = vstr + "f"
        elif (my_bw == tft_alloc.EPSILON_64 or my_bw == tft_alloc.EPSILON_128):
            vstr = vstr
        else:
            sys.exit("Error: unsupported constant bit-width: " + str(my_bw))

        return vstr

    elif (isinstance(expr, tft_expr.VariableExpr)
          or isinstance(expr, tft_expr.UnaryExpr)
          or isinstance(expr, tft_expr.BinaryExpr)):

        for e_eref in EREF_LIST:
            assert (len(e_eref) == 2)
            e = e_eref[0]
            eref = e_eref[1]

            if (e == expr):
                return ExprRef(eref)

        eref = NEW_EREF
        NEW_EREF = NEW_EREF + 1

        EREF_LIST.append([expr, eref])

        return ExprRef(eref)
Пример #6
0
def MakeBinaryExpr(op_label, op_gid, opd0, opd1, internal=False):
    global EXTERNAL_GIDS

    if ((not internal) and (TUNE_FOR_ALL)):
        op_gid = 0

    assert (type(op_label) is str)
    assert (type(op_gid) is int)
    assert (isinstance(opd0, tft_expr.Expr))
    assert (isinstance(opd1, tft_expr.Expr))

    if (COALESCE_CONST):
        #        if (isinstance(opd0, tft_expr.ConstantExpr) and isinstance(opd1, tft_expr.ConstantExpr)):
        if (isinstance(opd0, tft_expr.ConstantExpr)
                and isinstance(opd1, tft_expr.ConstantExpr)
                and tft_expr.isPreciseConstantExpr(opd0)
                and tft_expr.isPreciseConstantExpr(opd1)):
            v0 = opd0.value()
            v1 = opd1.value()

            if (op_label == "+"):
                eret = tft_expr.ConstantExpr(v0 + v1)
                AppendCppInst(eret)
                return eret

            elif (op_label == "-"):
                eret = tft_expr.ConstantExpr(v0 - v1)
                AppendCppInst(eret)
                return eret

            elif (op_label == "*"):
                eret = tft_expr.ConstantExpr(v0 * v1)
                AppendCppInst(eret)
                return eret

            elif (op_label == "/"):
                eret = tft_expr.ConstantExpr(v0 / v1)
                AppendCppInst(eret)
                return eret

            else:
                sys.exit("ERROR: unknown Binary Operator: " + op_label)

    # possibly bind the constant type
    if ((not tft_utils.FIX_CONST_TYPE) and tft_expr.isConstVar(opd0)):
        if (opd0.getGid() == tft_expr.PRESERVED_CONST_GID):
            CountGID(tft_expr.PRESERVED_CONST_GID, -1)
            opd0.gid = op_gid
        else:
            if (opd0.getGid() != op_gid):
                print("Warning: conflicting constant type...")
    if ((not tft_utils.FIX_CONST_TYPE) and tft_expr.isConstVar(opd1)):
        if (opd1.getGid() == tft_expr.PRESERVED_CONST_GID):
            CountGID(tft_expr.PRESERVED_CONST_GID, -1)
            opd1.gid = op_gid
        else:
            if (opd1.getGid() != op_gid):
                print("Warning: conflicting constant type...")

    if (not internal):
        CountGID(op_gid)
        CountCasting(opd0, op_gid)
        CountCasting(opd1, op_gid)

    if (internal):
        assert (-1 == op_gid)
    else:
        assert (0 <= op_gid)
    if (op_gid not in EXTERNAL_GIDS):
        EXTERNAL_GIDS.append(op_gid)

    ret_expr = tft_expr.BinaryExpr(tft_expr.BinaryOp(op_gid, op_label),
                                   opd0.copy((not internal)),
                                   opd1.copy((not internal)))

    AppendCppInst(ret_expr)

    return ret_expr
Пример #7
0
def MakeUnaryExpr(op_label, op_gid, opd0, internal=False):
    global EXTERNAL_GIDS

    if ((not internal) and (TUNE_FOR_ALL)):
        op_gid = 0

    assert (type(op_label) is str)
    assert (type(op_gid) is int)
    assert (isinstance(opd0, tft_expr.Expr))

    if (COALESCE_CONST):
        if (isinstance(opd0, tft_expr.ConstantExpr)):
            if (op_label == "abs"):
                eret = tft_expr.ConstantExpr(abs(opd0.value()))
                AppendCppInst(eret)
                return eret

            elif (op_label == "-"):
                eret = tft_expr.ConstantExpr(-1.0 * opd0.value())
                AppendCppInst(eret)
                return eret

            elif (op_label == "sqrt"):
                cv = opd0.value()
                assert (cv >= 0.0)
                eret = tft_expr.ConstantExpr(math.sqrt(cv))
                AppendCppInst(eret)
                return eret

            else:
                sys.exit("ERROR: unknown Unary Operator: " + op_label)

    # possibly bind the constant type
    if ((not tft_utils.FIX_CONST_TYPE) and tft_expr.isConstVar(opd0)):
        if (opd0.getGid() == tft_expr.PRESERVED_CONST_GID):
            CountGID(tft_expr.PRESERVED_CONST_GID, -1)
            opd0.gid = op_gid
        else:
            if (opd0.getGId() != op_gid):
                print("Warning: conflicting constant type...")

    if (not internal):
        CountGID(op_gid)
        CountCasting(opd0, op_gid)

    if (internal):
        assert (-1 == op_gid)
    else:
        assert (0 <= op_gid)
    if (op_gid not in EXTERNAL_GIDS):
        EXTERNAL_GIDS.append(op_gid)

    ret_expr = None
    if (op_label == "-"):
        ret_expr = BE("*", op_gid, FConst(-1.0), opd0)

    else:
        ret_expr = tft_expr.UnaryExpr(tft_expr.UnaryOp(op_gid, op_label),
                                      opd0.copy((not internal)))

        AppendCppInst(ret_expr)

    return ret_expr
Пример #8
0
    def maxObj(self, expr_optobj, id_query=None, id_retry=None):
        assert (isinstance(expr_optobj, tft_expr.Expr))
        assert (self.tolerance is not None)
        assert ((id_query is None) or (type(id_query) is int))
        assert ((id_retry is None) or (type(id_retry) is int))

        tft_utils.checkGelpiaInstallation("master")

        if ((id_retry is not None) and (id_retry >= MAX_RETRIES)):
            print("WARNING: Gelpia reached the max. # of retries...")

        self.cached_result = None

        fname_query = os.path.abspath(FNAME_GELPIA_QUERY)
        fname_log = os.path.abspath(FNAME_GELPIA_LOG)
        if (id_query is not None):
            fname_query = fname_query + "." + str(id_query)
            fname_log = fname_log + "." + str(id_query)

        if (tft_utils.FPTUNER_DEBUG):
            if (os.path.isfile(fname_query)):
                print(
                    "WARNING: automatically overwrite Gelpia's query file: " +
                    fname_query)
                return None

            if (os.path.isfile(fname_log)):
                print("WARNING: automatically overwrite Gelpia's log file: " +
                      fname_log)
                return None

        # ---- write query file ----
        qfile = open(fname_query, "w")

        # write input and output tolerances
        qfile.write("-ie .0000000001\n")

        qfile.write("-oe " + str(float(self.tolerance)) + "\n")

        # maximization objective
        qfile.write("-f \"" + expr_optobj.toCString(True) + "\"\n")

        # specify the timeout
        qfile.write("-t " + str(tft_utils.GOPT_TIMEOUT) + "\n")

        # turn off divide-by-zero analysis
        qfile.write("-z\n")

        # redirect temporal results to stderr
        qfile.write("-L " + fname_log + "\n")

        # variables and their ranges
        non_const_vars = [
            v for v in expr_optobj.vars() if (not tft_expr.isConstVar(v))
        ]
        str_vars = "-i \"{"
        if (len(non_const_vars) == 0):
            str_vars = str_vars + "}\"\n"
        else:
            for var in non_const_vars:
                assert (isinstance(var, tft_expr.VariableExpr))
                assert (var.hasBounds())
                if (var.type() is Fraction):
                    str_vars = str_vars + "\'" + var.label(
                    ) + "\' : (" + var.lb().toCString() + "," + var.ub(
                    ).toCString() + "), "

                elif (var.type() is int):
                    vlb = var.lb().value()
                    vub = var.ub().value()
                    assert ((vlb == int(vlb)) and (vub == int(vub)))
                    vlb = int(vlb)
                    vub = int(vub)

                    str_vars = str_vars + "\'" + var.label() + "\' : (" + str(
                        vlb) + "," + str(vub) + "), "

                else:
                    sys.exit("ERROR: Gelpia doesn't support variable type: " +
                             str(var.type()))

            assert (str_vars.endswith(", "))

            str_vars = str_vars[0:len(str_vars) - 2] + "}\"\n"

        qfile.write(str_vars)

        qfile.close()

        # ---- save the query file ----
        if (SAVE_QUERY):
            qi = 0

            if (not os.path.isdir(DIR_SAVED_QUERIES)):
                os.system("mkdir " + DIR_SAVED_QUERIES)
                assert (os.path.isdir(DIR_SAVED_QUERIES))

            assert (os.path.isfile(FNAME_GELPIA_QUERY))

            while (True):
                qname = DIR_SAVED_QUERIES + "/" + NAME_QUERY + "_" + str(qi)

                if (not os.path.isfile(qname)):
                    os.system("cp " + FNAME_GELPIA_QUERY + " " + qname)
                    break

                else:
                    qi = qi + 1

        # ---- run gelpia ----
        assert (tft_utils.GOPT_TIMEOUT > 0)
        assert ((0 < POLL_INTERVAL)
                and (POLL_INTERVAL <= tft_utils.GOPT_TIMEOUT))

        now_dir = os.path.abspath(os.getcwd())
        os.chdir(os.environ["GELPIA_PATH"])

        exe_gelpia = subp.Popen([os.environ["GELPIA"], "@" + fname_query],
                                shell=False,
                                stdout=subp.PIPE,
                                stderr=subp.PIPE,
                                bufsize=0)

        finished = False
        wait_time = 0
        while (True):
            time.sleep(POLL_INTERVAL)
            wait_time = wait_time + POLL_INTERVAL

            if (exe_gelpia.poll() is not None):
                finished = True
                break

            if (wait_time >= (tft_utils.GOPT_TIMEOUT + 15)):
                break

        os.chdir(now_dir)

        if (not finished):
            print(
                "WARNING: Manually timeout Gelpia... Gelpia's timeout facility may failed..."
            )
            return None

        # ---- read result ----
        not_certain = False
        value_bound = None

        if (finished):  # Gelpia terminated itself
            for aline in exe_gelpia.stdout:
                aline = aline.decode(encoding='UTF-8').strip()

                if (aline == "error"):
                    print("Warning : Gelpia returned \"error\"")

                if (aline == "ERROR: Division by zero"):
                    print("Warning : Gelpia encounter division by zero")

                str_val = None

                if (aline.startswith("[[")):
                    i_first_end = aline.find("]")

                    if (i_first_end >= 5):
                        aline = aline[2:i_first_end]

                        i_coma = aline.find(",")

                        if (i_coma >= 1):
                            str_val = aline[i_coma + 1:]

                elif (aline.startswith("[") and aline.endswith(", {")):
                    str_val = aline[1:len(aline) - 3]

                elif (aline.startswith("[") and aline.endswith(", {}]")):
                    str_val = aline[1:len(aline) - 5]

                else:
                    pass

                if (str_val is not None):
                    if (str_val == "inf" or str_val == "nan"):
                        print("WARNING: pessimistic bound: " + str_val)
                        print("   expr: " + str(expr_optobj.toCString()))
                        print("Gelpia retry...")

                        if (id_retry is None):
                            return self.maxObj(expr_optobj, id_query, 1)
                        else:
                            assert (type(id_retry) is int)
                            return self.maxObj(expr_optobj, id_query,
                                               (id_retry + 1))

                    if (str_val == "inf"):
                        raise InfValueException()

                    try:
                        value_bound = Fraction(float(str_val))
                    except:
                        print("WARNING: cannot convert " + str_val +
                              " to float...")
                        return None

            if (value_bound is None):
                not_certain = True
                print("WARNING: Gelpia didn't return a certain answer...")
            # assert(value_bound is not None)

        if (
                not finished or not_certain
        ):  # 1) Gelpia didn't terminate itself OR 2) Gelpia didn't return a certain answer...
            if (not finished):
                exe_gelpia.terminate()
                exe_gelpia.kill()

            assert (os.path.isfile(fname_log))
            flog = open(fname_log, "r")

            target_token = "guaranteed ub:"

            for aline in flog:
                if (type(aline) is not str):
                    aline = aline.decode(encoding='UTF-8').strip()

                if (VERBOSE):
                    print("Gelpia (stderr) >> " + aline)

                target_id = aline.find(target_token)

                if (target_id >= 0):
                    aline = aline[target_id + len(target_token):].strip()

                    try:
                        value_bound = Fraction(float(aline))
                    except:
                        print("WARNING: cannot convert " + aline +
                              " to float...")

                        sys.exit(1)

            flog.close()

            if (value_bound is None):
                print("WARNING: Gelpia terminated prematurely... retry...")

                if (id_retry is None):
                    return self.maxObj(expr_optobj, id_query, 1)
                else:
                    assert (type(id_retry) is int)
                    return self.maxObj(expr_optobj, id_query, (id_retry + 1))

        if (value_bound is None):
            print("EXIT: Gelpia abort with value_bound = None...")
            print(":: " + str(expr_optobj))
            sys.exit(1)

        # ---- finalize ----
        self.cached_result = value_bound
        return value_bound
Пример #9
0
def LoadExprsFile(fname):
    global FNAME_EXPRS
    global FILE_PREFIX
    global FILE_GID2EPSS
    global FILE_POSTFIX

    assert (fname.endswith(".exprs"))
    FNAME_EXPRS = fname

    f_stage = "prefix"
    efile = open(fname, "r")
    for aline in efile:
        # decide loading stage
        if (aline.strip() == "var-ranges:"):
            assert (f_stage == "prefix")
            f_stage = "var-ranges"
            continue

        elif (aline.strip() == "group-epsilons:"):
            assert (f_stage == "var-ranges")
            f_stage = "group-epsilons"
            continue

        elif (aline.strip() == "eq-gids:"):
            assert (f_stage == "group-epsilons")
            f_stage = "postfix"
            FILE_POSTFIX.append("\n")

        else:
            pass

        # handle based on stage
        if (f_stage == "prefix"):
            FILE_PREFIX.append(aline)

        elif (f_stage == "var-ranges"):
            if (aline.strip() != ""):

                ve = tft_parser.String2BoundedVariableExpr(aline.strip())
                assert (ve.label() not in DEF.VNames)

                if (not tft_expr.isConstVar(ve)):
                    DEF.VarExprs.append(ve)
                    DEF.VNames.append(ve.label())
                    DEF.VRanges.append(
                        (float(ve.lb().value()), float(ve.ub().value())))

        elif (f_stage == "group-epsilons"):
            if (aline.strip() != ""):
                tokens = tft_utils.String2Tokens(aline.strip(), ":")
                assert (len(tokens) == 2)

                gid = int(tokens[0])
                epss = tokens[1]

                assert (gid not in FILE_GID2EPSS.keys())
                FILE_GID2EPSS[gid] = epss

        elif (f_stage == "postfix"):
            FILE_POSTFIX.append(aline)

        else:
            assert (False)

    efile.close()

    # generate N_Var_Intervals
    DEF.assert_VNames()
    DEF.assert_VRanges()
    DEF.N_Var_Intervals = [DEF.N_Partitions for i in range(0, len(DEF.VNames))]
Пример #10
0
def FPTaylorExpr(expr, alloc):
    assert (isinstance(expr, tft_expr.Expr))
    assert (isinstance(alloc, tft_alloc.Alloc))

    if (isinstance(expr, tft_expr.ConstantExpr)):
        return "rnd128(" + str(float(expr.value())) + ")"

    if (isinstance(expr, tft_expr.VariableExpr)):
        bw_mine = alloc[expr.getGid()]

        if (tft_expr.isConstVar(expr)):
            assert (expr.lb() == expr.ub())
            return FPTaylorTypeCastWrap(bw_mine, expr.ub().toCString())
        else:
            return FPTaylorTypeCastWrap(bw_mine, expr.label())

    if (isinstance(expr, tft_expr.UnaryExpr)):
        go_cast = False
        bw_mine = alloc[expr.getGid()]

        if (isinstance(expr.opd(), tft_expr.ConstantExpr)):
            go_cast = True
        else:
            bw_opd = alloc[expr.opd().getGid()]
            if (bw_opd != bw_mine):
                go_cast = True

        str_opd = FPTaylorExpr(expr.opd(), alloc)

        if (go_cast):
            if (bw_mine == tft_alloc.EPSILON_32):
                str_opd = "rnd32(" + str_opd + ")"
            elif (bw_mine == tft_alloc.EPSILON_64):
                str_opd = "rnd64(" + str_opd + ")"
            elif (bw_mine == tft_alloc.EPSILON_128):
                str_opd = "rnd128(" + str_opd + ")"
            else:
                assert (False)

        return FPTaylorTypeCastWrap(bw_mine,
                                    expr.operator.label + "(" + str_opd + ")")

    if (isinstance(expr, tft_expr.BinaryExpr)):
        cast_lhs = False
        cast_rhs = False
        bw_mine = alloc[expr.getGid()]

        if (isinstance(expr.lhs(), tft_expr.ConstantExpr)):
            cast_lhs = True
        else:
            bw_lhs = alloc[expr.lhs().getGid()]
            if (bw_lhs != bw_mine):
                cast_lhs = True

        if (isinstance(expr.rhs(), tft_expr.ConstantExpr)):
            cast_rhs = True
        else:
            bw_rhs = alloc[expr.rhs().getGid()]
            if (bw_rhs != bw_mine):
                cast_rhs = True

        str_lhs = FPTaylorExpr(expr.lhs(), alloc)
        str_rhs = FPTaylorExpr(expr.rhs(), alloc)

        if (cast_lhs):
            if (bw_mine == tft_alloc.EPSILON_32):
                str_lhs = "rnd32(" + str_lhs + ")"
            elif (bw_mine == tft_alloc.EPSILON_64):
                str_lhs = "rnd64(" + str_lhs + ")"
            elif (bw_mine == tft_alloc.EPSILON_128):
                str_lhs = "rnd128(" + str_lhs + ")"
            else:
                assert (False)

        if (cast_rhs):
            if (bw_mine == tft_alloc.EPSILON_32):
                str_rhs = "rnd32(" + str_rhs + ")"
            elif (bw_mine == tft_alloc.EPSILON_64):
                str_rhs = "rnd64(" + str_rhs + ")"
            elif (bw_mine == tft_alloc.EPSILON_128):
                str_rhs = "rnd128(" + str_rhs + ")"
            else:
                assert (False)

        return FPTaylorTypeCastWrap(
            bw_mine,
            "(" + str_lhs + " " + expr.operator.label + " " + str_rhs + ")")

    sys.exit("Error: not supported expr 4 FPTaylorExpr...")