Number eval issue python - python

I want to evaluate the following differential using the values in list y however I cant figure out what I am doing wrong. I am supposed to get 1.9256 for y=5, 1.9956 for y=10 and 2.1356 for y=20. What I'm trying to do is ask the user to input an equation with x as its variable, derive this equation with respect to x, ask the user to input as many values as he wants and evaluate the expression using these inputted values. Thanks for your help.
import sympy as sym
print('Sensitivity: ')
#exp = input('Enter the expression to find the sensitivity: ')
exp='(0.007*(x**2))+(1.8556*x)-1.8307'
#values=list(map(float,input('Enter the values at which you want to compute the sensitivity seperated by spaces: ').split()))
values=[5,10,20]
x=sym.Symbol('x')
differential=str(sym.diff(exp,x))
print(differential)
for i in y:
expression=differential.replace(str(x),str(values))
value=eval(expression)
print('The sensitivity at',i,'is: ',value)

What I believe you intended to write is:
import sympy as sym
exp='(0.007*(x**2))+(1.8556*x)-1.8307'
values=[5,10,20]
x=sym.Symbol('x')
differential=str(sym.diff(exp,x))
print(differential)
for value in values:
expression=differential.replace(str(x),str(value))
result=eval(expression)
print('The sensitivity at',value,'is: ',result)
...which emits as output:
The sensitivity at 5 is: 1.9256
The sensitivity at 10 is: 1.9956
The sensitivity at 20 is: 2.1356
Note the changes:
We're iterating for value in values -- values exists, y does not.
We're assigning the eval result to a separate variable (in this case, result)
This still is not by any means good code. Good code would not do string substitution to substitute values into code. Substituting repr(value) instead of str(value) would be at least somewhat less broken.

Related

Insert a string within another string based with probability based on location

I'm working in Python and I would like to insert a string within another string at a random location. But I would like the choice of random location based on a probability distribution that favors certain locations more than others. Specifically, I want to insert more strings towards beginning of the original string and less towards the end.
For example, if the insertion string is "I go here" and the original string is "this is a test string and it can be long." I want to insert the insertion string at a random location in the original string. But if I do it say 100 times, I would the result "I go here this is a test string and it can be long" to be the result more number of times than "this is a test string and it can be long. I go here". I want to be able to tune the probability distribution.
Any help is appreciated.
You can use the random.gauss() function.
It returns a random number with gaussian distribution.
The function takes two parameters: mean and sigma. mean is the expected mean of the function outputs and sigma is the standard deviation- 'how far the values will be from the mean'.
Try something like this:
import random
original_str_len = 7
mean = 0
sigma= original_str_len # just an example.
r = random.gauss(mean, sigma) # random number- can be negative
r = abs(r)
insertion_index = int(r)
Notice, this code is not perfect but the general idea should work.
I recommend you to read more about the Gaussian Distribution.

Solve system of equations using scipy.optimize.root with text input: how to assign equations and variables?

As part of a program, I am struggling to implement a function to solve a system of equations.
First, I receive a set of equations from text input. Please note that the number of equations and thus variables are unknown, as well as the name of variables. For simplicity, I consider only two equations in a list of strings. Afterwards, equations are edited, variables are identified, and the guesses array is created.
from math import exp
import sympy
from sympy import sympify
eq_list = ["x + y**2 = 4", "exp(x) + x*y = 3"]
eq_list_altered = []
for eq in eq_list:
start, end = eq.split('=')
eq_list_altered.append(start + '-' + end)
guess = [0.1 for i in eq_list_altered]
vars_set = set()
for eq in eq_list_altered:
vars_set.update((sympify(eq)).free_symbols)
vars_lst = list(vars_set)
The second step is where I am struggling. The main issue is that the input can have n equations and n unknowns. WHilst the equations are easy to deal with, I am trying to find the simplest way to assign the variables to the guess values, i.e.:
def f(variables) :
x, y = variables # How to this for any variable name and len ?
res = []
for eq in eq_list_edit:
res.append(eval(eq))
return res
solution = opt.root(f, guess)
print(solution.x)
I already tried using locals(), globals() and dictionaries without success. It seems a simple procedure to set a list of variables equal to a list of values; however, after two days of searching and reading, I could not find a simple solution. The only one working is:
dict_tmp = {vars_lst[i]: variables[i] for i in range(len(vars_lst))}
print(dict_tmp)
for k in dict_tmp:
globals()['{}'.format(k)] = dict_tmp[k]
That may result in issues as the input is external.
Thank you.
I found a solution; thus, I am answering my question if anyone has the same problem.
First, other solutions exist for this problem; however, they imply risk issues if the user cannot control the input, e.g., eval(), exec(), locals() or globals(). The solution consists on:
1. Format the equation list
eq_list = ["x + y**2 = 4", "exp(x) + x*y = 3"]
new_eq_list = ['{x}+y**2-(4)', '{exp}({x})+{x}*y-(3)']
Like that, each variable is within brackets. I got this idea from: stackoverflow_question.
2. Create a dictionary where the variable is assigned to the guess:
def f(variables, new_eq_list, guess) :
# dictionary with variables assigned to guess value
var_values = {str(variables[i]): guess[i] for i in range(len(variables))}
res = []
for eqn in new_eq_list:
eq_to_eval = eqn.format(**var_values) #replace eq var with guess value
res.append(safe_eval(eq_to_eval))
Additionally, I removed the sympify, due to the warning about eval() use as I cannot control the input. That part is still messy to identify variables (symbols) using regex. Nothing against sympy, on the contrary; simply not adequate for this purpose.
Also, I found an alternative for the eval().
I explored AST functionalities, but in my opinion, it is not adequate for arithmetic operations.
I found a good solution with ASTEVAL module. Still not sure how safe the module is, but the authors claim a safe alternative to eval(). I still need to read the module details.
In the aforementioned code:
from asteval import Interpreter
safe_eval = Interpreter()
In any case, further suggestions or alternatives are welcome.

