Plotting a sympy plot for simultanous ODE solutions - sympy

g, d = symbols("g d", cls=Function)
T, G= symbols("T G")
system = [Eq( d(t).diff(t), - d(t)/T), Eq( g(t).diff(t), - G*g(t) + d(t)/T )]
ics = {d(0): 1, g(0): 0}
e = sym.dsolve(system, [g(t), d(t)], ics=ics)
is the code I am using to find solutions. How do I plot the functions across time with G and T as constants ?
I tried using lambdify function, but pops up an error.
lmbd_sol = lambdify(t, e.rhs)

Related

Substitute numerical constants with symbols in sympy

I have a question similar to this one: How to substitute multiple symbols in an expression in sympy? but in reverse.
I have a sympy expression with numerical values and symbols alike. I would like to substitute all numerical values with symbolic constants. I appreciate that such query is uncommon for sympy. What can I try next?
For example, I have:
-0.5967695*sin(0.15280747*x0 + 0.89256966) + 0.5967695*sin(sin(0.004289882*x0 - 1.5390939)) and would like to replace all numbers with a, b, c etc. ideally in a batch type of way.
The goal is to then apply trig identities to simplify the expression.
I'm not sure if there is already such a function. If there is not, it's quite easy to build one. For example:
import string
def num2symbols(expr):
# wild symbol to select all numbers
w = Wild("w", properties=[lambda t: isinstance(t, Number)])
# extract the numbers from the expression
n = expr.find(w)
# get a lowercase alphabet
alphabet = list(string.ascii_lowercase)
# create a symbol for each number
s = symbols(" ".join(alphabet[:len(n)]))
# create a dictionary mapping a number to a symbol
d = {k: v for k, v in zip(n, s)}
return d, expr.subs(d)
x0 = symbols("x0")
expr = -0.5967695*sin(0.15280747*x0 + 0.89256966) + 0.5967695*sin(sin(0.004289882*x0 - 1.5390939))
d, new_expr = num2symbols(expr)
print(new_expr)
# out: b*sin(c + d*x0) - b*sin(sin(a + f*x0))
print(d):
# {-1.53909390000000: a, -0.596769500000000: b, 0.892569660000000: c, 0.152807470000000: d, 0.596769500000000: e, 0.00428988200000000: f}
I feel like dict.setdefault was made for this purpose in Python :-)
>>> c = numbered_symbols('c',cls=Dummy)
>>> d = {}
>>> econ = expr.replace(lambda x:x.is_Float, lambda x: sign(x)*d.setdefault(abs(x),next(c)))
>>> undo = {v:k for k,v in d.items()}
Do what you want with econ and when done (after saving results to econ)
>>> econ.xreplace(undo) == expr
True
(But if you change econ the exact equivalence may no longer hold.) This uses abs to store symbols so if the expression has constants that differ by a sign they will appear in econ with +/-ci instead of ci and cj.

How to replace log(x) by log(abs(x)) automatically in SymPy

I am trying to solve differential equation y'=cot(x) using Sympy:
x = symbols("x")
y = Function("y")(x)
dsolve(diff(y, x) - cot(x))
It gives me solution with logarithm: y(x) = C1 + log(sin(x)).
How I can replace in this expression log by combination log + abs: log(sin(x)) -> log(abs(sin(x)))? I can do it manually, but it's not very convenient. Is there any way to do it with SymPy tools (something like subs command)?
Note that the abs isn't actually needed: the integration constant C1 can include I*pi. The form without abs is valid for all complex x whereas the abs form is only valid for real x.
In any case, you can do it like this:
In [6]: sol
Out[6]: y(x) = C₁ + log(sin(x))
In [7]: sol.replace(log, lambda e: log(abs(e)))
Out[7]: y(x) = C₁ + log(│sin(x)│)

SYMPY : How to simplify expression with exponential functions?

