Beispiel #1
0
    def _array(self,
               name,
               matrix,
               allocate=False,
               operator='=',
               atomic=False,
               ignore_symbols=[]):
        opscount = 0
        code = ""

        # Testing on Godbolt with GCC 9.1 and ICPC shows that
        # pow(x, 0.5) generates fewer instructions than
        # sqrt(x), so will swap. However, leave R here in case
        # it gets used in expansions in future for some reason.

        light_ignore = []
        if sp.symbols('R') in matrix.free_symbols:
            code += f'{self.precision} R = sqrt(x*x + y*y + z*z);\n'
            light_ignore.append('R')
        if sp.symbols('Rinv') in matrix.free_symbols:
            code += f'{self.precision} Rinv = pow(x*x + y*y + z*z, -0.5);\n'
            light_ignore.append('Rinv')

        if allocate:
            code += f'{self.precision} {name}[{len(matrix)}];\n'

        if not self.debug:
            # print('Printing with CSE')
            iterator = SymbolIterator(name)
            # print(f'ignoring {name} in cse')
            sub_expressions, rmatrix = cse(matrix,
                                           optimizations=opts,
                                           symbols=iterator,
                                           ignore=(ignore_symbols),
                                           light_ignore=light_ignore)

            rmatrix = sp.Matrix(rmatrix)
            for i, (var, sub_expr) in enumerate(sub_expressions):
                opscount += count_ops(sub_expr)
                code += f'{self.precision} ' + self.printer.doprint(
                    sub_expr, assign_to=var) + "\n"

            opscount += count_ops(rmatrix)
            tmp = self.printer.doprint(rmatrix,
                                       assign_to=name).replace('=', operator)

        else:
            # print('Printing without CSE')
            opscount += count_ops(matrix)
            tmp = self.printer.doprint(matrix,
                                       assign_to=name).replace('=', operator)

        if atomic:
            lines = tmp.split('\n')
            for l in lines:
                code += '#pragma omp atomic\n'
                code += l + '\n'
        else:
            code += tmp + '\n'
        return code, opscount
Beispiel #2
0
def test_simplify_ratio():
    # roots of x**3-3*x+5
    roots = ['(5/2 + 21**(1/2)/2)**(1/3)*(1/2 - I*3**(1/2)/2)'
             ' + 1/((1/2 - I*3**(1/2)/2)*(5/2 + 21**(1/2)/2)**(1/3))',
             '(5/2 + 21**(1/2)/2)**(1/3)*(1/2 + I*3**(1/2)/2)'
             ' + 1/((1/2 + I*3**(1/2)/2)*(5/2 + 21**(1/2)/2)**(1/3))',
             '-1/(5/2 + 21**(1/2)/2)**(1/3) - (5/2 + 21**(1/2)/2)**(1/3)']
    for r in roots:
        r = S(r)
        assert count_ops(simplify(r, ratio=1)) <= count_ops(r)
        # If ratio=oo, simplify() is always applied:
        assert simplify(r, ratio=oo) is not r
Beispiel #3
0
def test_simplify_ratio():
    # roots of x**3-3*x+5
    roots = ['(5/2 + 21**(1/2)/2)**(1/3)*(1/2 - I*3**(1/2)/2)'
             ' + 1/((1/2 - I*3**(1/2)/2)*(5/2 + 21**(1/2)/2)**(1/3))',
             '(5/2 + 21**(1/2)/2)**(1/3)*(1/2 + I*3**(1/2)/2)'
             ' + 1/((1/2 + I*3**(1/2)/2)*(5/2 + 21**(1/2)/2)**(1/3))',
             '-1/(5/2 + 21**(1/2)/2)**(1/3) - (5/2 + 21**(1/2)/2)**(1/3)']

    for r in roots:
        r = S(r)
        assert count_ops(simplify(r, ratio=1)) <= count_ops(r)
        # If ratio=oo, simplify() is always applied:
        assert simplify(r, ratio=oo) is not r
Beispiel #4
0
def test_simplify_ratio():
    # roots of x**3-3*x+5
    roots = ['(1/2 - sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3) + 1/((1/2 - '
             'sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3))',
             '1/((1/2 + sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3)) + '
             '(1/2 + sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3)',
             '-(sqrt(21)/2 + 5/2)**(1/3) - 1/(sqrt(21)/2 + 5/2)**(1/3)']

    for r in roots:
        r = S(r)
        assert count_ops(simplify(r, ratio=1)) <= count_ops(r)
        # If ratio=oo, simplify() is always applied:
        assert simplify(r, ratio=oo) is not r
Beispiel #5
0
def test_simplify_ratio():
    # roots of x**3-3*x+5
    roots = ['(1/2 - sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3) + 1/((1/2 - '
             'sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3))',
             '1/((1/2 + sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3)) + '
             '(1/2 + sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3)',
             '-(sqrt(21)/2 + 5/2)**(1/3) - 1/(sqrt(21)/2 + 5/2)**(1/3)']

    for r in roots:
        r = S(r)
        assert count_ops(simplify(r, ratio=1)) <= count_ops(r)
        # If ratio=oo, simplify() is always applied:
        assert simplify(r, ratio=oo) is not r
Beispiel #6
0
def my_measure(expr):
    from sympy import sqrt, simplify, count_ops, oo
    from sympy import Symbol, S

    count = 0
    # Discourage powers by giving POW a weight of 10
    count += count_ops(expr, visual=True).subs(Symbol('EXP'), 100)
    count += count_ops(expr, visual=True).subs(Symbol('HEAVISIDE'), 10)
    #count = count_ops(expr, visual=True).subs(Symbol('HEAVISIDE'), 1)

    # Every other operation gets a weight of 1 (the default)
    count = count.replace(Symbol, type(S.One))

    return count
Beispiel #7
0
def sympy_key(expr):
    """Get the key for ordering SymPy expressions.

    This function assumes that the given expression is already sympified.
    """

    return count_ops(expr), default_sort_key(expr)
Beispiel #8
0
    def process_diff_list(diff_list, label, superscript):
        if len(diff_list) == 0:
            return 0
        elif len(diff_list) == 1:
            return diff_list[0].pre_factor * Diff(diff_list[0].argument, label,
                                                  superscript)

        result = 0
        matches = []
        for i in range(1, len(diff_list)):
            match_result = match_diff_splits(diff_list[i], diff_list[0])
            if match_result is not None:
                matches.append((i, match_result))

        if len(matches) == 0:
            result += diff_list[0].pre_factor * Diff(diff_list[0].argument,
                                                     label, superscript)
        else:
            other_idx, match_result = sorted(
                matches, key=lambda e: sp.count_ops(e[1]))[0]
            new_argument = diff_list[0].argument * diff_list[other_idx].argument
            result += (diff_list[0].pre_factor /
                       diff_list[other_idx].argument) * Diff(
                           new_argument, label, superscript)
            if match_result == 0:
                del diff_list[other_idx]
            else:
                diff_list[other_idx].pre_factor = match_result * diff_list[
                    0].argument
        result += process_diff_list(diff_list[1:], label, superscript)
        return result
Beispiel #9
0
def expression_complexity(expr, complexity=None):
    '''
    Returns the complexity of an expression (either string or sympy)

    The complexity is defined as 1 for each arithmetic operation except divide which is 2,
    and all other operations are 20. This can be overridden using the complexity
    argument.

    Note: calling this on a statement rather than an expression is likely to lead to errors.

    Parameters
    ----------
    expr: `sympy.Expr` or str
        The expression.
    complexity: None or dict (optional)
        A dictionary mapping expression names to their complexity, to overwrite default behaviour.

    Returns
    -------
    complexity: int
        The complexity of the expression.
    '''
    subs = {'ADD':1, 'DIV':2, 'MUL':1, 'SUB':1}
    if complexity is not None:
        subs.update(complexity)
    ops = sympy.count_ops(expr, visual=True)
    for atom in ops.atoms():
        if hasattr(atom, 'name'):
            subs[atom.name] = 20 # unknown operations assumed to have a large cost
    return ops.evalf(subs=subs)
Beispiel #10
0
def test_simplify_measure():
    measure1 = lambda expr: len(str(expr))
    measure2 = lambda expr: -count_ops(expr
                                       )  # Return the most complicated result
    expr = (x + 1) / (x + sin(x)**2 + cos(x)**2)
    assert measure1(simplify(expr, measure=measure1)) <= measure1(expr)
    assert measure2(simplify(expr, measure=measure2)) <= measure2(expr)
Beispiel #11
0
def subs_matrix_verbose(A_expr,subs,simultaneous=False):

    print "flashlight.sympy: subs_matrix_verbose(...) begin..."
    A_subs_expr = sympy.Matrix.zeros(A_expr.rows,A_expr.cols)
    for r in range(A_expr.rows):
        for c in range(A_expr.cols):
            print "    ",r,c,len(subs),sympy.count_ops(A_expr[r,c])
            A_subs_expr[r,c] = A_expr[r,c].subs(subs,simultaneous=simultaneous)
    print "flashlight.sympy: subs_matrix_verbose(...) end."
    return A_subs_expr
Beispiel #12
0
def test_simplify_measure():
    measure1 = lambda expr: len(str(expr))
    measure2 = lambda expr: -count_ops(expr)
                                       # Return the most complicated result
    expr = (x + 1)/(x + sin(x)**2 + cos(x)**2)
    assert measure1(simplify(expr, measure=measure1)) <= measure1(expr)
    assert measure2(simplify(expr, measure=measure2)) <= measure2(expr)

    expr2 = Eq(sin(x)**2 + cos(x)**2, 1)
    assert measure1(simplify(expr2, measure=measure1)) <= measure1(expr2)
    assert measure2(simplify(expr2, measure=measure2)) <= measure2(expr2)
Beispiel #13
0
def erank(list_L):    # rearrange list of eqns by length
                    # by putting shortest eqns last, system will prefer to solve
                    #   shorter equations (i.e. prefer shorter solutions where two exist)

    # since the sorting is from lower to higher
    # it should not be reversed when putting into the list - D.Z.
    sorted_ls = []
    list_d = {}
    for e in list_L:
        count = int(sp.count_ops(e.RHS)) + int(sp.count_ops(e.LHS))
        if count not in list_d.keys():
            list_d[count] = []
        list_d[count].append(e)

    keys = list_d.keys()
    keys = sorted(keys, reverse= False)

    for key in keys:
        sorted_ls.extend(list_d[key])
    return sorted_ls
Beispiel #14
0
    def is_zero(self, n=100):
        """
        simplifies zero candidates with count_ops <  n
        """

        Z = self.nonzero_tuples()
        for c, idcs in Z:
            if sp.count_ops(c) < n:
                c = sp.simplify(c)
            if c != 0:
                return False
        return True
