Sympy substitute in fractions won't work as expected - python-3.x

Simpy is not detecting basic substitions with subs.
I have the following fraction:
d₂⋅n₁⋅n₂
──────── + m₂⋅n₁ + mm₂⋅n₂
nc
─────────────────────────
nc
Written as
cm2 = (d2*n1*n2/nc + m2*n1 + mm2*n2)/nc
Now I want to replace n1/nc = np1 and n2/nc = np2. So I've written:
cm2.subs({n1/nc : symbols("np1"), n2/nc: symbols("np2")})
The result is:
d₂⋅n1p⋅n₂ + m₂⋅n₁ + mm₂⋅n₂
──────────────────────────
nc
Instead I expected that sympy would figure out the other substitutions and output:
d2⋅n1p⋅n2p + m2⋅n1p + mm2⋅n2p
What I'm missing here?

subs is mostly literal, so after the first substitution, say n1/nc->n1p, then n2/nc no longer appears and so it cannot be replaced. But it's not necessary to do the re-arrangement of expressions to get them in the form needed to make the substitution, you can use solve to resolve everything for you:
>>> eqs
(Eq(cm2, (d2*n1*n2/nc + m2*n1 + mm2*n2)/nc), Eq(n1/nc, np1), Eq(n2/nc, np2))
>>> solve(eqs,cm2,n1,n2, dict=True)
[{cm2: d2*np1*np2 + m2*np1 + mm2*np2, n1: nc*np1, n2: nc*np2}]
There is also an unimplemented feature described here that offers, perhaps, a more intuitive way of doing this.

Sympy's subs can have troubles converting an expression by another expression, especially if they don't appear literally in the source expression. It also can be quite ambiguous.
When the goal is that all n1 and n2 disappear from cm2, the substitution can be written differently:
from sympy import symbols
d2, n1, n2, nc, m2, mm2, n = symbols("d2 n1 n2 nc m2 mm2 n")
np1, np2 = symbols("np1 np2")
cm2 = (d2 * n1 * n2 / nc + m2 * n1 + mm2 * n2) / nc
cm2.subs({n1: np1 * nc, n2: np2 * nc}).simplify()
Result: d2*np1*np2 + m2*np1 + mm2*np2

Related

Add brackets to an expression with regex

I want to add parentheses to parts of an expression.
The parts are any multiplied expressions that are NOT in parentheses.
For example, change:
a * b + c + d * e * f + g
to:
(a * b)+ c +( d * e * f) + g
another example, change:
(a1+b1) + ( c1 * d1) + e1 * f1 *g1 * h1 + J1
to:
(a1+b1) + ( c1 * d1) + (e1 * f1 *g1 * h1) + J1
The only elements in the expression to check will be * + ( ) and variable names with no spaces, like a1 f1 p3 etc.
I came up with something but it shows the expressions WITH brackets. I want the opposite of that.
This is what I have:
Function testParen()
Dim cText As String, cPattern As String
Dim itemFound As Variant, nItems
Dim getParen As New RegExp
getParen.Global = True
getParen.IgnoreCase = True
cText = "(a1*q1) + (b1*c1) + d1*e1*f1 * (g1+h1) + (k1*m1) "
cPattern = "(^|[^*])\(([^()]+)\)"
'cPattern = "\("
getParen.Pattern = cPattern
cText = Replace(cText, " ", "")
Dim mc As MatchCollection
Set mc = getParen.Execute(cText)
nItems = mc.Count
'Debug.Print vbNewLine
If nItems > 0 Then
Debug.Print nItems
For Each itemFound In mc
Debug.Print Replace(itemFound, "+", "")
Next
Else
Debug.Print "No items"
End If
End Function
I recommend you rethink your approach and parse the expression properly rather than just inserting parentheses. Perhaps initially splitting on + would be simpler, rather than using a regex that you don't fully understand and can't confidently adjust.
Anyway, here is an example in JavaScript of the kind of regex that could be used. I will leave any conversion to VBA to you.
const rx = /(\+\s*|^\s*)((?:\s*\w+\s*\*)+\s*\w+)(?=\s*\+|\s*$)/g;
const expression = '(a1+b1) + ( c1 * d1) + e1 * f1 * g1 * h1 + J1';
console.log(expression.replace(rx, '$1($2)'));
Note that the above has not been properly tested and may be brittle. I am not going to try and explain it, but you could enter the regex into for example https://regex101.com/ if you want a breakdown of how it works.
In the regex, the first \+ could be replaced with for example [^(\s\w] and the second \+ with [^)\s\w], if for example you want - to work also.