I have expression with exponential functions and I would like to simplify them. Some of the exponential functions have a negative parameters.
To sum up my problem with a very trivial example :
a,b,c,d=sp.symbols("a b c d",real=True, positive=True)
myExpr=(sp.exp(c)+sp.exp(d))*sp.exp(-c-d)
myExpr.simplify() gave a simplified expression. That is perfect.
BUT, with a denominator in the expression, exponential functions with a negative parameter are not simplified :
a,b,c,d=sp.symbols("a b c d",real=True, positive=True)
myExpr=(sp.exp(c)+sp.exp(d))*sp.exp(-c-d)/a
How can I simplify it ?
As suggested in the comments, I submit a more complicated example :
import sympy as sp
a, b, c, d, e, f, c1, c2, t = sp.symbols("a b c d e f c_1 c_2 t", real=True, positive = True)
myExpr=((c1*sp.exp((a+b+c)*t)+c2*sp.exp((d+e+f)*t)))/(c1+c2)*sp.exp(-(a+b+c+d+e+f)*t)
And I would like an output as this one :
output= ((c1*sp.exp(-(e+d+f)*t)+c2*sp.exp(-(a+b+c)*t)))/(c1+c2)
Rq : with (a+b+c) in the same exp : exp ( -(a+b+c)*t ) and not as a product of exp : exp(-a*t)*exp(-b*t)*exp(-c*t), similarly for (d+e+f)
Thanks for answer.
Okay, I see the problem. When you have an Add in the numerator and the denominator expand distributes a "negative" power into the denominator:
In [45]: expr = (a*x + b*x)*(1/x)*(1/(c + d))
In [46]: expr
Out[46]:
a⋅x + b⋅x
─────────
x⋅(c + d)
In [47]: expand(expr)
Out[47]:
a⋅x b⋅x
───────── + ─────────
c⋅x + d⋅x c⋅x + d⋅x
It's less obvious with the exponential function because it shows in the numerator
In [48]: expr.subs(x, exp(t))
Out[48]:
⎛ t t⎞ -t
⎝a⋅ℯ + b⋅ℯ ⎠⋅ℯ
─────────────────
c + d
however expand still treats it as belonging to the denominator just as a power E**(-t) would.
In [51]: expand_mul(expr.subs(x, exp(t)))
Out[51]:
t t
a⋅ℯ b⋅ℯ
─────────── + ───────────
t t t t
c⋅ℯ + d⋅ℯ c⋅ℯ + d⋅ℯ
I can't think of an easier way to do it than this:
In [84]: factor_terms(sum(powsimp(factor_terms(cancel(a))) for a in Add.make_args(myExpr.expand())))
Out[84]:
-t⋅(d + e + f) -t⋅(a + b + c)
c₁⋅ℯ + c₂⋅ℯ
───────────────────────────────────────
c₁ + c₂

Matching coefficients with sympy

I am attempting to work a problem from a textbook in sympy, but sympy fails to find a solution which appears valid. For interest, it is the design of a PID controller using direct synthesis with a second order plus dead time model.
The whole problem can be reduced to finding K_C, tau_I and tau_D which will make
K_C*(s**2*tau_D*tau_I + s*tau_I + 1)/(s*tau_I)
= (s**2*tau_1*tau_2 + s*tau_1 + s*tau_2 + 1)/(K*s*(-phi + tau_c))
for given tau_1, tau_2, K and phi.
I have tried to solve this by matching coefficients:
import sympy
s, tau_c, tau_1, tau_2, phi, K = sympy.symbols('s, tau_c, tau_1, tau_2, phi, K')
target = (s**2*tau_1*tau_2 + s*tau_1 + s*tau_2 + 1)/(K*s*(-phi + tau_c))
K_C, tau_I, tau_D = sympy.symbols('K_C, tau_I, tau_D', real=True)
PID = K_C*(1 + 1/(tau_I*s) + tau_D*s)
eq = (target - PID).together()
eq *= sympy.denom(eq).simplify()
eq = sympy.poly(eq, s)
sympy.solve(eq.coeffs(), [K_C, tau_I, tau_D])
This returns an empty list. However, the textbook provides the following solution:
booksolution = {K_C: 1/K*(tau_1 + tau_2)/(tau_c - phi),
tau_I: tau_1 + tau_2,a
tau_D: tau_1*tau_2/(tau_1 + tau_2)}
Which appears to satisfy the equations I'm trying to solve:
[c.subs(booksolution).simplify() for c in eq.coeffs()]
returns
[0, 0, 0]
Can I massage this into a form which sympy can solve? What am I doing wong?
Edit: This finds the correct solution, but requires a little too much thought from my side to order the equations:
eqs = eq.coeffs()
solution = {}
solution[K_C] = sympy.solve(eqs[1], K_C)[0]
solution[tau_D] = sympy.solve(eqs[0], tau_D)[0].subs(solution)
solution[tau_I] = sympy.solve(eqs[2], tau_I)[0].subs(solution).simplify()
In SymPy 1.0 (to be released soon) I get this answer
In [25]: sympy.solve(eq.coeffs(), [K_C, tau_I, tau_D])
Out[25]:
⎡ ⎧ -(τ₁ + τ₂) τ₁⋅τ₂ ⎫⎤
⎢{K_C: 0, τ_I: 0}, ⎨K_C: ───────────, τ_D: ───────, τ_I: τ₁ + τ₂⎬⎥
⎣ ⎩ K⋅(φ - τ_c) τ₁ + τ₂ ⎭⎦
which looks like your textbook's solution.

