Solve Equation (String) with Python to every Symbol - python

I have to solve a equation in python, which i get as a string input. I don't know how many symbols are in the equation or what their signature is. A typical Symbol could be "mm", "cm", "x" or something like this. The function should return some kind of array/json with the solved equation.
Little Example how it should look like:
solve("x/2=4")
>> ["x=8"]
>>
solve("x + 2 = y - 1")
>> ["x=y-3", "y=x+3"]
I tried to use SymPy-Module for this, but I didn't find a way to enter a dynamic string like above. SymPy seems to only accept "hardcoded" Symbols.
Note: String comes from a "sys.argv"-Parameter.

SymPy can parse strings with sympify, but its format for equations is Eq(x/2, 4) instead of x/2 = 4. So a little preprocessing is necessary: surround the string with Eq( ) and replace "=" by a comma.
eq = "x/2=4"
sympy_eq = sympify("Eq(" + eq.replace("=", ",") + ")")
solve(sympy_eq) # [8]
and
eq = "x + 2 = y - 1"
sympy_eq = sympify("Eq(" + eq.replace("=", ",") + ")")
solve(sympy_eq) # [{x: y - 3}]
In the latter case, SymPy picked one of the variables to solve for. To choose which one it should be, you can provide a Symbol:
solve(sympy_eq, Symbol('y')) # [x + 3]
Or, to solve for every symbol:
[solve(sympy_eq, sym, dict=True) for sym in sympy_eq.free_symbols]
returns [[{y: x + 3}], [{x: y - 3}]]. The list is nested because multiple solutions could appear for each symbol. Flatten the nested list if necessary.
The options list=True and dict=True of solve are convenient for enforcing particular forms of output.

The answer is most probably two different parts.
Parsing:
Parsing means turning some input into a usable output, where in your case the input is some string and the output is something, sympy can work with. A simple parsing step for example is turning strings into integers by doing int(your_string). In your case, you should iterate through your string and find variables, units etc. for example by comparing with a dictionary or a list of strings. Parsing arbitrary input is quite hard, so the best idea is starting with a small set of options, e.g. search the string for occurences of typical variable names like x, y and z by comparing with a list variables=['x','y','z'].
Computing
Once the parsing is clean, simply plug everything into your number crunching / solvers used by sympy.
To see how such a system can work if done correctly, you can have a look at wolfram alpha. They do a quite good parsing / natural language processing and try to guess what to do from there.

Related

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 to solve equations in python

I try to write a script that simulates a resistor. It takes 2 arguments for example P and R and it should calculate all missing values of this resistor.
The problem is that I don't want to write every single possible equation for every value. This means I want to write something like (U=RxI, R=U/R, I=U/R , P=UxI) and the script should then complete all equation with the given values for every equation.
For example, something like this:
in R=10
in I=5
out U=R*I
out P=I**2 * R
You can use https://pypi.org/project/Equation/ Packages.
Example
>>> from Equation import Expression
>>> fn = Expression("sin(x+y^2)",["y","x"])
>>> fn
sin((x + (y ^ (2+0j))))
>>> print fn
\sin\left(\left(x + y^{(2+0j)}\right)\right)
>>> fn(3,4)
(0.42016703682664092+0j)
Sympy
Second: https://github.com/sympy/sympy/wiki
Arbitrary precision integers, rationals and floats, as well as symbolic expressions
Simplification (e.g. ( abb + 2bab ) → (3ab^2)), expansion (e.g. ((a+b)^2) → (a^2 + 2ab + b^2)), and other methods of rewriting expressions
Functions (exp, log, sin, ...)
Complex numbers (like exp(Ix).expand(complex=True) → cos(x)+Isin(x))
Taylor (Laurent) series and limits
Differentiation and integration
In vanilla python, there is no solution as general as the one you are looking for.
The typical solution would be to write an algorithm for every option (only given U, only given R) and then logically select which option to execute.
You may also want to consider using a module like SymPy, which has a solver module that may be more up your alley.

Python: Regular expression for quadratic equations

I am currently trying to do a quadratic equation solver. I searched on the web how people did their version, but all of them implied that the user entered the coefficients, which, although the easiest way, I really hate it.
I want the user to introduce the whole equation, and let the program know which are the coefficients, and calculate the solution. I discovered the concept of regex, and automatically, the re module.
I understand how to implement the quadratic formula to solve the problem, but the problem is that I don't know which function should I use, and how to get the coefficients from the input.
I want the regex to be like:
\d(\sx\s\(\^)\s2/x\^2)(\s\+\s)\dbx(\s\+\s)\d = 0
To find the coefficients in this:
ax^2 + bx + c = 0
I am aware that the regex sucks, because I only started to understand it yesterday, so you can also tell me how to improve that.
EDIT:
Let's clarify what I exactly want.
How to improve the regex that I tried doing above?
What Python function should I use so that I can only have the coefficients?
How can I take the groups and turn them into usable integers, assuming that it doesn't store those groups?
Assumptions: the coefficients are numbers and the variable is x:
(-?\d+)x\^2 ([+-]\d+)x ([+-]\d+)
Now for -3x^2 +7x -44 your first group match will be -3, second group will be +7 and third group will be -44.
Round brackets (()) define a group
? says that what was followed can be matched one or zero times
[+-] defines a character set that will match either a + or a - one time
EDIT: Start to end solution (excuse my rusty python skills, but I hope you get an idea of how to use the regex):
import re
quadratic_equation_matcher = re.compile(r'(-?\d+)x\^2 ([+-]\d+)x ([+-]\d+)')
quadratic_equation = '-3x^2 +7x -44'
matches = quadratic_equation_matcher.match(quadratic_equation)
a = int(matches.group(1))
b = int(matches.group(2))
c = int(matches.group(3))
d = b**2 - 4*a*b
x1 = (-b + d**0.5)/(2*a)
x2 = (-b - d**0.5)/(2*a)
x1 # => -0.75542709911179939
x2 # => 3.0887604324451328
Note that you can make the regex more space permissive like so:
(-? ?\d+) ?x\^2 ([+-] ?\d+) ?x ([+-] ?\d+)
I'd recommend cleaning the input up a but first. Get rid of all the white space, or at least the spaces. Check for an equal sign and see if there's a 0 on one side or the other. If there is you can remove it. If not you have to decide how clever you want to be.
Get it close to a format you want to deal with, in other words. Then you can check if they've entered a valid re.
You also need to decide if you can handle shuffling the order of the terms around and letters other than x. Also whether you want the ^ or ** or just x2.
You probably want to grab each term individually (all the terms between the + or -) and decide what kind of term it is.
In other words there's a lot to do before the re expression.
Incidentally have you seen SymPy