Calculate a serie in python

n is a knwon integer.
I need to print the serie:
Sn = 1/n + 2/(n-1) + 3/(n-2) + ... + n.
I tried:
n =2
soma =1
for i in range(1,n+1):
if n>i:
soma+=i/n + i/(n-1)
What is wrong?
You are doing it like this for now:
(1/2 + 1/1) + (2/2 + 2/1) .....
When actually what you want is to accumulate only one of them each iteration.
Therefore: soma+=i/(n-(i-1))
Also the condition n>i is always true in that case so you can try and omit it.

How to use the Python (with numpy?) to do the recursive calculation for a self-referencing expression?

Since after re-writting my question there is still no further answer, I try to describe my question in another way.
The expression looks as follow:
y = a*(datas + Prev(datas,1)/2) + b*Prev(y,1) + c*Prev(y,2)
The a, b and c are constants.
The datas is a Series and has n-elements.
The Prev(datas,1) is the privious value of datas.
The initial values of y are 0 and can be defined as:
y = pd.Series(np.zeros_like(datas))
The Prev(y, 1) is the privious of y and the Prev(y,2) is the privious of Prev(y,1)
if you want to change a global variable in python you need to reference it again in your function
def computeSuperSmootherFilter(price, cutoffLength):
global filt # Needed to modify global copy of globvar
a1 = np.exp(-math.pi * math.sqrt(2)/cutoffLength )
b1 = 2 * a1 * math.cos( math.sqrt(2) * math.pi / cutoffLength )
c2 = b1
c3 = -a1*a1
c1 = 1- c2 - c3
filt = c1*(price + price.shift(1))/2 + c2*filt.shift(1) + c3*filt.shift(2)
return filt
I think I've found the solution to my question myself. I do as follow:
y=pd.Series(np.zeros_like(datas))
for i in range(len(datas)):
try:
y[i] = c1*(datas[i] + datas[i-1])/2 + c2*y[i-1] + c3*y[i-2]
except Exception as e:
print(e)
y

Getting Type Mismatch on one line but nearly identical line evaluates correctly

I am getting a Type Mismatch on the "Pc" line only. Zc and Tc evaluate correctly. All values are coming from a User Form. Values are all floating point with 2 - 4 decimals. I have tried Dim Pc as Double and get same result. Any ideas why this is happening?
Portion of code that is flaky:
Private Sub VelocityCalc()
Zc = Zf.Value / Zb.Value
Pc = Pb.Value / (Pf.Value + Patm.Value)
Tc = (Tf.Value + 459.67) / 519.67
If your values are strings, Pc = Pb.Value / (Pf.Value + Patm.Value) could be, for instance, Pc = "123.4567" / ("4563.342" + "231.123").
This would evaluate to Pc = "123.4567" / ("4563.342231.123") (because the + operator can act as a concatenation operator for strings).
Because "4563.342231.123" can't be cast to a numeric value, it will crash when the division is attempted.
Always convert strings to numeric types before using them as numbers:
Zc = CDbl(Zf.Value) / CDbl(Zb.Value)
Pc = CDbl(Pb.Value) / (CDbl(Pf.Value) + CDbl(Patm.Value))
Tc = (CDbl(Tf.Value) + 459.67) / 519.67

Python Find all letter chars in string and surround with text

So lets say I have a string that says "m * x + b", I want to find any letter chars, other than x, and surround them with text.
In this example, output should be "var['m'] * x + var['b']"
A tiny regular expression solves your problem:
import re
s = "m * x + b"
print re.sub("([a-wyzA-Z])", r"var['\1']", s)
Output:
var['m'] * x + var['b']
Explanation:
[a-wyzA-Z] matches all characters within the brackets: a-w, y, z and A-Z (so basically every letter but x)
(...) makes the found match accessible later via \1
r"var['\1']" is the replacement referring to the match\1`

Resources