Beispiel #15
0
def try_solving_moving_endpoints_of_spline():
    import sympy as sy
    sy.init_printing()

    a0, a1, a2, a3, k0, k1, j0, j1, new_t = sy.symbols(
        'a0, a1, a2, a3, k0, k1, j0, j1, new_t')

    # Q: How much simpler is it if we only move one end?
    #j0 = k0  # A: Wow, much simpler!  30+ ops instead of 80+
    #j1 = k1  # A: GADS, not much simpler at all, still 80+ operations.

    years = new_t * (j1 - j0) + j0
    old_t = (years - k0) / (k1 - k0)
    d = (((a3 * old_t + a2) * old_t) + a1) * old_t + a0

    #d = sy.factor(d)
    #d = sy.expand(d)
    #d = sy.simplify(d)
    d = sy.expand(d)

    d = sy.collect(d, new_t)
    b0 = d.coeff(new_t, 0)
    b1 = d.coeff(new_t, 1)
    b2 = d.coeff(new_t, 2)
    b3 = d.coeff(new_t, 3)

    commons, outputs = sy.cse(
        [b0, b1, b2, b3],
        sy.numbered_symbols('u'),
        #optimizations='basic',
    )
    n = 0
    for symbol, expr in commons:
        n += sy.count_ops(expr)
        print(symbol, '=', expr)
    print()
    for i, expr in enumerate(outputs):
        n += sy.count_ops(expr)
        print('b{} = {}'.format(i, expr))
    print('Total operations: {}'.format(n))
Beispiel #16
0
def test_issue_2827_trigsimp_methods():
    measure1 = lambda expr: len(str(expr))
    measure2 = lambda expr: -count_ops(expr)
                                       # Return the most complicated result
    expr = (x + 1)/(x + sin(x)**2 + cos(x)**2)
    ans = Matrix([1])
    M = Matrix([expr])
    assert trigsimp(M, method='fu', measure=measure1) == ans
    assert trigsimp(M, method='fu', measure=measure2) != ans
    # all methods should work with Basic expressions even if they
    # aren't Expr
    M = Matrix.eye(1)
    assert all(trigsimp(M, method=m) == M for m in
        'fu matching groebner old'.split())
    # watch for E in exptrigsimp, not only exp()
    eq = 1/sqrt(E) + E
    assert exptrigsimp(eq) == eq
Beispiel #17
0
def test_issue_2827_trigsimp_methods():
    measure1 = lambda expr: len(str(expr))
    measure2 = lambda expr: -count_ops(expr)
    # Return the most complicated result
    expr = (x + 1) / (x + sin(x)**2 + cos(x)**2)
    ans = Matrix([1])
    M = Matrix([expr])
    assert trigsimp(M, method='fu', measure=measure1) == ans
    assert trigsimp(M, method='fu', measure=measure2) != ans
    # all methods should work with Basic expressions even if they
    # aren't Expr
    M = Matrix.eye(1)
    assert all(
        trigsimp(M, method=m) == M for m in 'fu matching groebner old'.split())
    # watch for E in exptrigsimp, not only exp()
    eq = 1 / sqrt(E) + E
    assert exptrigsimp(eq) == eq
Beispiel #18
0
def TestTraverseExpr(tmpExp):
    # Inspired from sympy-master/sympy/core/expr.py:

    assert isinstance(tmpExp, sympy.Expr)  #fraction)  #Equality)
    assert tmpExp.is_Mul  #fraction)  #Equality)
    print("Number of operators on the rhs exp: %s" % \
                sympy.count_ops(tmpExp, visual=True))
    args = tmpExp.as_ordered_factors()  #order=order)
    print("args = %s" % args)
    print("args[1] = %s" % args[1])
    assert args[1].is_Pow
    args1 = args[1].args
    print args1
    print args1[0]
    assert args1[1] == -1
    #print("args1 (the denominator factors) = %s" % str(args1))
    #print type(args[1])
    assert args[1].is_Mul
Beispiel #19
0
def TestTraverseExpr(tmpExp):
    # Inspired from sympy-master/sympy/core/expr.py:

    assert isinstance(tmpExp, sympy.Expr) #fraction)  #Equality)
    assert tmpExp.is_Mul #fraction)  #Equality)
    print("Number of operators on the rhs exp: %s" % \
                sympy.count_ops(tmpExp, visual=True))
    args = tmpExp.as_ordered_factors() #order=order)
    print("args = %s" % args)
    print("args[1] = %s" % args[1])
    assert args[1].is_Pow
    args1 = args[1].args
    print args1
    print args1[0]
    assert args1[1] == -1
    #print("args1 (the denominator factors) = %s" % str(args1))
    #print type(args[1])
    assert args[1].is_Mul
Beispiel #20
0
    def render_node(self, node):
        expr = NodeRenderer(use_vectorisation_idx=False).render_node(node)

        if is_scalar_expression(expr, self.variables) and not has_non_float(expr,
                                                                            self.variables):
            if expr in self.optimisations:
                name = self.optimisations[expr]
            else:
                # Do not pull out very simple expressions (including constants
                # and numbers)
                sympy_expr = str_to_sympy(expr)
                if sympy.count_ops(sympy_expr, visual=False) < 2:
                    return expr
                self.n += 1
                name = '_lio_const_'+str(self.n)
                self.optimisations[expr] = name
            return name
        else:
            return NodeRenderer.render_node(self, node)
Beispiel #21
0
    def render_node(self, node):
        expr = NodeRenderer(use_vectorisation_idx=False).render_node(node)

        if is_scalar_expression(expr, self.variables) and not has_non_float(
                expr, self.variables):
            if expr in self.optimisations:
                name = self.optimisations[expr]
            else:
                # Do not pull out very simple expressions (including constants
                # and numbers)
                sympy_expr = str_to_sympy(expr)
                if sympy.count_ops(sympy_expr, visual=False) < 2:
                    return expr
                self.n += 1
                name = '_lio_const_' + str(self.n)
                self.optimisations[expr] = name
            return name
        else:
            return NodeRenderer.render_node(self, node)
def get_expr_complexity(expr):
    expr = parse_expr(expr)
    compl = 0

    is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
    numbers_expr = [subexpression for subexpression in preorder_traversal(expr) if is_atomic_number(subexpression)]

    for j in numbers_expr:
        try:
            compl = compl + get_number_DL_snapped(float(j))
        except:
            compl = compl + 1000000

    n_variables = len(expr.free_symbols)
    n_operations = len(count_ops(expr,visual=True).free_symbols)

    if n_operations!=0 or n_variables!=0:
        compl = compl + (n_variables+n_operations)*np.log2((n_variables+n_operations))

    return compl
Beispiel #23
0
def expression_complexity(expr, complexity=None):
    '''
    Returns the complexity of an expression (either string or sympy)

    The complexity is defined as 1 for each arithmetic operation except divide which is 2,
    and all other operations are 20. This can be overridden using the complexity
    argument.

    Note: calling this on a statement rather than an expression is likely to lead to errors.

    Parameters
    ----------
    expr: `sympy.Expr` or str
        The expression.
    complexity: None or dict (optional)
        A dictionary mapping expression names to their complexity, to overwrite default behaviour.

    Returns
    -------
    complexity: int
        The complexity of the expression.
    '''
    if isinstance(expr, str):
        # we do this because sympy.count_ops doesn't handle inequalities (TODO: handle sympy as well str)
        for op in ['<=', '>=', '==', '<', '>']:
            expr = expr.replace(op, '+')
        # work around bug with rand() and randn() (TODO: improve this)
        expr = expr.replace('rand()', 'rand(0)')
        expr = expr.replace('randn()', 'randn(0)')
    subs = {'ADD': 1, 'DIV': 2, 'MUL': 1, 'SUB': 1}
    if complexity is not None:
        subs.update(complexity)
    ops = sympy.count_ops(expr, visual=True)
    for atom in ops.atoms():
        if hasattr(atom, 'name'):
            subs[atom.
                 name] = 20  # unknown operations assumed to have a large cost
    return ops.evalf(subs=subs)
Beispiel #24
0
def Read(fileName):
    fin = open(fileName)

    while (True):
        str = fin.readline()
        if str:
            #pass
            str = str.rstrip(rstripStr)
        else:
            break

        if str.startswith("#"):
            continue

        for index, v in enumerate(defVars):
            cmpStr = v + " = "
            #print("cmpStr = %s" % cmpStr)
            #" - v"
            if str.startswith(cmpStr):
                #TestTraverseExpr(tmpExp)

                tmpExp = Parse(str[len(cmpStr):])
                lhs = sympy.Symbol(v)
                print(tmpExp - lhs)
                lhs, rhs = PreprocessEq(lhs, tmpExp)

                #assert False

                #eqList[index] = Parse(str[len(cmpStr) : ] + " - " + v)
                eqList[index] = rhs - lhs

                #print("eqList[index] = %s" % str(eqList[index]))
                print("eqList[%d] = %s" % (index, eqList[index]))
                #print(separatevars(expr=eqList[index], symbols=[xdst, xsrc]))
                print("Number of operators: %s" % \
                        sympy.count_ops(eqList[index], visual=True))
                GenCode(eqList[index])
Beispiel #25
0
def expression_complexity(expr, complexity=None):
    '''
    Returns the complexity of an expression (either string or sympy)

    The complexity is defined as 1 for each arithmetic operation except divide which is 2,
    and all other operations are 20. This can be overridden using the complexity
    argument.

    Note: calling this on a statement rather than an expression is likely to lead to errors.

    Parameters
    ----------
    expr: `sympy.Expr` or str
        The expression.
    complexity: None or dict (optional)
        A dictionary mapping expression names to their complexity, to overwrite default behaviour.

    Returns
    -------
    complexity: int
        The complexity of the expression.
    '''
    if isinstance(expr, str):
        # we do this because sympy.count_ops doesn't handle inequalities (TODO: handle sympy as well str)
        for op in ['<=', '>=', '==', '<', '>']:
            expr = expr.replace(op, '+')
        # work around bug with rand() and randn() (TODO: improve this)
        expr = expr.replace('rand()', 'rand(0)')
        expr = expr.replace('randn()', 'randn(0)')
    subs = {'ADD':1, 'DIV':2, 'MUL':1, 'SUB':1}
    if complexity is not None:
        subs.update(complexity)
    ops = sympy.count_ops(expr, visual=True)
    for atom in ops.atoms():
        if hasattr(atom, 'name'):
            subs[atom.name] = 20 # unknown operations assumed to have a large cost
    return ops.evalf(subs=subs)
Beispiel #26
0
def Read(fileName):
    fin = open(fileName)

    while (True):
        str = fin.readline()
        if str:
            #pass
            str = str.rstrip(rstripStr)
        else:
            break

        if str.startswith("#"):
            continue

        for index, v in enumerate(defVars):
            cmpStr = v + " = "
            #print("cmpStr = %s" % cmpStr)
            #" - v"
            if str.startswith(cmpStr):
                #TestTraverseExpr(tmpExp)

                tmpExp = Parse(str[len(cmpStr) : ])
                lhs = sympy.Symbol(v)
                print (tmpExp - lhs)
                lhs, rhs = PreprocessEq(lhs, tmpExp)

                #assert False

                #eqList[index] = Parse(str[len(cmpStr) : ] + " - " + v)
                eqList[index] = rhs - lhs

                #print("eqList[index] = %s" % str(eqList[index]))
                print("eqList[%d] = %s" % (index, eqList[index]))
                #print(separatevars(expr=eqList[index], symbols=[xdst, xsrc]))
                print("Number of operators: %s" % \
                        sympy.count_ops(eqList[index], visual=True))
                GenCode(eqList[index])
