Python equation parser - python

I'm writing a program which needs a user input for an polynomial function of x. I'm using Tkinter and python 2.5.
I have a parser method which so far takes the inputted equation and splits it into terms without dropping the signs.
I want to take each term and parse it to get a tuple of the (coefficient, degree). For example, -2x^3 returns (-2,3). I can then add these to an array and manipulate them accordingly in the program.
Is there a way or standard module that can do this?
Here is the beginning of the parse method.
def parse(a):
termnum=[]
terms=[]
hi=[]
num1=0
num=0
f=list(a)
count=0
negative=False
coef=0.0
deg=0.0
codeg=[]
for item in f:
if (item=='-' or item=='+') and count!=0:
termnum.append(count)
count+=1
for item in termnum:
num1=num
num=item
current=''
while num1<num:
current=current+f[num1]
num1+=1
terms.append(current)
num1=num
num=len(f)
current=''
while num1<num:
current=current+f[num1]
num1+=1
terms.append(current)
print terms
parse('-x^2+3x+2x^3-x')
Thanks!
P.S I don't want to use external packages.

you can use regular expressions,
import re
test = '-x^2+3x+2x^3-x'
for m in re.finditer( r'(-{0,1}\d*)x\^{0,1}(-{0,1}\d*)', test ):
coef, expn = list( map( lambda x: x if x != '' and x != '-' else x + '1' ,
m.groups( ) ))
print ( 'coef:{}, exp:{}'.format( coef, expn ))
output:
coef:-1, exp:2
coef:3, exp:1
coef:2, exp:3
coef:-1, exp:1

Look for "recursive descent parser". It's the canonical method for analysis of strings where some operator precedence is involved.

It looks like you're implementing something that already exists, in python and other math languages. See for example:
http://www.gnu.org/software/octave/doc/interpreter/Solvers.html
http://stat.ethz.ch/R-manual/R-devel/library/base/html/solve.html

Related

Python Latex Library

I often work with groups of materials and my file/materials are named as alphanumeric strings. Is there a library to turn a string like r"Mxene - Ti3C2" to latex styled r"Mxene - Ti$_\mathrm{3}$C$_\mathrm{2}$"?
I usually use a dictionary but going through every name is a hassle and prone to error because materials can always be added or removed from the study.
I know that I can use str.maketrans() to generate subscripts but I haven't had very consistent results using the output with matplotlib so I'd much rather use latex.
I've ultimately created this solution in case anyone else needs it. Since my problem is mostly to create subscripts, the following code will look for numbers and replace them with a latex equivalent to create one.
def latexify(s):
import re
nums = re.findall(r'\d+', s)
pos = [[m.start(0), m.end(0)] for m in re.finditer(r'\d+', s)]
numpos = list(zip(nums, pos))
for num, pos in numpos:
string = f"$_\mathrm{{{num}}}$"
s = s[:pos[0]] + string + s[pos[1]:]
for ind, (n, [p_st, p_end]) in enumerate(numpos):
if p_st > pos[1]:
numpos[ind][1][0] += len(string)-len(num)
numpos[ind][1][1] += len(string)-len(num)
pass
return s
latexify("Ti32C2")
Returns:
'Ti$_\\mathrm{32}$C$_\\mathrm{2}$'

How to add "*" inside an equation?

I'm new to python.
I want to make a calculator and I am facing a problem right now.
Here's a simplified code I am trying to make:
from math import *
input = "(2)(3)e(sqrt(49))pi" #This is an example of equation
equation = "(2)*(3)*e*(sqrt(49))*pi" #The output
How can I add " * " between every ")(", ")e", "e(", and others based on the equation so that I can eval (equation) without having to put "*" manually, just like real life math?
I have tried to do it by making a code like this:
from math import *
input = "(2)(3)e(sqrt(49))pi"
input = input.replace(")(", ")*(")
input = input.replace(")e", ")*e")
input = input.replace("e(", "e*(")
input = input.replace(")pi", ")*pi")
#^^^I can loop this using for loop^^^
equation = input
print(eval(equation))
This definitely only works in this equation. I can loop the replacing method but that would be very inefficient. I don't want to have 49 iterations to just check if 7 different symbols need "*" between it or not.
The issue you will encounter here is that "e(" should be transformed to "e*(" but "sqrt(" should stay. As comments have suggested, the best or "cleanest" solution would be to write a proper parser for your equation. You could put "calculator parser" into your favorite search engine for a quick solution, or if you are interested in over-engineering but learning a lot, you could have a look at parser generators such as ANTLr.
If, for some reason, neither of those are an option, a quick-and-dirty solution could be this:
import re
def add_multiplication_symbols(equation: str) -> str:
constants = ['e', 'pi']
constants_re = '|'.join(f'(?:{re.escape(c)})' for c in constants)
equation = re.sub(r'(\))(\(|\w+)', r'\1*\2', equation)
equation = re.sub(f'({constants_re})' + r'(\()', r'\1*\2', equation)
return equation
Then print(add_multiplication_symbols("(2)(3)e(sqrt(49))pi")) results in (2)*(3)*e*(sqrt(49))*pi.
The function makes use of the re module (regular expressions) to group the cases for all constants together. It tries to work around the issue I described above by defining a set of constant variables (e.g. "e" and "pi") by hand.

