def test_symbol_splitting(): # By default Greek letter names should not be split (lambda is a keyword # so skip it) transformations = standard_transformations + (split_symbols,) greek_letters = ('alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', 'iota', 'kappa', 'mu', 'nu', 'xi', 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon', 'phi', 'chi', 'psi', 'omega') for letter in greek_letters: assert(parse_expr(letter, transformations=transformations) == parse_expr(letter)) # Make sure custom splitting works def can_split(symbol): if symbol not in ('unsplittable', 'names'): return _token_splittable(symbol) return False transformations = standard_transformations transformations += (split_symbols_custom(can_split), implicit_multiplication) assert(parse_expr('unsplittable', transformations=transformations) == parse_expr('unsplittable')) assert(parse_expr('names', transformations=transformations) == parse_expr('names')) assert(parse_expr('xy', transformations=transformations) == parse_expr('x*y')) for letter in greek_letters: assert(parse_expr(letter, transformations=transformations) == parse_expr(letter))
def test_implicit_multiplication(): cases = { '5x': '5*x', 'abc': 'a*b*c', '3sin(x)': '3*sin(x)', '(x+1)(x+2)': '(x+1)*(x+2)', '(5 x**2)sin(x)': '(5*x**2)*sin(x)', '2 sin(x) cos(x)': '2*sin(x)*cos(x)', 'pi x': 'pi*x', 'x pi': 'x*pi', 'E x': 'E*x', 'EulerGamma y': 'EulerGamma*y', 'E pi': 'E*pi', 'pi (x + 2)': 'pi*(x+2)', '(x + 2) pi': '(x+2)*pi', 'pi sin(x)': 'pi*sin(x)', } transformations = standard_transformations + (convert_xor,) transformations2 = transformations + (split_symbols, implicit_multiplication) for case in cases: implicit = parse_expr(case, transformations=transformations2) normal = parse_expr(cases[case], transformations=transformations) assert(implicit == normal) application = ['sin x', 'cos 2*x', 'sin cos x'] for case in application: raises(SyntaxError, lambda: parse_expr(case, transformations=transformations2)) raises(TypeError, lambda: parse_expr('sin**2(x)', transformations=transformations2))
def ode_is_lin_const_coeff(ode_symbol, ode_definition, shapes): """ TODO: improve the original code: the function should take a list of shape names, not objects :param ode_symbol string encoding the LHS :param ode_definition string encoding RHS :param shapes A list with shape names :return true iff the ode definition is a linear and constant coefficient ODE """ ode_symbol_sp = parse_expr(ode_symbol) ode_definition_sp = parse_expr(ode_definition) # Check linearity ddvar = diff(diff(ode_definition_sp, ode_symbol_sp), ode_symbol_sp) if simplify(ddvar) != 0: return False # Check coefficients dvar = diff(ode_definition_sp, ode_symbol_sp) for shape in shapes: for symbol in dvar.free_symbols: if shape == str(symbol): return False return True
def test_local_dict_symbol_to_fcn(): x = Symbol('x') d = {'foo': Function('bar')} assert parse_expr('foo(x)', local_dict=d) == d['foo'](x) # XXX: bit odd, but would be error if parser left the Symbol d = {'foo': Symbol('baz')} assert parse_expr('foo(x)', local_dict=d) == Function('baz')(x)
def test_issue_10560(): inputs = { '4*-3' : '(-3)*4', '-4*3' : '(-4)*3', } for text, result in inputs.items(): assert parse_expr(text, evaluate=False) == parse_expr(result, evaluate=False)
def test_issue_10773(): inputs = { '-10/5': '(-10)/5', '-10/-5' : '(-10)/(-5)', } for text, result in inputs.items(): assert parse_expr(text, evaluate=False) == parse_expr(result, evaluate=False)
def test_implicit_multiplication(): cases = { "5x": "5*x", "abc": "a*b*c", "3sin(x)": "3*sin(x)", "(x+1)(x+2)": "(x+1)*(x+2)", "(5 x**2)sin(x)": "(5*x**2)*sin(x)", "2 sin(x) cos(x)": "2*sin(x)*cos(x)", "pi x": "pi*x", "x pi": "x*pi", "E x": "E*x", "EulerGamma y": "EulerGamma*y", "E pi": "E*pi", "pi (x + 2)": "pi*(x+2)", "(x + 2) pi": "(x+2)*pi", "pi sin(x)": "pi*sin(x)", } transformations = standard_transformations + (convert_xor,) transformations2 = transformations + (split_symbols, implicit_multiplication) for case in cases: implicit = parse_expr(case, transformations=transformations2) normal = parse_expr(cases[case], transformations=transformations) assert implicit == normal application = ["sin x", "cos 2*x", "sin cos x"] for case in application: raises(SyntaxError, lambda: parse_expr(case, transformations=transformations2)) raises(TypeError, lambda: parse_expr("sin**2(x)", transformations=transformations2))
def eq_sympy(input_dim, output_dim, ARD=False): """ Latent force model covariance, exponentiated quadratic with multiple outputs. Derived from a diffusion equation with the initial spatial condition layed down by a Gaussian process with lengthscale given by shared_lengthscale. See IEEE Trans Pattern Anal Mach Intell. 2013 Nov;35(11):2693-705. doi: 10.1109/TPAMI.2013.86. Linear latent force models using Gaussian processes. Alvarez MA, Luengo D, Lawrence ND. :param input_dim: Dimensionality of the kernel :type input_dim: int :param output_dim: number of outputs in the covariance function. :type output_dim: int :param ARD: whether or not to user ARD (default False). :type ARD: bool """ real_input_dim = input_dim if output_dim>1: real_input_dim -= 1 X = sp.symbols('x_:' + str(real_input_dim)) Z = sp.symbols('z_:' + str(real_input_dim)) scale = sp.var('scale_i scale_j',positive=True) if ARD: lengthscales = [sp.var('lengthscale%i_i lengthscale%i_j' % i, positive=True) for i in range(real_input_dim)] shared_lengthscales = [sp.var('shared_lengthscale%i' % i, positive=True) for i in range(real_input_dim)] dist_string = ' + '.join(['(x_%i-z_%i)**2/(shared_lengthscale%i**2 + lengthscale%i_i**2 + lengthscale%i_j**2)' % (i, i, i) for i in range(real_input_dim)]) dist = parse_expr(dist_string) f = variance*sp.exp(-dist/2.) else: lengthscales = sp.var('lengthscale_i lengthscale_j',positive=True) shared_lengthscale = sp.var('shared_lengthscale',positive=True) dist_string = ' + '.join(['(x_%i-z_%i)**2' % (i, i) for i in range(real_input_dim)]) dist = parse_expr(dist_string) f = scale_i*scale_j*sp.exp(-dist/(2*(lengthscale_i**2 + lengthscale_j**2 + shared_lengthscale**2))) return kern(input_dim, [spkern(input_dim, f, output_dim=output_dim, name='eq_sympy')])
def __dot(self,vector2): product = 0.0 for i in range(len(vector2)): try: product += (parse_expr(self.user_fn[i])*parse_expr(vector2[i])) except: product += (parse_expr(self.user_fn[i])*vector2[i]) return product
def test_split_symbols(): transformations = standard_transformations + (split_symbols, implicit_multiplication) x = Symbol("x") y = Symbol("y") xy = Symbol("xy") assert parse_expr("xy") == xy assert parse_expr("xy", transformations=transformations) == x * y
def _check(self, res, ref): if hasattr(res, "get_x"): x = res.get_x() for k in list(res.keys()): if np.all(res[k] == x): continue elif np.any(np.iscomplex(res[k])) or np.any(np.iscomplex(ref[k])): # Interpolate Re and Im of the results to compare. x = x.reshape((-1,)) refx = ref[ref.x].reshape((-1,)) d1 = InterpolatedUnivariateSpline(x, np.real(res[k]).reshape((-1,))) d2 = InterpolatedUnivariateSpline(refx, np.real(ref[k]).reshape((-1,))) ok(d1(x), d2(x), rtol=self.er, atol=self.ea, msg=("Test %s FAILED (Re)" % self.test_id)) d1 = InterpolatedUnivariateSpline(x, np.imag(res[k]).reshape((-1,))) d2 = InterpolatedUnivariateSpline(refx, np.imag(ref[k]).reshape((-1,))) ok(d1(x), d2(x), rtol=self.er, atol=self.ea, msg=("Test %s FAILED (Im)" % self.test_id)) else: # Interpolate the results to compare. x = x.reshape((-1,)) refx = ref[ref.x].reshape((-1,)) d1 = InterpolatedUnivariateSpline(x, np.real_if_close(res[k]).reshape((-1,))) d2 = InterpolatedUnivariateSpline(refx, np.real_if_close(ref[k]).reshape((-1,))) ok(d1(x), d2(x), rtol=self.er, atol=self.ea, msg=("Test %s FAILED" % self.test_id)) elif isinstance(res, results.op_solution): for k in list(res.keys()): assert k in ref ok(res[k], ref[k], rtol=self.er, atol=self.ea, msg=("Test %s FAILED" % self.test_id)) elif isinstance(res, results.pz_solution): # recover the reference signularities from Re/Im data ref_sing_keys = list(ref.keys())[:] ref_sing_keys.sort() assert len(ref_sing_keys) % 2 == 0 ref_sing = [ ref[ref_sing_keys[int(len(ref_sing_keys) / 2) + k]] + ref[ref_sing_keys[k]] * 1j for k in range(int(len(ref_sing_keys) / 2)) ] ref_poles_num = len([k for k in ref.keys() if k[:4] == "Re(p"]) poles_ref, zeros_ref = ref_sing[:ref_poles_num], ref_sing[ref_poles_num:] assert len(poles_ref) == len(res.poles) pz._check_singularities(res.poles, poles_ref) assert len(zeros_ref) == len(res.zeros) pz._check_singularities(res.zeros, zeros_ref) else: if isinstance(res, list) or isinstance(res, tuple): for i, j in zip(res, ref): self._check(i, j) elif res is not None: for k in list(res.keys()): assert k in ref if isinstance(res[k], dict): # hence ref[k] will be a dict too self._check(res[k], ref[k]) elif isinstance(ref[k], sympy.Basic) and isinstance(res[k], sympy.Basic): # get rid of assumptions. Evaluate only expression rf = parse_expr(str(ref[k])) rs = parse_expr(str(res[k])) assert (rs == rf) or (sympy.simplify(rf / rs) == 1) else: assert res[k] == ref[k]
def test_split_symbols_function(): transformations = standard_transformations + (split_symbols, implicit_multiplication) x = Symbol("x") y = Symbol("y") a = Symbol("a") f = Function("f") assert parse_expr("ay(x+1)", transformations=transformations) == a * y * (x + 1) assert parse_expr("af(x+1)", transformations=transformations, local_dict={"f": f}) == a * f(x + 1)
def test_factorial_fail(): inputs = ['x!!!', 'x!!!!', '(!)'] for text in inputs: try: parse_expr(text) assert False except TokenError: assert True
def test_split_symbols(): transformations = standard_transformations + \ (split_symbols, implicit_multiplication,) x = Symbol('x') y = Symbol('y') xy = Symbol('xy') assert parse_expr("xy") == xy assert parse_expr("xy", transformations=transformations) == x*y
def test_fixedpoints(self): # Module B1 Page 26 points = fixed_points(parse_expr('x**2 + 1/8')) self.assertEqual(points[0], parse_expr('1/2 - 1/4 * sqrt(2)')) self.assertEqual(points[1], parse_expr('1/2 + 1/4 * sqrt(2)')) # Module B1 Page 28 points = fixed_points(parse_expr('-1/8*x**2+5/8*x+7/2')) self.assertEqual(points[0], -7) self.assertEqual(points[1], 4)
def test_convert_equals_signs(): transformations = standard_transformations + \ (convert_equals_signs, ) x = Symbol('x') y = Symbol('y') assert parse_expr("1*2=x", transformations=transformations) == Eq(2, x) assert parse_expr("y = x", transformations=transformations) == Eq(y, x) assert parse_expr("(2*y = x) = False", transformations=transformations) == Eq(Eq(2*y, x), False)
def parse_using_sympy_simplify(s): transformations = standard_transformations + (convert_xor, implicit_multiplication_application,) print(s) s = s.split('==') new_s = [] for x in s: new_s.append(str(simplify(parse_expr(x, transformations=transformations, global_dict=None, evaluate=True)))) new_s = '=='.join(new_s) return parse_expr(new_s, transformations=transformations, global_dict=None, evaluate=True)
def __init__(self,config,sec) : for it in config.options(sec) : # chaque it est la liste des variables if config.get(sec,it) == '' : # on teste si c'est vide vars(self)[it] = None elif config.get(sec,it).count(',')>=1 : # on teste si c'est une liste de param if config.get(sec,it).count('pi')==0 : # pas de pi try : vars(self)[it] = map(float,config.get(sec,it).split(',')) except ValueError : vars(self)[it] = config.get(sec,it).split(',') # une liste de chaines elif config.get(sec,it).count('pi')>=1 : # au moins un pi vars(self)[it] = [float(parse_expr(el).n()) for el in config.get(sec,it).split(',')] # on teste si c'est une chaine elif config.get(sec,it).isalpha() and config.get(sec,it).count('pi')==0: vars(self)[it]=config.get(sec,it) elif config.get(sec,it).count('pi')>=1 : vars(self)[it]=float(parse_expr(config.get(sec,it)).n()) else : # dans les autre cas c'est un float try : vars(self)[it] = config.getfloat(sec,it) except ValueError : # a-priori on a un mélange float + str vars(self)[it] = config.get(sec,it) for k in vars(self).keys() : if k[-5:]=='param' and vars(self).get(k)!=None : param=vars(self).get(k) if type(param)==str : # afin de conserver le nom du fichier d'entrée # on crée un dict avec l'extension _filename Dict_filename={k[:-6]+'_filename':param} vars(self).update(Dict_filename) # si param est une chaine c'est un fichier à charger # on doit avoir un fichier csv avec : # le delimiter= tab ou espace # les nombres au format GB # la colonne 1 = abscisses # la colonne 2 = ordonnées param=np.loadtxt(param) # afin d'eviter de lire le fichier n fois on change # la variable param en un array issu du loadtxt vars(self)[k]=param typeDyn=vars(self).get(k[:-6]+'_type') # on crée la fonction qui renvoie la propriété # la fonction partial est indispensable vars(self)[k[:-6]]=partial(self._dynamicProp,param=param,typeDyn=typeDyn) if k[-4:]=='expr' : expr=vars(self).get(k) vars(self)[k[:-5]]= parse_expr(expr) delattr(self, k)
def parse(self, context): """ Parses the string with sympy. Arguments: context: This is a dictionary of name-symbol pairs. This is used by sympy to parse the input text. Raises: EquationError """ variables = self.model.variables parameters = self.model.parameters # Rewrite the equation into canonical form equation = _rewrite(variables, parameters, self.equation) # Find the location of the equal sign, also need to ignore # things like <=, >=, ==, !=, etc... sides = re.split(r"(?<![<>=!])=(?!=)", equation) if len(sides) != 2: raise EquationError('equals-sign', self.equation, "Equation must be of the form f(...) = g(...)") transforms = (factorial_notation, auto_number) # need to examine the left-hand side rhs = parse_expr(sides[1], context, transformations=transforms) lhs = parse_expr(sides[0], context, transformations=transforms) lhs = lhs.expand() # Determine how to isolate the variable by addition/division variable, add_terms, mul_terms = self._isolate_variable(lhs) if not _is_linear(lhs, variable): raise EquationError('non-linear', self.equation, 'the main variable is not linear') if variable is not None and variable.equation is not None: raise EquationError('var-eqn-exists', self.equation, 'equation for variable already defined : ' + variable.name) if add_terms is not None: rhs = rhs - add_terms if mul_terms is not None: rhs = rhs / mul_terms self.variable = variable self.expr = rhs variable.equation = self
def test_split_symbols_function(): transformations = standard_transformations + \ (split_symbols, implicit_multiplication,) x = Symbol('x') y = Symbol('y') a = Symbol('a') f = Function('f') assert parse_expr("ay(x+1)", transformations=transformations) == a*y*(x+1) assert parse_expr("af(x+1)", transformations=transformations, local_dict={'f':f}) == a*f(x+1)
def test_repeated_fail(): inputs = ['1[1]', '.1e1[1]', '0x1[1]', '1.1j[1]', '1.1[1 + 1]', '0.1[[1]]', '0x1.1[1]'] # All are valid Python, so only raise TypeError for invalid indexing for text in inputs: raises(TypeError, lambda: parse_expr(text)) inputs = ['0.1[', '0.1[1', '0.1[]'] for text in inputs: raises((TokenError, SyntaxError), lambda: parse_expr(text))
def CheckAnswerType5 (problem, answer): facN = parse_expr('factorial('+problem.vars['n']+')') str = answer.split("/")[0] fac_ans = parse_expr(str) if (facN == fac_ans): return '5' facTop = parse_expr('factorial('+problem.vars['n']+'+'+problem.vars['k']+'-1)') if(facTop == fac_ans): return '4' else: return '-1'
def quadratic_find_roots(quad_val): x = sympy.Symbol("x") solution_ls = sympy.solve(sympy.Eq(parse_expr(quad_val), parse_expr("0")), x) solution_str = "" for sol_ind in range(0, len(solution_ls)): if (len(solution_ls) - 1) != sol_ind: solution_str += "x = " + str(solution_ls[sol_ind]) + "\n" else: solution_str += "x = " + str(solution_ls[sol_ind]) return solution_str
def test_functional_exponent(): t = standard_transformations + (convert_xor, function_exponentiation) x = Symbol('x') y = Symbol('y') a = Symbol('a') yfcn = Function('y') assert parse_expr("sin^2(x)", transformations=t) == (sin(x))**2 assert parse_expr("sin^y(x)", transformations=t) == (sin(x))**y assert parse_expr("exp^y(x)", transformations=t) == (exp(x))**y assert parse_expr("E^y(x)", transformations=t) == exp(yfcn(x)) assert parse_expr("a^y(x)", transformations=t) == a**(yfcn(x))
def test_split_symbols_numeric(): transformations = ( standard_transformations + (implicit_multiplication_application,)) n = Symbol('n') expr1 = parse_expr('2**n * 3**n') expr2 = parse_expr('2**n3**n', transformations=transformations) assert expr1 == expr2 == 2**n*3**n expr1 = parse_expr('n12n34', transformations=transformations) assert expr1 == n*12*n*34
def test_function_exponentiation(): cases = {"sin**2(x)": "sin(x)**2", "exp^y(z)": "exp(z)^y", "sin**2(E^(x))": "sin(E^(x))**2"} transformations = standard_transformations + (convert_xor,) transformations2 = transformations + (function_exponentiation,) for case in cases: implicit = parse_expr(case, transformations=transformations2) normal = parse_expr(cases[case], transformations=transformations) assert implicit == normal other_implicit = ["x y", "x sin x", "2x", "sin x", "cos 2*x", "sin cos x"] for case in other_implicit: raises(SyntaxError, lambda: parse_expr(case, transformations=transformations2))
def CheckAnswer (problem, answer): answerType = MatchAnswer(problem, answer) if (answerType == '-1'): answerType = '4' #assumption that the user was trying to answer type 4 instead of type 5 elif (answerType == '0'): #if the user enters garbage or a completely wrong formula return -2 if problem.problem_type == answerType: if (parse_expr (answer) == parse_expr(problem.formula)): return 1 else: return 0 else: return -1
def simplifyWrapper(expr): if type(expr) == type([]): for e in range(len(expr)): expr[e] = expr[e].replace('.','_6174823504_').replace('^','**') #expr[e] = str(simplify(parse_expr(expr[e]))) expr[e] = str(together(parse_expr(expr[e]))) expr[e] = expr[e].replace('_6174823504_','.').replace('**','^') return expr else: expr = expr.replace('.','_6174823504_').replace('^','**') #expr = str(simplify(parse_expr(expr))) expr = str(together(parse_expr(expr))) expr = expr.replace('_6174823504_','.').replace('**','^') return expr
def equation_of_line_slope_int(x1, y1, x2, y2): m = slope(x1, y1, x2, y2) b = sympy.Symbol("b") equation = "y = " + str(m) + " * x + b" equation = equation.replace("y", str(y1)) equation = equation.replace("x", str(x1)) equation = equation.split("=") b = sympy.solve(sympy.Eq(parse_expr(equation[0]), parse_expr(equation[1])), b) if b[0] != 0 and m != 0: return "y = " + str(m) + " * x + " + str(float(b[0])) elif b[0] == 0 and m != 0: return "y = " + str(m) + " * x" elif b[0] != 0 and m == 0: return "y = " + str(float(b[0]))
def test_rationalize(): inputs = { '0.123': Rational(123, 1000) } transformations = standard_transformations + (rationalize,) for text, result in inputs.items(): assert parse_expr(text, transformations=transformations) == result
def test_repeated_dot_only(): assert parse_expr('.[1]') == Rational(1, 9) assert parse_expr('1 + .[1]') == Rational(10, 9)
def final_gd(data_file, math_expr, lr=1e-2, N_epochs=5000): param_dict = {} unsnapped_param_dict = {'p': 1} def unsnap_recur(expr, param_dict, unsnapped_param_dict): """Recursively transform each numerical value into a learnable parameter.""" import sympy from sympy import Symbol if isinstance(expr, sympy.numbers.Float): used_param_names = list( param_dict.keys()) + list(unsnapped_param_dict) unsnapped_param_name = get_next_available_key(used_param_names, "p", is_underscore=False) unsnapped_param_dict[unsnapped_param_name] = float(expr) unsnapped_expr = Symbol(unsnapped_param_name) return unsnapped_expr elif isinstance(expr, sympy.symbol.Symbol): return expr else: unsnapped_sub_expr_list = [] for sub_expr in expr.args: unsnapped_sub_expr = unsnap_recur(sub_expr, param_dict, unsnapped_param_dict) unsnapped_sub_expr_list.append(unsnapped_sub_expr) return expr.func(*unsnapped_sub_expr_list) def get_next_available_key(iterable, key, midfix="", suffix="", is_underscore=True): """Get the next available key that does not collide with the keys in the dictionary.""" if key + suffix not in iterable: return key + suffix else: i = 0 underscore = "_" if is_underscore else "" while "{}{}{}{}{}".format(key, underscore, midfix, i, suffix) in iterable: i += 1 new_key = "{}{}{}{}{}".format(key, underscore, midfix, i, suffix) return new_key # Load the actual data data = np.loadtxt(data_file) # Turn BF expression to pytorch expression eq = parse_expr(math_expr) # eq = parse_expr("cos(0.5*a)") # this is for test_sympy.txt # eq = parse_expr("cos(0.5*a)+sin(1.2*b)+6") # this is for test_sympy_2.txt eq = unsnap_recur(eq, param_dict, unsnapped_param_dict) N_vars = len(data[0]) - 1 N_params = len(unsnapped_param_dict) possible_vars = ["x%s" % i for i in np.arange(0, 30, 1)] variables = [] params = [] for i in range(N_vars): #variables = variables + ["x%s" %i] variables = variables + [possible_vars[i]] for i in range(N_params - 1): params = params + ["p%s" % i] symbols = params + variables f = lambdify(symbols, N(eq), torch) # Set the trainable parameters in the expression trainable_parameters = [] for i in unsnapped_param_dict: if i != "p": vars()[i] = torch.tensor(unsnapped_param_dict[i]) vars()[i].requires_grad = True trainable_parameters = trainable_parameters + [vars()[i]] # Prepare the loaded data real_variables = [] for i in range(len(data[0]) - 1): real_variables = real_variables + [ torch.from_numpy(data[:, i]).float() ] input = trainable_parameters + real_variables y = torch.from_numpy(data[:, -1]).float() for i in range(N_epochs): # this order is fixed i.e. first parameters yy = f(*input) loss = torch.mean((yy - y)**2) loss.backward() with torch.no_grad(): for j in range(N_params - 1): trainable_parameters[j] -= lr * trainable_parameters[j].grad trainable_parameters[j].grad.zero_() for i in range(N_epochs): # this order is fixed i.e. first parameters yy = f(*input) loss = torch.mean((yy - y)**2) loss.backward() with torch.no_grad(): for j in range(N_params - 1): trainable_parameters[ j] -= lr / 10 * trainable_parameters[j].grad trainable_parameters[j].grad.zero_() # get the updated symbolic regression ii = -1 complexity = 0 for parm in unsnapped_param_dict: if ii == -1: ii = ii + 1 else: eq = eq.subs(parm, trainable_parameters[ii]) complexity = complexity + get_number_DL( trainable_parameters[ii].detach().numpy()) n_variables = len(eq.free_symbols) n_operations = len(count_ops(eq, visual=True).free_symbols) if n_operations != 0 or n_variables != 0: complexity = complexity + (n_variables + n_operations) * np.log2( (n_variables + n_operations)) ii = ii + 1 error = torch.mean((f(*input) - y)**2).data.numpy() * 1 return error, complexity, eq
def parse(self): assert Names.ruleDef in self.toks assert len(self.toks[Names.ruleDef]) == 1 k2v = self.toks[Names.ruleDef][0] self.name = k2v[Names.ruleName] self.vars = [] self.constraints = [] self.equations = [] self.use = set() self.n2u = {} for expr in k2v[Names.ruleBody]: if Names.varName in expr: self.vars.append(VarNode(expr)) var = self.vars[-1] assert not var.name in self.a2n, \ 'duplicate variable {} in {}'.format( var.name, self.name) self.a2n[var.name] = var.name assert not var.short_name in self.a2n or var.short_name == var.name, \ 'duplicate variable {} in {}'.format( var.short_name, self.name) self.a2n[var.short_name] = var.name self.n2u[var.name] = var.unit for expr in k2v[Names.ruleBody]: if Names.shortName in expr: assert expr[Names.shortName] in self.a2n elif Names.constraint in expr: flatten = expr[Names.constraint] self.constraints.append(Relation(flatten, self.a2n, self.n2u)) # self.use.update([self.a2n[a] for a in extract_variables(self.constraints[-1].str)]) self.use.update(self.constraints[-1].names) elif Names.equation in expr: flatten = expr[Names.equation] eq_str = ''.join(flatten) short_names = set(extract_variables(eq_str)) if len(short_names) == 1: # Handle assumptions, e.g. x = 1 val = solve( parse_expr(eq_str, transformations=( convert_equals_signs, auto_symbol, ))) if isinstance(val, list): self.given[self.a2n[short_names.pop()]] = \ str(val[0]) if len(val) == 1 else str(val) else: if not val: raise ValueError( 'Unsat equation: {} in rule {}'.format( ''.join(flatten), self.name)) else: logging.warning('WARNING: infinitely underdetermined equation' \ 'ignored: {} in rule "{}"'.format( ''.join(flatten), self.name)) else: self.equations.append(Relation(flatten, self.a2n, self.n2u)) # self.use.update([self.a2n[a] for a in extract_variables(eq_str)]) self.use.update(self.equations[-1].names) else: assert Names.varName in expr, 'Unknown expr in rule def: {}'.format( expr)
def from_json(j): return Equation(parse_expr(j['full']))
def test_issue_7663(): x = Symbol('x') e = '2*(x+1)' assert parse_expr(e, evaluate=0) == parse_expr(e, evaluate=False)
def test_match_parentheses_implicit_multiplication(): transformations = standard_transformations + \ (implicit_multiplication,) raises(TokenError, lambda: parse_expr('(1,2),(3,4]', transformations=transformations))
def set_expression(self, function): self.expression = parse_expr(function)
e_step /= 0.85 iter_e = 0 xe = np.array(xe) plt.plot(xe[:, 0], xe[:, 1], 'b-o') if __name__ == '__main__': #################### # Quadratic function #################### # Start location x_start = [-4.0, 6.0] # obj = spp.parse_expr('x1**2 - x2 * x1 - x1 + 4 * x2**2') # x_result = np.array([16/15, 2/15]) obj = spp.parse_expr('x1**2 - 2 * x1 * x2 + 4 * x2**2') x_result = np.array([0, 0]) # Design variables at mesh points i1 = np.arange(plot_from, plot_to, plot_step) i2 = np.arange(plot_from, plot_to, plot_step) x1_mesh, x2_mesh = np.meshgrid(i1, i2) f_str = obj.__str__().replace('x1', 'x1_mesh').replace('x2', 'x2_mesh') f_mesh = eval(f_str) # Create a contour plot plt.figure() plt.imshow( f_mesh, cmap='Paired',
def parse_side(cls, s): s = cls.clean(s) base = parse_expr(s, evaluate=False) return cls.numbers_to_symbols(base).expand()
def test_global_dict(): global_dict = {'Symbol': Symbol} inputs = {'Q & S': And(Symbol('Q'), Symbol('S'))} for text, result in inputs.items(): assert parse_expr(text, global_dict=global_dict) == result
def test_local_dict(): local_dict = {'my_function': lambda x: x + 2} inputs = {'my_function(2)': Integer(4)} for text, result in inputs.items(): assert parse_expr(text, local_dict=local_dict) == result
def update_graph(n_clicks, function_string, circle_radius, circle_center): # Parse the input function string into a sympy expression and compute derivatives transformations = standard_transformations + ( implicit_multiplication_application, convert_xor, ) eq = parse_expr(function_string, transformations=transformations) deq = diff(eq, 'z') # convert sympy equations into python functions f = lambdify('z', eq, modules='numpy') df = lambdify('z', deq, modules='numpy') # find the roots circle_center = complex( parse_expr(circle_center, transformations=standard_transformations)) C = cxroots.Circle(circle_center, float(circle_radius)) rootResult = C.roots(f, df) # get values to plot the contour conourVals = C(np.linspace(0, 1, 1001)) figure = { 'data': [{ 'x': np.real(conourVals), 'y': np.imag(conourVals), 'mode': 'lines', 'line': { 'color': 'black', 'dash': 'dash' }, 'name': 'Contour bounding sought roots', 'hoverinfo': 'skip', }, { 'x': np.real(rootResult.roots), 'y': np.imag(rootResult.roots), 'text': list( map(hovertext, zip(rootResult.roots, rootResult.multiplicities))), 'type': 'scatter', 'mode': 'markers', 'name': 'Roots', 'marker': { 'color': 'blue' }, 'hoverinfo': 'text', }], 'layout': { 'xaxis': { 'title': 'Re[z]' }, 'yaxis': { 'title': 'Im[z]', 'scaleanchor': 'x', 'scaleratio': 1 }, 'hovermode': 'closest', } } return figure
#4x^3+x^2-2x+1 #x^4+x^3-2x^2 import math as m from sympy import * from sympy.parsing.sympy_parser import parse_expr from sympy.parsing.sympy_parser import standard_transformations, implicit_multiplication_application transformations = (standard_transformations + (implicit_multiplication_application,)) x = Symbol('x') #from sympy #equ = raw_input("Equation: ") equ = "x^4+x^3-2x^2" equ = equ.replace('^', '**') y = parse_expr(equ, transformations=transformations) #from str to sympy equation type yprime = y.diff(x) #derivative of y CPs = solve(yprime) #solves for zeros, set them as a list of critical points print '\n' + str(len(CPs)) CPs.sort() #convert CPs from str to float #for i in range(len(CPs)): # if str( type(CPs[i]) ) is not "<type 'complex'>": # CPs[i] = float(CPs[i]) # else: # print 'no cmplex pls'
def solid_harmonics(l, return_all=False, vectorize=False, standard_symbols=True): """ Generate a set of spherical solid harmonic functions for a given angular momentum. >>> solid_harmonics(0) {(0, 0): 1} >>> solid_harmonics(1, True) {(0, 0): 1, (1, 1): x, (1, -1): y, (1, 0): z} Args: l (int): Orbital angular moment return_all (bool): If true, return all computed solid harmonics vectorize (bool): If true, return vectorized functions (for numerical methods) standard_symbols (bool): If true (default), convert to standard symbol notation (e.g. x*y => xy) Returns: functions (dict): Dictionary of (l, ml) keys and symbolic function values """ x, y, z = sy.symbols('x y z', imaginary=False) r2 = x**2 + y**2 + z**2 desired_l = l # Recursion relations come from Molecular Electronic Structure, Helgaker 2nd ed. s = {(0, 0): 1} for l in range(1, desired_l + 1): lminus1 = l - 1 if l >= 1 else 0 negl = -lminus1 if lminus1 != 0 else 0 # top s[(l, l)] = sy.sqrt(2**kr(lminus1, 0) * (2 * lminus1 + 1) / (2 * lminus1 + 2)) * \ (x * s[(lminus1, lminus1)] - (1 - kr(lminus1, 0)) * y * s[(lminus1, negl)]) # bottom s[(l, negl - 1)] = sy.sqrt(2**kr(lminus1, 0) * (2 * lminus1 + 1) / (2 * lminus1 + 2)) * \ (y * s[(lminus1, lminus1)] + (1 - kr(lminus1, 0)) * x * s[(lminus1, negl)]) for m in range(-l, l + 1)[1:-1]: lminus2 = lminus1 - 1 if lminus1 - 1 >= 0 else 0 s_lminus2_m = 0 if (lminus2, m) in s: s_lminus2_m = s[(lminus2, m)] s[(l, m)] = ((2 * lminus1 + 1) * z * s[(lminus1, m)] - sy.sqrt((lminus1 + m) * (lminus1 - m)) * \ r2 * s_lminus2_m) / sy.sqrt((lminus1 + m + 1) * (lminus1 - m + 1)) # If true, transform the symbolic notation of things like x*y (which represents dxy) # to simply xy (which is also a symbol and therefore possible to manipulate # with .subs({})). if standard_symbols: match1 = r'([xyz])\*\*(\d+)' for i in range(2, desired_l + 1): match0 = r'\*'.join(['([xyz])'] * i) replace0 = r''.join(['\\' + str(j) for j in range(1, i + 1)]) for k, v in [(k, v) for k, v in s.items() if k[0] == i]: expr = str(v.expand()) expr = re.sub(match0, replace0, expr) while len(re.findall(match1, expr)) > 0: for arg, count in re.findall(match1, expr): count = int(count) f = r''.join([arg[0], r'\*\*', str(count)]) r = r''.join([arg[0]] * count) expr = re.sub(f, r, expr) expr = re.sub(match0, replace0, expr) for j in range(1, i + 1): match0 = r'\*'.join(['([xyz])'] * j) replace0 = r''.join( ['\\' + str(k) for k in range(1, j + 1)]) expr = re.sub(match0, replace0, expr) s[k] = parse_expr(expr) if vectorize: funcs = {} for key in s: if isinstance(s[key], int): funcs[key] = ([None], lambda r: r) else: symbols = sorted([str(sym) for sym in s[key].free_symbols]) if symbols == ['x'] or symbols == ['y'] or symbols == ['z']: funcs[key] = (symbols, lambda r: r) else: f = sy.lambdify(symbols, s[key], 'numpy') vec = nb.vectorize([ 'float64({})'.format(', '.join( ['float64'] * len(symbols))) ], nopython=True) f = vec(f) funcs[key] = (symbols, f) s = funcs if return_all: return s return {key: value for key, value in s.items() if key[0] == desired_l}
import numpy as np import matplotlib.pyplot as plt import math # METODO DE BUSQUEDAS INCREMENTALES #fx = Function introduce by the user #a = First value of the interval #b = Last value of the interval #delta = cada incremento en la busqueda #fa = funcion evaluada en a #fb = funcion evaluada en b print("\nIncremental Search Method\n") x = sympy.symbols('x') fx = parse_expr(input("Introduce the function \n> ")) a = int(input("Introduce the first interval value (a) \n> ")) b = int(input("Introduce the last interval value (b) \n> ")) delta = float(input("Introduce the Delta wanted \n> ")) fa = sympy.sympify(fx).subs(x, a) fb = sympy.sympify(fx).subs(x, b) if fa * fb > 0: print("\n In the interval [%d,%d] There is no a root" % (a, b)) if fb == 0: print('\n\n %d Is a root because f(%d) is equal to %f\n\n' % (b, b, fb)) else: Xi = a + delta
def to_parmed(top, refer_type=True): """Convert a topology.Topology to a parmed.Structure At this point we only assume a three level structure for topology Topology - Subtopology - Sites, which transform to three level of Parmed Structure - Residue - Atoms. If we decide to support multiple level Subtopology in the future, this method will need some re-work. Tentative plan is to have the Parmed Residue to be equivalent to the Subtopology right above Site. Parameters ---------- top : topology.Topology topology.Topology instance that need to be converted refer_type : bool, optional, default=True Whether or not to transfer AtomType, BondType, AngleTye, and DihedralType information Returns ------- structure : parmed.Structure """ # Sanity check msg = "Provided argument is not a topology.Topology." assert isinstance(top, gmso.Topology) # Set up Parmed structure and define general properties structure = pmd.Structure() structure.title = top.name structure.box = np.concatenate((top.box.lengths.to('angstrom').value, top.box.angles.to('degree').value)) # Maps subtop_map = dict() # Map site to subtop atom_map = dict() # Map site to atom bond_map = dict() # Map top's bond to structure's bond angle_map = dict() # Map top's angle to strucutre's angle dihedral_map = dict() # Map top's dihedral to structure's dihedral # Set up unparametrized system # Build subtop_map (site -> top) default_residue = pmd.Residue('RES') for subtop in top.subtops: for site in subtop.sites: subtop_map[site] = subtop # Build up atom for site in top.sites: if site in subtop_map: residue = subtop_map[site].name residue_name = residue[:residue.find('[')] residue_idx = int(residue[residue.find('[') + 1:residue.find(']')]) #since subtop contains information needed to build residue else: residue = default_residue # Check element if site.element: atomic_number = site.element.atomic_number charge = site.element.charge else: atomic_number = 0 charge = 0 pmd_atom = pmd.Atom(atomic_number=atomic_number, name=site.name, mass=site.mass, charge=site.charge) pmd_atom.xx, pmd_atom.xy, pmd_atom.xz = site.position.to( 'angstrom').value # Add atom to structure structure.add_atom(pmd_atom, resname=residue_name, resnum=residue_idx) atom_map[site] = pmd_atom # "Claim" all of the item it contains and subsequently index all of its item structure.residues.claim() # Create and add bonds to Parmed structure for bond in top.bonds: site1, site2 = bond.connection_members pmd_bond = pmd.Bond(atom_map[site1], atom_map[site2]) structure.bonds.append(pmd_bond) bond_map[bond] = pmd_bond # Create and add angles to Parmed structure for angle in top.angles: site1, site2, site3 = angle.connection_members pmd_angle = pmd.Angle(atom_map[site1], atom_map[site2], atom_map[site3]) structure.angles.append(pmd_angle) angle_map[angle] = pmd_angle # Create and add dihedrals to Parmed structure for dihedral in top.dihedrals: site1, site2, site3, site4 = dihedral.connection_members pmd_dihedral = pmd.Dihedral(atom_map[site1], atom_map[site2], atom_map[site3], atom_map[site4]) if (dihedral.connection_type and dihedral.connection_type.expression == parse_expr('c0 * cos(phi)**0 + ' + 'c1 * cos(phi)**1 + ' + 'c2 * cos(phi)**2 + ' + 'c3 * cos(phi)**3 + ' + 'c4 * cos(phi)**4 + ' + 'c5 * cos(phi)**5')): structure.rb_torsions.append(pmd_dihedral) else: structure.dihedrals.append(pmd_dihedral) dihedral_map[dihedral] = pmd_dihedral # Set up structure for Connection Type conversion if refer_type: # Need to add a warning if Topology does not have types information if top.atom_types: _atom_types_from_gmso(top, structure, atom_map) if top.bond_types: _bond_types_from_gmso(top, structure, bond_map) if top.angle_types: _angle_types_from_gmso(top, structure, angle_map) if top.dihedral_types: _dihedral_types_from_gmso(top, structure, dihedral_map) return structure
def __init__(self, expression: str): super().__init__() self.function_symbol: Symbol = Symbol('t') self.expression = parse_expr(expression) print(self.expression)
def shape_from_function(symbol, definition, **kwargs): """Create a Shape object given a function of time. The goal of the algorithm is to calculate the factors of the ODE, assuming they exist. It uses a matrix whose entries correspond to the evaluation of derivatives of the shape function at certain points `t` in time. The idea is to create a system of equations by substituting natural numbers into the homogeneous linear ODE with variable derivative factors order many times for varying natural numbers and solving for derivative factors. Once we have derivative factors, the ODE is uniquely defined. This is assuming that shape satisfies an ODE of this order, which we check after determining the factors. In the function, the symbol `t` is assumed to stand for the current time. The algorithm used in this function is described in full detail together with the mathematical foundations in the following publication: Inga Blundell, Dimitri Plotnikov, Jochen Martin Eppler, Abigail Morrison (201Y) Automatically selecting an optimal integration scheme for systems of differential equations in neuron models. Front. Neuroinf. doi:10.3389/neuro.11.XXX.201Y. Examples -------- shape_from_function("I_in", "(e/tau_syn_in) * t * exp(-t/tau_syn_in)") Parameters ---------- symbol : string The symbol of the shape (e.g. "alpha", "I", "exp") definition : string The definition of the shape (e.g. "(e/tau_syn_in) * t * exp(-t/tau_syn_in)") Returns ------- shape : Shape The canonical representation of the postsynaptic shape """ # Set variables for the limits of loops max_t = 100 max_order = 10 # Create a SymPy symbols the time (`t`) t = Symbol("t") # The symbol and the definition of the shape function were given as # strings. We have to transform them to SymPy symbols for using # them in symbolic calculations. symbol = parse_expr(symbol) shape = parse_expr(definition) # `derivatives` is a list of all derivatives of `shape` up to the # order we are checking, starting at 0. derivatives = [shape, diff(shape, t)] # We first check if `shape` satisfies satisfies a linear # homogeneous ODE of order 1. order = 1 # To avoid a division by zero below, we have to find a `t` so that # the shape function is not zero at this `t`. t_val = None for t_ in range(1, max_t): if derivatives[0].subs(t, t_) != 0: t_val = t_ break # It is very unlikely that the shape obeys a linear homogeneous # ODE of order 1 and we still did not find a suitable # `t_val`. This would mean that the function evaluates to zero at # `t_` = 1, ..., `max_t`, which usually hints at an error in the # specification of the function. if t_val is not None: # `derivative_factors` contains the factor in front of the # derivative in the ODE that the shape function potentially # obeys. This is a list just for consistency with later # cases, where multiple factors are calculatedrequired derivative_factors = [ (1 / derivatives[0] * derivatives[1]).subs(t, t_val) ] # `diff_rhs_lhs` is the difference between the derivative of # shape and the shape itself times its derivative factor. diff_rhs_lhs = derivatives[1] - derivative_factors[0] * derivatives[0] # If `diff_rhs_lhs` equals 0, `shape` satisfies a first order # linear homogeneous ODE. We set the flag `found_ode` # correspondingly. found_ode = simplify(diff_rhs_lhs) == sympify(0) # If `shape` does not satisfy a linear homogeneous ODE of order 1, # we try to find one of higher order in a loop. The loop runs # while no linear homogeneous ODE was found and the maximum # order to check for was not yet reached. while not found_ode and order < max_order: # Set the potential order for the iteration order += 1 # Add the next higher derivative to the list derivatives.append(diff(derivatives[-1], t)) # `X` is an `order`x`order` matrix that will be assigned # the derivatives up to `order`-1 of some natural numbers # as rows (differing in each row) X = zeros(order) # `Y` is a vector of length `order` that will be assigned # the derivatives of `order` of the natural number in the # corresponding row of `X` Y = zeros(order, 1) # It is possible that by choosing certain natural numbers, # the system of equations will not be solvable, i.e. `X` # is not invertible. This is unlikely but we check for # invertibility of `X` for varying sets of natural # numbers. invertible = False for t_ in range(max_t): for i in range(order): substitute = i + t_ + 1 Y[i] = derivatives[order].subs(t, substitute) for j in range(order): X[i, j] = derivatives[j].subs(t, substitute) if det(X) != 0: invertible = True break # If we failed to find an invertible `X` for `t` = 1, ..., # `max_t`, it is very unlikely that the shape function # obeys a linear homogeneous ODE of order `order` and we # go on checking the next potential order. Else we # calculate the derivative factors and check if shape # actually obeys the corresponding ODE. if invertible: # The `order`th derivative of the shape equals `C_i` # times the `i`th derivative of the shape (`C_i` are # the derivative factors). This means we can find the # derivative factors for `order-1` by evaluating the # previous equation as a linear system of order # `order-1` such that Y = [shape^order] = X * # [C_i]. Hence [C_i] can be found by inverting X. derivative_factors = X.inv() * Y diff_rhs_lhs = 0 # We calculated the `derivative_factors` of the linear # homogeneous ODE of order `order` and only assumed # that shape satisfies such an ODE. We now have to # check that this is actually the case: for k in range(order): diff_rhs_lhs -= derivative_factors[k] * derivatives[k] diff_rhs_lhs += derivatives[order] if simplify(diff_rhs_lhs) == sympify(0): found_ode = True break if not found_ode: msg = "Shape does not satisfy any ODE of order <= " % max_order raise Exception(msg) # Calculate the initial values of the found ODE and simplify the # derivative factors before creating and returning the Shape # object. initial_values = [x.subs(t, 0) for x in derivatives[:-1]] derivative_factors = [simplify(df) for df in derivative_factors] return Shape(symbol, order, initial_values, derivative_factors)
def set_vars(self, fx, upto): self.fx = fx self.expr = parse_expr(fx) self.upto = upto
def test_python3_features(): # Make sure the tokenizer can handle Python 3-only features if sys.version_info < (3, 6): skip("test_python3_features requires Python 3.6 or newer") assert parse_expr("123_456") == 123456 assert parse_expr("1.2[3_4]") == parse_expr("1.2[34]") == Rational( 611, 495) assert parse_expr("1.2[012_012]") == parse_expr("1.2[012012]") == Rational( 400, 333) assert parse_expr('.[3_4]') == parse_expr('.[34]') == Rational(34, 99) assert parse_expr('.1[3_4]') == parse_expr('.1[34]') == Rational(133, 990) assert parse_expr('123_123.123_123[3_4]') == parse_expr( '123123.123123[34]') == Rational(12189189189211, 99000000)
def test_unicode_names(): assert parse_expr('α') == Symbol('α')
def test_parse_function_issue_3539(): x = Symbol('x') f = Function('f') assert parse_expr('f(x)') == f(x)
def check_answer(): if 'curr_id' not in request.cookies: return abort(500) data = request.json id = request.cookies.get("curr_id") cursor.execute( "SELECT * FROM users AS u WHERE u.RandomID = '{}' LIMIT 1".format(id)) user = UserModel.from_tuple(cursor.fetchall()[0]) cursor.execute("""SELECT * FROM equations AS e WHERE e.ID IN ( SELECT EquationID FROM progress AS p WHERE p.UserID = {} AND p.Correct IS NULL ) LIMIT 1; """.format(user.id)) curr_eq = cursor.fetchall() if not curr_eq: return abort(500) eq = Equation.from_model(curr_eq[0]) solution = eq.solution() users_attempt = parse_expr(LinearUtils.to_expr(data["value"]), evaluate=True) if solution == users_attempt: new_rating = Glicko.new_rating(user.rating, user.kfactor, eq.rating, STANDARD_DEVIATION, Result.Win) new_kfactor = Glicko.new_deviation(user.rating, user.kfactor, eq.rating, STANDARD_DEVIATION) correct = True else: new_rating = Glicko.new_rating(user.rating, user.kfactor, eq.rating, STANDARD_DEVIATION, Result.Loss) new_kfactor = Glicko.new_deviation(user.rating, user.kfactor, eq.rating, STANDARD_DEVIATION) correct = False cursor.execute("UPDATE progress " "SET Correct = {}, RatingGain = {}, UserAnswer = '{}' " "WHERE UserID = {} AND EquationID = {}".format( correct, new_rating - user.rating, data["value"], user.id, eq.id)) db.commit() cursor.execute( "UPDATE users SET Rating = {}, KFactor = {} WHERE ID = {}".format( new_rating, new_kfactor, user.id)) db.commit() new_eq = new_equation(user) resp = get_history(request.cookies.get("curr_id")) return jsonify({ "newRating": new_rating, "correct": correct, "equation": { "latex": new_eq.to_latex(), "variable": str(new_eq.variables[0]), "rating": new_eq.rating }, "history": resp })
def parse(s): return parse_expr(s, transformations=standard_transformations)
def test_issue_2515(): raises(TokenError, lambda: parse_expr('(()')) raises(TokenError, lambda: parse_expr('"""'))
def test_sympy_parser(): x = Symbol('x') inputs = { '2*x': 2 * x, '3.00': Float(3), '22/7': Rational(22, 7), '2+3j': 2 + 3 * I, 'exp(x)': exp(x), 'x!': factorial(x), 'x!!': factorial2(x), '(x + 1)! - 1': factorial(x + 1) - 1, '3.[3]': Rational(10, 3), '.0[3]': Rational(1, 30), '3.2[3]': Rational(97, 30), '1.3[12]': Rational(433, 330), '1 + 3.[3]': Rational(13, 3), '1 + .0[3]': Rational(31, 30), '1 + 3.2[3]': Rational(127, 30), '.[0011]': Rational(1, 909), '0.1[00102] + 1': Rational(366697, 333330), '1.[0191]': Rational(10190, 9999), '10!': 3628800, '-(2)': -Integer(2), '[-1, -2, 3]': [Integer(-1), Integer(-2), Integer(3)], 'Symbol("x").free_symbols': x.free_symbols, "S('S(3).n(n=3)')": 3.00, 'factorint(12, visual=True)': Mul(Pow(2, 2, evaluate=False), Pow(3, 1, evaluate=False), evaluate=False), 'Limit(sin(x), x, 0, dir="-")': Limit(sin(x), x, 0, dir='-'), } for text, result in inputs.items(): assert parse_expr(text) == result raises(TypeError, lambda: parse_expr('x', standard_transformations)) raises(TypeError, lambda: parse_expr('x', transformations=lambda x, y: 1)) raises(TypeError, lambda: parse_expr('x', transformations=(lambda x, y: 1, ))) raises(TypeError, lambda: parse_expr('x', transformations=((), ))) raises(TypeError, lambda: parse_expr('x', {}, [], [])) raises(TypeError, lambda: parse_expr('x', [], [], {})) raises(TypeError, lambda: parse_expr('x', [], [], {}))
def format_useranswer(user_answer, display=False): user_answer = user_answer.lower() user_answer = user_answer.replace('^', '**') user_answer = parse_expr(user_answer, transformations=transformations) user_answer = simplify_for_long_division(user_answer) return f'\({sy.latex(user_answer)}\)'
def sympify(a, locals=None, convert_xor=True, strict=False, rational=False, evaluate=None): """Converts an arbitrary expression to a type that can be used inside SymPy. For example, it will convert Python ints into instances of sympy.Integer, floats into instances of sympy.Float, etc. It is also able to coerce symbolic expressions which inherit from Basic. This can be useful in cooperation with SAGE. It currently accepts as arguments: - any object defined in sympy - standard numeric python types: int, long, float, Decimal - strings (like "0.09" or "2e-19") - booleans, including ``None`` (will leave ``None`` unchanged) - lists, sets or tuples containing any of the above .. warning:: Note that this function uses ``eval``, and thus shouldn't be used on unsanitized input. If the argument is already a type that SymPy understands, it will do nothing but return that value. This can be used at the beginning of a function to ensure you are working with the correct type. >>> from sympy import sympify >>> sympify(2).is_integer True >>> sympify(2).is_real True >>> sympify(2.0).is_real True >>> sympify("2.0").is_real True >>> sympify("2e-45").is_real True If the expression could not be converted, a SympifyError is raised. >>> sympify("x***2") Traceback (most recent call last): ... SympifyError: SympifyError: "could not parse u'x***2'" Locals ------ The sympification happens with access to everything that is loaded by ``from sympy import *``; anything used in a string that is not defined by that import will be converted to a symbol. In the following, the ``bitcount`` function is treated as a symbol and the ``O`` is interpreted as the Order object (used with series) and it raises an error when used improperly: >>> s = 'bitcount(42)' >>> sympify(s) bitcount(42) >>> sympify("O(x)") O(x) >>> sympify("O + 1") Traceback (most recent call last): ... TypeError: unbound method... In order to have ``bitcount`` be recognized it can be imported into a namespace dictionary and passed as locals: >>> from sympy.core.compatibility import exec_ >>> ns = {} >>> exec_('from sympy.core.evalf import bitcount', ns) >>> sympify(s, locals=ns) 6 In order to have the ``O`` interpreted as a Symbol, identify it as such in the namespace dictionary. This can be done in a variety of ways; all three of the following are possibilities: >>> from sympy import Symbol >>> ns["O"] = Symbol("O") # method 1 >>> exec_('from sympy.abc import O', ns) # method 2 >>> ns.update(dict(O=Symbol("O"))) # method 3 >>> sympify("O + 1", locals=ns) O + 1 If you want *all* single-letter and Greek-letter variables to be symbols then you can use the clashing-symbols dictionaries that have been defined there as private variables: _clash1 (single-letter variables), _clash2 (the multi-letter Greek names) or _clash (both single and multi-letter names that are defined in abc). >>> from sympy.abc import _clash1 >>> _clash1 {'C': C, 'E': E, 'I': I, 'N': N, 'O': O, 'Q': Q, 'S': S} >>> sympify('I & Q', _clash1) I & Q Strict ------ If the option ``strict`` is set to ``True``, only the types for which an explicit conversion has been defined are converted. In the other cases, a SympifyError is raised. >>> print(sympify(None)) None >>> sympify(None, strict=True) Traceback (most recent call last): ... SympifyError: SympifyError: None Evaluation ---------- If the option ``evaluate`` is set to ``False``, then arithmetic and operators will be converted into their SymPy equivalents and the ``evaluate=False`` option will be added. Nested ``Add`` or ``Mul`` will be denested first. This is done via an AST transformation that replaces operators with their SymPy equivalents, so if an operand redefines any of those operations, the redefined operators will not be used. >>> sympify('2**2 / 3 + 5') 19/3 >>> sympify('2**2 / 3 + 5', evaluate=False) 2**2/3 + 5 Extending --------- To extend ``sympify`` to convert custom objects (not derived from ``Basic``), just define a ``_sympy_`` method to your class. You can do that even to classes that you do not own by subclassing or adding the method at runtime. >>> from sympy import Matrix >>> class MyList1(object): ... def __iter__(self): ... yield 1 ... yield 2 ... return ... def __getitem__(self, i): return list(self)[i] ... def _sympy_(self): return Matrix(self) >>> sympify(MyList1()) Matrix([ [1], [2]]) If you do not have control over the class definition you could also use the ``converter`` global dictionary. The key is the class and the value is a function that takes a single argument and returns the desired SymPy object, e.g. ``converter[MyList] = lambda x: Matrix(x)``. >>> class MyList2(object): # XXX Do not do this if you control the class! ... def __iter__(self): # Use _sympy_! ... yield 1 ... yield 2 ... return ... def __getitem__(self, i): return list(self)[i] >>> from sympy.core.sympify import converter >>> converter[MyList2] = lambda x: Matrix(x) >>> sympify(MyList2()) Matrix([ [1], [2]]) Notes ===== Sometimes autosimplification during sympification results in expressions that are very different in structure than what was entered. Until such autosimplification is no longer done, the ``kernS`` function might be of some use. In the example below you can see how an expression reduces to -1 by autosimplification, but does not do so when ``kernS`` is used. >>> from sympy.core.sympify import kernS >>> from sympy.abc import x >>> -2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1 -1 >>> s = '-2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1' >>> sympify(s) -1 >>> kernS(s) -2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1 """ if evaluate is None: if global_evaluate[0] is False: evaluate = global_evaluate[0] else: evaluate = True try: if a in sympy_classes: return a except TypeError: # Type of a is unhashable pass try: cls = a.__class__ except AttributeError: # a is probably an old-style class object cls = type(a) if cls in sympy_classes: return a if cls is type(None): if strict: raise SympifyError(a) else: return a # Support for basic numpy datatypes # Note that this check exists to avoid importing NumPy when not necessary if type(a).__module__ == 'numpy': import numpy as np if np.isscalar(a): return _convert_numpy_types(a) try: return converter[cls](a) except KeyError: for superclass in getmro(cls): try: return converter[superclass](a) except KeyError: continue if isinstance(a, CantSympify): raise SympifyError(a) try: return a._sympy_() except AttributeError: pass if not strict: # Put numpy array conversion _before_ float/int, see # <https://github.com/sympy/sympy/issues/13924>. try: from ..tensor.array import Array return Array(a.flat, a.shape) # works with e.g. NumPy arrays except AttributeError: pass if not isinstance(a, string_types): for coerce in (float, int): try: return sympify(coerce(a)) except (TypeError, ValueError, AttributeError, SympifyError): continue if strict: raise SympifyError(a) if iterable(a): try: return type(a)([ sympify(x, locals=locals, convert_xor=convert_xor, rational=rational) for x in a ]) except TypeError: # Not all iterables are rebuildable with their type. pass if isinstance(a, dict): try: return type(a)([ sympify(x, locals=locals, convert_xor=convert_xor, rational=rational) for x in a.items() ]) except TypeError: # Not all iterables are rebuildable with their type. pass # At this point we were given an arbitrary expression # which does not inherit from Basic and doesn't implement # _sympy_ (which is a canonical and robust way to convert # anything to SymPy expression). # # As a last chance, we try to take "a"'s normal form via unicode() # and try to parse it. If it fails, then we have no luck and # return an exception try: from .compatibility import unicode a = unicode(a) except Exception as exc: raise SympifyError(a, exc) from sympy.parsing.sympy_parser import (parse_expr, TokenError, standard_transformations) from sympy.parsing.sympy_parser import convert_xor as t_convert_xor from sympy.parsing.sympy_parser import rationalize as t_rationalize transformations = standard_transformations if rational: transformations += (t_rationalize, ) if convert_xor: transformations += (t_convert_xor, ) try: a = a.replace('\n', '') expr = parse_expr(a, local_dict=locals, transformations=transformations, evaluate=evaluate) except (TokenError, SyntaxError) as exc: raise SympifyError('could not parse %r' % a, exc) return expr
def test_rationalize(): inputs = {'0.123': Rational(123, 1000)} transformations = standard_transformations + (rationalize, ) for text, result in inputs.items(): assert parse_expr(text, transformations=transformations) == result
def fitness_function(function: str, population: np.ndarray) -> np.ndarray: x, y = symbols("x y") expr = parse_expr(function) f = lambdify((x, y), expr, 'numpy') return f(population[:, 0], population[:, 1])