Beispiel #27
0
 def count_ops(self, visual=None):
     """wrapper for count_ops that returns the operation count."""
     from sympy import count_ops
     return count_ops(self, visual)
     return sum(a.count_ops(visual) for a in self.args)
from sympy import simplify, cos, sin, trigsimp, cancel
from sympy import sqrt, count_ops, oo, symbols, log
from sympy.abc import x, y

expr = (2*x + 3*x**2)/(4*x*sin(y)**2 + 2*x*cos(y)**2)
expr
simplify(expr)

trigsimp(expr)
cancel(_)

root = 4/(sqrt(2)+3)
simplify(root, ratio=1) == root
count_ops(simplify(root, ratio=oo)) > count_ops(root)
x, y = symbols('x y', positive=True)
expr2 = log(x) + log(y) + log(x)*log(1/y)

expr3 = simplify(expr2)
expr3
count_ops(expr2)
count_ops(expr3)
print(count_ops(expr2, visual=True))
print(count_ops(expr3, visual=True))
Beispiel #29
0
def cgen_ncomp(ncomp=3, nporder=2, aggstat=False, debug=False):
    """Generates a C function for ncomp (int) number of components.
    The jth key component is always in the first position and the kth
    key component is always in the second.  The number of enrichment 
    stages (NP) is calculated via a taylor series approximation.  The
    order of this approximation may be set with nporder.  Only values
    of 1 or 2 are allowed. The aggstat argument determines whether the
    status messages should be aggreated and printed at the end or output
    as the function executes.
    """
    start_time = time.time()
    stat = _aggstatus('', "generating {0} component enrichment".format(ncomp), aggstat)
    r = range(0, ncomp)
    j = 0
    k = 1

    # setup-symbols
    alpha = Symbol('alpha', positive=True, real=True)
    LpF = Symbol('LpF', positive=True, real=True)
    PpF = Symbol('PpF', positive=True, real=True)
    TpF = Symbol('TpF', positive=True, real=True)
    SWUpF = Symbol('SWUpF', positive=True, real=True)
    SWUpP = Symbol('SWUpP', positive=True, real=True)
    NP = Symbol('NP', positive=True, real=True)   # Enrichment Stages
    NT = Symbol('NT', positive=True, real=True)   # De-enrichment Stages
    NP0 = Symbol('NP0', positive=True, real=True) # Enrichment Stages Initial Guess
    NT0 = Symbol('NT0', positive=True, real=True) # De-enrichment Stages Initial Guess
    NP1 = Symbol('NP1', positive=True, real=True) # Enrichment Stages Computed Value
    NT1 = Symbol('NT1', positive=True, real=True) # De-enrichment Stages Computed Value
    Mstar = Symbol('Mstar', positive=True, real=True)
    MW = [Symbol('MW[{0}]'.format(i), positive=True, real=True) for i in r]
    beta = [alpha**(Mstar - MWi) for MWi in MW]

    # np_closed helper terms
    NP_b = Symbol('NP_b', real=True)
    NP_2a = Symbol('NP_2a', real=True)
    NP_sqrt_base = Symbol('NP_sqrt_base', real=True)


    xF = [Symbol('xF[{0}]'.format(i), positive=True, real=True) for i in r]
    xPi = [Symbol('xP[{0}]'.format(i), positive=True, real=True) for i in r]
    xTi = [Symbol('xT[{0}]'.format(i), positive=True, real=True) for i in r]
    xPj = Symbol('xPj', positive=True, real=True)
    xFj = xF[j]
    xTj = Symbol('xTj', positive=True, real=True)
    ppf = (xFj - xTj)/(xPj - xTj)
    tpf = (xFj - xPj)/(xTj - xPj)

    xP = [(((xF[i]/ppf)*(beta[i]**(NT+1) - 1))/(beta[i]**(NT+1) - beta[i]**(-NP))) \
                                                                            for i in r]
    xT = [(((xF[i]/tpf)*(1 - beta[i]**(-NP)))/(beta[i]**(NT+1) - beta[i]**(-NP))) \
                                                                            for i in r]
    rfeed = xFj / xF[k]
    rprod = xPj / xP[k]
    rtail = xTj / xT[k]

    # setup constraint equations
    numer = [ppf*xP[i]*log(rprod) + tpf*xT[i]*log(rtail) - xF[i]*log(rfeed) for i in r]
    denom = [log(beta[j]) * ((beta[i] - 1.0)/(beta[i] + 1.0)) for i in r]
    LoverF = sum([n/d for n, d in zip(numer, denom)])
    SWUoverF = -1.0 * sum(numer)
    SWUoverP = SWUoverF / ppf

    prod_constraint = (xPj/xFj)*ppf - (beta[j]**(NT+1) - 1)/\
                      (beta[j]**(NT+1) - beta[j]**(-NP))
    tail_constraint = (xTj/xFj)*(sum(xT)) - (1 - beta[j]**(-NP))/\
                      (beta[j]**(NT+1) - beta[j]**(-NP))
    #xp_constraint = 1.0 - sum(xP)
    #xf_constraint = 1.0 - sum(xF)
    #xt_constraint = 1.0 - sum(xT)

    # This is NT(NP,...) and is correct!
    #nt_closed = solve(prod_constraint, NT)[0] 

    # However, this is NT(NP,...) rewritten (by hand) to minimize the number of NP 
    # and M* instances in the expression.  Luckily this is only depends on the key 
    # component and remains general no matter the number of components.
    nt_closed = (-MW[0]*log(alpha) + Mstar*log(alpha) + log(xTj) + log((-1.0 + xPj/\
        xF[0])/(xPj - xTj)) - log(alpha**(NP*(MW[0] - Mstar))*(xF[0]*xPj - xPj*xTj)/\
        (-xF[0]*xPj + xF[0]*xTj) + 1))/((MW[0] - Mstar)*log(alpha))

    # new expression for normalized flow rate
    # NOTE: not needed, solved below
    #loverf = LoverF.xreplace({NT: nt_closed})

    # Define the constraint equation with which to solve NP. This is chosen such to 
    # minimize the number of ops in the derivatives (and thus np_closed).  Other, 
    # more verbose possibilities are commented out.
    #np_constraint = (xP[j]/sum(xP) - xPj).xreplace({NT: nt_closed})
    #np_constraint = (xP[j]- sum(xP)*xPj).xreplace({NT: nt_closed})
    #np_constraint = (xT[j]/sum(xT) - xTj).xreplace({NT: nt_closed})
    np_constraint = (xT[j] - sum(xT)*xTj).xreplace({NT: nt_closed})

    # get closed form approximation of NP via symbolic derivatives
    stat = _aggstatus(stat, "  order-{0} NP approximation".format(nporder), aggstat)
    d0NP = np_constraint.xreplace({NP: NP0})
    d1NP = diff(np_constraint, NP, 1).xreplace({NP: NP0})
    if 1 == nporder:
        np_closed = NP0 - d1NP / d0NP
    elif 2 == nporder:
        d2NP = diff(np_constraint, NP, 2).xreplace({NP: NP0})/2.0
        # taylor series polynomial coefficients, grouped by order
        # f(x) = ax**2 + bx + c
        a = d2NP
        b = d1NP - 2*NP0*d2NP
        c = d0NP - NP0*d1NP + NP0*NP0*d2NP
        # quadratic eq. (minus only)
        #np_closed = (-b - sqrt(b**2 - 4*a*c)) / (2*a)
        # However, we need to break up this expr as follows to prevent 
        # a floating point arithmetic bug if b**2 - 4*a*c is very close
        # to zero but happens to be negative.  LAME!!!
        np_2a = 2*a
        np_sqrt_base = b**2 - 4*a*c
        np_closed = (-NP_b - sqrt(NP_sqrt_base)) / (NP_2a)
    else:
        raise ValueError("nporder must be 1 or 2")

    # generate cse for writing out
    msg = "  minimizing ops by eliminating common sub-expressions"
    stat = _aggstatus(stat, msg, aggstat)
    exprstages = [Eq(NP_b, b), Eq(NP_2a, np_2a), 
                  # fix for floating point sqrt() error
                  Eq(NP_sqrt_base, np_sqrt_base), Eq(NP_sqrt_base, Abs(NP_sqrt_base)), 
                  Eq(NP1, np_closed), Eq(NT1, nt_closed).xreplace({NP: NP1})]
    cse_stages = cse(exprstages, numbered_symbols('n'))
    exprothers = [Eq(LpF, LoverF), Eq(PpF, ppf), Eq(TpF, tpf), 
                  Eq(SWUpF, SWUoverF), Eq(SWUpP, SWUoverP)] + \
                 [Eq(*z) for z in zip(xPi, xP)] + [Eq(*z) for z in zip(xTi, xT)]
    exprothers = [e.xreplace({NP: NP1, NT: NT1}) for e in exprothers]
    cse_others = cse(exprothers, numbered_symbols('g'))
    exprops = count_ops(exprstages + exprothers)
    cse_ops = count_ops(cse_stages + cse_others)
    msg = "    reduced {0} ops to {1}".format(exprops, cse_ops)
    stat = _aggstatus(stat, msg, aggstat)

    # create function body
    ccode, repnames = cse_to_c(*cse_stages, indent=6, debug=debug)
    ccode_others, repnames_others = cse_to_c(*cse_others, indent=6, debug=debug)
    ccode += ccode_others
    repnames |= repnames_others

    msg = "  completed in {0:.3G} s".format(time.time() - start_time)
    stat = _aggstatus(stat, msg, aggstat)
    if aggstat:
        print(stat)
    return ccode, repnames, stat
Beispiel #30
0
	def intersect(self, other, **flags):
		if not isinstance(other, Circle):
			raise BaryException()
		if sympy.count_ops(self.eqn()) > sympy.count_ops(other.eqn()):
			raise BaryException()
		return [Point(*sol) for sol in hsolve([self.eqn(), ((self._eqn - other._eqn) / (x + y + z)).simplify()], x, y, z, **flags)]
Beispiel #31
0
 def count_ops(self, visual=None):
     """wrapper for count_ops that returns the operation count."""
     from sympy import count_ops
     return count_ops(self, visual)
     return sum(a.count_ops(visual) for a in self.args)
