I am trying to use solve_bvp from scipy. To that effect I need to create the RHS function, which on paper I ahve as
(1+y^2) / 2(1-x)
I am not sure how to define the function that takes the vecotrs as inputs and rewrite it for my case.
I.e. I am trying to rewrite the function fun_measles in this tutorial into my function.
mu = 0.02
l = 0.0279
eta = 0.01
def fun_measles(x, y):
beta = 1575 * (1 + np.cos(2 * np.pi * x))
return np.vstack((
mu - beta * y[0] * y[2],
beta * y[0] * y[2] - y[1] / l,
y[1] / l - y[2] / eta
))
This line y[1] / l - y[2] / eta computes a scalar rather than a vector. Hence, when np.vstack is called, it fails to execute because dimensions of the input don't match.
You fix the formula (this line) and you will be able to vectorize the function.
In your case you can just implement it the same as the scalar case. You only need to take care when you use operations that are different between scalar and vector cases, such as branching based on the y value, where in the array case you need to use the numpy functions such as p.where.
One has to care about the shape of the return array. So it is either
return (1+y**2) / (2*(1-x))
or
return [ (1+y[0]**2) / (2*(1-x)) ]
(I'm not sure if explicit numpy-ification is really helpful, the solver will do that correctly anyway, so it is only the question of where the overhead happens.)
For some ungodly reason I'm trying to make a program to display wireframe graphics in pure python 3.6.3 with the turtle library. I've got to the point where I would like to skip drawing unnecessary tris for optimisation purposes. Unnecessary tris meaning tris that should be obscured by other parts of the model - ie, the normal facing away from the 3d camera.
The model data that the program is working with is just a huge 3d array with the following formatting for each tri.
[[Vert],[Vert],[Vert],[Normal]]
My current version of the code only has one model made for it (a cube) and looks like this:
from turtle import *
Cube = [[[-50,50,-50],[-50,50,50,],[50,50,50],[0,1,0]],
[[-50,50,-50],[50,50,50,],[50,50,-50],[0,1,0]],
[[-50,50,-50],[-50,50,50],[-50,-50,50],[1,0,0]],
[[-50,50,-50],[-50,-50,-50],[-50,-50,50],[1,0,0]],
[[-50,50,50],[50,50,50],[50,-50,50],[0,0,1]],
[[-50,50,50],[50,-50,50],[-50,50,50],[0,0,1]],
[[-50,-50,-50],[-50,-50,50,],[50,-50,50],[0,-1,0]],
[[-50,-50,-50],[50,-50,50,],[50,-50,-50],[0,-1,0]],
[[50,50,-50],[50,50,50],[50,-50,50],[-1,0,0]],
[[50,50,-50],[50,-50,-50],[50,-50,50],[-1,0,0]],
[[-50,50,-50],[50,50,-50],[50,-50,-50],[0,0,-1]],
[[-50,50,-50],[50,-50,-50],[-50,50,-50],[0,0,-1]]]
CamVector = [0,1,0]
def DrawModel(Model):
for i in range(0,len(Model)):
goto(Model[i][0][0],Model[i][0][1])
pd()
goto(Model[i][1][0],Model[i][1][1])
goto(Model[i][2][0],Model[i][2][1])
goto(Model[i][0][0],Model[i][0][1])
pu()
Model = Cube
DrawModel(Model)
But I would like to compare each tri's normal to the CamVector so the code ends up looking like this:
def DrawModel(Model):
for i in range(0,len(Model)):
AngleAwayFromCamera = *Math voodoo*
if AngleAwayFromCamera <= 90:
*draw tri*
If anyone has any idea on how to help that could be explained to someone with with a walnut-sized brain like myself that would be great. I've looked at a lot of documentation but most has flown right over my head - Probably because I failed GCSE maths.
Without going too much into the mathematical details, there's something called a dot product in mathematics:
Basically, it's a way of combining two vectors (call them a and b) to get a single number. This number is equal to the magnitude of a, multiplied by the magnitude of b, multiplied by the cosine of the angle between them (which we can call θ).
Thanks to this equation, by shifting things around, we can eventually get to what we want, which is θ.
Say we have a: [1, 2, 3] and b: [4, 5, 6]. We can calculate their magnitudes by squaring their elements and taking the square root of the sum. Therefore, the magnitude of a is (1 ** 2 + 2 ** 2 + 3 ** 2) ** 0.5 = 14 ** 0.5, and that of b is (4 ** 2 + 5 ** 2 + 6 ** 2) ** 0.5 = 77 ** 0.5.
Multiplying them together gives us 1078 ** 0.5. Therefore, the dot product is equal to (1078 ** 0.5) * cos θ.
It turns out that the dot product can be calculated by multiplying corresponding elements of two vectors together and summing the result. So, for a and b above, the dot product is 1 * 4 + 2 * 5 + 3 * 6 = 32.
Given these two different (but equal) expressions of the dot product, we can equate them to solve for θ, as follows (arccos is the function that turns cos θ into θ):
(1078 ** 0.5) * cos θ = 32
cos θ = 32 / (1078 ** 0.5)
θ = arccos(32 / (1078 ** 0.5))
θ ≈ 12.93 (in degrees)
Now, all that is left is to implement this in code:
from numpy import arccos
def angle_between_vectors(v1, v2):
def magnitude(v):
return sum(e ** 2 for e in v) ** 0.5
dot_product = sum(e1 * e2 for e1, e2 in zip(v1, v2))
magnitudes = magnitude(v1) * magnitude(v2)
angle = arccos(dot_product / magnitudes)
return angle
Applying this function to a and b above and converting from radians to degrees (divide by π and multiply by 180) gives us 12.93, as expected.
I'm lambdifying a sympy piecewise function trying to do something like this:
f = Piecewise((1,(p > -1e-10) & (p < 1e-10)), (1/p, True))
g = lambdify(p,f,"numpy")
While
>>> f.subs(p,0)
1
I get
>>> g(0)
/usr/lib/python2.7/dist-packages/numpy/__init__.py:1: RuntimeWarning: divide by zero encountered in true_divide
"""
array(1.0)
It seems, that (the lambdified ?)-Piecewise evaluates all expressions before returning the one with the true condition. Is there a way around this?
The NumPy code printer used by lambdify translates Piecewise to
numpy.select(conditions, expressions, default=numpy.nan)
This means that the array expressions is computed in its entirety before numpy.select selects one element of that array. Some ways to get around it are:
1) Change the backend to math (or mpmath, or anything other than numpy), which will cause Piecewise to be translated as a nested if statement.
g = lambdify(p, f, "math")
g(0) # 1, no warnings
2) Rewrite the formula in terms of Max/Min/Abs/sign, which can express some piecewise functions and lambdify easily. This isn't always possible but in your case,
f = 0.5 * (sign(p + 1e-10) + sign(p - 1e-10)) / Max(1e-10, Abs(p)) + 0.5 * (sign(p + 1e-10) - sign(p - 1e-10))
does the job. The trick is that 0.5 * (sign(p + 1e-10) + sign(p - 1e-10)) is sign(p) when p is not too close to 0, and is 0 when it is. Similarly, 0.5 * (sign(p + 1e-10) - sign(p - 1e-10)) is 1 if p is not too close to 0 and is 0 when it is. These factors cause the formula to switch from one mode to the other, and Max in the denominator avoids the division by zero error in any case.
3) Suppress Runtime Warnings
How do I simplify a*sin(wt) + b*cos(wt) into c*sin(wt+theta) using SymPy? For example:
f = sin(t) + 2*cos(t) = 2.236*sin(t + 1.107)
I tried the following:
from sympy import *
t = symbols('t')
f=sin(t)+2*cos(t)
trigsimp(f) #Returns sin(t)+2*cos(t)
simplify(f) #Returns sin(t)+2*cos(t)
f.rewrite(sin) #Returns sin(t)+2*sin(t+Pi/2)
PS.: I dont have direct access to a,b and w. Only to f
Any suggestion?
The general answer can be achieved by noting that you want to have
a * sin(t) + b * cos(t) = A * (cos(c)*sin(t) + sin(c)*cos(t))
This leads to a simultaneous equation a = A * cos(c) and b = A * sin(c).
Dividing the second equation by the second, we can solve for c. Substituting its solution into the first equation, you can solve for A.
I followed the same pattern but just to get it in terms of cos. If you want to get it in terms of sin, you can use Rodrigo's formula.
The following code should be able to take any linear combination of the form x * sin(t - w) or y * cos(t - z). There can be multiple sins and cos'.
from sympy import *
t = symbols('t', real=True)
expr = sin(t)+2*cos(t) # unknown
d = collect(expr.expand(trig=True), [sin(t), cos(t)], evaluate=False)
a = d[sin(t)]
b = d[cos(t)]
cos_phase = atan(a/b)
amplitude = a / sin(cos_phase)
print(amplitude.evalf() * cos(t - cos_phase.evalf()))
Which gives
2.23606797749979*cos(t - 0.463647609000806)
This seems to be a satisfactory match after plotting both graphs.
You could even have something like
expr = 2*sin(t - 3) + cos(t) - 3*cos(t - 2)
and it should work fine.
a * sin(wt) + b * cos(wt) = sqrt(a**2 + b**2) * sin(wt + acos(a / sqrt(a**2 + b**2)))
While the amplitude is the radical sqrt(a**2 + b**2), the phase is given by the arccosine of the ratio a / sqrt(a**2 + b**2), which may not be expressible in terms of arithmetic operations and radicals. Hence, you may be asking SymPy to do the impossible. Better use floating-point values, but you do not need SymPy for that.
I'm trying to symbolically solve a polynomial with complex numbers and their conjugates with SymPy. I think I've come a long way, but solve does not give me any solutions although the polynomial is solveable.
from sympy import *
# set up symbols
a, b = symbols("a b", real=True)
t = a+I*b
T = functions.conjugate(t)
# set up polynomial
a1=0.005+I*0.0009
a2=0.9+I*-0.9
a3=0.4+I*0.5
a4=8+I*-80
a5=284+I*-1.5
a6=27100+I*-11500
poly=t**2 * T * a1 + t * T * a2 + t**2 * a3 + T * a4 + t * a5 + a6
# Trying to solve symbolically...
solve([re(poly), im(poly)], a, b)
# Output: []
# Solving numerically works, but only finds one solution...
nsolve((re(poly), im(poly)), (a, b), (0, 0))
# Output: matrix(
# [['-137.962596090596'],
# ['52.6296963395752']])
# verify with two solutions obtained in Maxima
poly.subs({a:-137.9625935162095, b:52.6296992481203}).n()
# Output: 0.000540354631040322 + 0.00054727003909351*I
poly.subs({a:-332.6474382554614+I*-185.9848818313149, b:258.0065640091016+I*-272.3344263478699}).n()
# Output: -6.55448222470652e-12 - 1.41238056784605e-12*I
Any ideas?
One problem could be that your coefficients contain floating point numbers. This often does not work with symbolic software.
Using f=10000*simplify(re(poly)) and g=10000*simplify(im(poly)) and editing the results gives polynomials with integer coefficients. The CAS (Magma in my case) then can produce a triangular representation of the ideal of f and g, which is given as the polynomials
a - 2483798807340123709959247/13545514719183259347425004828125*b^4
+ 66732206412048596386372283/541820588767330373897000193125*b^3
- 3849759933277117021785191063/86691294202772859823520030900*b^2
+ 9245906471290310401430681453/1733825884055457196470400618*b
- 31414499425567273751868164900/866912942027728598235200309,
b^5 - 189465979625/206648369*b^4
+ 330827538698125/826593476*b^3
- 17645868534640625/206648369*b^2
+ 1724106750659765625/206648369*b
- 52548859891484375000/206648369
which tells us that 5 solutions exist. The numerical solutions for the second polynomial are
174.10461010682254746847015187264557067610513554291323564643772
+ 63.402741884833821878468926640811609033267039765104756747285816*i
174.104610106822547468470151872645570676105135542913235646437738
- 63.402741884833821878468926640811609033267039765104756747285804*i
258.006564009101655109715962546854008929462784282347754971379392
+ 272.334426347869856080204881056671278679761260094680345276069337*i
258.006564009101655109715962546854008929462784282347754971379382
- 272.334426347869856080204881056671278679761260094680345276069359*i
52.62969633957523864698147679803879873180829265956656342643376
resulting in exactly one real solution. The numerical result of sympy was correct and complete.