Solve expression with iterative method in Python - python

I'm new with Python, and started to work on a Coordinate Conversion program. The problem is that I can't find an iterative method to solve one of the expressions.
Expressions:
N = a / math.sqrt(1 - (e2 * (math.sin(phi))**2))
phi = math.atan((Z / math.sqrt((X**2) + (Y**2))) * ((1-e2) * (N / N + hei)**-1))
lam = math.atan(Y / X)
hei = (math.sqrt((X ** 2) + (Y ** 2))) / math.cos(phi)
Here, a and e2 are constants.
The user is supposed to introduce the values of X, Y and Z and obtain phi, lam and hei. But, given that N is a function that depends of phi, it is necessary to create a loop, making hei = 0 in the second equation as an initial value, in order to procure a first approximation for phi. However, I don't know how to end that cycle when phi has reached a certain value (for instance, when 9 or more of the decimals of phi are equal to the previous value in the loop).

You could break the loop based on the difference between the value of phi in the previous loop and that in the current loop, i.e. if the difference is smaller than 10^(-9).

Related

Python - Find x and y values of a 2D gaussian given a value for the function

I have a 2D gaussian function f(x,y). I know the values x₀ and y₀ at which the peak g₀ of the function occurs. But then I want to find xₑ and yₑ values at which f(xₑ, yₑ) = g₀ / e¹. I know there are multiple solutions to this, but at least one is sufficient.
So far I have
def f(x, y, g0,x0,y0,sigma_x,sigma_y,offset):
return offset + g0* np.exp(-(((x-x0)**(2)/(2*sigma_x**(2))) + ((y-y0)**(2)/(2*sigma_y**(2)))))
All variables taken as parameters are known as they were extracted from a curve fit.
I understand that taking the derivative in x and setting f() = 0 and similarly in y, gives a solvable linear system for (x,y), but this seems like overkill to manually implement, there must be some library or tool out there that can do what I am trying to achieve?
There are an infinite number of possibilities (or possibly 1 trivial or none in special cases regarding the value of g0). A solution can be computed analytically in constant time using a direct method. No need for approximations or iterative methods to find roots of a given function. It is just pure maths.
Gaussian kernel have interesting symmetries. One of them is the invariance to the rotation when the peak is translated to (0,0). Another on is that the 1D section of a 2D gaussian surface is a gaussian curve.
Lets ignore offset for a moment: it does not really change the problem (it is just a Z-axis translation) and add additional useless term for the resolution.
The geometric solution to is problem is an ellipse so the solution (xe, ye) follows the conic expression : (xe-x0)² / a² + (ye-y0)² / b² = 1. If sigma_x = sigma_y, then the solution is simpler : this is a circle with the expression (xe-x0)² + (ye-y0)² = r. Note that a, b and r are dependant of the searched value and the kernel parameters (eg. sigma_x). Changing sigma_x and sigma_y is like stretching the space, and so the solution similarly. Changing x0 and y0 is like translating the space and so the solution too.
In fact, we could solve the problem for the simpler case where x0=0, y0=0, sigma_x=1 and sigma_y=1. Then we can apply a translation, followed by a linear transformation using a transformation matrix. A basic multiplication 4x4 matrix can do that. Solving the simpler case is much easier since there are are less parameter to consider. Actually, g0 and offset can also be partially discarded of f since it is on both side of the expression and one just need to solve the linear equation offset + g0 * h(xe,ye) = g0 / e so h(x,y) = 1 / e - offset / g0 where h(xe, ye) = exp(-(xe² + ye²)/2). Assuming we forget the translation and linear transformation for a moment, the problem can be solve quite easily:
h(xe, ye) = 1 / e - offset / g0
exp(-(xe² + ye²)/2) = 1 / e - offset / g0
-(xe² + ye²)/2 = ln(1 / e - offset / g0)
xe² + ye² = -2 * ln(1 / e - offset / g0)
That's it! We got our circle expression where the radius r is -2*ln(1 / e - offset / g0)! Note that ln in the expression is basically the natural logarithm.
Now we could try to find the 4x4 matrix coefficients, or actually try to directly solve the full expression which is finally not so difficult.
offset + g0 * exp(-((x-x0)²/(2*sigma_x²) + (y-y0)²/(2*sigma_y²))) = g0 / e
exp(-((x-x0)²/(2*sigma_x²) + (y-y0)²/(2*sigma_y²))) = 1 / e - offset / g0
-((x-x0)²/(2*sigma_x²) + (y-y0)²/(2*sigma_y²)) = ln(1 / e - offset / g0)
((x-x0)²/sigma_x² + (y-y0)²/sigma_y²)/2 = -ln(1 / e - offset / g0)
(x-x0)²/sigma_x² + (y-y0)²/sigma_y² = -2 * ln(1 / e - offset / g0)
That's it! We got you conic expression where r = -2 * ln(1 / e - offset / g0) is a constant, a = sigma_x and b = sigma_y are the unknown parameter in the above expression. It can be normalized using a = sigma_x/sqrt(r) and b = sigma_y/sqrt(r) so the right hand side is 1 fitting exactly with the above expression but this is just some math details.
You can find one point of the ellipse easily since you know the centre of the ellipse (x0, y0) and there is at least 1 point at the intersection of the line y=y0 and the above conic expression. Lets find it:
(x-x0)²/sigma_x² + (y0-y0)²/sigma_y² = -2 * ln(1 / e - offset / g0)
(x-x0)²/sigma_x² = -2 * ln(1 / e - offset / g0)
(x-x0)² = -2 * ln(1 / e - offset / g0) * sigma_x²
x = sqrt(-2 * ln(1 / e - offset / g0) * sigma_x²) + x0
Note there are two solutions (-sqrt(...) + x0) but you only need one of them. I hope I did not make any mistake in the computation (at least the details should be enough to find it easily) and the solution is not a complex number in your case. The benefit of this solution is that it is very very fast to compute.
The final solution is:
(xe, ye) = (sqrt(-2*ln(1/e-offset/g0)*sigma_x²)+x0, y0)