def add_snap_expr_on_pareto_polyfit(pathdir, filename, math_expr, PA): 
    def unsnap_recur(expr, param_dict, unsnapped_param_dict):
        """Recursively transform each numerical value into a learnable parameter."""
        import sympy
        from sympy import Symbol
        if isinstance(expr, sympy.numbers.Float) or isinstance(expr, sympy.numbers.Integer) or isinstance(expr, sympy.numbers.Rational) or isinstance(expr, sympy.numbers.Pi):
            used_param_names = list(param_dict.keys()) + list(unsnapped_param_dict)
            unsnapped_param_name = get_next_available_key(used_param_names, "p", is_underscore=False)
            unsnapped_param_dict[unsnapped_param_name] = float(expr)
            unsnapped_expr = Symbol(unsnapped_param_name)
            return unsnapped_expr
        elif isinstance(expr, sympy.symbol.Symbol):
            return expr
        else:
            unsnapped_sub_expr_list = []
            for sub_expr in expr.args:
                unsnapped_sub_expr = unsnap_recur(sub_expr, param_dict, unsnapped_param_dict)
                unsnapped_sub_expr_list.append(unsnapped_sub_expr)
            return expr.func(*unsnapped_sub_expr_list)


    def get_next_available_key(iterable, key, midfix="", suffix="", is_underscore=True):
        """Get the next available key that does not collide with the keys in the dictionary."""
        if key + suffix not in iterable:
            return key + suffix
        else:
            i = 0
            underscore = "_" if is_underscore else ""
            while "{}{}{}{}{}".format(key, underscore, midfix, i, suffix) in iterable:
                i += 1
            new_key = "{}{}{}{}{}".format(key, underscore, midfix, i, suffix)
            return new_key

    eq = parse_expr(str(math_expr))
    expr = eq
    
    # Get the numbers appearing in the expression
    is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
    eq_numbers = [subexpression for subexpression in preorder_traversal(expr) if is_atomic_number(subexpression)]
       
    # Do zero snap one parameter at a time
    zero_snapped_expr = []
    for w in range(len(eq_numbers)):
        try:
            param_dict = {}
            unsnapped_param_dict = {'p':1}
            eq = unsnap_recur(expr,param_dict,unsnapped_param_dict)
            new_numbers = zeroSnap(eq_numbers,w+1)
            for kk in range(len(new_numbers)):
                eq_numbers[new_numbers[kk][0]] = new_numbers[kk][1]
            jj = 0
            for parm in unsnapped_param_dict:
                if parm!="p":
                    eq = eq.subs(parm, eq_numbers[jj])
                    jj = jj + 1
            zero_snapped_expr = zero_snapped_expr + [eq]
        except:
            continue

    for i in range(len(zero_snapped_expr)):
        try:
        
            # Calculate the error of the new, snapped expression
            snapped_error = get_symbolic_expr_error(pathdir,filename,str(zero_snapped_expr[i]))
            # Calculate the complexity of the new, snapped expression
            expr = simplify(powsimp(zero_snapped_expr[i]))
            for s in (expr.free_symbols):
                s = symbols(str(s), real = True)
            expr =  simplify(parse_expr(str(zero_snapped_expr[i]),locals()))
            expr = intify(expr)

            is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
            numbers_expr = [subexpression for subexpression in preorder_traversal(expr) if is_atomic_number(subexpression)]

            snapped_complexity = 0
            for j in numbers_expr:
                snapped_complexity = snapped_complexity + get_number_DL_snapped(float(j))

            # Add the complexity due to symbols
            n_variables = len(expr.free_symbols)
            n_operations = len(count_ops(expr,visual=True).free_symbols)
            if n_operations!=0 or n_variables!=0:
                snapped_complexity = snapped_complexity + (n_variables+n_operations)*np.log2((n_variables+n_operations))

            PA.add(Point(x=snapped_complexity, y=snapped_error, data=str(expr)))
        except:
            print("error")
            print("")
            continue
    return(PA)
        
        
        
            
Beispiel #33
0
def cudaComputeRHSSourceUnStaged(fname,outs,varnames,headers=[],sharedMemSz=48*1024, max_alloc_threads=1024):

    with open(fname, 'w') as ofile:
        ofile.write("// generated by Dendro-GR SymPyGR code gernation framework\n")
        ofile.write("//date: "+str(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))+"\n")
        ofile.write("\n")
        ofile.write("\n")
        for header in headers:
            ofile.write("#include \""+header+"\"\n")

        mi = [0, 1, 2, 4, 5, 8]
        midx = ['00', '01', '02', '11', '12', '22']

        ofile.write("\n")
        idx="[pp]"

        for var_id in range(0,len(varnames)):
            varOut=varnames[var_id]
            exp=outs[var_id]

            print("code generation for : "+varOut)

            num_e = 0
            lexp = []
            lname = []

            if type(exp) == list:
                num_e = num_e + len(exp)
                for j, ev in enumerate(exp):
                    lexp.append(ev)
                    lname.append(varOut+repr(j)+idx)
            elif type(exp) == sympy.Matrix:
                num_e = num_e + len(exp)
                for j, k in enumerate(mi):
                    lexp.append(exp[k])
                    lname.append(varOut+midx[j]+idx)
            else:
                num_e = num_e + 1
                lexp.append(exp)
                lname.append(varOut+idx)

            # print("cse tree build begin")
            ee_name = 'DENDRO_' #''.join(random.choice(string.ascii_uppercase) for _ in range(5))
            ee_syms = sympy.utilities.numbered_symbols(prefix=ee_name)
            _v = sympy.cse(lexp, symbols=ee_syms, optimizations='basic')

            # print("cse tree build completed")

            # bssn variables needed for rhs computation.
            bssnInputVars=[]

            # bssn variables output
            bssnOutputVars=[]

            # derivative variables needed for rhs computation
            derivVars=[]

            # staged bssn variables.
            bssnStagedVars=[]

            if type(exp) == list:
                for j, ev in enumerate(exp):
                    regm=re.findall(re.compile(r"([A-Z,a-z,0-9,_]*\[pp\])"),dendro.change_deriv_names(str(ev)))
                    for varDep in regm:
                        if varDep[0:-4] in varEnumToInputSymbol.keys():
                            bssnInputVars.append(varDep[0:-4])
                        elif varDep[0:-4] in varEnumToOutputSymbol.keys():
                            bssnOutputVars.append(varDep[0:-4])
                        elif varDep[0:-4] in varEnumToStagedSymbol:
                            bssnStagedVars.append(varDep[0:-4])
                        else:
                            for key,value in custom_functions.items():
                                if value in varDep[0:-4]:
                                    derivVars.append(varDep[0:-4])
                                    break


            elif type(exp)==sympy.Matrix:
                regm=re.findall(re.compile(r"([A-Z,a-z,0-9,_]*\[pp\])"),dendro.change_deriv_names(str(exp)))
                for varDep in regm:
                    if varDep[0:-4] in varEnumToInputSymbol.keys():
                        bssnInputVars.append(varDep[0:-4])
                    elif varDep[0:-4] in varEnumToOutputSymbol.keys():
                        bssnOutputVars.append(varDep[0:-4])
                    elif varDep[0:-4] in varEnumToStagedSymbol:
                        bssnStagedVars.append(varDep[0:-4])
                    else:
                        for key,value in custom_functions.items():
                            if value in varDep[0:-4]:
                                derivVars.append(varDep[0:-4])
                                break


            else:
                regm=re.findall(re.compile(r"([A-Z,a-z,0-9,_]*\[pp\])"),dendro.change_deriv_names(str(exp)))
                for varDep in regm:
                    if varDep[0:-4] in varEnumToInputSymbol.keys():
                        bssnInputVars.append(varDep[0:-4])
                    elif varDep[0:-4] in varEnumToOutputSymbol.keys():
                        bssnOutputVars.append(varDep[0:-4])
                    elif varDep[0:-4] in varEnumToStagedSymbol:
                        bssnStagedVars.append(varDep[0:-4])
                    else:
                        for key,value in custom_functions.items():
                            if value in varDep[0:-4]:
                                derivVars.append(varDep[0:-4])
                                break

            for lvar in lname:
                if lvar[0:-4] in varEnumToOutputSymbol.keys():
                    bssnOutputVars.append(lvar[0:-4])
                else:
                    bssnStagedVars.append(lvar[0:-4])
                    varEnumToStagedSymbol.append(lvar[0:-4]) 

            bssnInputVars=list(set(bssnInputVars))
            bssnOutputVars=list(set(bssnOutputVars))
            bssnStagedVars=list(set(bssnStagedVars))
            derivVars=list(set(derivVars))

            total_dep=len(bssnInputVars)+len(bssnStagedVars)+len(derivVars)+len(bssnOutputVars);
            total_shared_mem_vars=len(bssnInputVars)+len(bssnStagedVars)+len(derivVars);
            print("\n total_shared_mem_vars ="+str(total_shared_mem_vars)+"\n")
            # print("dependenacy computation completed\n")

            #calculating max  possible no of shared memory var allocations for each bssn var
            allocated_threads=max_alloc_threads
            if(total_shared_mem_vars>(sharedMemSz/(8*max_alloc_threads))):
                x=sharedMemSz /(8*total_shared_mem_vars)
                allocated_threads= (int)(math.pow(2,math.floor(math.log(x,2))))
            print("allocated_threads = "+str(allocated_threads)+"\n\n")


            ofile.write("/** computes rhs "+varOut+"*/\n")

            ofile.write("\n__device__ void "+varOut+"(int pp, double eta, double *"+ dev_var_in+",\n")
            ofile.write("\tdouble * "+dev_var_out+",\n")
            ofile.write("\t#include \"para_derivs_offsets.h\"\n,\n")
            ofile.write("\t#include \"para_staged.h\"\n){\n")

            # allocate memory for shared deriv variables.
            ofile.write("\t//allocate memory for shared deriv variables. \n")

            
            ofile.write("\n\n")
            ofile.write("\t //input vars  shared alloc begin\n")
            for var in bssnInputVars:
                ofile.write("\t__shared__ double "+var+"_shared[" + str(allocated_threads) +"];\n")
            ofile.write("\t //input vars shared alloc end\n")

            ofile.write("\t // staged vars shared alloc begin\n")
            for var in varEnumToStagedSymbol:
                if(var not in bssnStagedVars):
                    ofile.write("\t__shared__ double "+var+"_shared[" + str(allocated_threads) +"];\n")

            ofile.write("\t // staged vars shared alloc end\n")

            ofile.write("\t // deriv vars shared alloc begin\n")
            for var in derivVars:
                ofile.write("\t__shared__ double "+var+"_shared[" + str(allocated_threads) +"];\n")
            ofile.write("\t // deriv vars shared alloc end\n") 
            

            #ofile.write("\n\n\tint thread_id = blockIdx.x*"+str(allocated_threads)+" + threadIdx.x;\n")
            ofile.write("\tint t=threadIdx.x;\n")
            ofile.write("\t //input vars begin\n")
            for var in bssnInputVars:
                ofile.write("\t "+var+"_shared[t] = " +dev_var_in+"["+var+"Int+"+idx[1:-1]+"]"+";\n")
            ofile.write("\t //input vars end\n")

            ofile.write("\t // staged vars begin\n")
            for var in varEnumToStagedSymbol:
                if(var not in bssnStagedVars):
                    ofile.write("\t "+var+"_shared[t] = "+var+idx+";\n")

            ofile.write("\t // staged vars end\n")

            ofile.write("\t // deriv vars begin\n")
            for var in derivVars:
                ofile.write("\t "+var+"_shared[t] = " + var +idx+";\n")
            ofile.write("\t // deriv vars end\n")


            ofile.write("\t__syncthreads();\n")

            ofile.write("\t\t//load data from global to shared memory ends\n")

            ofile.write("\t\t      // Dendro: {{{ \n")
            ofile.write("\t\t      // Dendro: original ops: "+str(sympy.count_ops(lexp))+"\n")

            rops=0
            ofile.write("\t\t      // Dendro: printing temp variables\n")
            for (v1, v2) in _v[0]:
                ofile.write('\t\t   double ')
                ofile.write("\t\t"+change_to_shared_names(dendro.change_deriv_names(sympy.ccode(v2, assign_to=v1, user_functions=custom_functions)))+"\n")
                rops = rops + sympy.count_ops(v2)

            ofile.write("\t\t      // Dendro: printing variables\n\n")
            for i, e in enumerate(_v[1]):
                ofile.write("\t\t      "+change_to_shared_names(dendro.change_deriv_names(sympy.ccode(e, assign_to=lname[i], user_functions=custom_functions)))+"\n")
                rops = rops + sympy.count_ops(e)

            ofile.write("\t\t      // Dendro: reduced ops: "+str(rops)+"\n")
            ofile.write("\t\t      // Dendro: }}} \n")

            ofile.write("\t// store computed variables\n\n")
            ofile.write("} ")
