def split_stochastic(self): ''' Split the expression into a stochastic and non-stochastic part. Splits the expression into a tuple of one `Expression` objects f (the non-stochastic part) and a dictionary mapping stochastic variables to `Expression` objects. For example, an expression of the form ``f + g * xi_1 + h * xi_2`` would be returned as: ``(f, {'xi_1': g, 'xi_2': h})`` Note that the `Expression` objects for the stochastic parts do not include the stochastic variable itself. Returns ------- (f, d) : (`Expression`, dict) A tuple of an `Expression` object and a dictionary, the first expression being the non-stochastic part of the equation and the dictionary mapping stochastic variables (``xi`` or starting with ``xi_``) to `Expression` objects. If no stochastic variable is present in the code string, a tuple ``(self, None)`` will be returned with the unchanged `Expression` object. ''' stochastic_variables = [] for identifier in self.identifiers: if identifier == 'xi' or identifier.startswith('xi_'): stochastic_variables.append(identifier) # No stochastic variable if not len(stochastic_variables): return (self, None) s_expr = self.sympy_expr.expand() stochastic_symbols = [ sympy.Symbol(variable, real=True) for variable in stochastic_variables ] f = sympy.Wild('f', exclude=stochastic_symbols) # non-stochastic part match_objects = [ sympy.Wild('w_' + variable, exclude=stochastic_symbols) for variable in stochastic_variables ] match_expression = f for symbol, match_object in zip(stochastic_symbols, match_objects): match_expression += match_object * symbol matches = s_expr.match(match_expression) if matches is None: raise ValueError( ('Expression "%s" cannot be separated into stochastic ' 'and non-stochastic term') % self.code) f_expr = Expression(sympy_to_str(matches[f])) stochastic_expressions = dict( (variable, Expression(sympy_to_str(matches[match_object]))) for (variable, match_object) in zip(stochastic_variables, match_objects)) return (f_expr, stochastic_expressions)
def get_conditionally_linear_system(eqs): ''' Convert equations into a linear system using sympy. Parameters ---------- eqs : `Equations` The model equations. Returns ------- coefficients : dict of (sympy expression, sympy expression) tuples For every variable x, a tuple (M, B) containing the coefficients M and B (as sympy expressions) for M * x + B Raises ------ ValueError If one of the equations cannot be converted into a M * x + B form. Examples -------- >>> from brian2 import Equations >>> eqs = Equations(""" ... dv/dt = (-v + w**2) / tau : 1 ... dw/dt = -w / tau : 1 ... """) >>> system = get_conditionally_linear_system(eqs) >>> print(system['v']) (-1/tau, w**2.0/tau) >>> print(system['w']) (-1/tau, 0) ''' diff_eqs = eqs.substituted_expressions coefficients = {} for name, expr in diff_eqs: var = sp.Symbol(name, real=True) # Coefficients wildcard = sp.Wild('_A', exclude=[var]) #Additive constant constant_wildcard = sp.Wild('_B', exclude=[var]) pattern = wildcard * var + constant_wildcard # Factor out the variable s_expr = sp.collect(expr.sympy_expr.expand(), var) matches = s_expr.match(pattern) if matches is None: raise ValueError( ('The expression "%s", defining the variable %s, ' 'could not be separated into linear components') % (s_expr, name)) coefficients[name] = (matches[wildcard].simplify(), matches[constant_wildcard].simplify()) return coefficients
def trig_substitution_rule(integral): integrand, symbol = integral A = sympy.Wild('a', exclude=[0, symbol]) B = sympy.Wild('b', exclude=[0, symbol]) theta = sympy.Dummy("theta") target_pattern = A + B*symbol**2 matches = integrand.find(target_pattern) for expr in matches: match = expr.match(target_pattern) a = match.get(A, ZERO) b = match.get(B, ZERO) a_positive = ((a.is_number and a > 0) or a.is_positive) b_positive = ((b.is_number and b > 0) or b.is_positive) a_negative = ((a.is_number and a < 0) or a.is_negative) b_negative = ((b.is_number and b < 0) or b.is_negative) x_func = None if a_positive and b_positive: # a**2 + b*x**2. Assume sec(theta) > 0, -pi/2 < theta < pi/2 x_func = (sympy.sqrt(a)/sympy.sqrt(b)) * sympy.tan(theta) # Do not restrict the domain: tan(theta) takes on any real # value on the interval -pi/2 < theta < pi/2 so x takes on # any value restriction = True elif a_positive and b_negative: # a**2 - b*x**2. Assume cos(theta) > 0, -pi/2 < theta < pi/2 constant = sympy.sqrt(a)/sympy.sqrt(-b) x_func = constant * sympy.sin(theta) restriction = sympy.And(symbol > -constant, symbol < constant) elif a_negative and b_positive: # b*x**2 - a**2. Assume sin(theta) > 0, 0 < theta < pi constant = sympy.sqrt(-a)/sympy.sqrt(b) x_func = constant * sympy.sec(theta) restriction = sympy.And(symbol > -constant, symbol < constant) if x_func: # Manually simplify sqrt(trig(theta)**2) to trig(theta) # Valid due to assumed domain restriction substitutions = {} for f in [sympy.sin, sympy.cos, sympy.tan, sympy.sec, sympy.csc, sympy.cot]: substitutions[sympy.sqrt(f(theta)**2)] = f(theta) substitutions[sympy.sqrt(f(theta)**(-2))] = 1/f(theta) replaced = integrand.subs(symbol, x_func).trigsimp() replaced = replaced.subs(substitutions) if not replaced.has(symbol): replaced *= manual_diff(x_func, theta) replaced = replaced.trigsimp() secants = replaced.find(1/sympy.cos(theta)) if secants: replaced = replaced.xreplace({ 1/sympy.cos(theta): sympy.sec(theta) }) substep = integral_steps(replaced, theta) if not contains_dont_know(substep): return TrigSubstitutionRule( theta, x_func, replaced, substep, restriction, integrand, symbol)
def coeff(expr, term): expr = sp.collect(expr, term) symbols = list(term.atoms(sp.Symbol)) w = sp.Wild("coeff", exclude=symbols) m = expr.match(w * term + sp.Wild("rest")) if m: return m[w]
def holstein(Hdef): S = sympy.Symbol('S', real=True) print 'holstein' #print Hdef.atoms(sympy.Symbol) Hdef = Hdef.expand() #Hdef=Hdef.as_poly(S) p = sympy.Wild('p', exclude='S') q = sympy.Wild('q', exclude='S') r = sympy.Wild('r', exclude='S') l = sympy.Wild('l', exclude='S') #Hlin=Hdef.coeffs[0]*S**2+Hdef.coeffs[1]*S S2coeff = coeff(Hdef, S**2) Scoeff = coeff(Hdef, S) Hlin = None #Hlin=coeff(Hdef,S**2)*S**2+coeff(Hdef,S)*S #print 'S2Coeff', S2coeff #print 'Scoeff',Scoeff if Scoeff != None and S2coeff != None: Hlin = coeff(Hdef, S**2) * S**2 + coeff(Hdef, S) * S elif Scoeff == None and S2coeff != None: Hlin = coeff(Hdef, S**2) * S**2 elif Scoeff != None and S2coeff == None: #print 'S' Hlin = coeff(Hdef, S) * S return Hlin
def make_wilds(symbol): a = sympy.Wild('a', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) m = sympy.Wild('m', exclude=[symbol], properties=[lambda n: isinstance(n, sympy.Integer)]) n = sympy.Wild('n', exclude=[symbol], properties=[lambda n: isinstance(n, sympy.Integer)]) return a, b, m, n
def can_be_applied(self, dim_exprs, variable_context, node_range, orig_edges, dim_index, total_dims): # Pattern does not support unions of expressions if len(dim_exprs) > 1: return False dexpr = dim_exprs[0] # Pattern does not support ranges if not isinstance(dexpr, sympy.Basic): return False # Create wildcards val = sympy.Wild('val') mod = sympy.Wild('mod', exclude=variable_context[-1]) # Try to match an affine expression matches = dexpr.match(val % mod) if matches is None or len(matches) != 2: return False self.subexpr = matches[val] self.modulo = matches[mod] self.subpattern = None for pattern_class in SeparableMemletPattern.s_smpatterns: smpattern = pattern_class() if smpattern.can_be_applied([self.subexpr], variable_context, node_range, orig_edges, dim_index, total_dims): self.subpattern = smpattern return self.subpattern is not None
def test_match_for_assignment_collection(): x, y = pystencils.fields('x, y: float32[3d]') a, b, c, d = sp.symbols('a, b, c, d') assignments = pystencils.AssignmentCollection({ a: sp.floor(1), b: 2, c: a + c, y.center(): sp.ceiling(x.center()) + sp.floor(x.center()) }) w1 = sp.Wild('w1') w2 = sp.Wild('w2') w3 = sp.Wild('w3') wild_ceiling = sp.ceiling(w1) wild_addition = w1 + w2 assert assignments.match(pystencils.Assignment(w3, wild_ceiling + w2))[w1] == x.center() assert assignments.match(pystencils.Assignment(w3, wild_ceiling + w2)) == { w3: y.center(), w2: sp.floor(x.center()), w1: x.center() } assert assignments.find(wild_ceiling) == {sp.ceiling(x.center())} assert len([a for a in assignments.find(wild_addition) if isinstance(a, sp.Add)]) == 2
def tick(self, tick): Tm = tick.blackboard.get('Tm') # the current matrix equation unknowns = tick.blackboard.get('unknowns') R = tick.blackboard.get('Robot') u = tick.blackboard.get('curr_unk') if u.readytosolve: if(self.BHdebug): print "I'm trying to solve: ", u.symbol print " Using: ", print u.eqntosolve if u.solvemethod == "algebra": Aw = sp.Wild("Aw") Bw = sp.Wild("Bw") d = u.eqntosolve.RHS.match(Aw*u.symbol+Bw) A = d[Aw] B = d[Bw] u.solutions.append( (u.eqntosolve.LHS-B)/A ) # one soluntion u.nsolutions = 1 # or 1 u.set_solved(R,unknowns) # flag that this is solved tick.blackboard.set('curr_unk', u) tick.blackboard.set('unknowns', unknowns) return b3.SUCCESS
def Max_Stress(stress,graph,dir=[],num_list=[],Number_Average=5): a = syp.Wild('a') b = syp.Wild('b') c = syp.Wild('c') x = syp.symbols('x') y = syp.symbols('y') ccc = syp.collect(stress,[x,y],evaluate=False) try: a1 = float(ccc[x]) except: a1 = 0 try: b1 = float(ccc[y]) except: b1 = 0 try: c1 = float(ccc[S(1)]) except: c1 = 0 xdir = [float(dir[i][0]) for i in range(0,len(dir))] ydir = [float(dir[i][1]) for i in range(0,len(dir))] max_stress = 0 min_stress = 0 if num_list == []: for v in graph: for e in v.getConnections(): thick_ij = v.getWeight(e) if thick_ij != 0: xx = np.linspace(xdir[v.id],xdir[e.id],Number) yy = np.linspace(ydir[v.id],ydir[e.id],Number) zz = a1*xx + b1*yy + c1 a = max(zz) if a > max_stress: max_stress = a b = min(zz) if b < min_stress: min_stress = b if num_list: for i in range(len(num_list)): m = num_list[i][0] n = num_list[i][1] xx = np.linspace(xdir[m],xdir[n],Number_Average) yy = np.linspace(ydir[m],ydir[n],Number_Average) zz = a1*xx + b1*yy + c1 a = max(zz) if a > max_stress: max_stress = a b = min(zz) if b < min_stress: min_stress = b return [max_stress,min_stress]
def heaviside_pattern(symbol): m = sympy.Wild('m', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) g = sympy.Wild('g') pattern = sympy.Heaviside(m * symbol + b) * g return pattern, m, b, g
def tick(self, tick): unknowns = tick.blackboard.get("unknowns") R = tick.blackboard.get('Robot') Tm = tick.blackboard.get('Tm') solvedtag = False thx = sp.Wild('thx') thy = sp.Wild('thy') sgn = sp.Wild('sgn') #for unk in unknowns: #if unk.n == 0 and unk.solved: #joint varible has order of 0 if len(Tm.auxeqns) > 0: for e in Tm.auxeqns: #d = unk.joint_eq.match(thx + sgn * thy) print e d = e.RHS.match(thx + sgn * thy) unka = find_obj(d[thx], unknowns) #print unka unkb = find_obj(d[thy], unknowns) #print unkb if unka == None: print "variable %s doesn't exist" % (d[thx]) elif unkb == None: print "variable %s doesn't exist" % (d[thy]) else: if unka.solved and (not unkb.solved): sol = (e.LHS - unka.symbol) / d[sgn] unkb.solutions.append(sol) unkb.nsolutions = 1 unkb.set_solved(R, unknowns) solvedtag = True if self.BHdebug: print "I'm solving %s from joint variable %s" % ( unkb.symbol, e.LHS) print "solution: %s" % sol elif unkb.solved and (not unka.solved): sol = e.LHS - d[sgn] * unkb.symbol unka.solutions.append(sol) unka.nsolutions = 1 unka.set_solved(R, unknowns) solvedtag = True if self.BHdebug: print "I'm solving %s from joint variable %s" % ( unka.symbol, e.LHS) print "solution: %s" % sol #tick.blackboard.set('test_id', test_id) tick.blackboard.set('unknowns', unknowns) tick.blackboard.set('Robot', R) if solvedtag: return b3.SUCCESS return b3.FAILURE
def flip_variant(expr): """ Change every momentum in expr from contravariant to covariant or vice versa and returns the new expression. """ a = sy.Wild("a") b = sy.Wild("b") c = sy.Wild("c") return expr.replace(Momentum(a, b, c), Momentum(a, b, 1 - c))
def tick(self, tick): unknowns = tick.blackboard.get( 'unknowns') # the current list of unknowns R = tick.blackboard.get('Robot') one_unk = tick.blackboard.get('eqns_1u') two_unk = tick.blackboard.get('eqns_2u') u = tick.blackboard.get('curr_unk') # identify unknowns in T where one equation can be solved by # arcsin() or arccos() Aw = sp.Wild("Aw") Bw = sp.Wild("Bw") Cw = sp.Wild('Cw') Dw = sp.Wild('Dw') found = False if (not u.solved): # only if not already solved! for e in one_unk: # only look at the eqns with one unknowns print "Looking for unknown: ", u.symbol, " in equation: ", print e tmp = e.RHS - e.LHS lhs = l_1 - l_1 if (tmp.has(sp.sin(u.symbol)) and tmp.has(sp.cos(u.symbol))): es = tmp.expand() # collect terms in sin(x) and cos(x) es = es.collect(sp.sin(u.symbol)) es = es.collect(sp.cos(u.symbol)) d = {} d[Aw] = es.coeff(sp.sin(u.symbol)) d[Bw] = es.coeff(sp.cos(u.symbol)) d[Cw] = es - d[Aw] * sp.sin(u.symbol) - d[Bw] * sp.cos( u.symbol) if (self.BHdebug): print 'Sin AND Cos identifying: ', es print 'Aw: ', d[Aw], ' Bw: ', d[Bw], ' Cw: ', d[Cw] if not d[Cw].has(u.symbol): u.readytosolve = True u.eqntosolve = kc.kequation(lhs, es) u.solvemethod = "sinANDcos" found = True break tick.blackboard.set('curr_unk', u) tick.blackboard.set('Robot', R) tick.blackboard.set('unknowns', unknowns) # the current list of unknowns if found: return b3.SUCCESS else: return b3.FAILURE
def test_wild_typed_symbol(): x = pystencils.fields('x: float32[3d]') typed_symbol = pystencils.data_types.TypedSymbol('a', create_type('float64')) assert x.center().match(sp.Wild('w1')) assert typed_symbol.match(sp.Wild('w1')) wild_ceiling = sp.ceiling(sp.Wild('w1')) assert sp.ceiling(x.center()).match(wild_ceiling) assert sp.ceiling(typed_symbol).match(wild_ceiling)
def _check_map_conflicts(map, edge): for itervar, (_, _, mapskip) in zip(map.params, map.range): itersym = symbolic.pystr_to_symbolic(itervar) a = sp.Wild('a', exclude=[itersym]) b = sp.Wild('b', exclude=[itersym]) if not _check_range_conflicts(edge.data.subset, a, itersym, b, mapskip): return False # If matches all map params, good to go return True
def generate_cross_section(N, arg, atom_list): """Generates the Cross-Section Formula for the one magnon case""" S = sp.Symbol('S', commutative=True) gam = sp.Symbol('gamma', commutative=True) r = sp.Symbol('r0', commutative=True) h = sp.Symbol('hbar', commutative=True) k = sp.Symbol('k', commutative=True) kp = sp.Symbol('kp', commutative=True) g = sp.Symbol('g', commutative=True) F = sp.Function('F') kap = sp.Symbol('kappa', commutative=True) kapx = sp.Symbol('kappax', commutative=True) kapy = sp.Symbol('kappay', commutative=True) w = sp.Symbol('w', commutative=True) W = sp.Symbol('W', commutative=False) t = sp.Symbol('t', commutative=True) dif = sp.Symbol('diff', commutative=False) A = sp.Wild('A', exclude=[0]) B = sp.Wild('B', exclude=[0]) C = sp.Wild('C', exclude=[0]) D = sp.Wild('D', exclude=[0]) front_constant = (gam * r)**2 / (2 * pi * h) * (kp / k) * N front_func = (1. / 2.) * g * F(kap) * exp(-2 * W) temp2 = [] temp3 = [] temp4 = [] # This is were the heart of the calculation comes in. # First the exponentials are turned into delta functions: # exp(I(wq*t - w*t)) ---> delta(wq-w) # exp(I(wq*t - w*t)+I*(q-qp)*l) ---> delta(wq*t-w*t+q*l-qp*l) ---> delta(wq-w)*delta(q*l-qp*l) # NEEDS REVIEW for i in range(len(arg)): # _ for j in range(N): # ^ arg[i][j] = (arg[i][j] * exp(-I * w * t)).expand() # | arg[i][j] = sub_in(arg[i][j], exp(A * I * t + B * I * t), sp.DiracDelta(A + B)) # | arg[i][j] = sub_in(arg[i][j], exp(I * t * A + I * t * B + I * C + I * D), sp.DiracDelta(A * t + B * t + C + D)) # | arg[i][j] = sub_in(arg[i][j], sp.DiracDelta(A * t + B * t + C + D), sp.DiracDelta(A + B) * sp.DiracDelta(C + D)) # | temp2.append(exp(I * kap * atom_list[j]) * arg[i][j]) # | temp3.append(sum(temp2)) # | print "Converted to Delta Functions!" # | for i in range(len(temp3)): # | temp4.append((1 - kapx**2) * temp3[i]) # V dif = front_constant * front_func**2 * (sum(temp4)) # _ print "Cross-section calculated!" return dif
def write_conflicted_map_params(map, edge): result = [] for itervar, (_, _, mapskip) in zip(map.params, map.range): itersym = symbolic.pystr_to_symbolic(itervar) a = sp.Wild('a', exclude=[itersym]) b = sp.Wild('b', exclude=[itersym]) if not _check_range_conflicts(edge.data.subset, a, itersym, b, mapskip): result.append(itervar) return result
def _cases_from_branches( edges: List[Edge[InterstateEdge]], cblocks: Dict[Edge[InterstateEdge], GeneralBlock], ) -> Tuple[str, Dict[str, GeneralBlock]]: """ If the input list of edges correspond to a switch/case scope (with all conditions being "x == y" for a unique symbolic x and integers y), returns the switch/case scope parameters. :param edges: List of inter-state edges. :return: Tuple of (case variable C++ expression, mapping from case to control flow block). If not a valid switch/case scope, returns None. """ cond = edges[0].data.condition_sympy() if not isinstance(cond, sp.Basic): return None a = sp.Wild('a') b = sp.Wild('b', properties=[lambda k: k.is_Integer]) m = cond.match(sp.Eq(a, b)) if m: # Obtain original code for variable call_or_compare = edges[0].data.condition.code[0].value if isinstance(call_or_compare, ast.Call): astvar = call_or_compare.args[0] else: # Binary comparison astvar = call_or_compare.left else: # Try integer == symbol m = cond.match(sp.Eq(b, a)) if m: call_or_compare = edges[0].data.condition.code[0].value if isinstance(call_or_compare, ast.Call): astvar = call_or_compare.args[1] else: # Binary comparison astvar = call_or_compare.right else: return None # Get C++ expression from AST switchvar = cppunparse.pyexpr2cpp(astvar) # Check that all edges match criteria result = {} for e in edges: ematch = e.data.condition_sympy().match(sp.Eq(m[a], b)) if not ematch: ematch = e.data.condition_sympy().match(sp.Eq(b, m[a])) if not ematch: return None # Create mapping to codeblocks result[cpp.sym2cpp(ematch[b])] = cblocks[e] return switchvar, result
def sympy_ceiling_fix(expr): """ Fix for SymPy printing out reciprocal values when they should be integral in "ceiling/floor" sympy functions. """ nexpr = expr if not isinstance(expr, sympy.Basic): return expr # The properties avoid matching the silly case "ceiling(N/32)" as # ceiling of 1/N and 1/32 a = sympy.Wild('a', properties=[lambda k: k.is_Symbol or k.is_Integer]) b = sympy.Wild('b', properties=[lambda k: k.is_Symbol or k.is_Integer]) c = sympy.Wild('c') d = sympy.Wild('d') int_ceil = sympy.Function('int_ceil') int_floor = sympy.Function('int_floor') processed = 1 while processed > 0: processed = 0 for ceil in nexpr.find(sympy.ceiling): # Simple ceiling m = ceil.match(sympy.ceiling(a / b)) if m is not None: nexpr = nexpr.subs(ceil, int_ceil(m[a], m[b])) processed += 1 continue # Ceiling of ceiling: "ceil(ceil(c/d) / b)" m = ceil.match(sympy.ceiling(int_ceil(c, d) / b)) if m is not None: nexpr = nexpr.subs(ceil, int_ceil(int_ceil(m[c], m[d]), m[b])) processed += 1 continue # Ceiling of ceiling: "ceil(a / ceil(c/d))" m = ceil.match(sympy.ceiling(a / int_ceil(c, d))) if m is not None: nexpr = nexpr.subs(ceil, int_ceil(m[a], int_ceil(m[c], m[d]))) processed += 1 continue # Match ceiling of multiplication with our custom integer functions m = ceil.match(sympy.ceiling(a * int_floor(c, d))) if m is not None: nexpr = nexpr.subs(ceil, m[a] * int_floor(m[c], m[d])) processed += 1 continue m = ceil.match(sympy.ceiling(a * int_ceil(c, d))) if m is not None: nexpr = nexpr.subs(ceil, m[a] * int_ceil(m[c], m[d])) processed += 1 continue return nexpr
def arctan_rule(integral): integrand, symbol = integral base, exp = integrand.as_base_exp() if sympy.simplify(exp + 1) == 0: a = sympy.Wild('a', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) match = base.match(a + b * symbol**2) if match: a, b = match[a], match[b] if ((isinstance(a, sympy.Number) and a < 0) or (isinstance(b, sympy.Number) and b < 0)): return if (sympy.ask( sympy.Q.negative(a) | sympy.Q.negative(b) | sympy.Q.is_true(a <= 0) | sympy.Q.is_true(b <= 0))): return if a != 1 or b != 1: b_condition = b >= 0 u_var = sympy.Dummy("u") rewritten = (sympy.Integer(1) / a) * (base / a)**(-1) u_func = sympy.sqrt(sympy.sympify(b) / a) * symbol constant = 1 / sympy.sqrt(sympy.sympify(b) / a) substituted = rewritten.subs(u_func, u_var) if a == b: substep = ArctanRule(integrand, symbol) else: subrule = ArctanRule(substituted, u_var) if constant != 1: b_condition = b > 0 subrule = ConstantTimesRule(constant, substituted, subrule, substituted, symbol) substep = URule(u_var, u_func, constant, subrule, integrand, symbol) if a != 1: other = (base / a)**(-1) substep = ConstantTimesRule( sympy.Integer(1) / a, other, substep, integrand, symbol) return PiecewiseRule( [(substep, sympy.And(a > 0, b_condition))], integrand, symbol) return ArctanRule(integrand, symbol)
def canonise_log(equation): expanded_log = sympy.expand_log(equation, force=True) terms = expanded_log.as_ordered_terms() a, b = sympy.Wild('a'), sympy.Wild('b') total_interior = 1 for term in terms: if sympy.ask(sympy.Q.complex(term)): term_interior *= -1 else: term_interior = term.match(sympy.log(a) / b)[a] if term.could_extract_minus_sign(): total_interior /= term_interior else: total_interior *= term_interior if isinstance(total_interior, sympy.Add): invert = False elif isinstance(total_interior, sympy.Mul): match = total_interior.together().match(x / b) # for some reason, (x/3).match(a/b) gives {a: 1/3, b: 1/x} so we have to use a workaround if match is not None: invert = False else: match = total_interior.together().match(a / b) degree_numerator = 0 if isinstance(match[a], sympy.Rational) else match[a].as_poly().degree() degree_denominator = 0 if isinstance(match[b], sympy.Rational) else match[b].as_poly().degree() if degree_numerator < degree_denominator: invert = True else: invert = False elif isinstance(total_interior, sympy.Pow): index = total_interior.as_base_exp()[1] if index < 0: invert = True else: invert = False else: # for debugging - wtf kind of c-c-c-class is it??? print(total_interior, type(total_interior)) if invert: return -sympy.log((1 / total_interior).together(), evaluate=False) / terms[0].as_coeff_Mul()[0].q else: return sympy.log(total_interior.together(), evaluate=False) / terms[0].as_coeff_Mul()[0].q
def _set_axis_and_point(self, cond_eq: sympy.Equality, coords: cs.CoordinateSystem): coord_vars = coords.axises() self.axis, self.axis_point = None, None U = sympy.Function("u") u_entrances = list(cond_eq.find(U)) if len(u_entrances) != 1: raise ValueError( "Cannot contain different args in U for derivative and u function" ) a1 = sympy.Wild("a1", properties=[lambda x: x.is_constant]) a2 = sympy.Wild("a2", properties=[lambda x: x.is_constant]) u_pow = sympy.Wild("u_pow", properties=[lambda x: x.is_constant]) axis = sympy.Wild("axis", properties=[lambda x: x.is_symbol]) U_pattern = sympy.WildFunction("U_pattern", nargs=len(coords.axises())) res = cond_eq.lhs.match( a1 * U_pattern ** u_pow + a2 * sympy.Derivative(U_pattern, axis) ) if res is None: raise ValueError(f"Cannot parse {cond_eq}") self.a1 = res[a1] self.a2 = res[a2] u_with_args = res[U_pattern] if self.a1 != 0 and self.a2 == 0: self.kind = ConditionKind.First.name elif self.a1 == 0 and self.a2 != 0: self.kind = ConditionKind.Second.name elif self.a1 != 0 and self.a2 != 0: self.kind = ConditionKind.Third.name else: raise ValueError( f"Left side of boundary condition: {cond_eq} does" "not contain u function" ) for i, arg in enumerate(u_with_args.args): if arg.is_constant(): self.axis = coord_vars[i] self.axis_point = sympy.fcode(arg.evalf()) self._axis_point = arg break if self.axis is None: raise ValueError( "Bondary condition cannot be parsed" "Probably you did not specified U arguments or" "there is no constant in arguments" )
def quadratic_denom_rule(integral): integrand, symbol = integral a = sympy.Wild('a', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) c = sympy.Wild('c', exclude=[symbol]) match = integrand.match(a / (b * symbol ** 2 + c)) if not match: return a, b, c = match[a], match[b], match[c] return PiecewiseRule([(ArctanRule(a, b, c, integrand, symbol), sympy.Gt(c / b, 0)), (ArccothRule(a, b, c, integrand, symbol), sympy.And(sympy.Gt(symbol ** 2, -c / b), sympy.Lt(c / b, 0))), (ArctanhRule(a, b, c, integrand, symbol), sympy.And(sympy.Lt(symbol ** 2, -c / b), sympy.Lt(c / b, 0))), ], integrand, symbol)
def pinv(A_expr): a_wild_expr = sympy.Wild("a_wild") assert A_expr == A_expr.replace(sympy.conjugate(a_wild_expr),a_wild_expr) A_pinv_expr = A_expr.pinv() A_pinv_expr = A_pinv_expr.replace(sympy.conjugate(a_wild_expr),a_wild_expr) return A_pinv_expr
def can_be_applied(self, dim_exprs, variable_context, node_range, orig_edges, dim_index, total_dims): # Pattern does not support unions of expressions. TODO: Support if len(dim_exprs) > 1: return False dexpr = dim_exprs[0] # Create a wildcard that excludes current map's parameters cst = sympy.Wild('cst', exclude=variable_context[-1]) # Range case if isinstance(dexpr, tuple) and len(dexpr) == 3: # Try to match a constant expression for the range for rngelem in dexpr: if dtypes.isconstant(rngelem): continue matches = rngelem.match(cst) if matches is None or len(matches) != 1: return False if not matches[cst].is_constant(): return False else: # Single element case # Try to match a constant expression if not dtypes.isconstant(dexpr): matches = dexpr.match(cst) if matches is None or len(matches) != 1: return False if not matches[cst].is_constant(): return False return True
def test_floor_ceil_float_no_optimization(): x, y = pystencils.fields('x,y: float32[2d]') a, b, c = sp.symbols('a, b, c') int_symbol = sp.Symbol('int_symbol', integer=True) typed_symbol = pystencils.TypedSymbol('typed_symbol', create_type('float32')) assignments = pystencils.AssignmentCollection({ a: sp.floor(1), b: sp.ceiling(typed_symbol), c: sp.floor(int_symbol), y.center(): sp.ceiling(x.center()) + sp.floor(x.center()) }) assert not typed_symbol.is_integer print(sp.simplify(sp.ceiling(typed_symbol))) print(assignments) wild_floor = sp.floor(sp.Wild('w1')) assert not sp.floor(int_symbol).match(wild_floor) assert sp.floor(a).match(wild_floor) assert assignments.find(wild_floor)
def trig_sindouble_rule(integral): integrand, symbol = integral a = sympy.Wild('a', exclude=[sympy.sin(2*symbol)]) match = integrand.match(sympy.sin(2*symbol)*a) if match: sin_double = 2*sympy.sin(symbol)*sympy.cos(symbol)/sympy.sin(2*symbol) return integral_steps(integrand * sin_double, symbol)
def _modify_cond(self, condition, var, step): condition = pystr_to_symbolic(condition.as_string) itersym = pystr_to_symbolic(var) # Find condition by matching expressions end: Optional[sp.Expr] = None a = sp.Wild('a') op = '' match = condition.match(itersym < a) if match: op = '<' end = match[a] - self.count * step if end is None: match = condition.match(itersym <= a) if match: op = '<=' end = match[a] - self.count * step if end is None: match = condition.match(itersym > a) if match: op = '>' end = match[a] - self.count * step if end is None: match = condition.match(itersym >= a) if match: op = '>=' end = match[a] - self.count * step if len(op) == 0: raise ValueError('Cannot match loop condition for peeling') res = str(itersym) + op + str(end) return res
def expr_to_code(expr, symbols_replace, function_replace, display=None): import re if display is not None: print("+ expression to code {}".format(display), end="\r") # sympy function to replace into STL C++ functions math_to_stl = [(f, sp.Function("std::" + str(f), nargs=1)) for f in (sp.sin, sp.cos, sp.exp)] math_to_stl.append((sp.sqrt, sp.Function("std::sqrt", nargs=1))) # first step: replace symbols tmp = expr.subs(symbols_replace) # second step: use STL functions for old, new in math_to_stl: tmp = tmp.subs(old, new) # next step: use user-defined functions for old, new in function_replace: tmp = tmp.replace(old, new) # last step: convert all division by 2 by multiplication by 0.5 a = sp.Wild('a') tmp = tmp.replace(a / 2, 0.5 * a, exact=True).evalf() # and return a string (where remove every `1.0*` pattern where there is not a number before) return re.sub(r"([^0-9])1\.0\*", r"\1", str(tmp))