How to fit a piecewise (alternating linear and constant segments) function to a parabolic function?

I do have a function, for example , but this can be something else as well, like a quadratic or logarithmic function. I am only interested in the domain of . The parameters of the function (a and k in this case) are known as well.
My goal is to fit a continuous piece-wise function to this, which contains alternating segments of linear functions (i.e. sloped straight segments, each with intercept of 0) and constants (i.e. horizontal segments joining the sloped segments together). The first and last segments are both sloped. And the number of segments should be pre-selected between around 9-29 (that is 5-15 linear steps + 4-14 constant plateaus).
Formally
The input function:
The fitted piecewise function:
I am looking for the optimal resulting parameters (c,r,b) (in terms of least squares) if the segment numbers (n) are specified beforehand.
The resulting constants (c) and the breakpoints (r) should be whole natural numbers, and the slopes (b) round two decimal point values.
I have tried to do the fitting numerically using the pwlf package using a segmented constant models, and further processed the resulting constant model with some graphical intuition to "slice" the constant steps with the slopes. It works to some extent, but I am sure this is suboptimal from both fitting perspective and computational efficiency. It takes multiple minutes to generate a fitting with 8 slopes on the range of 1-50000. I am sure there must be a better way to do this.
My idea would be to instead using only numerical methods/ML, the fact that we have the algebraic form of the input function could be exploited in some way to at least to use algebraic transforms (integrals) to get to a simpler optimization problem.
import numpy as np
import matplotlib.pyplot as plt
import pwlf
# The input function
def input_func(x,k,a):
return np.power(x,1/a)*k
x = np.arange(1,5e4)
y = input_func(x, 1.8, 1.3)
plt.plot(x,y);
def pw_fit(func, x_r, no_seg, *fparams):
# working on the specified range
x = np.arange(1,x_r)
y_input = func(x, *fparams)
my_pwlf = pwlf.PiecewiseLinFit(x, y_input, degree=0)
res = my_pwlf.fit(no_seg)
yHat = my_pwlf.predict(x)
# Function values at the breakpoints
y_isec = func(res, *fparams)
# Slope values at the breakpoints
slopes = np.round(y_isec / res, decimals=2)
slopes = slopes[1:]
# For the first slope value, I use the intersection of the first constant plateau and the input function
slopes = np.insert(slopes,0,np.round(y_input[np.argwhere(np.diff(np.sign(y_input - yHat))).flatten()[0]] / np.argwhere(np.diff(np.sign(y_input - yHat))).flatten()[0], decimals=2))
plateaus = np.unique(np.round(yHat))
# If due to rounding slope values (to two decimals), there is no change in a subsequent step, I just remove those segments
to_del = np.argwhere(np.diff(slopes) == 0).flatten()
slopes = np.delete(slopes,to_del + 1)
plateaus = np.delete(plateaus,to_del)
breakpoints = [np.ceil(plateaus[0]/slopes[0])]
for idx, j in enumerate(slopes[1:-1]):
breakpoints.append(np.floor(plateaus[idx]/j))
breakpoints.append(np.ceil(plateaus[idx+1]/j))
breakpoints.append(np.floor(plateaus[-1]/slopes[-1]))
return slopes, plateaus, breakpoints
slo, plat, breaks = pw_fit(input_func, 50000, 8, 1.8, 1.3)
# The piecewise function itself
def pw_calc(x, slopes, plateaus, breaks):
x = x.astype('float')
cond_list = [x < breaks[0]]
for idx, j in enumerate(breaks[:-1]):
cond_list.append((j <= x) & (x < breaks[idx+1]))
cond_list.append(breaks[-1] <= x)
func_list = [lambda x: x * slopes[0]]
for idx, j in enumerate(slopes[1:]):
func_list.append(plateaus[idx])
func_list.append(lambda x, j=j: x * j)
return np.piecewise(x, cond_list, func_list)
y_output = pw_calc(x, slo, plat, breaks)
plt.plot(x,y,y_output);
(Not important, but I think the fitted piecewise function is not continuous as it is. Intervals should be x<=r1; r1<x<=r2; ....)
As Anatolyg has pointed out, it looks to me that in the optimal solution (for the function posted at least, and probably for any where the derivative is different from zero), the horizantal segments will collapse to a point or the minimum segment length (in this case 1).
EDIT---------------------------------------------
The behavior above could only be valid if the slopes could have an intercept. If the intercepts are zero, as posted in the question, one consideration must be taken into account: Is the initial parabolic function defined in zero or nearby? Imagine the function y=0.001 *sqrt(x-1000), then the segments defined as b*x will have a slope close to zero and will be so similar to the constant segments that the best fit will be just the line that without intercept that fits better all the function.
Provided that the function is defined in zero or nearby, you can start by approximating the curve just by linear segments (with intercepts):
divide the function domain in N intervals(equal intervals or whose size is a function of the average curvature (or second derivative) of the function along the domain).
linear fit/regression in each intervals
for each interval, if a point (or bunch of points) in the extreme of any interval is better fitted by the line of the neighbor interval than the line of its interval, this point is assigned to the neighbor interval.
Repeat from 2) until no extreme points are moved.
Linear regressions might be optimized not to calculate all the covariance matrixes from scratch on each iteration, but just adding the contributions of the moved points to the previous covariance matrixes.
Then each linear segment (LSi) is replaced by a combination of a small constant segment at the beginning (Cbi), a linear segment without intercept (Si), and another constant segment at the end (Cei). This segments are easy to calculate as Si will contain the middle point of LSi, and Cbi and Cei will have respectively the begin and end values of the segment LSi. Then the intervals of each segment has to be calculated as an intersection between lines.
With this, the constant end segment will be collinear with the constant begin segment from the next interval so they will merge, resulting in a series of constant and linear segments interleaved.
But this would be a floating point start solution. Next, you will have to apply all the roundings which will mess up quite a lot all the segments as the conditions integer intervals and linear segments without slope can be very confronting. In fact, b,c,r are not totally independent. If ci and ri+1 are known, then bi+1 is already fixed
If nothing is broken so far, the final task will be to minimize the error/cost function (I assume that it will be the integral of the error between the parabolic function and the segments). My guess is that gradients here will be quite a pain, as if you change for example one ci, all the rest of the bj and cj will have to adapt as well due to the integer intervals restriction. However, if you can generalize the derivatives between parameters ( how much do I have to adapt bi+1 if ci changes a unit), you can propagate the change of one parameter to all other parameters and have kind of a gradient. Then for each interval, you can estimate what would be the ideal parameter and averaging all intervals calculate the best gradient step. Let me illustrate this:
Assuming first that r parameters are fixed, if I change c1 by one unit, b2 changes by 0.1, c2 changes by -0.2 and b3 changes by 0.2. This would be the gradient.
Then I estimate, comparing with the parabolic curve, that c1 should increase 0.5 (to reduce the cost by 10 points), b2 should increase 0.2 (to reduce the cost by 5 points), c2 should increase 0.2 (to reduce the cost by 6 points) and b3 should increase 0.1 (to reduce the cost by 9 points).
Finally, the gradient step would be (0.5/1·10 + 0.2/0.1·5 - 0.2/(-0.2)·6 + 0.1/0.2·9)/(10 + 5 + 6 + 9)~= 0.45. Thus, c1 would increase 0.45 units, b2 would increase 0.45·0.1, and so on.
When you add the r parameters to the pot, as integer intervals do not have an proper derivative, calculation is not straightforward. However, you can consider r parameters as floating points, calculate and apply the gradient step and then apply the roundings.
We can integrate the squared error function for linear and constant pieces and let SciPy optimize it. Python 3:
import matplotlib.pyplot as plt
import numpy as np
import scipy.optimize
xl = 1
xh = 50000
a = 1.3
p = 1 / a
n = 8
def split_b_and_c(bc):
return bc[::2], bc[1::2]
def solve_for_r(b, c):
r = np.empty(2 * n)
r[0] = xl
r[1:-1:2] = c / b[:-1]
r[2::2] = c / b[1:]
r[-1] = xh
return r
def linear_residual_integral(b, x):
return (
(x ** (2 * p + 1)) / (2 * p + 1)
- 2 * b * x ** (p + 2) / (p + 2)
+ b ** 2 * x ** 3 / 3
)
def constant_residual_integral(c, x):
return x ** (2 * p + 1) / (2 * p + 1) - 2 * c * x ** (p + 1) / (p + 1) + c ** 2 * x
def squared_error(bc):
b, c = split_b_and_c(bc)
r = solve_for_r(b, c)
linear = np.sum(
linear_residual_integral(b, r[1::2]) - linear_residual_integral(b, r[::2])
)
constant = np.sum(
constant_residual_integral(c, r[2::2])
- constant_residual_integral(c, r[1:-1:2])
)
return linear + constant
def evaluate(x, b, c, r):
i = 0
while x > r[i + 1]:
i += 1
return b[i // 2] * x if i % 2 == 0 else c[i // 2]
def main():
bc0 = (xl + (xh - xl) * np.arange(1, 4 * n - 2, 2) / (4 * n - 2)) ** (
p - 1 + np.arange(2 * n - 1) % 2
)
bc = scipy.optimize.minimize(
squared_error, bc0, bounds=[(1e-06, None) for i in range(2 * n - 1)]
).x
b, c = split_b_and_c(bc)
r = solve_for_r(b, c)
X = np.linspace(xl, xh, 1000)
Y = [evaluate(x, b, c, r) for x in X]
plt.plot(X, X ** p)
plt.plot(X, Y)
plt.show()
if __name__ == "__main__":
main()
I have tried to come up with a new solution myself, based on the idea of #Amo Robb, where I have partitioned the domain, and curve fitted a dual - constant and linear - piece together (with the help of np.maximum). I have used the 1 / f(x)' as the function to designate the breakpoints, but I know this is arbitrary and does not provide a global optimum. Maybe there is some optimal function for these breakpoints. But this solution is OK for me, as it might be appropriate to have a better fit at the first segments, at the expense of the error for the later segments. (The task itself is actually a cost based retail margin calculation {supply price -> added margin}, as the retail POS software can only work with such piecewise margin function).
The answer from #David Eisenstat is correct optimal solution if the parameters are allowed to be floats. Unfortunately the POS software can not use floats. It is OK to round up c-s and r-s afterwards. But the b-s should be rounded to two decimals, as those are inputted as percents, and this constraint would ruin the optimal solution with long floats. I will try to further improve my solution with both Amo's and David's valuable input. Thank You for that!
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# The input function f(x)
def input_func(x,k,a):
return np.power(x,1/a) * k
# 1 / f(x)'
def one_per_der(x,k,a):
return a / (k * np.power(x, 1/a-1))
# 1 / f(x)' inverted
def one_per_der_inv(x,k,a):
return np.power(a / (x*k), a / (1-a))
def segment_fit(start,end,y,first_val):
b, _ = curve_fit(lambda x,b: np.maximum(first_val, b*x), np.arange(start,end), y[start-1:end-1])
b = float(np.round(b, decimals=2))
bp = np.round(first_val / b)
last_val = np.round(b * end)
return b, bp, last_val
def pw_fit(end_range, no_seg, **fparams):
y_bps = np.linspace(one_per_der(1, **fparams), one_per_der(end_range,**fparams) , no_seg+1)[1:]
x_bps = np.round(one_per_der_inv(y_bps, **fparams))
y = input_func(x, **fparams)
slopes = [np.round(float(curve_fit(lambda x,b: x * b, np.arange(1,x_bps[0]), y[:int(x_bps[0])-1])[0]), decimals = 2)]
plats = [np.round(x_bps[0] * slopes[0])]
bps = []
for i, xbp in enumerate(x_bps[1:]):
b, bp, last_val = segment_fit(int(x_bps[i]+1), int(xbp), y, plats[i])
slopes.append(b); bps.append(bp); plats.append(last_val)
breaks = sorted(list(x_bps) + bps)[:-1]
# If due to rounding slope values (to two decimals), there is no change in a subsequent step, I just remove those segments
to_del = np.argwhere(np.diff(slopes) == 0).flatten()
breaks_to_del = np.concatenate((to_del * 2, to_del * 2 + 1))
slopes = np.delete(slopes,to_del + 1)
plats = np.delete(plats[:-1],to_del)
breaks = np.delete(breaks,breaks_to_del)
return slopes, plats, breaks
def pw_calc(x, slopes, plateaus, breaks):
x = x.astype('float')
cond_list = [x < breaks[0]]
for idx, j in enumerate(breaks[:-1]):
cond_list.append((j <= x) & (x < breaks[idx+1]))
cond_list.append(breaks[-1] <= x)
func_list = [lambda x: x * slopes[0]]
for idx, j in enumerate(slopes[1:]):
func_list.append(plateaus[idx])
func_list.append(lambda x, j=j: x * j)
return np.piecewise(x, cond_list, func_list)
fparams = {'k':1.8, 'a':1.2}
end_range = 5e4
no_steps = 10
x = np.arange(1, end_range)
y = input_func(x, **fparams)
slopes, plats, breaks = pw_fit(end_range, no_steps, **fparams)
y_output = pw_calc(x, slopes, plats, breaks)
plt.plot(x,y_output,y);

Using fsolve to solve a set of equations where one is a sigma function that changes every iteration

I am new to python and I am working on a finance project to solve a set of equations that enables me to go from par spread to flat spread in terms of CDS.
I have a set of data for the upfront (U) and years (i), where to set the data sample, I name upfront with x and years in y
x = [-0.007,-0.01,-0.009,-0.004,0.005,0.011,0.018,0.027,0.037,0.048]
y = [1,2,3,4,5,6,7,8,9,10]
Here are the 3 equations that I am trying to solve together:
U = A(s(i)-c)
L(i) = 1 - (1 - (s(i) / (1 - R)) ** i) / (1 - (1 / (s(i-1) - R)) ** (i - 1))
A = sum([((1 - L(i)) / (1 + r)) ** j for j in range(1, i+1)])
Detailed explanation:
The goal is to solve and list the results for all 10 values of variable s
1st equation is used to calculate the upfront amount, where s is unknown
2nd equation is used to calculate the hazard rate L, where R is recovery rate, s(i) is the current s term and s(i-1) is the previous s term.
Visual representation of equation 2:
3rd equation is used to calculate the annual risky annuity, the purpose of this equation is to calculate and sum the risk annuities. For example, if i=1, then there should be one term in the equation. If i=2, then there should be 2 terms in the equation where they are summed. This repeats until the 10th iteration where there are 10 values and they are summed.
Visual representation of equation 3:
To attempt to solve the problem, I wrote the following code (which doesn't run yet):
x = [-0.007,-0.01,-0.009,-0.004,0.005,0.011,0.018,0.027,0.037,0.048]
y = [1,2,3,4,5,6,7,8,9,10]
c = 0.01
r = 0.01
R = 0.4
def eqs(s, U, t, c=0.01, r=0.01, R=0.4):
L = 1 - (1 - (s / (1 - R)) ** t) / (1 - (1 / (1 - R)) ** (t - 1))
A = sum([((1 - L) / (1 + r)) ** j for j in range(1, i+1)])
s = (U/A) + c
return L, A, s
for U, t in zip(x, y):
s = fsolve(eq1, 0.01, (U, t,))
print(s, U, t)
Main obstacles:
I haven't found a way where I can make Equation 3 work.
I also haven't been able to pass through 2 sets of values into the for loop that then calls the function
I wasn't able to loop the previous spread value, s(i-1), back into the iteration to compute the next value
I was able to solve it manually on python by changing the third equation every iteration and inputting the previous results
I am hoping I can find some solution to my problem, thank you for your help in advance!
It took me a bit but I think I got it. Your main problem is that you can't code formulas which describe a complex problem, then call a 'magic' fsolve function and hoping that python will solve it for you, without even defining what is the unknown.
It doesn't work that way. You have to make your problem simple enough so that it can be solved with existing functions from some libraries. Python has no form of intelligence nor divination.
As I said in my comments, the fsolve() from scipy.optimise can only solve problems of the form f(x)=0.
If you want to use it, you have to transform your complex problem in a simple f(x)=0. problem.
Starting from your 3rd equation s = (U/A) + c we can deduce that s - (U/A) - c = 0
Given that A is a function of L and L is a function of s, if you define a function f(s)= s - (U/A) - c then s is the solution of f(s)=0.
It is what I did in the following code :
from scipy.optimize import fsolve
def Lambda(s,sold,R,t):
num = (1 - s / (1 - R)) ** t
den = (1 - sold / (1 - R)) ** (t - 1)
return 1-num/den
def Annuity(L,r,Aold,j):
return Aold + ((1 - L) / (1 + r)) ** j
def f(s,U, sold,R,t,r,Aold,j):
L=Lambda(s,sold,R,t)
A=Annuity(L,r,Aold,j)
return s - (U/A) - c
x = [-0.007,-0.01,-0.009,-0.004,0.005,0.011,0.018,0.027,0.037,0.048]
y = [1,2,3,4,5,6,7,8,9,10]
c = 0.01
r = 0.01
R = 0.4
sold=0.
Aold=0.
for n,(U, t) in enumerate(zip(x, y)):
j=n+1
print("j={},U={},t={}".format(j,U,t))
init = 0.01 # The starting estimate for the roots of f(s) = 0.
roots = fsolve(f,init,args=(U, sold,R,t,r,Aold,j))
s=roots[0]
L=Lambda(s,sold,R,t)
A=Annuity(L,r,Aold,j)
print("s={},L={},A={}".format(s,L,A))
print
sold=s
Aold=A
It gives following outputs :
j=1,U=-0.007,t=1
s=0.00289571337037,L=0.00482618895061,A=0.985320604999
j=2,U=-0.01,t=2
s=0.00485464221105,L=0.0113452406083,A=1.94349944361
j=3,U=-0.009,t=3
s=0.00685582655826,L=0.0180633847507,A=2.86243751076
j=4,U=-0.004,t=4
s=0.00892769166807,L=0.0251666093582,A=3.73027037175
j=5,U=0.005,t=5
s=0.0111024600844,L=0.0328696834011,A=4.53531159145
j=6,U=0.011,t=6
s=0.0120640333844,L=0.0280806661972,A=5.32937116379
j=7,U=0.018,t=7
s=0.0129604367831,L=0.0305170484121,A=6.08018387787
j=8,U=0.027,t=8
s=0.0139861021632,L=0.0351929301367,A=6.77353436882
j=9,U=0.037,t=9
s=0.0149883645118,L=0.0382416644539,A=7.41726068981
j=10,U=0.048,t=10
s=0.0159931206639,L=0.041597709395,A=8.00918297693
No idea if it's correct, but it looks likely to me. I guess you got the idea now and you will be able to make some adjustments.

Solving a System of Ode's using scipy.integrate.ode

I am trying to solve a system of Odes of the form Du/Dt = F(u) in python, and I suspect I may have made a fairly dumb mistake somewhere.
Technically F(u) is actually the second derivative of u with respect to another variable y, but in practice we can consider it to be a system and some function.
#Settings#
minx = -20
h = float(1)
w = float(10)
U0 = float(10)
Nt = 10
Ny = 10
tmax = 10
v=float(1)
#Arrays#
y = np.linspace(0,h,Ny)
t = np.linspace(0,tmax,Nt)
#Variables from arrays#
dt = t[1]-t[0]
p = [0]*(Nt)
delta = y[1] - y[0]
def zo(y):
return math.cos(y/(2*math.pi))
z0 = [zo(i) for i in y]
def df(t,v1):
output = np.zeros(len(y))
it = 1
output[0] = math.cos(w*t)
output[len(y)-1] = math.cos(w*t)
while it < len(y)-1:
output[it] = ( v1[it - 1] + v1[it + 1] - 2 * v1[it] ) * ( v / ( ( delta )**2 ))
it += 1
return output
r = ode(df).set_integrator('zvode', method='bdf',order =15)
r.set_initial_value(z0, 0)
it=0
while r.successful() and r.t < tmax:
p[it] = r.integrate(r.t+dt)
it+=1
print(z0-p[0])
print(p[1])
Now the problem is twofold :
-First of all, the initial "condition" ie p[0] seems to be off.
(That may be just because of the way the ode function works though, so I don't know if that is normal)
-Second, p[1] and all p's after that are just 0.
So for some reason the ode function fails immediately... (you can check that by changing the values to 1 when initializing p)
Except that I know that this method should work.
This is the "equivalent" to ode45 in matlab after all and that definitely works.
Why did you choose a complex solver with an implicit backward differentiation formula of a rather high order if you wanted to use Dormand-Price rk45 resp. dopri5?
Please also correct the loop indentation in df. Why not a for loop over range(1, len(y)-1)?
As it currently stands p[0] contains the solution point after the first step, at t=1*dt. You would have to explicitly assign p[0]=z0 and start it=1 to get the full solution path in p. Check the length of p, it could be that you need Nt+1.

How to approximate a value from a formula

So I have one vector of alpha, one vector of beta, and I am trying to find a theta for when the sum of all the estimates (for alpha's 1 to N and beta's 1 to N) equals 60:
def CalcTheta(grensscore, alpha, beta):
theta = 0.0001
estimate = [grensscore-1]
while(sum(estimate) < grensscore):
theta += 0.00001
for x in range(len(beta)):
if x == 0:
estimate = []
estimate.append(math.exp(alpha[x] * (theta - beta[x])) /
(1 + math.exp(alpha[x] * (theta - beta[x]))))
return(theta)
Basically what I did is start from theta = 0.0001, and iterate through, calculating all these sums, and when it is lower than 60, continue by adding 0.0001 each time, while above 60 means we found the theta.
I found the value theta this way. Problem is, it took me about 60 seconds using Python, to find a theta of 0.456.
What is quicker approach to find this theta (since I would like to apply this for other data)?
If you know a lower and an upper bound for θ, and the function is monotonic in the range between these, then you could employ a bisection algorithm to easily and quickly find the desired value.

Categories