Beispiel #34
0
def _mellin_transform(f, x, s_, integrator=_default_integrator, simplify=True):
    """ Backend function to compute mellin transforms. """
    from sympy import re, Max, Min, count_ops
    # We use a fresh dummy, because assumptions on s might drop conditions on
    # convergence of the integral.
    s = _dummy('s', 'mellin-transform', f)
    F = integrator(x**(s-1) * f, x)

    if not F.has(Integral):
        return _simplify(F.subs(s, s_), simplify), (-oo, oo), True

    if not F.is_Piecewise:
        raise IntegralTransformError('Mellin', f, 'could not compute integral')

    F, cond = F.args[0]
    if F.has(Integral):
        raise IntegralTransformError('Mellin', f, 'integral in unexpected form')

    def process_conds(cond):
        """
        Turn ``cond`` into a strip (a, b), and auxiliary conditions.
        """
        a = -oo
        b = oo
        aux = True
        conds = conjuncts(to_cnf(cond))
        t = Dummy('t', real=True)
        for c in conds:
            a_ = oo
            b_ = -oo
            aux_ = []
            for d in disjuncts(c):
                d_ = d.replace(re, lambda x: x.as_real_imag()[0]).subs(re(s), t)
                if not d.is_Relational or (d.rel_op != '<' and d.rel_op != '<=') \
                   or d_.has(s) or not d_.has(t):
                    aux_ += [d]
                    continue
                soln = _solve_inequality(d_, t)
                if not soln.is_Relational or \
                   (soln.rel_op != '<' and soln.rel_op != '<='):
                    aux_ += [d]
                    continue
                if soln.lhs == t:
                    b_ = Max(soln.rhs, b_)
                else:
                    a_ = Min(soln.lhs, a_)
            if a_ != oo and a_ != b:
                a = Max(a_, a)
            elif b_ != -oo and b_ != a:
                b = Min(b_, b)
            else:
                aux = And(aux, Or(*aux_))
        return a, b, aux

    conds = [process_conds(c) for c in disjuncts(cond)]
    conds = filter(lambda x: x[2] is not False, conds)
    conds.sort(key=lambda x: (x[0]-x[1], count_ops(x[2])))

    if not conds:
        raise IntegralTransformError('Mellin', f, 'no convergence found')

    a, b, aux = conds[0]
    return _simplify(F.subs(s, s_), simplify), (a, b), aux
Beispiel #35
0
 def count_ops(self, visual=None):
     """wrapper for count_ops that returns the operation count."""
     from sympy import count_ops
     return count_ops(self, visual)
def simplifyfunc(eqs, occurrences=2):
    import sympy

    variables = eqs.atoms(sympy.Symbol)

    # the number of time the variable occurs in the equations
    occurrences = 1

    solvar = []
    solsol = []
    while True:

        # the variables in each eq of eqs
        eqs_vars = []
        # the number of variables in each eq of eqs
        eqs_vars_freq = []
        for i in range(0, len(eqs)):
            symbols = eqs[i, 0].atoms(sympy.Symbol)
            eqs_vars.append(symbols)
            eqs_vars_freq.append(len(symbols))

        varstar = None
        for var in variables:
            # I compute the number of times the variable occurs in the equations.
            # I then find whether equations exist with only one occurrence of that form of variable i.e. K - L has only one form of K but K + K^2 - L has two forms
            numoc = 0
            besteq = None
            for i in range(len(eqs)):
                # number of occurrences
                if var in eqs_vars[i]:
                    numoc = numoc + 1

                    # check number of times occurs
                    eq = eqs[i]
                    # replacing K + K**2 - L with K + K**2 - 1.
                    # ISSUE: what if constants cancel i.e. K + K**2 - L + T? Then get wrong number.
                    for var2 in variables:
                        if var2 != var:
                            eq = eq.subs(var2, 1)
                    # ignore integer
                    numterms = sympy.count_ops(eq) - 1

                    # set the best equation for this term
                    if besteq is None:
                        besteq = i
                    elif besteqnumterms > numterms:
                        besteq = i
                    elif besteqnumterms == numterms and eqs_vars_freq[
                            besteq] > eqs_vars_freq[i]:
                        besteq = i

                    if besteq == i:
                        besteqnumterms = numterms
            if numoc <= occurrences:
                if varstar is None or numocstar < numoc or (
                        numocstar == numoc and besteqnumterms < numtermsstar):
                    if besteqnumterms == 1 or numoc == 1:
                        varstar = var
                        numocstar = numoc
                        besteqstar = besteq
                        numtermsstar = besteqnumterms

                        # make replacements for single eq immediately.
                        # if numocstar == 1:
                        #     break

        # if no sol:
        if varstar is None:
            break
        sol = sympy.solve(eqs[besteqstar], varstar)
        # remove row
        eqs.row_del(besteqstar)
        # substitute out other instances of variable
        for i in range(len(eqs)):
            eqs[i, 0] = eqs[i, 0].subs(varstar, sol)

        variables.remove(varstar)

        solvar.append(str(varstar))
        if len(sol) == 1:
            sol = sol[0]
        solsol.append(sol)

    return (eqs, solvar, solsol)
 def count(val):
     return count_ops(val, visual=True)
 def count(val):
     return count_ops(val, visual=False)
def run_bf_polyfit(pathdir,pathdir_transformed,filename,BF_try_time,BF_ops_file_type, PA, polyfit_deg=4, output_type=""):
    
#############################################################################################################################
    
    # run BF on the data (+)
    print("Checking for brute force + \n")
    brute_force(pathdir_transformed,filename,BF_try_time,BF_ops_file_type,"+")
    
    try:
        # load the BF output data
        bf_all_output = np.loadtxt("results.dat", dtype="str")
        express = bf_all_output[:,2]
        prefactors = bf_all_output[:,1]
        prefactors = [str(i) for i in prefactors]
        
        # Calculate the complexity of the bf expression the same way as for gradient descent case
        complexity = []
        errors = []
        eqns = []
        for i in range(len(prefactors)):
            try:
                if output_type=="":
                    eqn = prefactors[i] + "+" + RPN_to_eq(express[i])
                elif output_type=="acos":
                    eqn = "cos(" + prefactors[i] + "+" + RPN_to_eq(express[i]) + ")"
                elif output_type=="asin":
                    eqn = "sin(" + prefactors[i] + "+" + RPN_to_eq(express[i]) + ")"
                elif output_type=="atan":
                    eqn = "tan(" + prefactors[i] + "+" + RPN_to_eq(express[i]) + ")"
                elif output_type=="cos":
                    eqn = "acos(" + prefactors[i] + "+" + RPN_to_eq(express[i]) + ")"
                elif output_type=="exp":
                    eqn = "log(" + prefactors[i] + "+" + RPN_to_eq(express[i]) + ")"
                elif output_type=="inverse":
                    eqn = "1/(" + prefactors[i] + "+" + RPN_to_eq(express[i]) + ")"
                elif output_type=="log":
                    eqn = "exp(" + prefactors[i] + "+" + RPN_to_eq(express[i]) + ")"
                elif output_type=="sin":
                    eqn = "acos(" + prefactors[i] + "+" + RPN_to_eq(express[i]) + ")"
                elif output_type=="sqrt":
                    eqn = "(" + prefactors[i] + "+" + RPN_to_eq(express[i]) + ")**2"
                elif output_type=="squared":
                    eqn = "sqrt(" + prefactors[i] + "+" + RPN_to_eq(express[i]) + ")"
                elif output_type=="tan":
                    eqn = "atan(" + prefactors[i] + "+" + RPN_to_eq(express[i]) + ")"
                
                eqns = eqns + [eqn]
                errors = errors + [get_symbolic_expr_error(pathdir,filename,eqn)]
                expr = parse_expr(eqn)
                is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
                numbers_expr = [subexpression for subexpression in preorder_traversal(expr) if is_atomic_number(subexpression)]
                compl = 0
                for j in numbers_expr:
                    try:
                        compl = compl + get_number_DL(float(j))
                    except:
                        compl = compl + 1000000

                # Add the complexity due to symbols
                n_variables = len(expr.free_symbols)
                n_operations = len(count_ops(expr,visual=True).free_symbols)
                if n_operations!=0 or n_variables!=0:
                    compl = compl + (n_variables+n_operations)*np.log2((n_variables+n_operations))

                complexity = complexity + [compl]
            except:
                continue

        for i in range(len(complexity)):
            PA.add(Point(x=complexity[i], y=errors[i], data=eqns[i]))

        # run gradient descent of BF output parameters and add the results to the Pareto plot
        for i in range(len(express)):
            try:
                bf_gd_update = RPN_to_pytorch(pathdir+filename,eqns[i])
                PA.add(Point(x=bf_gd_update[1],y=bf_gd_update[0],data=bf_gd_update[2]))
            except:
                continue
    except:
        pass