Python avoiding using for loop or need shorten the code base

I have write python code and it has too many for loop, as a result, my code readability is too low and pylint star too low.
I am finding a way to solve same with fewer line of code.
here you go for my snippet:
numberlist = [1,3,5]
stringlist = ['a', 'b', 'c']
id = '458'
numbered_string = []
for n, s in numberlist, stringlist:
num_str = "{}{}".format(
n,
s,
id,
)
numbered_string.append(num_str)
codes = []
for n,s, sn in numberlist, stringlist, numbered_string:
code = make_code(
n,
s,
sn
)
codes.append(code)
print(codes)
Ignore the function make_code() , or let's assume the make_code() is
def make_code(n,s, sn):
return str(n) + str(s) + str(sn)
Can anyone help me shorten the snippet?, please ignore the function. I want to improve this code much better and high readability, too many instance is not a solution.
Take a look at list comprehensions. So, instead of:
codes = []
for n, s, sn in zip(numberlist, stringlist, numbered_string):
code = make_code(
n,
s,
sn
)
codes.append(code)
you can write:
codes = [make_code(n, x, sn) for n, x, sn in zip(numberlist, stringlist, numbered_string)]
Note that I used zip(numberlist, stringlist, numbered_string) in the for statement instead of the bare numberlist, stringlist, numbered_string. At least for me, on python 3.6, the latter does not work.
List comprehensions (and relatives for sets, dictionaries, generators, etc.) are super useful, and have lots of features, such as filtering using an if clause after the for clause, and supporting nested loops.
If your goal is to improve the readability of your code, you might want to also make sure your spacing is consistent (e.g. n, s, sn instead of n,s, sn) and your naming of variables is consistent -- in general, in python, variables and functions should be written in snake_case(e.g. number_list instead of numberlist).

Python polynomial input [duplicate]

I'm writing a program which needs a user input for an polynomial function of x. I'm using Tkinter and python 2.5.
I have a parser method which so far takes the inputted equation and splits it into terms without dropping the signs.
I want to take each term and parse it to get a tuple of the (coefficient, degree). For example, -2x^3 returns (-2,3). I can then add these to an array and manipulate them accordingly in the program.
Is there a way or standard module that can do this?
Here is the beginning of the parse method.
def parse(a):
termnum=[]
terms=[]
hi=[]
num1=0
num=0
f=list(a)
count=0
negative=False
coef=0.0
deg=0.0
codeg=[]
for item in f:
if (item=='-' or item=='+') and count!=0:
termnum.append(count)
count+=1
for item in termnum:
num1=num
num=item
current=''
while num1<num:
current=current+f[num1]
num1+=1
terms.append(current)
num1=num
num=len(f)
current=''
while num1<num:
current=current+f[num1]
num1+=1
terms.append(current)
print terms
parse('-x^2+3x+2x^3-x')
Thanks!
P.S I don't want to use external packages.
you can use regular expressions,
import re
test = '-x^2+3x+2x^3-x'
for m in re.finditer( r'(-{0,1}\d*)x\^{0,1}(-{0,1}\d*)', test ):
coef, expn = list( map( lambda x: x if x != '' and x != '-' else x + '1' ,
m.groups( ) ))
print ( 'coef:{}, exp:{}'.format( coef, expn ))
output:
coef:-1, exp:2
coef:3, exp:1
coef:2, exp:3
coef:-1, exp:1
Look for "recursive descent parser". It's the canonical method for analysis of strings where some operator precedence is involved.
It looks like you're implementing something that already exists, in python and other math languages. See for example:
http://www.gnu.org/software/octave/doc/interpreter/Solvers.html
http://stat.ethz.ch/R-manual/R-devel/library/base/html/solve.html

Getting mathematical function as user's input

I need to know how transfer string input into executable function.
For example - user write string 'x*Sin(x**2)' and then programm takes it as function, can calculate a value for given x, can plot derivation of this function etc. I've read that there is module called scitools.stringfunction, but as far as I know this module is not callable in python-3.
Any ideas how to make it?
For Python 2.X
f = lambda x: input() # the user inputs: x**2 + 1
y = f(3)
print y # outputs: 10
For Python 3.X
f = lambda x: eval(input())
y = f(5)
print y
Just make sure to import the required mathematical functions. And make sure the user inputs a valid Python arithmetic expression.
using sympy you could do something like this:
from sympy import var
from sympy import sympify
x = var('x') # the possible variable names must be known beforehand...
user_input = 'x * sin(x**2)'
expr = sympify(user_input)
res = expr.subs(x, 3.14)
print(res) # -1.322...
if you want to turn the user input into a function you can call you could to this:
from sympy.utilities.lambdify import lambdify
f = lambdify(x, expr)
# f(3.14) -> -1.322...
sympy can do sybolic calculations (including derivatives); if you want to make plots i strongly suggest matplotlib.
the advantage of using a math library opposed to eval is that you do not need to sanitize the user input (against malicious code).
(deleted this thanks to a comment from ejm).

Categories

Resources