Error when calling Rcpp function from Tableau. How to interpret and debug Rserve logs?

I'm having a lot of trouble connecting an R function I wrote to Tableau. The function relies on Rcpp.
In R, if I call prob_1_beats_2(1, 2, 3, 4) it works just fine. However, when I try to connect to Tableau using Rserve, I get this error:
Error in eval(expr, envir, enclos) : expecting a single value
which I cannot seem to trace down. I tried running Rserve in debug mode but to no avail. I'm unsure how to interpret these results. It would be nice to traceback exactly what is being called in R.
Gist of debug logs: https://gist.github.com/FrankPortman/f5cfe32596fd47080286
prob_1_beats_2 <- function(alpha_1, beta_1, alpha_2, beta_2, percent_lift = 0) {
if(alpha_1 / beta_1 < alpha_2 / beta_2) {
t1 <- alpha_2
t2 <- beta_2
alpha_2 <- alpha_1
beta_2 <- beta_1
alpha_1 <- t1
beta_1 <- t2
}
alt_count(alpha_1, beta_1, alpha_2, beta_2)
}
And here is the Rcpp function:
double alt_count(double alpha_1, double beta_1, double alpha_2, double beta_2) {
double total = 0;
for(int i = 0; i < alpha_1; i++) {
total += exp(i * log(beta_1) + alpha_2 * log(beta_2) - (i + alpha_2) * log(beta_1 + beta_2) - log(i + alpha_2) - lbeta(i + 1, alpha_2));
}
return total;
}
As you can see:
> prob_1_beats_2(1, 2, 3, 4)
[1] 0.7037037
Finally, the Tableau call I am using:
SCRIPT_REAL("library(mypackage);prob_1_beats_2(.arg1, .arg2, .arg3, .arg4)", 1.0, 2.0, 3.0, 4.0)
Note that
SCRIPT_REAL("library(mypackage);prob_1_beats_2(1, 2, 3, 4)", 1.0, 2.0, 3.0, 4.0)
does return 0.7037037. The real Tableau call I will be using will not use constant values of 1:4 but I am trying this for debugging purposes.
It seems that Tableau was always passing values into R as vectors. When typing:
SCRIPT_REAL("library(mypackage);prob_1_beats_2(.arg1, .arg2, .arg3, .arg4)", 1.0, 2.0, 3.0, 4.0)
R was actually getting c(1 , 1 , 1 , 1 , etc.), c(2 , 2 , 2 , 2 , 2 , etc.) and so on as arguments to the function. For some reason this was handled without the Rcpp component, but failed when I rewrote the function to include Rcpp.
This workaround seems to be fine for now:
prob_1_beats_2 <- function(alpha_1, beta_1, alpha_2, beta_2, percent_lift = 0, min_lift = FALSE) {
alpha_1 <- as.numeric(alpha_1[1])
beta_1 <- as.numeric(beta_1[1])
alpha_2 <- as.numeric(alpha_2[1])
beta_2 <- as.numeric(beta_2[1])
...
}