Python string function parameter replacing - python

I would like to ask your help. I have started learning python, and there are a task that I can not figure out how to complete. So here it is.
We have a input.txt file containing the next 4 rows:
f(x, 3*y) * 54 = 64 / (7 * x) + f(2*x, y-6)
x + f(21*y, x - 32/y) + 4 = f(21 ,y)
86 - f(7 + x*10, y+ 232) = f(12*x-4, 2*y-61)*32 + f(2, x)
65 - 3* y = f(2*y/33 , x + 5)
The task is to change the "f" function and its 2 parameters into dividing. There can be any number of spaces between the two parameters. For example f(2, 5) is the same as f(2 , 5) and should be (2 / 5) with exactly one space before and after the divide mark after the running of the code. Also, if one of the parameters are a multiplification or a divide, the parameter must go into bracket. For example: f(3, 5*7) should become (3 / (5*7)). And there could be any number of function in one row. So the output should look like this:
(x / (3*y)) * 54 = 64 / (7 * x) + ((2*x) / (y-6))
x + ((21*y) / (x - 32/y)) + 4 = (21 / y)
86 - ((7 + x*10) / (y+ 232)) = ((12*x-4) / (2*y-61))*32 + (2 / x)
65 - 3* y = ((2*y/33) / (x + 5))
I would be very happy if anyone could help me.
Thank you in advance,
David

Using re:
In [84]: ss=r'f(x, 3*y) * 54 = 64 / (7 * x) + f(2*x, y-6)'
In [85]: re.sub(r'(f\()(.*?),(.*?)(\))', lambda m: '((%s) / (%s))'%(m.group(2), m.group(3)), ss)
Out[85]: '((x) / ( 3*y)) * 54 = 64 / (7 * x) + ((2*x) / ( y-6))'
Explanation:
re.sub(pattern, repl, string, count=0, flags=0) returns the string obtained by replacing the leftmost
non-overlapping occurrences of the pattern in string by the
replacement repl.
The () are used to catch the groups;
*? is a non-greedy qualifier, which matches as little text as possible.

