def genEval(self): text = " bool evaluate(\n" args=[] for name,v in self.variables: if v.is_Matrix: args.append(" const Eigen::MatrixXd & %s" % name) else: args.append(" double %s" % name) args.append(" bool evalF=true,bool evalJ=true") text += ",\n".join(args) + ") {\n" text += " if (evalF) {\n" (interm, expr) = cse(self.function,numbered_symbols("__x")); for dummy,exp in interm: text += " double %s = %s;\n" % (str(dummy),ccode(exp)) for i in range(self.function.rows): text += " F(%d) = %s;\n" % (i,ccode(expr[0][i])) text += " }\n" text += " if (evalJ) {\n" (interm, expr) = cse(self.J,numbered_symbols("__x")); for dummy,exp in interm: text += " double %s = %s;\n" % (str(dummy),ccode(exp)) for i in range(self.J.rows): for j in range(self.J.cols): text += " J(%d,%d) = %s;\n" % (i,j,ccode(expr[0][i,j])) text += " }\n" text += " return true;\n" text += " }\n" return text
def generate_avx(ex, vnames, idx): mi = [0, 1, 2, 4, 5, 8] midx = ['00', '01', '02', '11', '12', '22'] # total number of expressions # print("--------------------------------------------------------") num_e = 0 lexp = [] lname = [] for i, e in enumerate(ex): if type(e) == list: num_e = num_e + len(e) for j, ev in enumerate(e): lexp.append(ev) lname.append(vnames[i] + repr(j) + idx) elif type(e) == Matrix: num_e = num_e + len(e) for j, k in enumerate(mi): lexp.append(e[k]) lname.append(vnames[i] + midx[j] + idx) else: num_e = num_e + 1 lexp.append(e) lname.append(vnames[i] + idx) cse = construct_cse(ex, vnames, idx) _v = cse[0] print('// Dendro: {{{ ') print("// Dendro: original ops: %d " % (cse[1])) ee_name = 'DENDRO_' ee_syms = numbered_symbols(prefix=ee_name) print('// Dendro vectorized code: {{{') oper = {'mul': 'dmul', 'add': 'dadd', 'load': '*'} prevdefvars = set() for (v1, v2) in _v[0]: vv = numbered_symbols('v') vlist = [] gen_vector_code(v2, vv, vlist, oper, prevdefvars, idx) print(' double ' + repr(v1) + ' = ' + repr(vlist[0]) + ';') for i, e in enumerate(_v[1]): print("//--") vv = numbered_symbols('v') vlist = [] gen_vector_code(e, vv, vlist, oper, prevdefvars, idx) #st = ' ' + repr(lname[i]) + '[idx] = ' + repr(vlist[0]) + ';' st = ' ' + repr(lname[i]) + " = " + repr(vlist[0]) + ';' print(st.replace("'", "")) print('// Dendro vectorized code: }}} ')
def construct_cse(ex, vnames, idx): mi = [0, 1, 2, 4, 5, 8] midx = ['00', '01', '02', '11', '12', '22'] # total number of expressions # print("--------------------------------------------------------") num_e = 0 lexp = [] lname = [] for i, e in enumerate(ex): if type(e) == list: num_e = num_e + len(e) for j, ev in enumerate(e): lexp.append(ev) lname.append(vnames[i] + repr(j) + idx) elif type(e) == Matrix: num_e = num_e + len(e) for j, k in enumerate(mi): lexp.append(e[k]) lname.append(vnames[i] + midx[j] + idx) else: num_e = num_e + 1 lexp.append(e) lname.append(vnames[i] + idx) ee_name = 'DENDRO_' #''.join(random.choice(string.ascii_uppercase) for _ in range(5)) ee_syms = numbered_symbols(prefix=ee_name) _v = cse(lexp, symbols=ee_syms, optimizations='basic') return [_v, count_ops(lexp)]
def _linear_neq_order1_type3(match_): r""" System of n first-order nonconstant-coefficient linear homogeneous differential equations .. math:: X' = A(t) X where $X$ is the vector of $n$ dependent variables, $t$ is the dependent variable, $X'$ is the first order differential of $X$ with respect to $t$ and $A(t)$ is a $n \times n$ coefficient matrix. Let us define $B$ as antiderivative of coefficient matrix $A$: .. math:: B(t) = \int A(t) dt If the system of ODEs defined above is such that its antiderivative $B(t)$ commutes with $A(t)$ itself, then, the solution of the above system is given as: .. math:: X = \exp(B(t)) C where $C$ is the vector of constants. """ # Some parts of code is repeated, this needs to be taken care of # The constant vector obtained here can be done so in the match # function itself. eq = match_['eq'] func = match_['func'] fc = match_['func_coeff'] n = len(eq) t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] constants = numbered_symbols(prefix='C', cls=Symbol, start=1) # This needs to be modified in future so that fc is only of type Matrix M = -fc if type(fc) is Matrix else Matrix(n, n, lambda i,j:-fc[i,func[j],0]) Cvect = Matrix(list(next(constants) for _ in range(n))) # The code in if block will be removed when it is made sure # that the code works without the statements in if block. if "commutative_antiderivative" not in match_: B, is_commuting = _is_commutative_anti_derivative(M, t) # This course is subject to change if not is_commuting: return None else: B = match_['commutative_antiderivative'] sol_vector = B.exp() * Cvect # The expand_mul is added to handle the solutions so that # the exponential terms are collected properly. sol_vector = [collect(expand_mul(s), ordered(s.atoms(exp)), exact=True) for s in sol_vector] sol_dict = [Eq(func[i], sol_vector[i]) for i in range(n)] return sol_dict
def generate_cuda_code(ex,vname, arrIdx, idx): """ Generate the Cuda code by simplifying the expressions. """ mi = [0, 1, 2, 4, 5, 8] midx = ['0', '1','2', '3', '4', '5'] # total number of expressions # print("--------------------------------------------------------") num_e = 0 lexp = [] lname = [] for i, e in enumerate(ex): if type(e) == list: num_e = num_e + len(e) for j, ev in enumerate(e): lexp.append(ev) lname.append(vname+idx[:1]+arrIdx[i]+repr(j)+idx[1:]) elif type(e) == Matrix: num_e = num_e + len(e) for j, k in enumerate(mi): lexp.append(e[k]) lname.append(vname+idx[:1]+arrIdx[i]+midx[j]+idx[1:]) else: num_e = num_e + 1 lexp.append(e) lname.append(vname+idx[:1]+arrIdx[i]+idx[1:]) with open("bssneq.cu", 'w') as output_file: print_n_write('// Dendro: {{{ ', output_file) print_n_write('// Dendro: original ops: ' + str(count_ops(lexp)), output_file) ee_name = 'DENDRO_' ee_syms = numbered_symbols(prefix=ee_name) _v = cse(lexp, symbols=ee_syms, optimizations='basic') custom_functions = {'grad': 'grad', 'grad2': 'grad2', 'agrad': 'agrad', 'kograd': 'kograd'} rops=0 print_n_write('// Dendro: printing temp variables', output_file) for (v1, v2) in _v[0]: print_n_write('double ', output_file, isNewLineEnd=False) print_n_write(v2, output_file, assign_to=v1, user_functions=custom_functions, isCExp=True) rops = rops + count_ops(v2) print_n_write('\n// Dendro: printing variables', output_file) for i, e in enumerate(_v[1]): print_n_write("//--", output_file) print_n_write(e, output_file, assign_to=lname[i], user_functions=custom_functions, isCExp=True) rops = rops + count_ops(e) print_n_write('// Dendro: reduced ops: ' + str(rops), output_file) print_n_write('// Dendro: }}} ', output_file)
def iter_numbered_constants(self, start=1, prefix='C') -> Iterable[Symbol]: """ Returns an iterator of constants that do not occur in eq already. """ atom_set = self.eq.free_symbols func_set = self.eq.atoms(Function) if func_set: atom_set |= {Symbol(str(f.func)) for f in func_set} return numbered_symbols(start=start, prefix=prefix, exclude=atom_set)
def viete(f, roots=None, *gens, **args): """ Generate Viete's formulas for ``f``. Examples ======== >>> from sympy.polys.polyfuncs import viete >>> from sympy import symbols >>> x, a, b, c, r1, r2 = symbols('x,a:c,r1:3') >>> viete(a*x**2 + b*x + c, [r1, r2], x) [(r1 + r2, -b/a), (r1*r2, c/a)] """ allowed_flags(args, []) if isinstance(roots, Basic): gens, roots = (roots, ) + gens, None try: f, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('viete', 1, exc) if f.is_multivariate: raise MultivariatePolynomialError( "multivariate polynomials are not allowed") n = f.degree() if n < 1: raise ValueError( "can't derive Viete's formulas for a constant polynomial") if roots is None: roots = numbered_symbols('r', start=1) roots = take(roots, n) if n != len(roots): raise ValueError("required %s roots, got %s" % (n, len(roots))) lc, coeffs = f.LC(), f.all_coeffs() result, sign = [], -1 for i, coeff in enumerate(coeffs[1:]): poly = symmetric_poly(i + 1, roots) coeff = sign * (coeff / lc) result.append((poly, coeff)) sign = -sign return result
def viete(f, roots=None, *gens, **args): """ Generate Viete's formulas for ``f``. Examples ======== >>> from sympy.polys.polyfuncs import viete >>> from sympy import symbols >>> x, a, b, c, r1, r2 = symbols('x,a:c,r1:3') >>> viete(a*x**2 + b*x + c, [r1, r2], x) [(r1 + r2, -b/a), (r1*r2, c/a)] """ allowed_flags(args, []) if isinstance(roots, Basic): gens, roots = (roots,) + gens, None try: f, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('viete', 1, exc) if f.is_multivariate: raise MultivariatePolynomialError( "multivariate polynomials are not allowed") n = f.degree() if n < 1: raise ValueError( "can't derive Viete's formulas for a constant polynomial") if roots is None: roots = numbered_symbols('r', start=1) roots = take(roots, n) if n != len(roots): raise ValueError("required %s roots, got %s" % (n, len(roots))) lc, coeffs = f.LC(), f.all_coeffs() result, sign = [], -1 for i, coeff in enumerate(coeffs[1:]): poly = symmetric_poly(i + 1, roots) coeff = sign*(coeff/lc) result.append((poly, coeff)) sign = -sign return result
def _linear_neq_order1_type2(match_): r""" System of n first-order coefficient linear non-homogeneous differential equations .. math:: X' = A X + b(t) where $X$ is the vector of $n$ dependent variables, $t$ is the dependent variable, $X'$ is the first order differential of $X$ with respect to $t$, $A$ is a $n \times n$ constant coefficient matrix and $b(t)$ is the non-homogeneous term. The solution of the above system is: .. math:: X = e^{A t} ( \int e^{- A t} b \,dt + C) where $C$ is the vector of constants. """ eq = match_['eq'] func = match_['func'] fc = match_['func_coeff'] b = match_['rhs'] n = len(eq) t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] constants = numbered_symbols(prefix='C', cls=Symbol, start=1) # This needs to be modified in future so that fc is only of type Matrix M = -fc if type(fc) is Matrix else Matrix(n, n, lambda i, j: -fc[i, func[j], 0]) P, J = matrix_exp_jordan_form(M, t) P = simplify(P) Cvect = Matrix(list(next(constants) for _ in range(n))) sol_vector = P * J * ( (J.inv() * P.inv() * b).applyfunc(lambda x: Integral(x, t)) + Cvect) # sol_vector = sol_vector.applyfunc(_solsimp) # Removing the expand_mul can simplify the solutions of the ODEs # with symbolic coeffs. To be addressed in the future. sol_vector = [ collect(expand_mul(s), sol_vector.atoms(exp), exact=True) for s in sol_vector ] sol_dict = [Eq(func[i], sol_vector[i]) for i in range(n)] # sol_dict = [simpsol(eq) for eq in sol_dict] return sol_dict
def genEval(self): text = " bool evaluate(\n" args=[] for name,v,lD in self.variables: if isinstance(v, Matrix): args.append(" const Eigen::Matrix<double, %d, 1> & %s" % (v.rows, name)) else: args.append(" double %s" % name) args.append(" Eigen::Matrix<double, %d, 1> * F" % self.function.rows) for name,v,localDim in self.variables: if isinstance(v, Matrix): args.append(" Eigen::Matrix<double, %d, %d> * J%s" % (self.J.rows, localDim, name)) else: args.append(" Eigen::Matrix<double, %d, 1> * J%s" % (self.J.rows, name)) text += ",\n".join(args) + ") {\n" text += " if (F) {\n" (interm, expr) = cse(self.function,numbered_symbols("__x")); for dummy,exp in interm: text += " double %s = %s;\n" % (str(dummy),ccode(exp)) for i in range(self.function.rows): text += " (*F)(%d) = %s;\n" % (i,ccode(expr[0][i])) text += " }\n" text += " if (%s) {\n" % " && ".join([ "J" + name for name,v,lD in self.variables ]) (interm, expr) = cse(self.J,numbered_symbols("__x")); for dummy,exp in interm: text += " double %s = %s;\n" % (str(dummy),ccode(exp)) colBase = 0; for name,v,localDim in self.variables: for i in range(self.J.rows): for j in range(0, localDim): text += " (*J%s)(%d,%d) = %s;\n" % (name, i,j,ccode(expr[0][i,colBase + j])) colBase+=localDim text += " }\n" text += " return true;\n" text += " }\n" return text
def _linear_neq_order1_type1(match_): r""" System of n first-order constant-coefficient linear homogeneous differential equations .. math:: y'_k = a_{k1} y_1 + a_{k2} y_2 +...+ a_{kn} y_n; k = 1,2,...,n or that can be written as `\vec{y'} = A . \vec{y}` where `\vec{y}` is matrix of `y_k` for `k = 1,2,...n` and `A` is a `n \times n` matrix. These equations are equivalent to a first order homogeneous linear differential equation. The system of ODEs described above has a unique solution, namely: .. math :: \vec{y} = \exp(A t) C where $t$ is the independent variable and $C$ is a vector of n constants. These are constants from the integration. """ eq = match_['eq'] func = match_['func'] fc = match_['func_coeff'] n = len(eq) t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] constants = numbered_symbols(prefix='C', cls=Symbol, start=1) # This needs to be modified in future so that fc is only of type Matrix M = -fc if type(fc) is Matrix else Matrix(n, n, lambda i, j: -fc[i, func[j], 0]) P, J = matrix_exp_jordan_form(M, t) P = simplify(P) Cvect = Matrix(list(next(constants) for _ in range(n))) sol_vector = P * (J * Cvect) gens = sol_vector.atoms(exp) sol_vector = [collect(s, ordered(gens), exact=True) for s in sol_vector] sol_dict = [Eq(func[i], sol_vector[i]) for i in range(n)] return sol_dict
def _get_roots(cls, method, poly, radicals): """Return postprocessed roots of specified kind. """ if not poly.is_univariate: raise PolynomialError("only univariate polynomials are allowed") # get rid of gen and it's free symbol d = Dummy() poly = poly.subs(poly.gen, d) x = symbols('x') # see what others are left and select x or a numbered x # that doesn't clash free_names = {str(i) for i in poly.free_symbols} for x in chain((symbols('x'),), numbered_symbols('x')): if x.name not in free_names: poly = poly.xreplace({d: x}) break coeff, poly = cls._preprocess_roots(poly) roots = [] for root in getattr(cls, method)(poly): roots.append(coeff*cls._postprocess_root(root, radicals)) return roots
def apart_undetermined_coeffs(P, Q): """Partial fractions via method of undetermined coefficients. """ X = numbered_symbols(cls=Dummy) partial, symbols = [], [] _, factors = Q.factor_list() for f, k in factors: n, q = f.degree(), Q for i in range(1, k + 1): coeffs, q = take(X, n), q.quo(f) partial.append((coeffs, q, f, i)) symbols.extend(coeffs) dom = Q.get_domain().inject(*symbols) F = Poly(0, Q.gen, domain=dom) for i, (coeffs, q, f, k) in enumerate(partial): h = Poly(coeffs, Q.gen, domain=dom) partial[i] = (h, f, k) q = q.set_domain(dom) F += h * q system, result = [], S.Zero for (k,), coeff in F.terms(): system.append(coeff - P.nth(k)) from sympy.solvers import solve solution = solve(system, symbols) for h, f, k in partial: h = h.as_expr().subs(solution) result += h / f.as_expr() ** k return result
def apart_undetermined_coeffs(P, Q): """Partial fractions via method of undetermined coefficients. """ X = numbered_symbols(cls=Dummy) partial, symbols = [], [] _, factors = Q.factor_list() for f, k in factors: n, q = f.degree(), Q for i in xrange(1, k + 1): coeffs, q = take(X, n), q.quo(f) partial.append((coeffs, q, f, i)) symbols.extend(coeffs) dom = Q.get_domain().inject(*symbols) F = Poly(0, Q.gen, domain=dom) for i, (coeffs, q, f, k) in enumerate(partial): h = Poly(coeffs, Q.gen, domain=dom) partial[i] = (h, f, k) q = q.set_domain(dom) F += h * q system, result = [], S(0) for (k,), coeff in F.terms(): system.append(coeff - P.nth(k)) from sympy.solvers import solve solution = solve(system, symbols) for h, f, k in partial: h = h.as_expr().subs(solution) result += h / f.as_expr() ** k return result
def generate_cpu(ex, vnames, idx): """ Generate the C++ code by simplifying the expressions. """ # print(ex) mi = [0, 1, 2, 4, 5, 8] midx = ['00', '01', '02', '11', '12', '22'] # total number of expressions # print("--------------------------------------------------------") num_e = 0 lexp = [] lname = [] for i, e in enumerate(ex): if type(e) == list: num_e = num_e + len(e) for j, ev in enumerate(e): lexp.append(ev) lname.append(vnames[i] + repr(j) + idx) elif type(e) == Matrix: num_e = num_e + len(e) for j, k in enumerate(mi): lexp.append(e[k]) lname.append(vnames[i] + midx[j] + idx) else: num_e = num_e + 1 lexp.append(e) lname.append(vnames[i] + idx) cse = construct_cse(ex, vnames, idx) _v = cse[0] print("// Dendro: {{{ ") print("// Dendro: original ops: %d " % (cse[1])) ee_name = 'DENDRO_' ee_syms = numbered_symbols(prefix=ee_name) custom_functions = { 'grad': 'grad', 'grad2': 'grad2', 'agrad': 'agrad', 'kograd': 'kograd' } rops = 0 print('// Dendro: printing temp variables') for (v1, v2) in _v[0]: print('double ', end='') print( change_deriv_names( ccode(v2, assign_to=v1, user_functions=custom_functions))) rops = rops + count_ops(v2) print() print('// Dendro: printing variables') for i, e in enumerate(_v[1]): print("//--") print( change_deriv_names( ccode(e, assign_to=lname[i], user_functions=custom_functions))) rops = rops + count_ops(e) print('// Dendro: reduced ops: %d' % (rops)) print('// Dendro: }}} ')
def minimal_polynomial(ex, x=None, **args): """ Computes the minimal polynomial of an algebraic number. Parameters ========== ex : algebraic number expression x : indipendent variable of the minimal polynomial Options ======= compose : if ``True`` _minpoly1`` is used, else the ``groebner`` algorithm polys : if ``True`` returns a ``Poly`` object Notes ===== By default ``compose=True``, the minimal polynomial of the subexpressions of ``ex`` are computed, then the arithmetic operations on them are performed using the resultant and factorization. If ``compose=False``, a bottom-up algorithm is used with ``groebner``. The default algorithm stalls less frequently. Examples ======== >>> from sympy import minimal_polynomial, sqrt, solve >>> from sympy.abc import x >>> minimal_polynomial(sqrt(2), x) x**2 - 2 >>> minimal_polynomial(sqrt(2) + sqrt(3), x) x**4 - 10*x**2 + 1 >>> minimal_polynomial(solve(x**3 + x + 3)[0], x) x**3 + x + 3 """ from sympy.polys.polytools import degree from sympy.core.function import expand_multinomial from sympy.core.basic import preorder_traversal compose = args.get('compose', True) polys = args.get('polys', False) ex = sympify(ex) for expr in preorder_traversal(ex): if expr.is_AlgebraicNumber: compose = False break if ex.is_AlgebraicNumber: compose = False if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly if compose: result = _minpoly1(ex, x) result = result.primitive()[1] c = result.coeff(x**degree(result, x)) if c < 0: result = expand_mul(-result) c = -c return cls(result, x, field=True) if polys else result generator = numbered_symbols('a', cls=Dummy) mapping, symbols, replace = {}, {}, [] def update_mapping(ex, exp, base=None): a = generator.next() symbols[ex] = a if base is not None: mapping[ex] = a**exp + base else: mapping[ex] = exp.as_expr(a) return a def bottom_up_scan(ex): if ex.is_Atom: if ex is S.ImaginaryUnit: if ex not in mapping: return update_mapping(ex, 2, 1) else: return symbols[ex] elif ex.is_Rational: return ex elif ex.is_Add: return Add(*[ bottom_up_scan(g) for g in ex.args ]) elif ex.is_Mul: return Mul(*[ bottom_up_scan(g) for g in ex.args ]) elif ex.is_Pow: if ex.exp.is_Rational: if ex.exp < 0 and ex.base.is_Add: coeff, terms = ex.base.as_coeff_add() elt, _ = primitive_element(terms, polys=True) alg = ex.base - coeff # XXX: turn this into eval() inverse = invert(elt.gen + coeff, elt).as_expr() base = inverse.subs(elt.gen, alg).expand() if ex.exp == -1: return bottom_up_scan(base) else: ex = base**(-ex.exp) if not ex.exp.is_Integer: base, exp = ( ex.base**ex.exp.p).expand(), Rational(1, ex.exp.q) else: base, exp = ex.base, ex.exp base = bottom_up_scan(base) expr = base**exp if expr not in mapping: return update_mapping(expr, 1/exp, -base) else: return symbols[expr] elif ex.is_AlgebraicNumber: if ex.root not in mapping: return update_mapping(ex.root, ex.minpoly) else: return symbols[ex.root] raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) def simpler_inverse(ex): """ Returns True if it is more likely that the minimal polynomial algorithm works better with the inverse """ if ex.is_Pow: if (1/ex.exp).is_integer and ex.exp < 0: if ex.base.is_Add: return True if ex.is_Mul: hit = True a = [] for p in ex.args: if p.is_Add: return False if p.is_Pow: if p.base.is_Add and p.exp > 0: return False if hit: return True return False inverted = False ex = expand_multinomial(ex) if ex.is_AlgebraicNumber: if not polys: return ex.minpoly.as_expr(x) else: return ex.minpoly.replace(x) elif ex.is_Rational: result = ex.q*x - ex.p else: inverted = simpler_inverse(ex) if inverted: ex = ex**-1 res = None if ex.is_Pow and (1/ex.exp).is_Integer: n = 1/ex.exp res = _minimal_polynomial_sq(ex.base, n, x) elif _is_sum_surds(ex): res = _minimal_polynomial_sq(ex, S.One, x) if res is not None: result = res if res is None: bus = bottom_up_scan(ex) F = [x - bus] + mapping.values() G = groebner(F, symbols.values() + [x], order='lex') _, factors = factor_list(G[-1]) # by construction G[-1] has root `ex` result = _choose_factor(factors, x, ex) if inverted: result = _invertx(result, x) if result.coeff(x**degree(result, x)) < 0: result = expand_mul(-result) if polys: return cls(result, x, field=True) else: return result
def primitive_element(extension, x=None, **args): """Construct a common number field for all extensions. """ if not extension: raise ValueError("can't compute primitive element for empty extension") if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly if not args.get('ex', False): extension = [ AlgebraicNumber(ext, gen=x) for ext in extension ] g, coeffs = extension[0].minpoly.replace(x), [1] for ext in extension[1:]: s, _, g = sqf_norm(g, x, extension=ext) coeffs = [ s*c for c in coeffs ] + [1] if not args.get('polys', False): return g.as_expr(), coeffs else: return cls(g), coeffs generator = numbered_symbols('y', cls=Dummy) F, Y = [], [] for ext in extension: y = next(generator) if ext.is_Poly: if ext.is_univariate: f = ext.as_expr(y) else: raise ValueError("expected minimal polynomial, got %s" % ext) else: f = minpoly(ext, y) F.append(f) Y.append(y) coeffs_generator = args.get('coeffs', _coeffs_generator) for coeffs in coeffs_generator(len(Y)): f = x - sum([ c*y for c, y in zip(coeffs, Y)]) G = groebner(F + [f], Y + [x], order='lex', field=True) H, g = G[:-1], cls(G[-1], x, domain='QQ') for i, (h, y) in enumerate(zip(H, Y)): try: H[i] = Poly(y - h, x, domain='QQ').all_coeffs() # XXX: composite=False except CoercionFailed: # pragma: no cover break # G is not a triangular set else: break else: # pragma: no cover raise RuntimeError("run out of coefficient configurations") _, g = g.clear_denoms() if not args.get('polys', False): return g.as_expr(), coeffs, H else: return g, coeffs, H
def _minpoly_groebner(ex, x, cls): """ Computes the minimal polynomial of an algebraic number using Groebner bases Examples ======== >>> from sympy import minimal_polynomial, sqrt, Rational >>> from sympy.abc import x >>> minimal_polynomial(sqrt(2) + 3*Rational(1, 3), x, compose=False) x**2 - 2*x - 1 """ from sympy.polys.polytools import degree from sympy.core.function import expand_multinomial generator = numbered_symbols('a', cls=Dummy) mapping, symbols, replace = {}, {}, [] def update_mapping(ex, exp, base=None): a = next(generator) symbols[ex] = a if base is not None: mapping[ex] = a**exp + base else: mapping[ex] = exp.as_expr(a) return a def bottom_up_scan(ex): if ex.is_Atom: if ex is S.ImaginaryUnit: if ex not in mapping: return update_mapping(ex, 2, 1) else: return symbols[ex] elif ex.is_Rational: return ex elif ex.is_Add: return Add(*[ bottom_up_scan(g) for g in ex.args ]) elif ex.is_Mul: return Mul(*[ bottom_up_scan(g) for g in ex.args ]) elif ex.is_Pow: if ex.exp.is_Rational: if ex.exp < 0 and ex.base.is_Add: coeff, terms = ex.base.as_coeff_add() elt, _ = primitive_element(terms, polys=True) alg = ex.base - coeff # XXX: turn this into eval() inverse = invert(elt.gen + coeff, elt).as_expr() base = inverse.subs(elt.gen, alg).expand() if ex.exp == -1: return bottom_up_scan(base) else: ex = base**(-ex.exp) if not ex.exp.is_Integer: base, exp = ( ex.base**ex.exp.p).expand(), Rational(1, ex.exp.q) else: base, exp = ex.base, ex.exp base = bottom_up_scan(base) expr = base**exp if expr not in mapping: return update_mapping(expr, 1/exp, -base) else: return symbols[expr] elif ex.is_AlgebraicNumber: if ex.root not in mapping: return update_mapping(ex.root, ex.minpoly) else: return symbols[ex.root] raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) def simpler_inverse(ex): """ Returns True if it is more likely that the minimal polynomial algorithm works better with the inverse """ if ex.is_Pow: if (1/ex.exp).is_integer and ex.exp < 0: if ex.base.is_Add: return True if ex.is_Mul: hit = True a = [] for p in ex.args: if p.is_Add: return False if p.is_Pow: if p.base.is_Add and p.exp > 0: return False if hit: return True return False inverted = False ex = expand_multinomial(ex) if ex.is_AlgebraicNumber: return ex.minpoly.as_expr(x) elif ex.is_Rational: result = ex.q*x - ex.p else: inverted = simpler_inverse(ex) if inverted: ex = ex**-1 res = None if ex.is_Pow and (1/ex.exp).is_Integer: n = 1/ex.exp res = _minimal_polynomial_sq(ex.base, n, x) elif _is_sum_surds(ex): res = _minimal_polynomial_sq(ex, S.One, x) if res is not None: result = res if res is None: bus = bottom_up_scan(ex) F = [x - bus] + list(mapping.values()) G = groebner(F, list(symbols.values()) + [x], order='lex') _, factors = factor_list(G[-1]) # by construction G[-1] has root `ex` result = _choose_factor(factors, x, ex) if inverted: result = _invertx(result, x) if result.coeff(x**degree(result, x)) < 0: result = expand_mul(-result) return result
def primitive_element(extension, x=None, **args): """Construct a common number field for all extensions. """ if not extension: raise ValueError("can't compute primitive element for empty extension") if x is not None: x = sympify(x) else: x = Dummy('x') if not args.get('ex', False): extension = [AlgebraicNumber(ext, gen=x) for ext in extension] g, coeffs = extension[0].minpoly, [1] for ext in extension[1:]: s, _, g = sqf_norm(g, x, extension=ext) coeffs = [s * c for c in coeffs] + [1] if not args.get('polys', False): return g.as_basic(), coeffs else: return g, coeffs generator = numbered_symbols('y', cls=Dummy) F, Y = [], [] for ext in extension: y = generator.next() if ext.is_Poly: if ext.is_univariate: f = ext.as_basic(y) else: raise ValueError("expected minimal polynomial, got %s" % ext) else: f = minpoly(ext, y) F.append(f) Y.append(y) coeffs_generator = args.get('coeffs', _coeffs_generator) for coeffs in coeffs_generator(len(Y)): f = x - sum([c * y for c, y in zip(coeffs, Y)]) G = groebner(F + [f], Y + [x], order='lex') H, g = G[:-1], Poly(G[-1], x, domain='QQ') for i, (h, y) in enumerate(zip(H, Y)): try: H[i] = Poly(y - h, x, domain='QQ').all_coeffs() except CoercionFailed: # pragma: no cover break # G is not a triangular set else: break else: # pragma: no cover raise RuntimeError("run out of coefficient configurations") _, g = g.ground_to_ring() if not args.get('polys', False): return g.as_basic(), coeffs, H else: return g, coeffs, H
def _minpoly_groebner(ex, x, cls): """ Computes the minimal polynomial of an algebraic number using Groebner bases Examples ======== >>> from sympy import minimal_polynomial, sqrt, Rational >>> from sympy.abc import x >>> minimal_polynomial(sqrt(2) + 3*Rational(1, 3), x, compose=False) x**2 - 2*x - 1 """ generator = numbered_symbols('a', cls=Dummy) mapping, symbols = {}, {} def update_mapping(ex, exp, base=None): a = next(generator) symbols[ex] = a if base is not None: mapping[ex] = a**exp + base else: mapping[ex] = exp.as_expr(a) return a def bottom_up_scan(ex): """ Transform a given algebraic expression *ex* into a multivariate polynomial, by introducing fresh variables with defining equations. Explanation =========== The critical elements of the algebraic expression *ex* are root extractions, instances of :py:class:`~.AlgebraicNumber`, and negative powers. When we encounter a root extraction or an :py:class:`~.AlgebraicNumber` we replace this expression with a fresh variable ``a_i``, and record the defining polynomial for ``a_i``. For example, if ``a_0**(1/3)`` occurs, we will replace it with ``a_1``, and record the new defining polynomial ``a_1**3 - a_0``. When we encounter a negative power we transform it into a positive power by algebraically inverting the base. This means computing the minimal polynomial in ``x`` for the base, inverting ``x`` modulo this poly (which generates a new polynomial) and then substituting the original base expression for ``x`` in this last polynomial. We return the transformed expression, and we record the defining equations for new symbols using the ``update_mapping()`` function. """ if ex.is_Atom: if ex is S.ImaginaryUnit: if ex not in mapping: return update_mapping(ex, 2, 1) else: return symbols[ex] elif ex.is_Rational: return ex elif ex.is_Add: return Add(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Mul: return Mul(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Pow: if ex.exp.is_Rational: if ex.exp < 0: minpoly_base = _minpoly_groebner(ex.base, x, cls) inverse = invert(x, minpoly_base).as_expr() base_inv = inverse.subs(x, ex.base).expand() if ex.exp == -1: return bottom_up_scan(base_inv) else: ex = base_inv**(-ex.exp) if not ex.exp.is_Integer: base, exp = (ex.base**ex.exp.p).expand(), Rational( 1, ex.exp.q) else: base, exp = ex.base, ex.exp base = bottom_up_scan(base) expr = base**exp if expr not in mapping: if exp.is_Integer: return expr.expand() else: return update_mapping(expr, 1 / exp, -base) else: return symbols[expr] elif ex.is_AlgebraicNumber: if ex not in mapping: return update_mapping(ex, ex.minpoly_of_element()) else: return symbols[ex] raise NotAlgebraic("%s does not seem to be an algebraic number" % ex) def simpler_inverse(ex): """ Returns True if it is more likely that the minimal polynomial algorithm works better with the inverse """ if ex.is_Pow: if (1 / ex.exp).is_integer and ex.exp < 0: if ex.base.is_Add: return True if ex.is_Mul: hit = True for p in ex.args: if p.is_Add: return False if p.is_Pow: if p.base.is_Add and p.exp > 0: return False if hit: return True return False inverted = False ex = expand_multinomial(ex) if ex.is_AlgebraicNumber: return ex.minpoly_of_element().as_expr(x) elif ex.is_Rational: result = ex.q * x - ex.p else: inverted = simpler_inverse(ex) if inverted: ex = ex**-1 res = None if ex.is_Pow and (1 / ex.exp).is_Integer: n = 1 / ex.exp res = _minimal_polynomial_sq(ex.base, n, x) elif _is_sum_surds(ex): res = _minimal_polynomial_sq(ex, S.One, x) if res is not None: result = res if res is None: bus = bottom_up_scan(ex) F = [x - bus] + list(mapping.values()) G = groebner(F, list(symbols.values()) + [x], order='lex') _, factors = factor_list(G[-1]) # by construction G[-1] has root `ex` result = _choose_factor(factors, x, ex) if inverted: result = _invertx(result, x) if result.coeff(x**degree(result, x)) < 0: result = expand_mul(-result) return result
def _solve_undetermined_coefficients(eq, func, order, match, trialset): r""" Helper function for the method of undetermined coefficients. See the :py:meth:`~sympy.solvers.ode.single.NthLinearConstantCoeffUndeterminedCoefficients` docstring for more information on this method. The parameter ``trialset`` is the set of trial functions as returned by ``_undetermined_coefficients_match()['trialset']``. The parameter ``match`` should be a dictionary that has the following keys: ``list`` A list of solutions to the homogeneous equation. ``sol`` The general solution. """ r = match coeffs = numbered_symbols('a', cls=Dummy) coefflist = [] gensols = r['list'] gsol = r['sol'] f = func.func x = func.args[0] if len(gensols) != order: raise NotImplementedError( "Cannot find " + str(order) + " solutions to the homogeneous equation necessary to apply" + " undetermined coefficients to " + str(eq) + " (number of terms != order)") trialfunc = 0 for i in trialset: c = next(coeffs) coefflist.append(c) trialfunc += c * i eqs = sub_func_doit(eq, f(x), trialfunc) coeffsdict = dict(list(zip(trialset, [0] * (len(trialset) + 1)))) eqs = _mexpand(eqs) for i in Add.make_args(eqs): s = separatevars(i, dict=True, symbols=[x]) if coeffsdict.get(s[x]): coeffsdict[s[x]] += s['coeff'] else: coeffsdict[s[x]] = s['coeff'] coeffvals = solve(list(coeffsdict.values()), coefflist) if not coeffvals: raise NotImplementedError("Could not solve `%s` using the " "method of undetermined coefficients " "(unable to solve for coefficients)." % eq) psol = trialfunc.subs(coeffvals) return Eq(f(x), gsol.rhs + psol)
try: f, opt = poly_from_expr(f, *gens, **args) except PolificationFailed, exc: raise ComputationFailed("viete", 1, exc) if f.is_multivariate: raise MultivariatePolynomialError("multivariate polynomials are not allowed") n = f.degree() if n < 1: raise ValueError("can't derive Viete's formulas for a constant polynomial") if roots is None: roots = numbered_symbols("r", start=1) roots = take(roots, n) if n != len(roots): raise ValueError("required %s roots, got %s" % (n, len(roots))) lc, coeffs = f.LC(), f.all_coeffs() result, sign = [], -1 for i, coeff in enumerate(coeffs[1:]): poly = symmetric_poly(i + 1, roots) coeff = sign * (coeff / lc) result.append((poly, coeff)) sign = -sign
def default(cls): return numbered_symbols('s', start=1)
def generate(ex, vnames, idx): """ Generate the C++ code by simplifying the expressions. """ # print(ex) mi = [0, 1, 2, 4, 5, 8] midx = ['00', '01', '02', '11', '12', '22'] # total number of expressions # print("--------------------------------------------------------") num_e = 0 lexp = [] lname = [] for i, e in enumerate(ex): if type(e) == list: num_e = num_e + len(e) for j, ev in enumerate(e): lexp.append(ev) lname.append(vnames[i]+repr(j)+idx) elif type(e) == Matrix: num_e = num_e + len(e) for j, k in enumerate(mi): lexp.append(e[k]) lname.append(vnames[i]+midx[j]+idx) else: num_e = num_e + 1 lexp.append(e) lname.append(vnames[i]+idx) # print(num_e) # print(len(lname)) print('// Dendro: {{{ ') print('// Dendro: original ops: ', count_ops(lexp)) # print("--------------------------------------------------------") # print("Now trying Common Subexpression Detection and Collection") # print("--------------------------------------------------------") # Common Subexpression Detection and Collection # for i in range(len(ex)): # # print("--------------------------------------------------------") # # print(ex[i]) # # print("--------------------------------------------------------") # ee_name = ''.join(random.choice(string.ascii_uppercase) for _ in range(5)) # ee_syms = numbered_symbols(prefix=ee_name) # _v = cse(ex[i],symbols=ee_syms) # # print(type(_v)) # for (v1,v2) in _v[0]: # print("double %s = %s;" % (v1, v2)) # print("%s = %s" % (vnames[i], _v[1][0])) #mex = Matrix(ex) ee_name = 'DENDRO_' #''.join(random.choice(string.ascii_uppercase) for _ in range(5)) ee_syms = numbered_symbols(prefix=ee_name) _v = cse(lexp, symbols=ee_syms, optimizations='basic') custom_functions = {'grad': 'grad', 'grad2': 'grad2', 'agrad': 'agrad', 'kograd': 'kograd'} rops=0 print('// Dendro: printing temp variables') for (v1, v2) in _v[0]: # print("double %s = %s;" % (v1, v2)) # replace_pow(v2))) print('double ', end='') #print_ccode(v2, assign_to=v1, user_functions=custom_functions) print(change_deriv_names(ccode(v2, assign_to=v1, user_functions=custom_functions))) rops = rops + count_ops(v2) print() print('// Dendro: printing variables') for i, e in enumerate(_v[1]): print("//--") # print("%s = %s;" % (lname[i], e)) # replace_pow(e))) #f = open(str(lname[i])+'.gv','w') #print(dotprint(e), file=f) #f.close() #print_ccode(e, assign_to=lname[i], user_functions=custom_functions) print(change_deriv_names(ccode(e, assign_to=lname[i], user_functions=custom_functions))) rops = rops + count_ops(e) print('// Dendro: reduced ops: ', rops) print('// Dendro: }}} ')
try: f, opt = poly_from_expr(f, *gens, **args) except PolificationFailed, exc: raise ComputationFailed('viete', 1, exc) if f.is_multivariate: raise MultivariatePolynomialError("multivariate polynomials are not allowed") n = f.degree() if n < 1: raise ValueError("can't derive Viete's formulas for a constant polynomial") if roots is None: roots = numbered_symbols('r', start=1) roots = take(roots, n) if n != len(roots): raise ValueError("required %s roots, got %s" % (n, len(roots))) lc, coeffs = f.LC(), f.all_coeffs() result, sign = [], -1 for i, coeff in enumerate(coeffs[1:]): poly = symmetric_poly(i+1, roots) coeff = sign*(coeff/lc) result.append((poly, coeff)) sign = -sign
def minimal_polynomial(ex, x=None, **args): """ Computes the minimal polynomial of an algebraic number. Parameters ========== ex : algebraic number expression x : indipendent variable of the minimal polynomial Options ======= compose : if ``True`` _minpoly1`` is used, else the ``groebner`` algorithm polys : if ``True`` returns a ``Poly`` object Notes ===== By default ``compose=True``, the minimal polynomial of the subexpressions of ``ex`` are computed, then the arithmetic operations on them are performed using the resultant and factorization. If ``compose=False``, a bottom-up algorithm is used with ``groebner``. The default algorithm stalls less frequently. Examples ======== >>> from sympy import minimal_polynomial, sqrt, solve >>> from sympy.abc import x >>> minimal_polynomial(sqrt(2), x) x**2 - 2 >>> minimal_polynomial(sqrt(2) + sqrt(3), x) x**4 - 10*x**2 + 1 >>> minimal_polynomial(solve(x**3 + x + 3)[0], x) x**3 + x + 3 """ from sympy.polys.polytools import degree from sympy.core.function import expand_multinomial from sympy.core.basic import preorder_traversal compose = args.get('compose', True) polys = args.get('polys', False) ex = sympify(ex) for expr in preorder_traversal(ex): if expr.is_AlgebraicNumber: compose = False break if ex.is_AlgebraicNumber: compose = False if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly if compose: result = _minpoly1(ex, x) result = result.primitive()[1] c = result.coeff(x**degree(result, x)) if c < 0: result = expand_mul(-result) c = -c return cls(result, x, field=True) if polys else result generator = numbered_symbols('a', cls=Dummy) mapping, symbols, replace = {}, {}, [] def update_mapping(ex, exp, base=None): a = generator.next() symbols[ex] = a if base is not None: mapping[ex] = a**exp + base else: mapping[ex] = exp.as_expr(a) return a def bottom_up_scan(ex): if ex.is_Atom: if ex is S.ImaginaryUnit: if ex not in mapping: return update_mapping(ex, 2, 1) else: return symbols[ex] elif ex.is_Rational: return ex elif ex.is_Add: return Add(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Mul: return Mul(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Pow: if ex.exp.is_Rational: if ex.exp < 0 and ex.base.is_Add: coeff, terms = ex.base.as_coeff_add() elt, _ = primitive_element(terms, polys=True) alg = ex.base - coeff # XXX: turn this into eval() inverse = invert(elt.gen + coeff, elt).as_expr() base = inverse.subs(elt.gen, alg).expand() if ex.exp == -1: return bottom_up_scan(base) else: ex = base**(-ex.exp) if not ex.exp.is_Integer: base, exp = (ex.base**ex.exp.p).expand(), Rational( 1, ex.exp.q) else: base, exp = ex.base, ex.exp base = bottom_up_scan(base) expr = base**exp if expr not in mapping: return update_mapping(expr, 1 / exp, -base) else: return symbols[expr] elif ex.is_AlgebraicNumber: if ex.root not in mapping: return update_mapping(ex.root, ex.minpoly) else: return symbols[ex.root] raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) def simpler_inverse(ex): """ Returns True if it is more likely that the minimal polynomial algorithm works better with the inverse """ if ex.is_Pow: if (1 / ex.exp).is_integer and ex.exp < 0: if ex.base.is_Add: return True if ex.is_Mul: hit = True a = [] for p in ex.args: if p.is_Add: return False if p.is_Pow: if p.base.is_Add and p.exp > 0: return False if hit: return True return False inverted = False ex = expand_multinomial(ex) if ex.is_AlgebraicNumber: if not polys: return ex.minpoly.as_expr(x) else: return ex.minpoly.replace(x) elif ex.is_Rational: result = ex.q * x - ex.p else: inverted = simpler_inverse(ex) if inverted: ex = ex**-1 res = None if ex.is_Pow and (1 / ex.exp).is_Integer: n = 1 / ex.exp res = _minimal_polynomial_sq(ex.base, n, x) elif _is_sum_surds(ex): res = _minimal_polynomial_sq(ex, S.One, x) if res is not None: result = res if res is None: bus = bottom_up_scan(ex) F = [x - bus] + mapping.values() G = groebner(F, symbols.values() + [x], order='lex') _, factors = factor_list(G[-1]) # by construction G[-1] has root `ex` result = _choose_factor(factors, x, ex) if inverted: result = _invertx(result, x) if result.coeff(x**degree(result, x)) < 0: result = expand_mul(-result) if polys: return cls(result, x, field=True) else: return result
def minimal_polynomial(ex, x=None, **args): """ Computes the minimal polynomial of an algebraic number. Examples ======== >>> from sympy import minimal_polynomial, sqrt >>> from sympy.abc import x >>> minimal_polynomial(sqrt(2), x) x**2 - 2 >>> minimal_polynomial(sqrt(2) + sqrt(3), x) x**4 - 10*x**2 + 1 """ generator = numbered_symbols('a', cls=Dummy) mapping, symbols, replace = {}, {}, [] ex = sympify(ex) if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly def update_mapping(ex, exp, base=None): a = generator.next() symbols[ex] = a if base is not None: mapping[ex] = a**exp + base else: mapping[ex] = exp.as_expr(a) return a def bottom_up_scan(ex): if ex.is_Atom: if ex is S.ImaginaryUnit: if ex not in mapping: return update_mapping(ex, 2, 1) else: return symbols[ex] elif ex.is_Rational: return ex elif ex.is_Add: return Add(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Mul: return Mul(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Pow: if ex.exp.is_Rational: if ex.exp < 0 and ex.base.is_Add: coeff, terms = ex.base.as_coeff_add() elt, _ = primitive_element(terms, polys=True) alg = ex.base - coeff # XXX: turn this into eval() inverse = invert(elt.gen + coeff, elt).as_expr() base = inverse.subs(elt.gen, alg).expand() if ex.exp == -1: return bottom_up_scan(base) else: ex = base**(-ex.exp) if not ex.exp.is_Integer: base, exp = (ex.base**ex.exp.p).expand(), Rational( 1, ex.exp.q) else: base, exp = ex.base, ex.exp base = bottom_up_scan(base) expr = base**exp if expr not in mapping: return update_mapping(expr, 1 / exp, -base) else: return symbols[expr] elif ex.is_AlgebraicNumber: if ex.root not in mapping: return update_mapping(ex.root, ex.minpoly) else: return symbols[ex.root] raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) polys = args.get('polys', False) if ex.is_AlgebraicNumber: if not polys: return ex.minpoly.as_expr(x) else: return ex.minpoly.replace(x) elif ex.is_Rational: result = ex.q * x - ex.p else: F = [x - bottom_up_scan(ex)] + mapping.values() G = groebner(F, symbols.values() + [x], order='lex') _, factors = factor_list(G[-1]) if len(factors) == 1: ((result, _), ) = factors else: for result, _ in factors: if result.subs(x, ex).evalf(chop=True) == 0: break else: # pragma: no cover raise NotImplementedError( "multiple candidates for the minimal polynomial of %s" % ex) if polys: return cls(result, x, field=True) else: return result
def generate_fpcore(ex, vnames, idx): """ Generate the FPCore code, """ mi = [0, 1, 2, 4, 5, 8] midx = ['00', '01', '02', '11', '12', '22'] # total number of expressions # print("--------------------------------------------------------") num_e = 0 lexp = [] lname = [] for i, e in enumerate(ex): if type(e) == list: num_e = num_e + len(e) for j, ev in enumerate(e): lexp.append(ev) lname.append(vnames[i] + repr(j) + idx) elif type(e) == Matrix: num_e = num_e + len(e) for j, k in enumerate(mi): lexp.append(e[k]) lname.append(vnames[i] + midx[j] + idx) else: num_e = num_e + 1 lexp.append(e) lname.append(vnames[i] + idx) cse = construct_cse(ex, vnames, idx) _v = cse[0] #print("// Dendro: {{{ ") #print("// Dendro: original ops: %d " %(cse[1])) ee_name = 'DENDRO_' ee_syms = numbered_symbols(prefix=ee_name) custom_functions = { 'grad': 'grad', 'grad2': 'grad2', 'agrad': 'agrad', 'kograd': 'kograd' } rops = 0 #re_symbol=regex.compile(r"Symbol\('[a-z,A-Z,_]+[0-9,\[pp\],\[0-9\]]*'\)") re_symbol = regex.compile(r"Symbol\('([a-z,A-Z,0-9,_,\[\]]*)'\)") re_integer = regex.compile(r"Integer\(([\-,0-9]+)\)") re_float = regex.compile(r"Float\('([\-,0-9]*\.[0-9]*)'\s prec=([0-9]+)\)") re_grad = regex.compile( r"Function\('([a-z]+[0-9]*)'\)\(Integer\(([0-9]+)\),\s*Symbol\('([a-z,A-Z]+[0-9]*\[pp\])'\)\)" ) subs_functions = { "Add(": "(+ ", "Integer(-1)": "-1 ", "Mul(": "(* ", "Div(": "(/ ", "Pow(": "(pow ", "Rational(": "(/ " } #print('// Dendro: printing temp variables') tmp_vars = list() for (v1, v2) in _v[0]: tmp_vars.append(str(v1)) sym_sub = dict() srep = srepr(v2) #print(srep) res = re_grad.findall(srep) for g in res: s = "Function('%s')(Integer(%s), Symbol('%s'))" % (g[0], g[1], g[2]) #print(s) ss = "Symbol('%s')" % (g[0] + "_" + g[1] + "_" + g[2]) srep = srep.replace(s, ss) srep = srep.replace(",", " ") #print(srep) res = re_symbol.findall(srep) inp_params = list() #print(res) for s in res: ss = s.replace("[pp]", "") for index in range(0, 6): ss = ss.replace("[" + str(index) + "]", str(index)) inp_params.append(ss) tmp_vars.append(ss) sym_sub["Symbol(\'%s\')" % (s)] = ss int_sub = dict() res = re_integer.findall(srep) for s in res: int_sub["Integer(%s)" % (s)] = s float_sub = dict() res = re_float.findall(srep) for s in res: float_sub["Float('%s' prec=%s)" % (s[0], s[1])] = s[0] for key, val in sym_sub.items(): #print("{%s: %s} "%(key,val)) srep = srep.replace(key, val) for key, val in int_sub.items(): #print("{%s: %s} "%(key,val)) srep = srep.replace(key, val) for key, val in float_sub.items(): #print("{%s: %s} "%(key,val)) srep = srep.replace(key, val) for key, val in subs_functions.items(): srep = srep.replace(key, val) print("(FPCore (%s)" % (" ".join(inp_params))) print("\t%s" % (srep)) print(")\n") #print(tmp_vars) tmp_vars.clear() tmp_vars = list() for i, e in enumerate(_v[1]): srep = srepr(e) res = re_grad.findall(srep) for g in res: s = "Function('%s')(Integer(%s), Symbol('%s'))" % (g[0], g[1], g[2]) #print(s) ss = "Symbol('%s')" % (g[0] + "_" + g[1] + "_" + g[2]) srep = srep.replace(s, ss) srep = srep.replace(",", " ") res = re_symbol.findall(srep) inp_params = list() #print(res) for s in res: ss = s.replace("[pp]", "") for index in range(0, 6): ss = ss.replace("[" + str(index) + "]", str(index)) inp_params.append(ss) tmp_vars.append(ss) sym_sub["Symbol(\'%s\')" % (s)] = ss int_sub = dict() res = re_integer.findall(srep) for s in res: int_sub["Integer(%s)" % (s)] = s float_sub = dict() res = re_float.findall(srep) for s in res: float_sub["Float('%s' prec=%s)" % (s[0], s[1])] = s[0] for key, val in sym_sub.items(): #print("{%s: %s} "%(key,val)) srep = srep.replace(key, val) for key, val in int_sub.items(): #print("{%s: %s} "%(key,val)) srep = srep.replace(key, val) for key, val in float_sub.items(): #print("{%s: %s} "%(key,val)) srep = srep.replace(key, val) for key, val in subs_functions.items(): srep = srep.replace(key, val) tmp_vars = list(set(tmp_vars)) print("(FPCore (%s)" % (" ".join(tmp_vars))) print("\t%s" % (srep)) print(")")
def minimal_polynomial(ex, x=None, **args): """ Computes the minimal polynomial of an algebraic number. Examples ======== >>> from sympy import minimal_polynomial, sqrt >>> from sympy.abc import x >>> minimal_polynomial(sqrt(2), x) x**2 - 2 >>> minimal_polynomial(sqrt(2) + sqrt(3), x) x**4 - 10*x**2 + 1 """ from sympy.polys.polytools import degree from sympy.core.function import expand_mul from sympy.simplify.simplify import _is_sum_surds generator = numbered_symbols('a', cls=Dummy) mapping, symbols, replace = {}, {}, [] ex = sympify(ex) if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly def update_mapping(ex, exp, base=None): a = generator.next() symbols[ex] = a if base is not None: mapping[ex] = a**exp + base else: mapping[ex] = exp.as_expr(a) return a def bottom_up_scan(ex): if ex.is_Atom: if ex is S.ImaginaryUnit: if ex not in mapping: return update_mapping(ex, 2, 1) else: return symbols[ex] elif ex.is_Rational: return ex elif ex.is_Add: return Add(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Mul: return Mul(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Pow: if ex.exp.is_Rational: if ex.exp < 0 and ex.base.is_Add: coeff, terms = ex.base.as_coeff_add() elt, _ = primitive_element(terms, polys=True) alg = ex.base - coeff # XXX: turn this into eval() inverse = invert(elt.gen + coeff, elt).as_expr() base = inverse.subs(elt.gen, alg).expand() if ex.exp == -1: return bottom_up_scan(base) else: ex = base**(-ex.exp) if not ex.exp.is_Integer: base, exp = (ex.base**ex.exp.p).expand(), Rational( 1, ex.exp.q) else: base, exp = ex.base, ex.exp base = bottom_up_scan(base) expr = base**exp if expr not in mapping: return update_mapping(expr, 1 / exp, -base) else: return symbols[expr] elif ex.is_AlgebraicNumber: if ex.root not in mapping: return update_mapping(ex.root, ex.minpoly) else: return symbols[ex.root] raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) def simpler_inverse(ex): """ Returns True if it is more likely that the minimal polynomial algorithm works better with the inverse """ if ex.is_Pow: if (1 / ex.exp).is_integer and ex.exp < 0: if ex.base.is_Add: return True if ex.is_Mul: hit = True a = [] for p in ex.args: if p.is_Add: return False if p.is_Pow: if p.base.is_Add and p.exp > 0: return False if hit: return True return False polys = args.get('polys', False) prec = args.pop('prec', 10) inverted = False if ex.is_AlgebraicNumber: if not polys: return ex.minpoly.as_expr(x) else: return ex.minpoly.replace(x) elif ex.is_Rational: result = ex.q * x - ex.p else: inverted = simpler_inverse(ex) if inverted: ex = ex**-1 res = None if ex.is_Pow and (1 / ex.exp).is_Integer: n = 1 / ex.exp res = _minimal_polynomial_sq(ex.base, n, x, prec) elif _is_sum_surds(ex): res = _minimal_polynomial_sq(ex, S.One, x, prec) if res is not None: result = res if res is None: bus = bottom_up_scan(ex) F = [x - bus] + mapping.values() G = groebner(F, symbols.values() + [x], order='lex') _, factors = factor_list(G[-1]) # by construction G[-1] has root `ex` result = _choose_factor(factors, x, ex, prec) if result is None: raise NotImplementedError( "multiple candidates for the minimal polynomial of %s" % ex) if inverted: result = expand_mul(x**degree(result) * result.subs(x, 1 / x)) if result.coeff(x**degree(result)) < 0: result = expand_mul(-result) if polys: return cls(result, x, field=True) else: return result
def _minpoly_groebner(ex, x, cls): """ Computes the minimal polynomial of an algebraic number using Groebner bases Examples ======== >>> from sympy import minimal_polynomial, sqrt, Rational >>> from sympy.abc import x >>> minimal_polynomial(sqrt(2) + 3*Rational(1, 3), x, compose=False) x**2 - 2*x - 1 """ from sympy.polys.polytools import degree from sympy.core.function import expand_multinomial generator = numbered_symbols('a', cls=Dummy) mapping, symbols = {}, {} def update_mapping(ex, exp, base=None): a = next(generator) symbols[ex] = a if base is not None: mapping[ex] = a**exp + base else: mapping[ex] = exp.as_expr(a) return a def bottom_up_scan(ex): if ex.is_Atom: if ex is S.ImaginaryUnit: if ex not in mapping: return update_mapping(ex, 2, 1) else: return symbols[ex] elif ex.is_Rational: return ex elif ex.is_Add: return Add(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Mul: return Mul(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Pow: if ex.exp.is_Rational: if ex.exp < 0: minpoly_base = _minpoly_groebner(ex.base, x, cls) inverse = invert(x, minpoly_base).as_expr() base_inv = inverse.subs(x, ex.base).expand() if ex.exp == -1: return bottom_up_scan(base_inv) else: ex = base_inv**(-ex.exp) if not ex.exp.is_Integer: base, exp = (ex.base**ex.exp.p).expand(), Rational( 1, ex.exp.q) else: base, exp = ex.base, ex.exp base = bottom_up_scan(base) expr = base**exp if expr not in mapping: return update_mapping(expr, 1 / exp, -base) else: return symbols[expr] elif ex.is_AlgebraicNumber: if ex.root not in mapping: return update_mapping(ex.root, ex.minpoly) else: return symbols[ex.root] raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) def simpler_inverse(ex): """ Returns True if it is more likely that the minimal polynomial algorithm works better with the inverse """ if ex.is_Pow: if (1 / ex.exp).is_integer and ex.exp < 0: if ex.base.is_Add: return True if ex.is_Mul: hit = True for p in ex.args: if p.is_Add: return False if p.is_Pow: if p.base.is_Add and p.exp > 0: return False if hit: return True return False inverted = False ex = expand_multinomial(ex) if ex.is_AlgebraicNumber: return ex.minpoly.as_expr(x) elif ex.is_Rational: result = ex.q * x - ex.p else: inverted = simpler_inverse(ex) if inverted: ex = ex**-1 res = None if ex.is_Pow and (1 / ex.exp).is_Integer: n = 1 / ex.exp res = _minimal_polynomial_sq(ex.base, n, x) elif _is_sum_surds(ex): res = _minimal_polynomial_sq(ex, S.One, x) if res is not None: result = res if res is None: bus = bottom_up_scan(ex) F = [x - bus] + list(mapping.values()) G = groebner(F, list(symbols.values()) + [x], order='lex') _, factors = factor_list(G[-1]) # by construction G[-1] has root `ex` result = _choose_factor(factors, x, ex) if inverted: result = _invertx(result, x) if result.coeff(x**degree(result, x)) < 0: result = expand_mul(-result) return result
def generate(ex, vnames, idx): """ Generate the C++ code by simplifying the expressions. """ # print(ex) mi = [0, 1, 2, 4, 5, 8] midx = ['00', '01', '02', '11', '12', '22'] # total number of expressions # print("--------------------------------------------------------") num_e = 0 lexp = [] lname = [] for i, e in enumerate(ex): if type(e) == list: num_e = num_e + len(e) for j, ev in enumerate(e): lexp.append(ev) lname.append(vnames[i]+repr(j)+idx) elif type(e) == Matrix: num_e = num_e + len(e) for j, k in enumerate(mi): lexp.append(e[k]) lname.append(vnames[i]+midx[j]+idx) else: num_e = num_e + 1 lexp.append(e) lname.append(vnames[i]+idx) # print(num_e) # print(len(lname)) with open("bssn.cpp", 'w') as output_file: print_n_write('// Dendro: {{{ ', output_file) print_n_write('// Dendro: original ops: ' + str(count_ops(lexp)), output_file) # print("--------------------------------------------------------") # print("Now trying Common Subexpression Detection and Collection") # print("--------------------------------------------------------") # Common Subexpression Detection and Collection # for i in range(len(ex)): # # print("--------------------------------------------------------") # # print(ex[i]) # # print("--------------------------------------------------------") # ee_name = ''.join(random.choice(string.ascii_uppercase) for _ in range(5)) # ee_syms = numbered_symbols(prefix=ee_name) # _v = cse(ex[i],symbols=ee_syms) # # print(type(_v)) # for (v1,v2) in _v[0]: # print("double %s = %s;" % (v1, v2)) # print("%s = %s" % (vnames[i], _v[1][0])) #mex = Matrix(ex) ee_name = 'DENDRO_' #''.join(random.choice(string.ascii_uppercase) for _ in range(5)) ee_syms = numbered_symbols(prefix=ee_name) _v = cse(lexp, symbols=ee_syms, optimizations='basic') custom_functions = {'grad': 'grad', 'grad2': 'grad2', 'agrad': 'agrad', 'kograd': 'kograd'} rops=0 print_n_write('// Dendro: printing temp variables', output_file) for (v1, v2) in _v[0]: # print("double %s = %s;" % (v1, v2)) # replace_pow(v2))) print_n_write('double ', output_file, isNewLineEnd=False) print_n_write(v2, output_file, assign_to=v1, user_functions=custom_functions, isCExp=True) rops = rops + count_ops(v2) print_n_write('\n// Dendro: printing variables', output_file) for i, e in enumerate(_v[1]): print_n_write("//--", output_file) # print("%s = %s;" % (lname[i], e)) # replace_pow(e))) print_n_write(e, output_file, assign_to=lname[i], user_functions=custom_functions, isCExp=True) rops = rops + count_ops(e) print_n_write('// Dendro: reduced ops: ' + str(rops), output_file) print_n_write('// Dendro: }}} ', output_file) print_n_write('// Dendro vectorized code: {{{', output_file) oper = {'mul': 'dmul', 'add': 'dadd', 'load': '*'} prevdefvars = set() for (v1, v2) in _v[0]: vv = numbered_symbols('v') vlist = [] gen_vector_code(v2, vv, vlist, oper, prevdefvars, idx, output_file) print_n_write(' double ' + repr(v1) + ' = ' + repr(vlist[0]) + ';', output_file) for i, e in enumerate(_v[1]): print_n_write("//--", output_file) vv = numbered_symbols('v') vlist = [] gen_vector_code(e, vv, vlist, oper, prevdefvars, idx, output_file) #st = ' ' + repr(lname[i]) + '[idx] = ' + repr(vlist[0]) + ';' st = ' ' + repr(lname[i]) + " = " + repr(vlist[0]) + ';' print_n_write(st.replace("'",""), output_file) print_n_write('// Dendro vectorized code: }}} ', output_file)
def primitive_element(extension, x=None, **args): """Construct a common number field for all extensions. """ if not extension: raise ValueError("can't compute primitive element for empty extension") if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly if not args.get('ex', False): gen, coeffs = extension[0], [1] # XXX when minimal_polynomial is extended to work # with AlgebraicNumbers this test can be removed if isinstance(gen, AlgebraicNumber): g = gen.minpoly.replace(x) else: g = minimal_polynomial(gen, x, polys=True) for ext in extension[1:]: _, factors = factor_list(g, extension=ext) g = _choose_factor(factors, x, gen) s, _, g = g.sqf_norm() gen += s * ext coeffs.append(s) if not args.get('polys', False): return g.as_expr(), coeffs else: return cls(g), coeffs generator = numbered_symbols('y', cls=Dummy) F, Y = [], [] for ext in extension: y = next(generator) if ext.is_Poly: if ext.is_univariate: f = ext.as_expr(y) else: raise ValueError("expected minimal polynomial, got %s" % ext) else: f = minpoly(ext, y) F.append(f) Y.append(y) coeffs_generator = args.get('coeffs', _coeffs_generator) for coeffs in coeffs_generator(len(Y)): f = x - sum([c * y for c, y in zip(coeffs, Y)]) G = groebner(F + [f], Y + [x], order='lex', field=True) H, g = G[:-1], cls(G[-1], x, domain='QQ') for i, (h, y) in enumerate(zip(H, Y)): try: H[i] = Poly(y - h, x, domain='QQ').all_coeffs() # XXX: composite=False except CoercionFailed: # pragma: no cover break # G is not a triangular set else: break else: # pragma: no cover raise RuntimeError("run out of coefficient configurations") _, g = g.clear_denoms() if not args.get('polys', False): return g.as_expr(), coeffs, H else: return g, coeffs, H
def convert_to_symbolic_indices(seq, start=None, gen=None, qubit_map=None): """Returns the circuit with symbolic indices and the dictionary mapping symbolic indices to real indices. The mapping is 1 to 1 and onto (bijective). Parameters ========== seq : tuple, Gate/Integer/tuple or Mul A tuple of Gate, Integer, or tuple objects, or a Mul start : Symbol An optional starting symbolic index gen : object An optional numbered symbol generator qubit_map : dict An existing mapping of symbolic indices to real indices All symbolic indices have the format 'i#', where # is some number >= 0. """ if isinstance(seq, Mul): seq = seq.args # A numbered symbol generator index_gen = numbered_symbols(prefix='i', start=-1) cur_ndx = index_gen.next() # keys are symbolic indices; values are real indices ndx_map = {} def create_inverse_map(symb_to_real_map): rev_items = lambda item: tuple([item[1], item[0]]) return dict(map(rev_items, symb_to_real_map.items())) if start is not None: if not isinstance(start, Symbol): msg = 'Expected Symbol for starting index, got %r.' % start raise TypeError(msg) cur_ndx = start if gen is not None: if not isinstance(gen, numbered_symbols().__class__): msg = 'Expected a generator, got %r.' % gen raise TypeError(msg) index_gen = gen if qubit_map is not None: if not isinstance(qubit_map, dict): msg = ('Expected dict for existing map, got ' + '%r.' % qubit_map) raise TypeError(msg) ndx_map = qubit_map ndx_map = _sympify_qubit_map(ndx_map) # keys are real indices; keys are symbolic indices inv_map = create_inverse_map(ndx_map) sym_seq = () for item in seq: # Nested items, so recurse if isinstance(item, Gate): result = convert_to_symbolic_indices(item.args, qubit_map=ndx_map, start=cur_ndx, gen=index_gen) sym_item, new_map, cur_ndx, index_gen = result ndx_map.update(new_map) inv_map = create_inverse_map(ndx_map) elif isinstance(item, tuple) or isinstance(item, Tuple): result = convert_to_symbolic_indices(item, qubit_map=ndx_map, start=cur_ndx, gen=index_gen) sym_item, new_map, cur_ndx, index_gen = result ndx_map.update(new_map) inv_map = create_inverse_map(ndx_map) elif item in inv_map: sym_item = inv_map[item] else: cur_ndx = gen.next() ndx_map[cur_ndx] = item inv_map[item] = cur_ndx sym_item = cur_ndx if isinstance(item, Gate): sym_item = item.__class__(*sym_item) sym_seq = sym_seq + (sym_item,) return sym_seq, ndx_map, cur_ndx, index_gen
def generate(ex, vnames, idx): """ Generate the C++ code by simplifying the expressions. """ # print(ex) mi = [0, 1, 2, 4, 5, 8] midx = ['00', '01', '02', '11', '12', '22'] # total number of expressions # print("--------------------------------------------------------") num_e = 0 lexp = [] lname = [] for i, e in enumerate(ex): if type(e) == list: num_e = num_e + len(e) for j, ev in enumerate(e): lexp.append(ev) lname.append(vnames[i] + repr(j) + idx) elif type(e) == Matrix: num_e = num_e + len(e) for j, k in enumerate(mi): lexp.append(e[k]) lname.append(vnames[i] + midx[j] + idx) else: num_e = num_e + 1 lexp.append(e) lname.append(vnames[i] + idx) # print(num_e) # print(len(lname)) with open("bssn.cpp", 'w') as output_file: print_n_write('// Dendro: {{{ ', output_file) print_n_write('// Dendro: original ops: ' + str(count_ops(lexp)), output_file) # print("--------------------------------------------------------") # print("Now trying Common Subexpression Detection and Collection") # print("--------------------------------------------------------") # Common Subexpression Detection and Collection # for i in range(len(ex)): # # print("--------------------------------------------------------") # # print(ex[i]) # # print("--------------------------------------------------------") # ee_name = ''.join(random.choice(string.ascii_uppercase) for _ in range(5)) # ee_syms = numbered_symbols(prefix=ee_name) # _v = cse(ex[i],symbols=ee_syms) # # print(type(_v)) # for (v1,v2) in _v[0]: # print("double %s = %s;" % (v1, v2)) # print("%s = %s" % (vnames[i], _v[1][0])) #mex = Matrix(ex) ee_name = 'DENDRO_' #''.join(random.choice(string.ascii_uppercase) for _ in range(5)) ee_syms = numbered_symbols(prefix=ee_name) _v = cse(lexp, symbols=ee_syms, optimizations='basic') #dp.drawgragh(_v) #dependencies = dp.makeCompleteDependencies(_v) #dp.printDependencies(dependencies) #Generating the graph for dependencies #graph, dependencies = lg.makeDependencies(_v) #lg.printGraph(graph) #Graph Laplacian #graphLaplacian = lg.getGraphLaplacian(graph) #adj_mat = lg.getAdjecencyMatrix(graph) #print("Number of Nodes: "+str(lg.getNumNodes(graph))) #print("Dimensions of the matrix" + str(lg.getDimensions(adj_mat))) #print(str(type(graphLaplacian))) #vals, vecs = lg.getEigenValuesandVectors(graphLaplacian) #print("Printing Eigen Values") #print(vals) #print("Printing Eigen Vectors") #print(vecs) #spectral clustering #sc = lg.doSpectralClustering(adj_mat) #lg.printSpectralClustering(sc, graph, dependencies) dependencies = cl.makeCompleteDependencies(_v) originalVariables = cl.getAllOriginalVariables(dependencies) featureVectors = cl.getFeatureVectors(dependencies, originalVariables) cl.writeFeatureVectorstoCSV(originalVariables, featureVectors) # miniBatchKMeansClusterPoints # affinityPropagationClusterPoints # meanShiftClusterPoints # spectralClusteringClusterPoints # agglomerativeClusteringClusterPoints # dBSCANClusteringClusterPoints # BirchClusteringClusterPoints, # kmeans = cl.kMeansClusterPoints(dependencies, featureVectors) # cl.writeClusteredResultstoCSV("Kmeans",kmeans, dependencies) # # miniBatchKMeans = cl.miniBatchKMeansClusterPoints(dependencies, featureVectors) # cl.writeClusteredResultstoCSV("MiniBatchKMeans", miniBatchKMeans, dependencies) # # meanShift = cl.meanShiftClusterPoints(dependencies, featureVectors) # cl.writeClusteredResultstoCSV("MeanShift", meanShift, dependencies) # # spectralClustering = cl.spectralClusteringClusterPoints(dependencies, featureVectors) # cl.writeClusteredResultstoCSV("SpectralClustering", spectralClustering, dependencies) agglomerative = cl.agglomerativeClusteringClusterPoints( 7, featureVectors) cl.writeClusteredResultstoCSV("Agglomerative7", agglomerative, dependencies) #gnerating the graph for dependencies graph = lg.makeGraph(_v) lg.printGraph(graph, dependencies, agglomerative) # dBSCAN = cl.dBSCANClusteringClusterPoints(dependencies, featureVectors) # cl.writeClusteredResultstoCSV("DBSCAN", dBSCAN, dependencies) # # birch = cl.birchClusteringClusterPoints(dependencies, featureVectors) # cl.writeClusteredResultstoCSV("Birch", birch, dependencies) custom_functions = { 'grad': 'grad', 'grad2': 'grad2', 'agrad': 'agrad', 'kograd': 'kograd' } rops = 0 print_n_write('// Dendro: printing temp variables', output_file) for (v1, v2) in _v[0]: # print("double %s = %s;" % (v1, v2)) # replace_pow(v2))) print_n_write('double ', output_file, isNewLineEnd=False) print_n_write(v2, output_file, assign_to=v1, user_functions=custom_functions, isCExp=True) rops = rops + count_ops(v2) print_n_write('\n// Dendro: printing variables', output_file) for i, e in enumerate(_v[1]): print_n_write("//--", output_file) # print("%s = %s;" % (lname[i], e)) # replace_pow(e))) print_n_write(e, output_file, assign_to=lname[i], user_functions=custom_functions, isCExp=True) rops = rops + count_ops(e) print_n_write('// Dendro: reduced ops: ' + str(rops), output_file) print_n_write('// Dendro: }}} ', output_file) print_n_write('// Dendro vectorized code: {{{', output_file) oper = {'mul': 'dmul', 'add': 'dadd', 'load': '*'} prevdefvars = set() for (v1, v2) in _v[0]: vv = numbered_symbols('v') vlist = [] gen_vector_code(v2, vv, vlist, oper, prevdefvars, idx, output_file) print_n_write( ' double ' + repr(v1) + ' = ' + repr(vlist[0]) + ';', output_file) for i, e in enumerate(_v[1]): print_n_write("//--", output_file) vv = numbered_symbols('v') vlist = [] gen_vector_code(e, vv, vlist, oper, prevdefvars, idx, output_file) #st = ' ' + repr(lname[i]) + '[idx] = ' + repr(vlist[0]) + ';' st = ' ' + repr(lname[i]) + " = " + repr(vlist[0]) + ';' print_n_write(st.replace("'", ""), output_file) print_n_write('// Dendro vectorized code: }}} ', output_file)
def test_convert_to_symbolic_indices(): (x, y, z, h) = create_gate_sequence() i0 = Symbol('i0') exp_map = {i0: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x,)) assert actual == (X(i0),) assert act_map == exp_map expected = (X(i0), Y(i0), Z(i0), H(i0)) exp_map = {i0: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x, y, z, h)) assert actual == expected assert exp_map == act_map (x1, y1, z1, h1) = create_gate_sequence(1) i1 = Symbol('i1') expected = (X(i0), Y(i0), Z(i0), H(i0)) exp_map = {i0: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x1, y1, z1, h1)) assert actual == expected assert act_map == exp_map expected = (X(i0), Y(i0), Z(i0), H(i0), X(i1), Y(i1), Z(i1), H(i1)) exp_map = {i0: Integer(0), i1: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x, y, z, h, x1, y1, z1, h1)) assert actual == expected assert act_map == exp_map exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(Mul(x1, y1, z1, h1, x, y, z, h)) assert actual == expected assert act_map == exp_map expected = (X(i0), X(i1), Y(i0), Y(i1), Z(i0), Z(i1), H(i0), H(i1)) exp_map = {i0: Integer(0), i1: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices(Mul(x, x1, y, y1, z, z1, h, h1)) assert actual == expected assert act_map == exp_map exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x1, x, y1, y, z1, z, h1, h)) assert actual == expected assert act_map == exp_map cnot_10 = CNOT(1, 0) cnot_01 = CNOT(0, 1) cgate_z_10 = CGate(1, Z(0)) cgate_z_01 = CGate(0, Z(1)) expected = (X(i0), X(i1), Y(i0), Y(i1), Z(i0), Z(i1), H(i0), H(i1), CNOT(i1, i0), CNOT(i0, i1), CGate(i1, Z(i0)), CGate(i0, Z(i1))) exp_map = {i0: Integer(0), i1: Integer(1)} args = (x, x1, y, y1, z, z1, h, h1, cnot_10, cnot_01, cgate_z_10, cgate_z_01) actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map args = (x1, x, y1, y, z1, z, h1, h, cnot_10, cnot_01, cgate_z_10, cgate_z_01) expected = (X(i0), X(i1), Y(i0), Y(i1), Z(i0), Z(i1), H(i0), H(i1), CNOT(i0, i1), CNOT(i1, i0), CGate(i0, Z(i1)), CGate(i1, Z(i0))) exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map args = (cnot_10, h, cgate_z_01, h) expected = (CNOT(i0, i1), H(i1), CGate(i1, Z(i0)), H(i1)) exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map args = (cnot_01, h1, cgate_z_10, h1) exp_map = {i0: Integer(0), i1: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map args = (cnot_10, h1, cgate_z_01, h1) expected = (CNOT(i0, i1), H(i0), CGate(i1, Z(i0)), H(i0)) exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map i2 = Symbol('i2') ccgate_z = CGate(0, CGate(1, Z(2))) ccgate_x = CGate(1, CGate(2, X(0))) args = (ccgate_z, ccgate_x) expected = (CGate(i0, CGate(i1, Z(i2))), CGate(i1, CGate(i2, X(i0)))) exp_map = {i0: Integer(0), i1: Integer(1), i2: Integer(2)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map ndx_map = {i0: Integer(0)} index_gen = numbered_symbols(prefix='i', start=1) actual, act_map, sndx, gen = convert_to_symbolic_indices(args, qubit_map=ndx_map, start=i0, gen=index_gen) assert actual == expected assert act_map == exp_map i3 = Symbol('i3') cgate_x0_c321 = CGate((3, 2, 1), X(0)) exp_map = {i0: Integer(3), i1: Integer(2), i2: Integer(1), i3: Integer(0)} expected = (CGate((i0, i1, i2), X(i3)),) args = (cgate_x0_c321,) actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map
def _neq_linear_first_order_const_coeff_homogeneous(match_): r""" System of n first-order constant-coefficient linear homogeneous differential equations .. math:: y'_k = a_{k1} y_1 + a_{k2} y_2 +...+ a_{kn} y_n; k = 1,2,...,n or that can be written as `\vec{y'} = A . \vec{y}` where `\vec{y}` is matrix of `y_k` for `k = 1,2,...n` and `A` is a `n \times n` matrix. Since these equations are equivalent to a first order homogeneous linear differential equation. So the general solution will contain `n` linearly independent parts and solution will consist some type of exponential functions. Assuming `y = \vec{v} e^{rt}` is a solution of the system where `\vec{v}` is a vector of coefficients of `y_1,...,y_n`. Substituting `y` and `y' = r v e^{r t}` into the equation `\vec{y'} = A . \vec{y}`, we get .. math:: r \vec{v} e^{rt} = A \vec{v} e^{rt} .. math:: r \vec{v} = A \vec{v} where `r` comes out to be eigenvalue of `A` and vector `\vec{v}` is the eigenvector of `A` corresponding to `r`. There are three possibilities of eigenvalues of `A` - `n` distinct real eigenvalues - complex conjugate eigenvalues - eigenvalues with multiplicity `k` 1. When all eigenvalues `r_1,..,r_n` are distinct with `n` different eigenvectors `v_1,...v_n` then the solution is given by .. math:: \vec{y} = C_1 e^{r_1 t} \vec{v_1} + C_2 e^{r_2 t} \vec{v_2} +...+ C_n e^{r_n t} \vec{v_n} where `C_1,C_2,...,C_n` are arbitrary constants. 2. When some eigenvalues are complex then in order to make the solution real, we take a linear combination: if `r = a + bi` has an eigenvector `\vec{v} = \vec{w_1} + i \vec{w_2}` then to obtain real-valued solutions to the system, replace the complex-valued solutions `e^{rx} \vec{v}` with real-valued solution `e^{ax} (\vec{w_1} \cos(bx) - \vec{w_2} \sin(bx))` and for `r = a - bi` replace the solution `e^{-r x} \vec{v}` with `e^{ax} (\vec{w_1} \sin(bx) + \vec{w_2} \cos(bx))` 3. If some eigenvalues are repeated. Then we get fewer than `n` linearly independent eigenvectors, we miss some of the solutions and need to construct the missing ones. We do this via generalized eigenvectors, vectors which are not eigenvectors but are close enough that we can use to write down the remaining solutions. For a eigenvalue `r` with eigenvector `\vec{w}` we obtain `\vec{w_2},...,\vec{w_k}` using .. math:: (A - r I) . \vec{w_2} = \vec{w} .. math:: (A - r I) . \vec{w_3} = \vec{w_2} .. math:: \vdots .. math:: (A - r I) . \vec{w_k} = \vec{w_{k-1}} Then the solutions to the system for the eigenspace are `e^{rt} [\vec{w}], e^{rt} [t \vec{w} + \vec{w_2}], e^{rt} [\frac{t^2}{2} \vec{w} + t \vec{w_2} + \vec{w_3}], ...,e^{rt} [\frac{t^{k-1}}{(k-1)!} \vec{w} + \frac{t^{k-2}}{(k-2)!} \vec{w_2} +...+ t \vec{w_{k-1}} + \vec{w_k}]` So, If `\vec{y_1},...,\vec{y_n}` are `n` solution of obtained from three categories of `A`, then general solution to the system `\vec{y'} = A . \vec{y}` .. math:: \vec{y} = C_1 \vec{y_1} + C_2 \vec{y_2} + \cdots + C_n \vec{y_n} """ eq = match_['eq'] func = match_['func'] fc = match_['func_coeff'] n = len(eq) t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] constants = numbered_symbols(prefix='C', cls=Symbol, start=1) # This needs to be modified in future so that fc is only of type Matrix M = -fc if type(fc) is Matrix else Matrix(n, n, lambda i, j: -fc[i, func[j], 0]) P, J = matrix_exp_jordan_form(M, t) P = simplify(P) Cvect = Matrix(list(next(constants) for _ in range(n))) sol_vector = P * (J * Cvect) sol_vector = [ collect(s, ordered(J.atoms(exp)), exact=True) for s in sol_vector ] sol_dict = [Eq(func[i], sol_vector[i]) for i in range(n)] return sol_dict
def generate_separate(ex, vnames, idx): """ Generate the C++ code by simplifying the expressions. """ # print(ex) if len(ex)!=1 : print ('pass each variable separately ',end='\n') return mi = [0, 1, 2, 4, 5, 8] midx = ['00', '01', '02', '11', '12', '22'] # total number of expressions # print("--------------------------------------------------------") num_e = 0 lexp = [] lname = [] for i, e in enumerate(ex): if type(e) == list: num_e = num_e + len(e) for j, ev in enumerate(e): lexp.append(ev) lname.append(vnames[i]+repr(j)+idx) elif type(e) == Matrix: num_e = num_e + len(e) for j, k in enumerate(mi): lexp.append(e[k]) lname.append(vnames[i]+midx[j]+idx) else: num_e = num_e + 1 lexp.append(e) lname.append(vnames[i]+idx) # print(num_e) # print(len(lname)) c_file=open(vnames[0]+'.cpp','w') print('generating code for '+vnames[0]) print(' bssn::timer::t_rhs.start();',file=c_file) print('for (unsigned int k = 3; k < nz-3; k++) { ',file=c_file) print(' z = pmin[2] + k*hz;',file=c_file) print('for (unsigned int j = 3; j < ny-3; j++) { ',file=c_file) print(' y = pmin[1] + j*hy; ',file=c_file) print('for (unsigned int i = 3; i < nx-3; i++) {',file=c_file) print(' x = pmin[0] + i*hx;',file=c_file) print(' pp = i + nx*(j + ny*k);',file=c_file) print(' r_coord = sqrt(x*x + y*y + z*z);',file=c_file) print(' eta=ETA_CONST;',file=c_file) print(' if (r_coord >= ETA_R0) {',file=c_file) print(' eta *= pow( (ETA_R0/r_coord), ETA_DAMPING_EXP);',file=c_file) print(' }',file=c_file) print('// Dendro: {{{ ',file=c_file) print('// Dendro: original ops: ', count_ops(lexp),file=c_file) # print("--------------------------------------------------------") # print("Now trying Common Subexpression Detection and Collection") # print("--------------------------------------------------------") # Common Subexpression Detection and Collection # for i in range(len(ex)): # # print("--------------------------------------------------------") # # print(ex[i]) # # print("--------------------------------------------------------") # ee_name = ''.join(random.choice(string.ascii_uppercase) for _ in range(5)) # ee_syms = numbered_symbols(prefix=ee_name) # _v = cse(ex[i],symbols=ee_syms) # # print(type(_v)) # for (v1,v2) in _v[0]: # print("double %s = %s;" % (v1, v2)) # print("%s = %s" % (vnames[i], _v[1][0])) #mex = Matrix(ex) ee_name = 'DENDRO_' #''.join(random.choice(string.ascii_uppercase) for _ in range(5)) ee_syms = numbered_symbols(prefix=ee_name) _v = cse(lexp, symbols=ee_syms, optimizations='basic') custom_functions = {'grad': 'grad', 'grad2': 'grad2', 'agrad': 'agrad', 'kograd': 'kograd'} rops=0 print('// Dendro: printing temp variables',file=c_file) for (v1, v2) in _v[0]: # print("double %s = %s;" % (v1, v2)) # replace_pow(v2))) print('double ', end='', file=c_file) print(change_deriv_names(ccode(v2, assign_to=v1, user_functions=custom_functions)),file=c_file) rops = rops + count_ops(v2) print('// Dendro: printing variables',file=c_file) for i, e in enumerate(_v[1]): print("//--",file=c_file) # print("%s = %s;" % (lname[i], e)) # replace_pow(e))) f = open(str(vnames[0])+'.gv','w') print(dotprint(e), file=f) f.close() print(change_deriv_names(ccode(e, assign_to=lname[i], user_functions=custom_functions)),file=c_file) #c_file.write('\n') rops = rops + count_ops(e) print('// Dendro: reduced ops: ', rops,file=c_file) print('// Dendro: }}} ',file=c_file) print(' /* debugging */',file=c_file) print(' /*unsigned int qi = 46 - 1;',file=c_file) print(' unsigned int qj = 10 - 1;',file=c_file) print(' unsigned int qk = 60 - 1;',file=c_file) print(' unsigned int qidx = qi + nx*(qj + ny*qk);',file=c_file) print(' if (0 && qidx == pp) {',file=c_file) print(' std::cout << ".... end OPTIMIZED debug stuff..." << std::endl;',file=c_file) print(' }*/',file=c_file) print(' }',file=c_file) print(' }',file=c_file) print('}',file=c_file) print(' bssn::timer::t_rhs.stop();',file=c_file) c_file.close() print('generating code for '+vnames[0]+' completed')
def convert_to_symbolic_indices(seq, start=None, gen=None, qubit_map=None): """Returns the circuit with symbolic indices and the dictionary mapping symbolic indices to real indices. The mapping is 1 to 1 and onto (bijective). Parameters ========== seq : tuple, Gate/Integer/tuple or Mul A tuple of Gate, Integer, or tuple objects, or a Mul start : Symbol An optional starting symbolic index gen : object An optional numbered symbol generator qubit_map : dict An existing mapping of symbolic indices to real indices All symbolic indices have the format 'i#', where # is some number >= 0. """ if isinstance(seq, Mul): seq = seq.args # A numbered symbol generator index_gen = numbered_symbols(prefix='i', start=-1) cur_ndx = next(index_gen) # keys are symbolic indices; values are real indices ndx_map = {} def create_inverse_map(symb_to_real_map): rev_items = lambda item: tuple([item[1], item[0]]) return dict(map(rev_items, symb_to_real_map.items())) if start is not None: if not isinstance(start, Symbol): msg = 'Expected Symbol for starting index, got %r.' % start raise TypeError(msg) cur_ndx = start if gen is not None: if not isinstance(gen, numbered_symbols().__class__): msg = 'Expected a generator, got %r.' % gen raise TypeError(msg) index_gen = gen if qubit_map is not None: if not isinstance(qubit_map, dict): msg = ('Expected dict for existing map, got ' + '%r.' % qubit_map) raise TypeError(msg) ndx_map = qubit_map ndx_map = _sympify_qubit_map(ndx_map) # keys are real indices; keys are symbolic indices inv_map = create_inverse_map(ndx_map) sym_seq = () for item in seq: # Nested items, so recurse if isinstance(item, Gate): result = convert_to_symbolic_indices(item.args, qubit_map=ndx_map, start=cur_ndx, gen=index_gen) sym_item, new_map, cur_ndx, index_gen = result ndx_map.update(new_map) inv_map = create_inverse_map(ndx_map) elif isinstance(item, tuple) or isinstance(item, Tuple): result = convert_to_symbolic_indices(item, qubit_map=ndx_map, start=cur_ndx, gen=index_gen) sym_item, new_map, cur_ndx, index_gen = result ndx_map.update(new_map) inv_map = create_inverse_map(ndx_map) elif item in inv_map: sym_item = inv_map[item] else: cur_ndx = next(gen) ndx_map[cur_ndx] = item inv_map[item] = cur_ndx sym_item = cur_ndx if isinstance(item, Gate): sym_item = item.__class__(*sym_item) sym_seq = sym_seq + (sym_item, ) return sym_seq, ndx_map, cur_ndx, index_gen
def minimal_polynomial(ex, x=None, **args): """ Computes the minimal polynomial of an algebraic number. **Example** >>> from sympy import minimal_polynomial, sqrt >>> from sympy.abc import x >>> minimal_polynomial(sqrt(2), x) x**2 - 2 >>> minimal_polynomial(sqrt(2) + sqrt(3), x) x**4 - 10*x**2 + 1 """ generator = numbered_symbols('a', cls=Dummy) mapping, symbols, replace = {}, {}, [] ex = sympify(ex) if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly def update_mapping(ex, exp, base=None): a = generator.next() symbols[ex] = a if base is not None: mapping[ex] = a**exp + base else: mapping[ex] = exp.as_expr(a) return a def bottom_up_scan(ex): if ex.is_Atom: if ex is S.ImaginaryUnit: if ex not in mapping: return update_mapping(ex, 2, 1) else: return symbols[ex] elif ex.is_Rational and ex.q != 0: return ex elif ex.is_Add: return Add(*[ bottom_up_scan(g) for g in ex.args ]) elif ex.is_Mul: return Mul(*[ bottom_up_scan(g) for g in ex.args ]) elif ex.is_Pow: if ex.exp.is_Rational: if ex.exp < 0 and ex.base.is_Add: coeff, terms = ex.base.as_coeff_add() elt, _ = primitive_element(terms, polys=True) alg = ex.base - coeff # XXX: turn this into eval() inverse = invert(elt.gen + coeff, elt).as_expr() base = inverse.subs(elt.gen, alg).expand() if ex.exp == -1: return bottom_up_scan(base) else: ex = base**(-ex.exp) if not ex.exp.is_Integer: base, exp = (ex.base**ex.exp.p).expand(), Rational(1, ex.exp.q) else: base, exp = ex.base, ex.exp base = bottom_up_scan(base) expr = base**exp if expr not in mapping: return update_mapping(expr, 1/exp, -base) else: return symbols[expr] elif ex.is_AlgebraicNumber: if ex.root not in mapping: return update_mapping(ex.root, ex.minpoly) else: return symbols[ex.root] raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) polys = args.get('polys', False) if ex.is_AlgebraicNumber: if not polys: return ex.minpoly.as_expr(x) else: return ex.minpoly.replace(x) elif ex.is_Rational and ex.q != 0: result = ex.q*x - ex.p else: F = [x - bottom_up_scan(ex)] + mapping.values() G = groebner(F, symbols.values() + [x], order='lex') _, factors = factor_list(G[-1]) if len(factors) == 1: ((result, _),) = factors else: for result, _ in factors: if result.subs(x, ex).evalf(chop=True) == 0: break else: # pragma: no cover raise NotImplementedError("multiple candidates for the minimal polynomial of %s" % ex) if polys: return cls(result, x, field=True) else: return result
def minimal_polynomial(ex, x=None, **args): """ Computes the minimal polynomial of an algebraic number. Examples ======== >>> from sympy import minimal_polynomial, sqrt >>> from sympy.abc import x >>> minimal_polynomial(sqrt(2), x) x**2 - 2 >>> minimal_polynomial(sqrt(2) + sqrt(3), x) x**4 - 10*x**2 + 1 """ from sympy.polys.polytools import degree from sympy.core.function import expand_mul, expand_multinomial from sympy.simplify.simplify import _is_sum_surds generator = numbered_symbols("a", cls=Dummy) mapping, symbols, replace = {}, {}, [] ex = sympify(ex) if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy("x"), PurePoly def update_mapping(ex, exp, base=None): a = generator.next() symbols[ex] = a if base is not None: mapping[ex] = a ** exp + base else: mapping[ex] = exp.as_expr(a) return a def bottom_up_scan(ex): if ex.is_Atom: if ex is S.ImaginaryUnit: if ex not in mapping: return update_mapping(ex, 2, 1) else: return symbols[ex] elif ex.is_Rational: return ex elif ex.is_Add: return Add(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Mul: return Mul(*[bottom_up_scan(g) for g in ex.args]) elif ex.is_Pow: if ex.exp.is_Rational: if ex.exp < 0 and ex.base.is_Add: coeff, terms = ex.base.as_coeff_add() elt, _ = primitive_element(terms, polys=True) alg = ex.base - coeff # XXX: turn this into eval() inverse = invert(elt.gen + coeff, elt).as_expr() base = inverse.subs(elt.gen, alg).expand() if ex.exp == -1: return bottom_up_scan(base) else: ex = base ** (-ex.exp) if not ex.exp.is_Integer: base, exp = (ex.base ** ex.exp.p).expand(), Rational(1, ex.exp.q) else: base, exp = ex.base, ex.exp base = bottom_up_scan(base) expr = base ** exp if expr not in mapping: return update_mapping(expr, 1 / exp, -base) else: return symbols[expr] elif ex.is_AlgebraicNumber: if ex.root not in mapping: return update_mapping(ex.root, ex.minpoly) else: return symbols[ex.root] raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) def simpler_inverse(ex): """ Returns True if it is more likely that the minimal polynomial algorithm works better with the inverse """ if ex.is_Pow: if (1 / ex.exp).is_integer and ex.exp < 0: if ex.base.is_Add: return True if ex.is_Mul: hit = True a = [] for p in ex.args: if p.is_Add: return False if p.is_Pow: if p.base.is_Add and p.exp > 0: return False if hit: return True return False polys = args.get("polys", False) prec = args.pop("prec", 10) inverted = False ex = expand_multinomial(ex) if ex.is_AlgebraicNumber: if not polys: return ex.minpoly.as_expr(x) else: return ex.minpoly.replace(x) elif ex.is_Rational: result = ex.q * x - ex.p else: inverted = simpler_inverse(ex) if inverted: ex = ex ** -1 res = None if ex.is_Pow and (1 / ex.exp).is_Integer: n = 1 / ex.exp res = _minimal_polynomial_sq(ex.base, n, x, prec) elif _is_sum_surds(ex): res = _minimal_polynomial_sq(ex, S.One, x, prec) if res is not None: result = res if res is None: bus = bottom_up_scan(ex) F = [x - bus] + mapping.values() G = groebner(F, symbols.values() + [x], order="lex") _, factors = factor_list(G[-1]) # by construction G[-1] has root `ex` result = _choose_factor(factors, x, ex, prec) if result is None: raise NotImplementedError("multiple candidates for the minimal polynomial of %s" % ex) if inverted: result = expand_mul(x ** degree(result) * result.subs(x, 1 / x)) if result.coeff(x ** degree(result)) < 0: result = expand_mul(-result) if polys: return cls(result, x, field=True) else: return result