I'm trying to minimise a function using BFGS method. Initially, I'm creating my functions as expressions. In the first iteration, my first expression is
f_sym = ((x0 - x6)**2 + (y0 - y6)**2)**0.5 + ((x0 - x9)**2 + (y0 - y9)**2)**0.5 + ((-x1 + 36)**2 + (-y1 + 9)**2)**0.5 + ((x1 - x7)**2 + (y1 - y7)**2)**0.5 + ((-x10 + x3)**2 + (-y10 + y3)**2)**0.5 + ((-x10 + x7)**2 + (-y10 + y7)**2)**0.5 + ((-x12 + x3)**2 + (-y12 + y3)**2)**0.5 + ((-x12 + x6)**2 + (-y12 + y6)**2)**0.5 + ((-x9 + 48)**2 + (-y9 + 97)**2)**0.5
variables = [x1, y1, x9, y9, x0, y0, x6, y6, x7, y7, x3, y3, x10, y10, x12, y12] #variables of the function expression f_sym
fprime_sym = [f_sym.diff(x_) for x_ in variables] # derivative of f_sym
To create vectorised functions for the above symbolic expressions, I use sympy.lamdify as follows:
f_lmbda = sympy.lambdify(symvar, f_sym, 'numpy')
fprime_lmbda = sympy.lambdify(symvar, fprime_sym, 'numpy')
The functions produced by sympy.lambdify take one argument for each variable in the corresponding expression. Also the SciPy optimization functions expect a vectorized function where all coordinates are packed into one array. To obtain functions that are compatible with the SciPy optimization routines, we need to wrap each of the functions generated by sympy.lambdify with a Python function that reshuffles the arguments.I tried it as follows:
def func_XY_to_X_Y(f):
""" Wrapper for f(X) -> f(X[0], X[1])"""
return lambda X: np.array(f(X[0],X[1],X[2],X[3],X[4],X[5],X[6],X[7],X[8],X[9],X[10],X[11],X[12],X[13],X[14])) #since f_sym has 14 parameters we need 14 X[i]s
f = func_XY_to_X_Y(f_lmbda)
fprime = func_XY_to_X_Y(fprime_lmbda)
Now the functions f and fprime are vectorized Python functions. Then,
x_opt = optimize.fmin_ncg(f, x_0, fprime=fprime, fhess=fhess) #x_0 is the initial condition for all the variables
This solves the function and returns the new array of values for variables.
If there's only one function expression, this process can be done manually.
But if this happens inside a loop, the number of variables in each function expression will be different. Hence I need to make my def func_XY_to_X_Y(f): a dynamic one.
Can someone please help me to make this a dynamic one?
Use the *-argument unpacking operator:
def func_XY_to_X_Y(f):
""" Wrapper for f(X) -> f(X[0], X[1], ..., X[n])"""
return lambda X: np.array(f(*X))
Related
I got a equation in the following form
f(t) = 2*cos(t) + 3*sin(t)
and I want to reduce it to something like
f(t) = (9 + 4)^(1/2) * cos(t - atan(3/2))
None of the trigonometric simplify functions seems to work. Is there a way to do so?
I came across a problem. One string is taken as input say
input_string = "12345 + x = x * 5 + (1+x)* x + (1+18/100)"
And get output of x using python. I am not able to figure out logic for this.
Here is a complete SymPy example for your input:
from sympy import Symbol, solve, Eq
from sympy.parsing.sympy_parser import parse_expr
input_string = "12345 + x = x * 5 + (1+x)* x + (1+18/100)"
x = Symbol('x', real=True)
lhs = parse_expr(input_string.split('=')[0], local_dict={'x':x})
rhs = parse_expr(input_string.split('=')[1], local_dict={'x':x})
print(lhs, "=", rhs)
sol = solve(Eq(lhs, rhs), x)
print(sol)
print([s.evalf() for s in sol])
This outputs:
x + 12345 = x*(x + 1) + 5*x + 59/50
[-5/2 + 9*sqrt(15247)/10, -9*sqrt(15247)/10 - 5/2]
[108.630868798908, -113.630868798908]
Note that solve() gives a list of solutions. And that SymPy normally does not evaluate fractions and square roots, as it prefers solutions without loss of precision. evalf() evaluates a float value for these expressions.
Well, that example shows a quadratic equation which may have no solutions, one solution, or two solutions. You would have to rearrange the terms symbolically to come to
input_string = "x**2 + 5*x - 12345 + (118/100)"
But that means you need to implement rules for multiplication, addition, subtraction and potentially division. At least for Python there is a library called SymPy which can parse such strings and provide an expression that you can evaluate and even solve.
Im trying to call a function from a different file in python. Im trying to process satellite images from Goes 16 in NetCDF format. Im extracting different values from the file necessary for the functions saved in a .py file called "remap". A piece of my main code goes like this:
from remap import remap
# Calculate the image extent required for the reprojection
H = nc.variables['goes_imager_projection'].perspective_point_height
x1 = nc.variables['x_image_bounds'][0] * H
x2 = nc.variables['x_image_bounds'][1] * H
y1 = nc.variables['y_image_bounds'][1] * H
y2 = nc.variables['y_image_bounds'][0] * H
# Projection Prameters
lat_0 = nc.variables['goes_imager_projection'].latitude_of_projection_origin
lon_0 = nc.variables['goes_imager_projection'].longitude_of_projection_origin
a = nc.variables['goes_imager_projection'].semi_major_axis
b = nc.variables['goes_imager_projection'].semi_minor_axis
f = 1/nc.variables['goes_imager_projection'].inverse_flattening
# Call the reprojection funcion
grid = remap(path, extent, resolution, x1, y1, x2, y2)
In the .py file that I called "remap", the function is defined as:
# Define KM_PER_DEGREE
KM_PER_DEGREE = 111.32
# GOES-16 Spatial Reference System
sourcePrj = osr.SpatialReference()
sourcePrj.ImportFromProj4('+proj=geos +h=' + H + ' +a=' + a + ' +b=' + b + ' +f=' + f + 'lat_0=' + lat_0 + ' +lon_0=' + lon_0 + ' +sweep=x +no_defs')
# Lat/lon WSG84 Spatial Reference System
targetPrj = osr.SpatialReference()
targetPrj.ImportFromProj4('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
def remap(path, extent, resolution, x1, y1, x2, y2):
... (and so on)
Now I have two different problems:
(1) My frist problem is that Im getting an error from the system saying:
"remap() takes 4 positional arguments but 7 were given", which I dont understand why is happening, because I already defined those 7 arguments in the function from the second file called "remap"
(2) My second problem is that I don't know how to call values from my original code that where extracted from the NetCDF file such as: "lat_0, lon_0, a, b, f, and H" to be used in the second file which are necessary from the beginning to used the function "remap".
Any suggestions?
to your first problem:
How do you define the path, extent and resolution needed in remap()?
and to your second problem:
You don't need to call those arguments on the remap file, because from the main code your are calling remap and make the reprojection with those 7 arguments.
Given an expression in sympy, how do I re-write the expression as a polynomial defined as [1]:
D11*(omega**2/k**2)**3 + D22*(omega**2/k**2)**2 + D33*(omega**2/k**2) + D44 = 0
Note that this is different from the similar question asked here (Rewrite equation as polynomial).
Let
x=(omega**2/k**2)
then
D11*x**3 + D22*x**2 + D33*x + D44 = 0
I would like to find D11, D22, D33, and D44, given that x=omega**2/k**2
Normally, the collect function (http://docs.sympy.org/latest/tutorial/simplification.html) would collect similar terms, but in this situation, it does not seem to work well.
Here is a simple example that helps to explain what I am trying to accomplish. The output should be in the form D11*(omega**2/k**2)**3 + D22*(omega**2/k**2)**2 + D33*(omega**2/k**2) + D44 = 0
from sympy import symbols, collect
from IPython.display import display
omega = symbols('omega')
k = symbols('k')
a = symbols('a')
b = symbols('b')
c = symbols('c')
D11 = a*b*c
D22 = c+b
D33 = a+c*b + b
D44 = a+b
x = omega**2/k**2
expr = (D11*x**3 + D22*x**2 + D33*x + D44)
expr0 = expr.expand()
expr1 = collect(expr0, x)
display(expr1)
The output is:
a*b*c*omega**6/k**6 + a + b + omega**2*(a + b*c + b)/k**2 + omega**4*(b + c)/k**4
Although numerically correct, I would like the polynomial in the form [1] given above, and once it is in the form, I would like to extract the D11, D22, D33, and D44 coefficients.
Using evaluate=False in the collect function gets me closer to the goal, since the output now becomes:
{omega**2/k**2: a + b*c + b, omega**4/k**4: b + c, omega**6/k**6: a*b*c, 1: a + b}
Starting with your expr1,
expr1 = a*b*c*omega**6/k**6 + a + b + omega**2*(a + b*c + b)/k**2 + omega**4*(b + c)/k**4
it seems the easiest way to get the coefficients is to turn x into a symbol, at least temporarily:
Poly(expr1.subs(x, Symbol('x')), Symbol('x')).all_coeffs()
returns [a*b*c, b + c, a + b*c + b, a + b] (the coefficients are listed starting with the highest degree).
I would probably have x = Symbol('x') there to begin with, and only use expr.subs(x, omega**2/k**2) when needed.
SymPy's internal order of terms in a sum cannot be changed. To "rearrange" a SymPy expression means to print it in a more human-friendly form. This is largely a string manipulation problem, as we are no longer producing a SymPy object.
str(Poly(expr1.subs(x, Symbol('x')), Symbol('x'))).replace('x', '(' + str(x) + ')')
returns Poly(a*b*c*(omega**2/k**2)**3 + (b + c)*(omega**2/k**2)**2 + (a + b*c + b)*(omega**2/k**2) + a + b, (omega**2/k**2), domain='ZZ[a,b,c]')
Adding .split(',')[0].replace('Poly(', '') to the above removes the meta-data of a polynomial, leaving a*b*c*(omega**2/k**2)**3 + (b + c)*(omega**2/k**2)**2 + (a + b*c + b)*(omega**2/k**2) + a + b
I have a single of x-y coordinate system
This diagram should represent what you've told me.
The key point, is to express [x2],[y2] in CS1. (I can't use latex here so let's assume that [A] means the vector A, |A| is the length of the vector A)
[v2] = v2x * [x2] + v2y * [y2]
Since we have well defined [v1] and [d2], we can calculate [x']
[x`] = [d2] - [v1]
From [x'] we can calculate x2
[x2] = (|x2|/|x'|)[x`] = (|x1|/|x'|)[x'] since |x1| = |x2|
From x2 we can calculate y2, although I don't remember how. It's a simple 90° rotation.
Should be this:
y2x = - x2y
y2y = x2x
Once we have expressed x2,y2 in CS1, we can compute v2
v2 = v2x * [x2] + v2y * [y2] = v2x * (x2x*[x1]+x2y*[y1]) + v2y * (y2x*[x1]+y2y*[y1])
= (v2xx2x + v2yy2x)[x1] + (v2xx2y + v2yy2y) [y1] // Hope I didn't make any mistake here :)
And finally
[X] = [v1] + [v2]
I think the best option is to create a vector class and do all the math using vector algebra. You just need to define 3 operation: Addition, ScalarMultiplication, 90Rotation.