#############################################################################################################################
    # run BF on the data (*)
    print("Checking for brute force * \n")
    brute_force(pathdir_transformed,filename,BF_try_time,BF_ops_file_type,"*")

    try:
        # load the BF output data
        bf_all_output = np.loadtxt("results.dat", dtype="str")
        express = bf_all_output[:,2]
        prefactors = bf_all_output[:,1]
        prefactors = [str(i) for i in prefactors]
        
        # Calculate the complexity of the bf expression the same way as for gradient descent case
        complexity = []
        errors = []
        eqns = []
        for i in range(len(prefactors)):
            try:
                if output_type=="":
                    eqn = prefactors[i] + "*" + RPN_to_eq(express[i])
                elif output_type=="acos":
                    eqn = "cos(" + prefactors[i] + "*" + RPN_to_eq(express[i]) + ")"
                elif output_type=="asin":
                    eqn = "sin(" + prefactors[i] + "*" + RPN_to_eq(express[i]) + ")"
                elif output_type=="atan":
                    eqn = "tan(" + prefactors[i] + "*" + RPN_to_eq(express[i]) + ")"
                elif output_type=="cos":
                    eqn = "acos(" + prefactors[i] + "*" + RPN_to_eq(express[i]) + ")"
                elif output_type=="exp":
                    eqn = "log(" + prefactors[i] + "*" + RPN_to_eq(express[i]) + ")"
                elif output_type=="inverse":
                    eqn = "1/(" + prefactors[i] + "*" + RPN_to_eq(express[i]) + ")"
                elif output_type=="log":
                    eqn = "exp(" + prefactors[i] + "*" + RPN_to_eq(express[i]) + ")"
                elif output_type=="sin":
                    eqn = "acos(" + prefactors[i] + "*" + RPN_to_eq(express[i]) + ")"
                elif output_type=="sqrt":
                    eqn = "(" + prefactors[i] + "*" + RPN_to_eq(express[i]) + ")**2"
                elif output_type=="squared":
                    eqn = "sqrt(" + prefactors[i] + "*" + RPN_to_eq(express[i]) + ")"
                elif output_type=="tan":
                    eqn = "atan(" + prefactors[i] + "*" + RPN_to_eq(express[i]) + ")"
                
                eqns = eqns + [eqn]
                errors = errors + [get_symbolic_expr_error(pathdir,filename,eqn)]
                expr = parse_expr(eqn)
                is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
                numbers_expr = [subexpression for subexpression in preorder_traversal(expr) if is_atomic_number(subexpression)]
                compl = 0
                for j in numbers_expr:
                    try:
                        compl = compl + get_number_DL(float(j))
                    except:
                        compl = compl + 1000000

                # Add the complexity due to symbols
                n_variables = len(expr.free_symbols)
                n_operations = len(count_ops(expr,visual=True).free_symbols)
                if n_operations!=0 or n_variables!=0:
                    compl = compl + (n_variables+n_operations)*np.log2((n_variables+n_operations))

                complexity = complexity + [compl]
            except:
                continue

        # add the BF output to the Pareto plot
        for i in range(len(complexity)):
            PA.add(Point(x=complexity[i], y=errors[i], data=eqns[i]))

        # run gradient descent of BF output parameters and add the results to the Pareto plot
        for i in range(len(express)):
            try:
                bf_gd_update = RPN_to_pytorch(pathdir+filename,eqns[i])
                PA.add(Point(x=bf_gd_update[1],y=bf_gd_update[0],data=bf_gd_update[2]))
            except:
                continue
    except:
        pass
#############################################################################################################################
    # run polyfit on the data
    print("Checking polyfit \n")
    polyfit_result = polyfit(polyfit_deg, pathdir_transformed+filename)
    eqn = str(polyfit_result[0])
    
    # Calculate the complexity of the polyfit expression the same way as for gradient descent case    
    if output_type=="":
        eqn = eqn
    elif output_type=="acos":
        eqn = "cos(" + eqn + ")"
    elif output_type=="asin":
        eqn = "sin(" + eqn + ")" 
    elif output_type=="atan":
        eqn = "tan(" + eqn + ")"
    elif output_type=="cos":
        eqn = "acos(" + eqn + ")"
    elif output_type=="exp":
        eqn = "log(" + eqn + ")"
    elif output_type=="inverse":
        eqn = "1/(" + eqn + ")"
    elif output_type=="log":
        eqn = "exp(" + eqn + ")"
    elif output_type=="sin":
        eqn = "acos(" + eqn + ")"
    elif output_type=="sqrt":
        eqn = "(" + eqn + ")**2"
    elif output_type=="squared":
        eqn = "sqrt(" + eqn + ")"
    elif output_type=="tan":
        eqn = "atan(" + eqn + ")"
    
    polyfit_err = get_symbolic_expr_error(pathdir,filename,eqn)
    expr = parse_expr(eqn)
    is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
    numbers_expr = [subexpression for subexpression in preorder_traversal(expr) if is_atomic_number(subexpression)]
    complexity = 0
    for j in numbers_expr:
        complexity = complexity + get_number_DL(float(j))
    try:
        # Add the complexity due to symbols
        n_variables = len(polyfit_result[0].free_symbols)
        n_operations = len(count_ops(polyfit_result[0],visual=True).free_symbols)
        if n_operations!=0 or n_variables!=0:
            complexity = complexity + (n_variables+n_operations)*np.log2((n_variables+n_operations))
    except:
        pass

    
    #run zero snap on polyfit output
    PA_poly = ParetoSet()
    PA_poly.add(Point(x=complexity, y=polyfit_err, data=str(eqn)))
    PA_poly = add_snap_expr_on_pareto_polyfit(pathdir, filename, str(eqn), PA_poly)
    
    
    for l in range(len(PA_poly.get_pareto_points())):
        PA.add(Point(PA_poly.get_pareto_points()[l][0],PA_poly.get_pareto_points()[l][1],PA_poly.get_pareto_points()[l][2]))

    print("Complexity  RMSE  Expression")
    for pareto_i in range(len(PA.get_pareto_points())):
        print(PA.get_pareto_points()[pareto_i])
    
    return PA
def add_bf_on_numbers_on_pareto(pathdir, filename, PA, math_expr):
    def unsnap_recur(expr, param_dict, unsnapped_param_dict):
        """Recursively transform each numerical value into a learnable parameter."""
        import sympy
        from sympy import Symbol
        if isinstance(expr, sympy.numbers.Float) or isinstance(
                expr, sympy.numbers.Integer) or isinstance(
                    expr, sympy.numbers.Rational) or isinstance(
                        expr, sympy.numbers.Pi):
            used_param_names = list(
                param_dict.keys()) + list(unsnapped_param_dict)
            unsnapped_param_name = get_next_available_key(used_param_names,
                                                          "p",
                                                          is_underscore=False)
            unsnapped_param_dict[unsnapped_param_name] = float(expr)
            unsnapped_expr = Symbol(unsnapped_param_name)
            return unsnapped_expr
        elif isinstance(expr, sympy.symbol.Symbol):
            return expr
        else:
            unsnapped_sub_expr_list = []
            for sub_expr in expr.args:
                unsnapped_sub_expr = unsnap_recur(sub_expr, param_dict,
                                                  unsnapped_param_dict)
                unsnapped_sub_expr_list.append(unsnapped_sub_expr)
            return expr.func(*unsnapped_sub_expr_list)

    def get_next_available_key(iterable,
                               key,
                               midfix="",
                               suffix="",
                               is_underscore=True):
        """Get the next available key that does not collide with the keys in the dictionary."""
        if key + suffix not in iterable:
            return key + suffix
        else:
            i = 0
            underscore = "_" if is_underscore else ""
            while "{}{}{}{}{}".format(key, underscore, midfix, i,
                                      suffix) in iterable:
                i += 1
            new_key = "{}{}{}{}{}".format(key, underscore, midfix, i, suffix)
            return new_key

    eq = parse_expr(str(math_expr))
    expr = eq
    # Get the numbers appearing in the expression
    is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
    eq_numbers = [
        subexpression for subexpression in preorder_traversal(expr)
        if is_atomic_number(subexpression)
    ]
    # Do bf on one parameter at a time
    bf_on_numbers_expr = []
    for w in range(len(eq_numbers)):
        try:
            param_dict = {}
            unsnapped_param_dict = {'p': 1}
            eq_ = unsnap_recur(expr, param_dict, unsnapped_param_dict)
            eq = eq_

            np.savetxt(pathdir + "number_for_bf_%s.txt" % w, [eq_numbers[w]])
            brute_force_number(pathdir, "number_for_bf_%s.txt" % w)
            # Load the predictions made by the bf code
            bf_numbers = np.loadtxt("results.dat", usecols=(1, ), dtype="str")
            new_numbers = copy.deepcopy(eq_numbers)

            # replace the number under consideration by all the proposed bf numbers
            for kk in range(len(bf_numbers)):
                eq = eq_
                new_numbers[w] = parse_expr(RPN_to_eq(bf_numbers[kk]))

                jj = 0
                for parm in unsnapped_param_dict:
                    if parm != "p":
                        eq = eq.subs(parm, new_numbers[jj])
                        jj = jj + 1

                bf_on_numbers_expr = bf_on_numbers_expr + [eq]
        except:
            continue

    for i in range(len(bf_on_numbers_expr)):
        try:
            # Calculate the error of the new, snapped expression
            snapped_error = get_symbolic_expr_error(pathdir, filename,
                                                    str(bf_on_numbers_expr[i]))
            # Calculate the complexity of the new, snapped expression
            expr = simplify(powsimp(bf_on_numbers_expr[i]))
            is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
            numbers_expr = [
                subexpression for subexpression in preorder_traversal(expr)
                if is_atomic_number(subexpression)
            ]

            snapped_complexity = 0
            for j in numbers_expr:
                snapped_complexity = snapped_complexity + get_number_DL_snapped(
                    float(j))
            # Add the complexity due to symbols
            n_variables = len(expr.free_symbols)
            n_operations = len(count_ops(expr, visual=True).free_symbols)
            if n_operations != 0 or n_variables != 0:
                snapped_complexity = snapped_complexity + (
                    n_variables + n_operations) * np.log2(
                        (n_variables + n_operations))

            PA.add(Point(x=snapped_complexity, y=snapped_error,
                         data=str(expr)))
        except:
            continue

    return (PA)