Verify string as valid C code

I would like to verify that a given string is valid C code in the context of
int main() {
double x[3];
<insert code here>;
return EXIT_SUCCESS;
}
Effectively, I would like the verification to
verifyC('x[0]*x[0] + x[1] + 1') // pass
verifyC('x[0]*x[0] + x[1] +') // fail, syntax error
verifyC('x[0]*x[0] + a') // fail, `a` undefined
What would be a good way of verification?
The simplest way would be to just try to compile a small sample program containing the string you want to check.
This way you get your snippet checked by the real C compiler. This will be far easier and much more reliable than trying to implement all the C parsing and checking in the Python program.
Replace all occurrences of your known variables with a numeric constant. In your code, that would be x[0], x[1], and x[2]. Note that in C lots of intermediate whitespace is allowed, even inside variables: x [ 1 ] is valid. (Also: x[01] is valid. x[0x01] is valid. If the array is larger than 8 elements: x[010] is valid and is actually x[8]. 1[x] is valid and is equal to x[1].)
The numerical constant must in itself be valid, and preferably not equal to 0. (Just to prevent a parser stating 1/x[0] is invalid!)
When replacing, insert a single space before and after your constant. This is to prevent a change of x[1]2 to 12. Do not use parentheses! With those, sin x[1] is invalid but its replacement, sin(1), is.
With this, an input string
x[0]*x[0] + x[1] + 1
is translated into
1 * 1 + 1 + 1
which can be validated with regular procedures; see for example Safe expression parser in Python; or, since you don't need to calculate but only validate, write your own.

Python: Shorten ugly code?

I have a ridiculous code segment in one of my programs right now:
str(len(str(len(var_text)**255)))
Is there an easy way to shorten that? 'Cause, frankly, that's ridiculous.
A option to convert a number >500 digits to scientific notation would also be helpful
(that's what I'm trying to do)
Full code:
print("Useless code rating:" , str(len(var_text)**255)[1] + "e" + str(len(str(len(var_text)**255))))
TL;DR: y = 2.408 * len(var_text)
Lets assume that your passkey is a string of characters with 256 characters available (0-255). Then just as a 16bit number holds 65536 numbers (2**16) the permutations of a string of equal length would be
n_perms = 256**len(passkey)
If you want the number of (decimal) digits in n_perms, consider the logarithm:
>>> from math import log10
>>> log10(1000)
3.0
>>> log10(9999)
3.9999565683801923
>>>
So we have length = floor(log10(n_perms)) + 1. In python, int rounds down anyway, so I'd say you want
n_perms = 256**len(var_text)
length = int(log10(n_perms)) + 1
I'd argue that 'shortening' ugly code isn't always the best way - you want it to be clear what you're doing.
Edit: On further consideration I realised that choosing base-10 to find the length of your permutations is really arbitrary anyway - so why not choose base-256!
length = log256(256**len(var_text)
length = len(var_text) # the log and exp cancel!
You are effectively just finding the length of your passkey in a different base...
Edit 2: Stand back, I'm going to attempt Mathematics!
if x = len(var_text), we want y such that
y = log10(256**x)
10**y = 256**x
10**y = (10**log10(256))**x
10**y = (10**(log10(256)x))
y = log10(256) * x
So, how's this for short:
length = log10(256) * len(var_text) # or about (2.408 * x)
This looks like it's producing a string version of the number of digits in the 255th power of the length of a string. Is that right? I'd be curious what that's used for.
You could compute the number differently, but it's not shorter and I'm not sure it's prettier:
str(int(math.ceil(math.log10(len(var_text))*255)))
or:
"%d" % math.ceil(math.log10(len(v))*255)
Are you trying to determine the number of possible strings having the same length as var_text? If so, you have your base and exponent reversed. You want to use 255**len(var_text) instead of len(var_text)**255.
But, I have to ask ... how long do these passkeys get to be, and what are you using them for?
And, why not just use the length of the passkey as an indicator of its length?
Firstly, if your main problem is manipulating huge floating point expressions, use the bigfloat package:
>>> import bigfloat
>>> bigfloat.BigFloat('1e1000')
BigFloat.exact('1.0000000000000001e+1000', precision=53)
As for the details in your question: len(str(num)) is approximately equal to log(num, 10) + 1. This is not significantly shorter, but it's certainly a better way of expressing it in code (for the benefit of anyone who doesn't know that off the top of their head). You can then simplify it with log laws:
len(str(x**y))
= log(x**y, 10) + 1
= y * log(x, 10) + 1
So maybe you'll find:
"%i" % (log(len(var_text),10)*255 + 1)
... is better? It's not significantly shorter, but it's a much clearer mathematical relationship between input and output.

Categories