Here's some places to start:
You can check if one string is in another string using string1 in
string2 (e.g., 'bcd' in 'abcdefg' -> True)
You can identify the insides of f() calls by finding the locations of 'f(' in a
string and then adding 1 to an index (that starts at 1) when you find
a '(' and removing 1 when you find ')'. When you hit 0 you're done.
You can break a string into a list by a matching string by
string1.split(string2) (e.g., 'a,b'.split(',') -> ['a', 'b']
You can format a string easily using the
.format method
(e.g., '({0} % {1})'.format(string1, string2))

Related

recursive function multiply and sum

Hope to find some help here with a new excercise.
I luckily understand how to use recursive functions, but this one is killing me, im probably just thinking too much outside of the box.
We're given a string:
c = "3+4*5+6+1*3"
And now we have to code a function, which recursivly gives us the result of that calculation.
Now i know the recursive end should be the length of the string, which should be 1.
Our professor did give us another example which we should use for this function.
int(number)
string.split(symbol, 1)
we have following code given:
c = "3+4*5+6+1*3"
print(c)
print()
sub1, sub2 = c.split("+", 1)
print("Result with '+':")
print("sub1=" + sub1)
print("sub2=" + sub2)
print()
sub1, sub2 = c.split("*", 1)
print("Result with '*':")
print("sub1=" + sub1)
print("sub2=" + sub2)
print()
My thoughts were to split the strings to a minimum, so i can turn them into integers and than sum them together. But im absolutly lost there how the code should look like, im a real beginner so im really sorry. I dont even know it the beginning i was thinking of is right. Still hoping, someone can help!
what i had:
def calc(string):
if len(string) == 1:
return string
Thanks for all of you!
Greets
Chrissi
I created a function that solves equations like these. However, the only characters possible are numbers, and operators add (+) and mult (*). If you try to use any other characters such as spaces, there's going to be errors.
# Solves a mathematical equation containing digits [0-9], and operators
# such as add + or multiply *
def solve(equation, operators, oindex=0):
# If an operator is available, use the operator
if (oindex < len(operators)):
# Get the current operator and pair: a op b
op = operators[oindex]
pair = equation.split(op, 1)
# If the pair is a pair (has 2 elements)
if (len(pair) == 2):
# Solve left side
a = solve(pair[0], operators)
# Solve right side
b = solve(pair[1], operators)
# If current operator is multiply: multiply a and b
if (op == '*'):
print(a, '*', b, '=', a*b)
return a * b
# If current operator is add: add a and b
elif (op == '+'):
print(a, '+', b, '=', a+b)
return a + b
# If it's not a pair, try using another operator
else:
return solve(equation, operators, oindex+1)
else:
# If no operators are available, then equation is
# just a number.
return int(equation)
if __name__ == '__main__':
equation = "3+4*5+6+1*3"
# If mult (*) takes precedence, operator order is "+*"
# > 3+4*5+6+1*3 = ((3)+((4*5)+((6)+(1*3))))
# = ((3)+((20)+((6)+(3))))
# = ((3)+(20+(9)))
# = ((3)+(29))
# = (32)
print("MULT, then ADD -> ",equation + " = ", solve(equation, "+*"))
# If add (+) takes precedence, operator order is "*+"
# > 3+4*5+6+1*3 = ((3+4)*(((5)+(6+1))*(3)))
# = ((7)*((5+7)*(3)))
# = ((7)*(12*3))
# = (7*36)
# = (252)
print("ADD, then MULT -> ",equation + " = ", solve(equation, "*+"))
To set the operators, you can use the paramter operators, which is a string that takes all supported operators. In this case: +*.
The order of these characters matter, changing the precedence of each operator inside the equation.
Here's the output:
4 * 5 = 20
1 * 3 = 3
6 + 3 = 9
20 + 9 = 29
3 + 29 = 32
MULT, then ADD -> 3+4*5+6+1*3 = 32
3 + 4 = 7
6 + 1 = 7
5 + 7 = 12
12 * 3 = 36
7 * 36 = 252
ADD, then MULT -> 3+4*5+6+1*3 = 252

Sympy : simplification with expression substitution

I have several expressions involving the norm or norm squared of a vector u. I'd like to simplify these expressions by substituting a known value for the norm of u. However, it seems that obvious expressions involving even simple multiples of the norm are not simplified.
As an example, this code does what I would expect :
import sympy as sp
u1,u2,u3 = sp.symbols('u_1, u_2, u_3',real=True,positive=True)
utu = u1**2 + u2**2 + u3**2
print("Ex. 1")
print(utu.subs(utu,1))
This produces the expected output
Ex. 1
1
However, 2*utu does not simplify in the way I would expect :
print("Ex 2")
print((2*utu).subs(utu,1))
Ex 2
2*u_1**2 + 2*u_2**2 + 2*u_3**2
I can explicitly force the substitution with this :
print("Ex 3")
print((2*utu).subs(2*utu,2))
which produces the expected output :
Ex 3
2
Ideally, I'd like to substitute under a norm function, but the run into the same issue.
u = sp.Matrix(3, 1, [u1,u2,u3])
print("Ex 4")
print(u.norm().subs(utu,1))
print("Ex 5")
print((2*u).norm().subs(utu,1))
print("Ex 6")
print((2*u).norm().subs(4*utu,4))
which produces
Ex 4
1
Ex 5
sqrt(4*u_1**2 + 4*u_2**2 + 4*u_3**2)
Ex 6
2
Are there tricks I am missing that will catch these obvious (to me at least - maybe not to Sympy?) simplifications? I've tried factor and expand, without much luck.
Let's analyze this expression:
expr = 2*utu
# out: 2*u_1**2 + 2*u_2**2 + 2*u_3**2
The multiplication has been evaluated. This is SymPy's default behavior: it evaluates things. We can work with the expression manipulation functions to achieve our goal.
For example:
expr = collect_const(expr)
# out: 2*(u_1**2 + u_2**2 + u_3**2)
expr.subs(utu, 1)
# out: 2
Another example:
expr = (2 * u).norm()
# out: sqrt(4*u_1**2 + 4*u_2**2 + 4*u_3**2)
expr = expr.simplify() # Note that expr.factor() produces the same result with this expression
# out: 2*sqrt(u_1**2 + u_2**2 + u_3**2)
expr.subs(utu, 1)
# out: 2
If you play (and modify) with these examples, you will realize that the same result can be achieved with different functions (factor, simplify, collect, collect_const, ...), but even one little change in the expression might prevent one function from "doing its work", while others might be able to. Expression manipulation is kind of an art that one should practice (a lot).
For completeness, I'm going to show you UnevaluatedExpr, which allows a particular expression to remain unevaluated during expression manipulation, though it might not always be the best choice:
n = UnevaluatedExpr(utu)
# out: u_1**2 + u_2**2 + u_3**2
expr = 4 * n
# out: 4*(u_1**2 + u_2**2 + u_3**2)
Note that SymPy didn't proceed with the full evaluation. Now:
expr.subs(utu, 1)
# out: 4*1
Why is there a 4*1 instead of 4? The 1 refers to the UnevaluateExpr object that we created earlier: to evaluate it we can use the doit() method:
expr.subs(utu, 1).doit()
# 4
Keep in mind that while using UnevaluateExpr, the expression becomes non-commutative (I think it's a bug with SymPy), which will prevent other functions to produce the expected results.
Substituting compound expressions is problematic. For the most part you should only expect subs to work if the expression to be replaced is known to always appear literally as part of the expression tree that you are substituting into. When possible then it is better to rearrange for a single symbol like:
In [10]: utu
Out[10]:
2 2 2
u₁ + u₂ + u₃
In [11]: (2*utu).subs(u1**2, 1 - u2**2 - u3**2)
Out[11]: 2
Even here we are substituting for a power of a symbol (u1**2) which is potentially fragile if we can't be sure that exactly that power will always appear in the expression. More generally there are functions that can simplify expressions based on knowing some polynomial relation e.g. ratsimpmodprime:
In [16]: e = (1 - u1**2) / (u1**2 + u2**2 + u3**2)
In [17]: e
Out[17]:
2
1 - u₁
───────────────
2 2 2
u₁ + u₂ + u₃
In [18]: ratsimpmodprime(e, [u1**2 + u2**2 + u3**2 - 1])
Out[18]:
2 2
u₂ + u₃
Other possibilities could be using resultants or Groebner bases to do similar things. Note that u.norm() has a square root which is symbolically awkward so it is better to work with the square of the norm (same as when working on pen and paper):
In [20]: ratsimpmodprime((2*u).norm()**2, [u1**2 + u2**2 + u3**2 - 1])
Out[20]: 4
Also if you just want a more powerful version of subs then you can use replace but with patterns:
In [21]: a = Wild('a')
In [22]: p = a*u1**2 + a*u2**2 + a*u3**2
In [23]: (2*utu).replace(p, a)
Out[23]: 2
In [24]: (2*u).norm().replace(p, a)
Out[24]: 2
Both solid answers already. If you have an arbitrary expression that you expect to be a factor in another, factor_terms is what I try first to make that factor appear. It will collect common factors without doing factoring. But if this doesn't work and you know you have a factor, div is a nice way to check and see the expression with the factor removed:
>>> expr = 2*(x + y)
>>> factor_terms(expr)
2*(x + y)
>>> e2 = expand(expr*(x -y)) # 2*x**2 - y**2
>>> factor_terms(e2)
2*(x**2 - y**2)
>>> div(_,-x-y)
(-2*x + 2*y, 0)
>>> _[0]*z # if you wanted to replace factor -x-y with z
z*(-2*x + 2*y)

sympy.subs - wrong substitution

I have this equation:
(1 - tau2)**3 + (tau2-tau1)**5
And I want to substitute (1-tau2) by (1-tau3). However, I get the wrong result.
This is my code:
tau1,tau2,tau3= symbols('tau1,tau2,tau3')
exp= (1-tau2)**3+(tau2-tau1)**5
res=exp.subs((1-tau2),(1-tau3))
print('exp:',exp)
print('res:',res)
And the result is:
exp= (1 - tau2)**3 + (-tau1 + tau2)**5
res= (1 - tau3)**3 + (-tau1 + tau3)**5
But it should be:
res= (1 - tau3)**3 + (-tau1 + tau2)**5
How can I solve this?
Sometimes you want a smart substitution -- in this case, recognizing that your substitution is equivalent to replacing tau2 with tau3 -- and sometimes you want an exact substitution. In case of the latter, use xreplace:
>>> from sympy.abc import x, y
>>> (1-x)**3+(x-y)**5
(1 - x)**3 + (x - y)**5
>>> _.xreplace({1-x: z})
z**3 + (x - y)**5

how to pattern match and change all occurrences of subexpression in expression?

Using sympy, I need to replace all occurrence of exp(C+anything) with C*exp(anything). Because exp(C) is constant, I just write at as C.
I can do this for one occurrence of exp in the expression. But do not how to do it if there are than one instance.
For example, for one instance, as in x+exp(C_0+3*x)+3*y, I need to change it to x+C_0*exp(3*x)+3*y
For one instance, this seems to work after some trial and error
from sympy import *
x,y,C_0 = symbols('x y C_0')
expr=x+exp(C_0+3*x)+3*y
#first check if exp is in the expression
if any([isinstance(a, exp) for a in preorder_traversal(expr)]):
p_1=Wild('p1');p_2=Wild('p_2');p_3=Wild('p_3')
r=(p_1+exp(C_0+p_2)+p_3).matches(expr)
expr.subs(exp(C_0+r[p_2]),C_0*exp(r[p_2]))
Which gives
C_0*exp(3*x) + x + 3*y
But what about something like x+exp(C_0+3*x)+3*y+exp(C_0+30*x+y) which I need to change to x+C_0*exp(3*x)+3*y+C_0*exp(30*x+y) I can't make special pattern match for each possible case. I need a way to change all occurrences
In Mathematica, I do the above as follows
expr = x + Exp[c + 3*x]*3*y + 3*y + Exp[c + 30*x + y]
expr /. Exp[c + any_] :> (c Exp[any])
Which gives
I actually prefer to tell Python just to change exp(C+anything) to C*exp(anything) without having to give pattern for the overall expression, since that can change in many way.
I am sure the above is also possible in python/sympy. Any hints how to do it?
I would look for function exp inside of the expression, check whether its argument is Add, and then whether C_0 is among the arguments of Add. Then build a thing to replace exp with. Consider the following:
from sympy import *
x, y, C_0 = symbols('x y C_0')
expr = x + exp(C_0+3*x) + 3*y + exp(y+C_0+30*x) - exp(x+y-C_0) + exp(x*y)
exp_sum = [(a, a.args[0].args) for a in preorder_traversal(expr) if a.func == exp and a.args[0].func == Add]
exp_sum = [p for p in exp_sum if C_0 in p[1]]
new_exp = [C_0*exp(Add(*[x for x in p[1] if x != C_0])) for p in exp_sum]
for (old, new) in zip(exp_sum, new_exp):
expr = expr.subs(old[0], new)
Initially, exp_sum contains all parts of the form exp(Add(...)). After that it's filtered down to sums containing C_0. New exponentials are formed by taking all summands that are not C_0, adding them, applying exp and multiplying by C_0. Then substitution happens.
To clarify the process, here is what exp_sum is in the above example: a list of tuples (exponential and the summands inside):
[(exp(C_0 + 3*x), (C_0, 3*x)), (exp(C_0 + 30*x + y), (C_0, y, 30*x))]
And this is new_exp
[C_0*exp(3*x), C_0*exp(30*x + y)]
Finally, expr at the end:
C_0*exp(3*x) + C_0*exp(30*x + y) + x + 3*y + exp(x*y) - exp(-C_0 + x + y)
Notice that exp(-C_0...) is not affected by the change; it's not a part of the pattern.

search and replace text in python

I am kinda to python programming
I have no clue how to solve that task:
for line in f: br
m = re.search("f(\S+\s+,\s+\S+)",
"56 - f(32 , 6*3) + 62 * ( 54 - 3 ) + f(5 , 9+y)")
print m.group()
I have to convert all f(x , y) to x*y.
I haven't got an idea how to solve that. I tried with splitting but didn't worked.
Thanks!
I would recommend a tour towards the python tutorial, perhaps the string section.
After that, the regexp tutorial.
Regular expressions can be a complicated beast, I suggest reading up on them. For this particular scenario re.sub should do the trick.
Here's a sample of what I've come up with using the input you provided.
import re
inp = "56 - f(32 , 6*3) + 62 * ( 54 - 3 ) + f(5 , 9+y)"
# Matches on characters, arithmetic operations, and digits (hopefully)
pattern = r"f\(\s*([a-z\d\-\+\*/]+)\s*,\s*([a-z\d\-\+\*/]+)\s*\)"
print re.sub(pattern, r"\1 * \2", inp)
This should produce:
56 - 32 * 6*3 + 62 * ( 54 - 3 ) + 5 * 9+y
I am no expert when it comes to regular expressions but hopefully the above will get you started. I doubt the above regex will catch all occurrences and for that I suggest you ask someone with better regex-fu. Merely providing this as an example.
Try re.sub.
regex = re.compile('a+')
x = re.sub(regex, 'd', 'baac')
print(x)
Prints:
bdc
Like this!?
>>> inp = "56 - f(32 , 6*3) + 62 * ( 54 - 3 ) + f(5 , 9+y)"
>>> import re
>>> re.sub(r'f\((\S+)\s*,\s*(\S+)\)',r'\1*\2',inp)
'56 - 32*6*3 + 62 * ( 54 - 3 ) + 5*9+y'
probably its useful to put the multiplication in parantheses? Then you could use the following regexp:
>>> re.sub(r'f\((\S+\s*),(\s*\S+)\)',r'(\1*\2)',inp)
'56 - (32 * 6*3) + 62 * ( 54 - 3 ) + (5 * 9+y)'

Categories