def add_snap_expr_on_pareto_polyfit(pathdir, filename, math_expr, PA):
    input_data = np.loadtxt(pathdir + filename)

    def unsnap_recur(expr, param_dict, unsnapped_param_dict):
        """Recursively transform each numerical value into a learnable parameter."""
        import sympy
        from sympy import Symbol
        if isinstance(expr, sympy.numbers.Float) or isinstance(
                expr, sympy.numbers.Integer) or isinstance(
                    expr, sympy.numbers.Rational) or isinstance(
                        expr, sympy.numbers.Pi):
            used_param_names = list(
                param_dict.keys()) + list(unsnapped_param_dict)
            unsnapped_param_name = get_next_available_key(used_param_names,
                                                          "p",
                                                          is_underscore=False)
            unsnapped_param_dict[unsnapped_param_name] = float(expr)
            unsnapped_expr = Symbol(unsnapped_param_name)
            return unsnapped_expr
        elif isinstance(expr, sympy.symbol.Symbol):
            return expr
        else:
            unsnapped_sub_expr_list = []
            for sub_expr in expr.args:
                unsnapped_sub_expr = unsnap_recur(sub_expr, param_dict,
                                                  unsnapped_param_dict)
                unsnapped_sub_expr_list.append(unsnapped_sub_expr)
            return expr.func(*unsnapped_sub_expr_list)

    def get_next_available_key(iterable,
                               key,
                               midfix="",
                               suffix="",
                               is_underscore=True):
        """Get the next available key that does not collide with the keys in the dictionary."""
        if key + suffix not in iterable:
            return key + suffix
        else:
            i = 0
            underscore = "_" if is_underscore else ""
            while "{}{}{}{}{}".format(key, underscore, midfix, i,
                                      suffix) in iterable:
                i += 1
            new_key = "{}{}{}{}{}".format(key, underscore, midfix, i, suffix)
            return new_key

    eq = parse_expr(str(math_expr))
    expr = eq

    #    # Get the numbers appearing in the expression
    #    is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
    #    eq_numbers = [subexpression for subexpression in preorder_traversal(expr) if is_atomic_number(subexpression)]
    #
    #    # Do zero snap one parameter at a time
    #    zero_snapped_expr = []
    #    for w in range(len(eq_numbers)):
    #        try:
    #            param_dict = {}
    #            unsnapped_param_dict = {'p':1}
    #            eq = unsnap_recur(expr,param_dict,unsnapped_param_dict)
    #            new_numbers = zeroSnap(eq_numbers,w+1)
    #            for kk in range(len(new_numbers)):
    #                eq_numbers[new_numbers[kk][0]] = new_numbers[kk][1]
    #            jj = 0
    #            for parm in unsnapped_param_dict:
    #                if parm!="p":
    #                    eq = eq.subs(parm, eq_numbers[jj])
    #                    jj = jj + 1
    #            zero_snapped_expr = zero_snapped_expr + [eq]
    #        except:
    #            continue

    # Get the numbers appearing in the expression
    is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
    eq_numbers = [
        subexpression for subexpression in preorder_traversal(expr)
        if is_atomic_number(subexpression)
    ]

    # Do integer snap one parameter at a time
    integer_snapped_expr = []
    for w in range(len(eq_numbers)):
        try:
            param_dict = {}
            unsnapped_param_dict = {'p': 1}
            eq = unsnap_recur(expr, param_dict, unsnapped_param_dict)
            del unsnapped_param_dict["p"]
            temp_unsnapped_param_dict = copy.deepcopy(unsnapped_param_dict)
            new_numbers = integerSnap(eq_numbers, w + 1)
            new_numbers = {"p" + str(k): v for k, v in new_numbers.items()}
            temp_unsnapped_param_dict.update(new_numbers)
            #for kk in range(len(new_numbers)):
            #    eq_numbers[new_numbers[kk][0]] = new_numbers[kk][1]
            new_eq = re.sub(r"(p\d*)", r"{\1}", str(eq))
            new_eq = new_eq.format_map(temp_unsnapped_param_dict)
            integer_snapped_expr = integer_snapped_expr + [parse_expr(new_eq)]
        except:
            continue

            # Get the numbers appearing in the expression

    is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
    eq_numbers = [
        subexpression for subexpression in preorder_traversal(expr)
        if is_atomic_number(subexpression)
    ]

    # Do rational snap one parameter at a time
    rational_snapped_expr = []
    for w in range(len(eq_numbers)):
        try:
            param_dict = {}
            unsnapped_param_dict = {'p': 1}
            eq = unsnap_recur(expr, param_dict, unsnapped_param_dict)
            del unsnapped_param_dict["p"]
            temp_unsnapped_param_dict = copy.deepcopy(unsnapped_param_dict)
            new_numbers = rationalSnap(eq_numbers, w + 1)
            new_numbers = {"p" + str(k): v for k, v in new_numbers.items()}
            temp_unsnapped_param_dict.update(new_numbers)
            #for kk in range(len(new_numbers)):
            #    eq_numbers_snap[new_numbers[kk][0]] = new_numbers[kk][1][1:3]
            new_eq = re.sub(r"(p\d*)", r"{\1}", str(eq))
            new_eq = new_eq.format_map(temp_unsnapped_param_dict)
            rational_snapped_expr = rational_snapped_expr + [
                parse_expr(new_eq)
            ]
        except:
            continue

    snapped_expr = np.append(integer_snapped_expr, rational_snapped_expr)
    #    snapped_expr = np.append(snapped_expr,rational_snapped_expr)

    integer_snapped_expr = snapped_expr

    for i in range(len(snapped_expr)):
        try:
            # Calculate the error of the new, snapped expression
            snapped_error = get_symbolic_expr_error(input_data,
                                                    str(snapped_expr[i]))
            # Calculate the complexity of the new, snapped expression
            expr = snapped_expr[i]
            for s in (expr.free_symbols):
                s = symbols(str(s), real=True)
            expr = parse_expr(str(snapped_expr[i]), locals())
            expr = intify(expr)
            is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
            numbers_expr = [
                subexpression for subexpression in preorder_traversal(expr)
                if is_atomic_number(subexpression)
            ]
            snapped_complexity = 0
            for j in numbers_expr:
                snapped_complexity = snapped_complexity + get_number_DL_snapped(
                    float(j))
            # Add the complexity due to symbols
            n_variables = len(expr.free_symbols)
            n_operations = len(count_ops(expr, visual=True).free_symbols)
            if n_operations != 0 or n_variables != 0:
                snapped_complexity = snapped_complexity + (
                    n_variables + n_operations) * np.log2(
                        (n_variables + n_operations))
            PA.add(Point(x=snapped_complexity, y=snapped_error,
                         data=str(expr)))
        except:
            continue

    return (PA)
Beispiel #42
0
 def count(val):
     return count_ops(val, visual=True)
Beispiel #43
0
 def count(val):
     return count_ops(val, visual=False)
Beispiel #44
0
 def count_ops(self, visual=None):
     """wrapper for count_ops that returns the operation count."""
     from sympy import count_ops
     return count_ops(self, visual)
Beispiel #45
0
def cgen_ncomp(ncomp=3, nporder=2, aggstat=False, debug=False):
    """Generates a C function for ncomp (int) number of components.
    The jth key component is always in the first position and the kth
    key component is always in the second.  The number of enrichment 
    stages (NP) is calculated via a taylor series approximation.  The
    order of this approximation may be set with nporder.  Only values
    of 1 or 2 are allowed. The aggstat argument determines whether the
    status messages should be aggreated and printed at the end or output
    as the function executes.
    """
    start_time = time.time()
    stat = _aggstatus('', "generating {0} component enrichment".format(ncomp), aggstat)
    r = range(0, ncomp)
    j = 0
    k = 1

    # setup-symbols
    alpha = Symbol('alpha', positive=True, real=True)
    LpF = Symbol('LpF', positive=True, real=True)
    PpF = Symbol('PpF', positive=True, real=True)
    TpF = Symbol('TpF', positive=True, real=True)
    SWUpF = Symbol('SWUpF', positive=True, real=True)
    SWUpP = Symbol('SWUpP', positive=True, real=True)
    NP = Symbol('NP', positive=True, real=True)   # Enrichment Stages
    NT = Symbol('NT', positive=True, real=True)   # De-enrichment Stages
    NP0 = Symbol('NP0', positive=True, real=True) # Enrichment Stages Initial Guess
    NT0 = Symbol('NT0', positive=True, real=True) # De-enrichment Stages Initial Guess
    NP1 = Symbol('NP1', positive=True, real=True) # Enrichment Stages Computed Value
    NT1 = Symbol('NT1', positive=True, real=True) # De-enrichment Stages Computed Value
    Mstar = Symbol('Mstar', positive=True, real=True)
    MW = [Symbol('MW[{0}]'.format(i), positive=True, real=True) for i in r]
    beta = [alpha**(Mstar - MWi) for MWi in MW]

    # np_closed helper terms
    NP_b = Symbol('NP_b', real=True)
    NP_2a = Symbol('NP_2a', real=True)
    NP_sqrt_base = Symbol('NP_sqrt_base', real=True)


    xF = [Symbol('xF[{0}]'.format(i), positive=True, real=True) for i in r]
    xPi = [Symbol('xP[{0}]'.format(i), positive=True, real=True) for i in r]
    xTi = [Symbol('xT[{0}]'.format(i), positive=True, real=True) for i in r]
    xPj = Symbol('xPj', positive=True, real=True)
    xFj = xF[j]
    xTj = Symbol('xTj', positive=True, real=True)
    ppf = (xFj - xTj)/(xPj - xTj)
    tpf = (xFj - xPj)/(xTj - xPj)

    xP = [(((xF[i]/ppf)*(beta[i]**(NT+1) - 1))/(beta[i]**(NT+1) - beta[i]**(-NP))) \
                                                                            for i in r]
    xT = [(((xF[i]/tpf)*(1 - beta[i]**(-NP)))/(beta[i]**(NT+1) - beta[i]**(-NP))) \
                                                                            for i in r]
    rfeed = xFj / xF[k]
    rprod = xPj / xP[k]
    rtail = xTj / xT[k]

    # setup constraint equations
    numer = [ppf*xP[i]*log(rprod) + tpf*xT[i]*log(rtail) - xF[i]*log(rfeed) for i in r]
    denom = [log(beta[j]) * ((beta[i] - 1.0)/(beta[i] + 1.0)) for i in r]
    LoverF = sum([n/d for n, d in zip(numer, denom)])
    SWUoverF = -1.0 * sum(numer)
    SWUoverP = SWUoverF / ppf

    prod_constraint = (xPj/xFj)*ppf - (beta[j]**(NT+1) - 1)/\
                      (beta[j]**(NT+1) - beta[j]**(-NP))
    tail_constraint = (xTj/xFj)*(sum(xT)) - (1 - beta[j]**(-NP))/\
                      (beta[j]**(NT+1) - beta[j]**(-NP))
    #xp_constraint = 1.0 - sum(xP)
    #xf_constraint = 1.0 - sum(xF)
    #xt_constraint = 1.0 - sum(xT)

    # This is NT(NP,...) and is correct!
    #nt_closed = solve(prod_constraint, NT)[0] 

    # However, this is NT(NP,...) rewritten (by hand) to minimize the number of NP 
    # and M* instances in the expression.  Luckily this is only depends on the key 
    # component and remains general no matter the number of components.
    nt_closed = (-MW[0]*log(alpha) + Mstar*log(alpha) + log(xTj) + log((-1.0 + xPj/\
        xF[0])/(xPj - xTj)) - log(alpha**(NP*(MW[0] - Mstar))*(xF[0]*xPj - xPj*xTj)/\
        (-xF[0]*xPj + xF[0]*xTj) + 1))/((MW[0] - Mstar)*log(alpha))

    # new expression for normalized flow rate
    # NOTE: not needed, solved below
    #loverf = LoverF.xreplace({NT: nt_closed})

    # Define the constraint equation with which to solve NP. This is chosen such to 
    # minimize the number of ops in the derivatives (and thus np_closed).  Other, 
    # more verbose possibilities are commented out.
    #np_constraint = (xP[j]/sum(xP) - xPj).xreplace({NT: nt_closed})
    #np_constraint = (xP[j]- sum(xP)*xPj).xreplace({NT: nt_closed})
    #np_constraint = (xT[j]/sum(xT) - xTj).xreplace({NT: nt_closed})
    np_constraint = (xT[j] - sum(xT)*xTj).xreplace({NT: nt_closed})

    # get closed form approximation of NP via symbolic derivatives
    stat = _aggstatus(stat, "  order-{0} NP approximation".format(nporder), aggstat)
    d0NP = np_constraint.xreplace({NP: NP0})
    d1NP = diff(np_constraint, NP, 1).xreplace({NP: NP0})
    if 1 == nporder:
        np_closed = NP0 - d1NP / d0NP
    elif 2 == nporder:
        d2NP = diff(np_constraint, NP, 2).xreplace({NP: NP0})/2.0
        # taylor series polynomial coefficients, grouped by order
        # f(x) = ax**2 + bx + c
        a = d2NP
        b = d1NP - 2*NP0*d2NP
        c = d0NP - NP0*d1NP + NP0*NP0*d2NP
        # quadratic eq. (minus only)
        #np_closed = (-b - sqrt(b**2 - 4*a*c)) / (2*a)
        # However, we need to break up this expr as follows to prevent 
        # a floating point arithmetic bug if b**2 - 4*a*c is very close
        # to zero but happens to be negative.  LAME!!!
        np_2a = 2*a
        np_sqrt_base = b**2 - 4*a*c
        np_closed = (-NP_b - sqrt(NP_sqrt_base)) / (NP_2a)
    else:
        raise ValueError("nporder must be 1 or 2")

    # generate cse for writing out
    msg = "  minimizing ops by eliminating common sub-expressions"
    stat = _aggstatus(stat, msg, aggstat)
    exprstages = [Eq(NP_b, b), Eq(NP_2a, np_2a), 
                  # fix for floating point sqrt() error
                  Eq(NP_sqrt_base, np_sqrt_base), Eq(NP_sqrt_base, Abs(NP_sqrt_base)), 
                  Eq(NP1, np_closed), Eq(NT1, nt_closed).xreplace({NP: NP1})]
    cse_stages = cse(exprstages, numbered_symbols('n'))
    exprothers = [Eq(LpF, LoverF), Eq(PpF, ppf), Eq(TpF, tpf), 
                  Eq(SWUpF, SWUoverF), Eq(SWUpP, SWUoverP)] + \
                 [Eq(*z) for z in zip(xPi, xP)] + [Eq(*z) for z in zip(xTi, xT)]
    exprothers = [e.xreplace({NP: NP1, NT: NT1}) for e in exprothers]
    cse_others = cse(exprothers, numbered_symbols('g'))
    exprops = count_ops(exprstages + exprothers)
    cse_ops = count_ops(cse_stages + cse_others)
    msg = "    reduced {0} ops to {1}".format(exprops, cse_ops)
    stat = _aggstatus(stat, msg, aggstat)

    # create function body
    ccode, repnames = cse_to_c(*cse_stages, indent=6, debug=debug)
    ccode_others, repnames_others = cse_to_c(*cse_others, indent=6, debug=debug)
    ccode += ccode_others
    repnames |= repnames_others

    msg = "  completed in {0:.3G} s".format(time.time() - start_time)
    stat = _aggstatus(stat, msg, aggstat)
    if aggstat:
        print(stat)
    return ccode, repnames, stat
