I have a task where I need to convert equations in one language (MATLAB) to another (C++) using Python. Everything is straightforward except the power operation. The equations are represented by Python strings.
For example, I want to convert
Eq = ((a+b)^2 + (c+d)^(1/2)) * e
to,
Eq = (pow((a+b),2) + pow(c+d, 1/2)) * e
I tried regular expression, but it does not seem to work because of nested parenthesis. Is there any good way to do this?
The best way to solve this would be to use Abstract Syntax Tree of Python. We can get that using ast module.
import ast, _ast
ops = {_ast.Mult: "*", _ast.Add: "+", _ast.BitXor: "pow", _ast.Div: "/"}
def rec(n):
if isinstance(n, _ast.Expr):
return rec(n.value)
elif isinstance(n, _ast.BinOp):
if isinstance(n.op, _ast.BitXor):
return "{}({}, {})".format(ops[type(n.op)], rec(n.left),rec(n.right))
else:
return "({} {} {})".format(rec(n.left), ops[type(n.op)],rec(n.right))
elif isinstance(n, _ast.Name):
return n.id
elif isinstance(n, _ast.Num):
return n.n
print rec(ast.parse("(((a+b)^2) + ((c+d)^(1/2))) * e").body[0])
# ((pow((a + b), 2) + pow((c + d), (1 / 2))) * e)
Note: Since ^ means Binary XOR operation in Python, you need to enclose that expression with an extra parenthesis, like I have shown in the example.
First, we check if it is an expression, then we process its value. If it is a binary operation, we check of it is Bitwise XOR, in that case we return the result in a different format, otherwise we return the result like left op right. If the current item looks like a name, then we return its id or if it is a number we return the attribute n.
You can do it as follows. Note: This is still a very primitive approach and I'd be careful about relying on it 100%:
import re
s = "Eq = ((a+b)^2 + (c+d)^(1/2)) * e"
>>> print re.sub(r'\(([^()\s]*)\)\^\(?([^()\s]*)\)?', 'pow(\\1,\\2)', s)
Eq = (pow(a+b,2) + pow(c+d,1/2)) * e
I think I'd do this with a simple tokeniser and parser rather than regular expressions. It's not that hard to write and will be more robust and readable than a regular expression based parser.
Related
I'm trying to write a simple script to do some math, and print out some specific intermediate steps in LaTeX. I've found there's no real simple way to do this using sympy, so I've started manually writing functions to print out each step I want to see.
I need to take a sympy function and format it so that every variable is replaced by it's associated value, I've been accessing the values through a dictionary.
basically,
import sympy as sym
x,a = sym.symbols("x a")
var_Values = {'x':3, 'a':2}
f=(x+1)/a
print(some_Function(f, var_Values))
so that the print statement reads \frac{3+1}{2}.
I've already tried two methods, using f.subs() to replace the variable with the value, which prints out 2 in this case, since it evaluates the expression's value.
I've also tried this textual method:
def some_Function(f, var_Values):
expression = sym.latex(f)
for variable in f.free_symbols:
expression = expression.replace(variable.name, var_Values.get(variable.name)
return expression
which is even worse, as it returns \fr2c{3+1}{2}, which turns more than what I wanted into numbers. It could be possible to get around this by using variable names that don't appear in the LaTeX commands I"m using, but that approach is impossible for me, as I don't choose my variable names.
SymPy is not great when it comes to leaving an expression unchanged because it inherently tries to simplify anything to make any future computations faster. subs and replace try to simplify the expression afterwards.
Here is the best I can think of:
import sympy as sym
x, a = sym.symbols("x a")
var_values = {x: 3, a: 2}
f = (x + 1) / a
def some_function(func: sym.Expr, var_dict: dict) -> sym.Expr:
new_dict = {key: sym.Symbol(str(val)) for key, val in var_dict.items()}
result = func.subs(new_dict)
return result
print(some_function(f, var_values))
This produces (3 + 1)/2. It should work for most cases. Sadly, this does not work in general as SymPy since with addition, it will sort the terms on its own. That means (x + y + 1) / a; var_values = {x: 3, y: 1, a: 2} produces (1 + 3 + 1)/2 which is not right. I have opened up an issue about this.
The reason why the second method does not produce valid latex is because expression is a string and has nothing to do with SymPy variables. Running in debug mode or in interactive mode, you'll see that it is "x + \frac{1}{a}". When you replace "a" for 2, "\frac" becomes "\fr2c". It is best to keep in mind what variable type each object is and to use SymPy Symbols instead of strings when replacing variables in an expression.
What about
>>> with evaluate(False):
... u = f.subs(val_Values)
That gives the (1 + 3)/2 unevaluated result. If you want the order you wrote terms to be respected then you have to do 2 things: create the expression and do the replacement in an unevaluated context and 2) use a printer that doesn't re-order the args:
>>> with evaluate(False):
... a=(1 + x).subs(var_Values)
... b=(x + 1).subs(var_Values)
>>> a,b
(1 + 3, 1 + 3)
>>> p=StrPrinter(dict(order='none'))
>>> p.doprint(a),p.doprint(b)
(1 + 3, 3 + 1)
Hi everyone and thanks to help me.
I have a function called factorial like this:
def fact(n):
if n == 0:
return 1
else:
return n * fact(n-1)
How i transform this function in a character like '!'?
for example:
>> fact(3)
6
>> 3!
6
use fact function when i put a number before '!', thanks for all!
Python allows you to define new meanings for two kinds of things:
names: sequences of characters starting with a letter or _ followed by any number of characters belonging to the 3 categories (digits, letters, digits).
existing operators, including but not limited to +, -, *, [], ==, in etc.
In order to define factorial as a trailing exclamation mark, as you desire, ! would have to be an existing postfix operator in Python. This is not the case.
The summary of all of that is: what you want cannot be done in Python.
considering "3!" is a string, you can always manipulate it. I'd recommend using a more sophisticated system, to check if the input is legit etc.
def fact(n):
return fact_number(int(n[:-1]))
def fact_number(n):
if n == 0:
return 1
else:
return n * fact_number(n-1)
print(fact("3!"))
output:
6
You can't do that in python, as suggested by #sheldonzy, you could parse a string somehow to give mathematical meaning to the ! operator.
When it comes to python operator overriding, these are the ones python provides you and you can override. So for instance, you could have your own int class and using the unary invert operator ~, like this:
class DontUseMe(int):
def __new__(cls, a, *args, **kwargs):
return super().__new__(cls, a)
def __invert__(self):
x = 1
for v in list(range(2, self + 1)):
x = x * v
return x
for i in range(10):
print(~DontUseMe(i))
In any case, I don't suggest overriding the builtin types for something like this, better continue using the method fact or parsing strings as mathematical expressions.
I recommend you to take a look at sympy, it's really handy to make mathematical operations on python.
I am creating a program that takes in a boolean expression as a string and converts the infix formula to postfix, while making sure the formula is in a valid form. What I'm having a hard time doing is figuring out a way to check if the inputed formula is valid or not. NO IMPORTING is permitted (use built-in python functions/methods), loops and recursion are allowed. If the formula is invalid, return None.
The formula can contain:
variables in 'abcdefghijklmnopqrstuvwxyz'
operators in '-+*'
where - is NOT, + is OR, * is AND
Here are some valid formulas (as Python strings).
"x"
"-y"
"(x*y)"
"((-x+y)*(-y+x))"
Here are some strings that are not formulas.
"X" variable not lower case letter
"x*y" missing parentheses
"-(x)" extraneous parentheses
"(x+(y)*z)" mismatched parentheses
Some conversion examples are:
(x+y) -> xy+
(x*y) -> xy*
-(x+y) -> xy+-
-x -> x-
((x*y)+(z*x)) -> xy*zx*+
A full working program isn't necessary, an algorithm to check if the formula is valid or not is fine.
My current implementation to convert formula from infix to postfix:
def infix_to_postfix(infix_expression):
precedence = {}
precedence["*"] = 2
precedence["+"] = 2
precedence["-"] = 2
precedence["("] = 1
storage_stack = Stack()
postfix_list = []
tokenList = list(infix_expression)
for token in tokenList:
if(token not in "-+*()"):
postfix_list.append(token)
elif(token == '-'):
storage_stack.push(token)
elif(token == '('):
storage_stack.push(token)
elif(token == ')'):
topToken = storage_stack.pop()
while(topToken != '('):
postfix_list.append(topToken)
topToken = storage_stack.pop()
else:
while(not storage_stack.is_empty() and precedence[storage_stack.peek()] >= precedence[token]):
postfix_list.append(storage_stack.pop())
storage_stack.push(token)
while(not storage_stack.is_empty()):
postfix_list.append(storage_stack.pop())
result = "".join(postfix_list)
return result
I need to find a way to check that the formula is valid while changing the positions of the operators and variables.
Edit:
I've come up with part of an algorithm to check if the formula is valid or not:
((a+b)*(c+d))
F1 = (a+b)
F2 = (c+d)
((a+b)*(c+d)) = (F1 * F2)
If F1 and F2 are valid, then the whole thing is valid.
A formula enclosed with parenthesis is valid if:
There is ( and ), there is either a + or * in between 2 sub-formulas, and both sub-formulas are valid.
I have this idea of checking, but I have no idea how to implement it. Most likely recursion.
This is an old question, however here is a potential solution to someone having the same issue.
import re
def formula(string):
if not string: return 0
string = re.sub("[^0-9+*/%-=]", "", string)
try:
string, result = string.split("=")
return eval(string) == int(result)
except:
return 0
Recently, I got an interview question which says to convert string expressions like "1+2-3" and "-2+4" to 0 and 2 respectively. Assuming the inputs are single digits numbers followed by signs and no NULL input. I tried this output but the interviewer said I am close but not perfect solution. Please help me here. Thanks.
def ans(input):
result, j = 0, 0
for i in input:
if i == '+' or i == '-':
j = i
else:
i = int(i)
result = result j i
return result
ans("1+2-3")
ans("-2+4")
I am making some silly mistake but I am learning. Thanks in advance.
Two things need fixing to work at all:
You need to handle the initial value properly; when the initial value is non-negative, this fails. Before the loop, set j = '+' so a non-sign prefixed value is added (also, for style points, j is a terrible name, could you use op or something?).
You can't use variables as operators.
Replace:
result = result j i
with:
if j == '+':
result += i
else:
result -= i
Note: If modules are allowed, a generalization can be used to handle operators the "nice" way (though more work would be needed to obey operator precedence). You'd define:
import operator
ops = {'+': operator.add, '-': operator.sub, ...}
then make the initial value of op operator.add and change the test for operators to:
if i in ops:
op = ops[i]
else:
result = op(result, int(i))
which scales to many more operators, dynamically selecting the operation to perform without cascading if/elif checks.
Side-note: While violating the spirit of the challenge, ast.literal_eval (at least as of Python 3.5, and this may change, see bug #22525) will actually safely parse strings like this (eval is unsafe, since it can execute arbitrary code, but ast.literal_eval can only parse Python literals and apparently some basic compile-time math). So you could just do:
import ast
ans = ast.literal_eval
Sure, it handles many other literals too, but we never defined the failure case behavior anyway. :-)
Using eval() is the simplest solution. Like
eval("1+2-3")
The following code give another solution without using built-in eval
import operator
class Parse(object):
def __init__(self, input):
self.input = input
self.pos = 0
self.end = len(input)
def eval(self):
result = self.match_digits()
while self.pos < self.end:
op = self.match_operator()
operand = self.match_digits()
result = op(result, operand)
return result
def match_operator(self):
look_ahead = self.input[self.pos]
self.advance()
return operator.add if look_ahead == '+' else operator.sub
def match_digits(self):
look_ahead = self.input[self.pos]
positive = 1
if look_ahead == '-':
positive = -1
self.advance()
digits, s = 0, self.pos
while s < self.end and self.input[s].isdigit():
digits = digits * 10 + int(self.input[s])
s += 1
self.advance(s-self.pos)
return digits * positive
def advance(self, offset=1):
self.pos += offset
For testing
p = Parse(input='2+1+0-3')
print p.eval()
p = Parse(input='-2+-13+3')
print p.eval()
I think the most flexible solution (not using eval and able to handle any operations) is to parse the string into a binary (red-black) tree, where leafs are numbers and branches operators (+,-,/,*,etc).
For example, "1+(5*12)/17" would be parsed into following structure:
"+"
/ \
1 "/"
/ \
"()" 17
/
"*"
/ \
5 12
Once you've parsed a string into this structure, it's easy to compute by traversing branches depth-first, right to left.
If you need to handle variables, then you'd have to get locals() and replace accordingly, either as you parse the string, or as you traverse the tree.
EDIT:
I created a working example to illustrate this, you can find the source on github: https://github.com/MJWunderlich/py-math-expression-evaluator
what about:
def f(s):
s = s.strip()
for i, c in enumerate(s):
if c == '+':
return f(s[:i]) + f(s[i+1:])
if c == '-':
return f(s[:i]) - f(s[i+1:])
for i, c in enumerate(s):
if c == '*':
return f(s[:i]) * f(s[i+1:])
if c == '/':
return f(s[:i]) / f(s[i+1:])
return 0 if s == '' else int(s)
? Doesn't work with parenthesis
This question already has answers here:
Evaluating a mathematical expression in a string
(14 answers)
Closed 8 years ago.
I've got a python formula that randomly places operands in between numbers. The list could, for example, look like this:
['9-8+7', '7-8-6']
What I want to do is get the value of each string, so that looping through the strings, an array would see 9-8+7 and would append 8 and 7-8-6 would append -7. I can't convert a string with operands to int, so is this possible at all? Or should I change the algorithm so that instead of creating a string with each random output it calculates the value of it immediately?
Thank you in advance.
You can do eval on the list items, but that's a potential security hole and should only be used if you fully trust the source.
>>> map(eval, ['9-8+7', '7-8-6'])
[8, -7]
If you control the code producing the string, computing the values directly sounds like a better approach (safer and probably faster).
As Fredrik pointed out, you can do eval in Python. I thought I'd add a more general approach that would work in any language, and might shed some light on simple parsers for those that haven't seen them in action.
You're describing a language whose formal definition looks something like this:
expr := sum
sum := prod [("+" | "-") prod]...
prod := digit [("*" | "/") digit]...
digit := '0'..'9'
This grammar (which I'm not bothering to make correct EBNF) accepts these strings: "3", "4*5/2", and "8*3+9", and so on.
This gives us a clue how to parse it, and evaluation is no more work than accumulating results as we go. The following is working Python 2 code. Notice how closely the code follows the grammar.
class ParseFail(Exception):
pass
def eval_expr(str):
value, pos = eval_sum(str, 0)
return value
def eval_sum(str, pos):
value, pos = eval_product(str, pos)
accum = value
while pos != len(str):
op = str[pos]
if not str[pos] in ['+', '-']:
raise ParseFail("Unexpected symbol at position "
"{pos} of {str}".format(str=str, pos=pos))
value, pos = eval_product(str, pos + 1)
if op == '+':
accum += value
else:
accum -= value
return accum, pos
def eval_product(str, pos):
value, pos = eval_digit(str, pos)
accum = value
while pos != len(str):
op = str[pos]
if not str[pos] in ['*', '/']:
return accum, pos
value, pos = eval_digit(str, pos + 1)
if op == '*':
accum *= value
else:
accum /= value
return accum, pos
def eval_digit(str, pos):
if not str[pos].isdigit():
raise ParseFail("Unexpected symbol at position "
"{pos} of {str}".format(str=str, pos=pos))
return int(str[pos]), pos + 1
try:
print "3 ->", eval_expr("3")
print "3*4 ->", eval_expr("3*4")
print "2+3*4-5 ->", eval_expr("2+3*4-5")
# Should raise ParseFail
print "2+3*4^2-5 ->", eval_expr("2+3*4^2-5")
except ParseFail as err:
print
print err.args[0]
Here's a sample run:
$ python simple_expr.py
3 -> 3
3*4 -> 12
2+3*4-5 -> 9
2+3*4^2-5 ->
Unexpected symbol at position 5 of 2+3*4^2-5
It would be pretty easy to extend this to a full string calculator with more operators, such as the exponent operator '^' and multi-digit integers. Parentheses, floats and functions might be a bit of work, but not that hard either. Every programmer should try it once in their lives, in my opinion.
This of course depends on how well-behaved and restricted your expressions are.
Since subtraction is addition with a negative number, you can write the subtractions as additions with a negative number. Spit on + to find the terms. Then parse the terms of the sum to integers, and sum them. Do so for each expression.
[sum(map(int,l.replace('-', '+-').split('+'))) for l in ['9-8+7','7-8-6']]