How do I create Symbols in SymPy based on user input?

I am trying to create a python programme that takes a function from the user (in terms of x) and returns its derivative using SymPy. However, when I enter letters other than x, SymPy throws an error of undefined symbols. I want it to treat letters apart from x as constant.
For example, if a user enters a*x**2 + bx, they should get 2*a*x + b, and if they enter z*x**2 + px, they should get 2*z*x + p. How can I treat letters apart from 'x' as constants without having to hard-code every letter as a symbol?
I hope my question is clear. Feel free to ask for any clarifications if required.
You should first parse the user input and collect all symbols. To parse string to sympy expression use sympy.sympify. I assume you want to get derivative only W.R.T x. The full code will be:
import sympy as sp
expr = sp.sympify(input('enter expression: '))
print('Derivative w.r.t x: ', sp.diff(expr, 'x'))

Wrong result of evalf in SymPy but only for some values of the precision

I think I have encountered a bug of Sympy's evalf() method with substitutions passed.
By accident, I found an expression that evaluates to a wrong value if I replace the variable x by an integer rather than a Float. The funny thing is that this happens only for some values of the precision.
The expression looks somewhat arbitrary, but if I attempt to simplify it further the bug disappears. This is a minimal working example
#!/usr/bin/env python
import sympy
from sympy.abc import x
# Some valid mathematical expression
expr = 1/((x - 9)*(x - 8)*(x - 7)*(x - 4)**2*(x - 3)**3*(x - 2))
def example(prec):
# This is the string 1.( prec-2 zeroes )1
almost1 = '1.'+(prec-2)*'0'+'1'
# We replace the integer 1
res1 = expr.evalf(prec, subs={x:1})
# We replace a Float veeery close to 1
res_almost1 = expr.evalf(prec, subs={x:sympy.Float(almost1,prec)})
return res1, res_almost1
The expected outcome is that the returned tuple should contain similar numbers since 1 and almost1 are very close. However, for some values of prec the result obtained by replacing 1 to expr is zero. (While the one obtained by replacing almost1 is close to the correct one.)
You may ask: "What are the values of prec for which the expression is wrong?". By running the code
wrong = [str(a) for a in range(10,1001) if example(a)[0] == 0]
print(','.join(wrong))
I obtain this seemingly completely random list
11,20,22,29,31,38,40,49,58,67,76,78,85,87,94,96,105,114,123,132,134,141,143,150,152,159,161,170,179,188,190,197,199,206,208,215,217,226,235,244,253,255,262,264,271,273,282,291,300,309,311,318,320,327,329,338,347,356,365,367,374,376,383,385,392,394,403,412,421,423,430,432,439,441,448,450,459,468,477,486,488,495,497,504,506,515,524,533,542,544,551,553,560,562,571,580,589,598,600,607,609,616,618,625,627,636,645,654,663,665,672,674,681,683,692,701,710,719,721,728,730,737,739,748,757,766,775,777,784,786,793,795,802,804,813,822,831,833,840,842,849,851,858,860,869,878,887,896,898,905,907,914,916,925,934,943,952,954,961,963,970,972,981,990,999
I posted it here so see whether I made some blunder in my code, otherwise I plan to post a bug issue on Sympy's github.

make calculator by spliting input text in python

guys thanks for having me I've got a question already.
What I wanna do is to get sum of the list without for loop after splitting the given text by math symbols which the text as an example ** (1+3) * 3 ** should obtain the math priority for calculation.
my first question is how to get sum and sub and multiply or divide by the list and then how to check the priority and check it first.
# my calc
a = input()
result = a.split('+')
print(sum(result))
sol1: split brackets and mul /dev earlier sum /sub later but I know that split is not the best way!
sol2: make a tree I don t know what it is lol but mind it
it has answered here I know but with no split
Calculator in python
You could use eval (but be aware that it is usually a bad practice, see this answer):
result = eval(input())
If you input a string like (3-8)*4+5/2, the result will be automatically computed using normal priorities: -17.5.

Categories