Beispiel #46
0
from sympy import simplify, cos, sin, trigsimp, cancel
from sympy import sqrt, count_ops, oo, symbols, log
from sympy.abc import x, y

expr = (2 * x + 3 * x**2) / (4 * x * sin(y)**2 + 2 * x * cos(y)**2)
expr
simplify(expr)

trigsimp(expr)
cancel(_)

root = 4 / (sqrt(2) + 3)
simplify(root, ratio=1) == root
count_ops(simplify(root, ratio=oo)) > count_ops(root)
x, y = symbols('x y', positive=True)
expr2 = log(x) + log(y) + log(x) * log(1 / y)

expr3 = simplify(expr2)
expr3
count_ops(expr2)
count_ops(expr3)
print(count_ops(expr2, visual=True))
print(count_ops(expr3, visual=True))
def add_snap_expr_on_pareto(pathdir, filename, math_expr, PA, DR_file=""):
    def unsnap_recur(expr, param_dict, unsnapped_param_dict):
        """Recursively transform each numerical value into a learnable parameter."""
        import sympy
        from sympy import Symbol
        if isinstance(expr, sympy.numbers.Float) or isinstance(
                expr, sympy.numbers.Integer) or isinstance(
                    expr, sympy.numbers.Rational) or isinstance(
                        expr, sympy.numbers.Pi):
            used_param_names = list(
                param_dict.keys()) + list(unsnapped_param_dict)
            unsnapped_param_name = get_next_available_key(used_param_names,
                                                          "p",
                                                          is_underscore=False)
            unsnapped_param_dict[unsnapped_param_name] = float(expr)
            unsnapped_expr = Symbol(unsnapped_param_name)
            return unsnapped_expr
        elif isinstance(expr, sympy.symbol.Symbol):
            return expr
        else:
            unsnapped_sub_expr_list = []
            for sub_expr in expr.args:
                unsnapped_sub_expr = unsnap_recur(sub_expr, param_dict,
                                                  unsnapped_param_dict)
                unsnapped_sub_expr_list.append(unsnapped_sub_expr)
            return expr.func(*unsnapped_sub_expr_list)

    def get_next_available_key(iterable,
                               key,
                               midfix="",
                               suffix="",
                               is_underscore=True):
        """Get the next available key that does not collide with the keys in the dictionary."""
        if key + suffix not in iterable:
            return key + suffix
        else:
            i = 0
            underscore = "_" if is_underscore else ""
            while "{}{}{}{}{}".format(key, underscore, midfix, i,
                                      suffix) in iterable:
                i += 1
            new_key = "{}{}{}{}{}".format(key, underscore, midfix, i, suffix)
            return new_key

    eq = parse_expr(str(math_expr))
    expr = eq

    # Get the numbers appearing in the expression
    is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
    eq_numbers = [
        subexpression for subexpression in preorder_traversal(expr)
        if is_atomic_number(subexpression)
    ]

    # Do integer snap one parameter at a time
    integer_snapped_expr = []
    for w in range(len(eq_numbers)):
        try:
            param_dict = {}
            unsnapped_param_dict = {'p': 1}
            eq = unsnap_recur(expr, param_dict, unsnapped_param_dict)
            new_numbers = integerSnap(eq_numbers, w + 1)
            for kk in range(len(new_numbers)):
                eq_numbers[new_numbers[kk][0]] = new_numbers[kk][1]
            jj = 0
            for parm in unsnapped_param_dict:
                if parm != "p":
                    eq = eq.subs(parm, eq_numbers[jj])
                    jj = jj + 1
            integer_snapped_expr = integer_snapped_expr + [eq]
        except:
            continue

#    # Get the numbers appearing in the expression
#    is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
#    eq_numbers = [subexpression for subexpression in preorder_traversal(expr) if is_atomic_number(subexpression)]
#
#    # Do zero snap one parameter at a time
#    zero_snapped_expr = []
#    for w in range(len(eq_numbers)):
#        try:
#            param_dict = {}
#            unsnapped_param_dict = {'p':1}
#            eq = unsnap_recur(expr,param_dict,unsnapped_param_dict)
#            new_numbers = zeroSnap(eq_numbers,w+1)
#            for kk in range(len(new_numbers)):
#                eq_numbers[new_numbers[kk][0]] = new_numbers[kk][1]
#            jj = 0
#            for parm in unsnapped_param_dict:
#                if parm!="p":
#                    eq = eq.subs(parm, eq_numbers[jj])
#                    jj = jj + 1
#            zero_snapped_expr = zero_snapped_expr + [eq]
#        except:
#            continue

# Get the numbers appearing in the expression
    is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
    eq_numbers = [
        subexpression for subexpression in preorder_traversal(expr)
        if is_atomic_number(subexpression)
    ]

    # Do rational snap one parameter at a time
    rational_snapped_expr = []
    for w in range(len(eq_numbers)):
        try:
            eq_numbers_snap = copy.deepcopy(eq_numbers)
            param_dict = {}
            unsnapped_param_dict = {'p': 1}
            eq = unsnap_recur(expr, param_dict, unsnapped_param_dict)
            new_numbers = rationalSnap(eq_numbers, w + 1)
            for kk in range(len(new_numbers)):
                eq_numbers_snap[new_numbers[kk][0]] = new_numbers[kk][1][1:3]
            jj = 0
            for parm in unsnapped_param_dict:
                if parm != "p":

                    try:
                        eq = eq.subs(
                            parm,
                            Rational(eq_numbers_snap[jj][0],
                                     eq_numbers_snap[jj][1]))
                    except:
                        eq = eq.subs(parm, eq_numbers_snap[jj])
                    jj = jj + 1
            rational_snapped_expr = rational_snapped_expr + [eq]
        except:
            continue

    snapped_expr = np.append(integer_snapped_expr, rational_snapped_expr)
    #    snapped_expr = np.append(snapped_expr,rational_snapped_expr)

    for i in range(len(snapped_expr)):
        try:
            # Calculate the error of the new, snapped expression
            snapped_error = get_symbolic_expr_error(pathdir, filename,
                                                    str(snapped_expr[i]))
            # Calculate the complexity of the new, snapped expression
            expr = simplify(powsimp(snapped_expr[i]))
            for s in (expr.free_symbols):
                s = symbols(str(s), real=True)
            expr = simplify(parse_expr(str(snapped_expr[i]), locals()))
            #print("expr 0", expr)
            expr = intify(expr)
            is_atomic_number = lambda expr: expr.is_Atom and expr.is_number
            numbers_expr = [
                subexpression for subexpression in preorder_traversal(expr)
                if is_atomic_number(subexpression)
            ]

            if DR_file == "":
                snapped_complexity = 0
                for j in numbers_expr:
                    snapped_complexity = snapped_complexity + get_number_DL_snapped(
                        float(j))

                n_variables = len(expr.free_symbols)
                n_operations = len(count_ops(expr, visual=True).free_symbols)
                if n_operations != 0 or n_variables != 0:
                    snapped_complexity = snapped_complexity + (
                        n_variables + n_operations) * np.log2(
                            (n_variables + n_operations))

            # If a bf file is provided, replace the variables with the actual ones before calculating the complexity
            else:
                dr_data = np.loadtxt(DR_file, dtype="str", delimiter=",")

                expr = str(expr)
                old_vars = ["x%s" % k for k in range(len(dr_data) - 3)]
                for i_dr in range(len(old_vars)):
                    expr = expr.replace(old_vars[i_dr],
                                        "(" + dr_data[i_dr + 2] + ")")
                expr = "(" + dr_data[1] + ")*(" + expr + ")"

                expr = parse_expr(expr)
                for s in (expr.free_symbols):
                    s = symbols(str(s), real=True)
                expr = simplify(parse_expr(str(expr), locals()))
                #print("expr 1", expr)
                #expr = intify(expr)
                #print("expr 2", expr)
                snapped_complexity = 0
                for j in numbers_expr:
                    snapped_complexity = snapped_complexity + get_number_DL_snapped(
                        float(j))

                n_variables = len(expr.free_symbols)
                n_operations = len(count_ops(expr, visual=True).free_symbols)
                if n_operations != 0 or n_variables != 0:
                    snapped_complexity = snapped_complexity + (
                        n_variables + n_operations) * np.log2(
                            (n_variables + n_operations))

            PA.add(Point(x=snapped_complexity, y=snapped_error,
                         data=str(expr)))
        except:
            continue
    return (PA)