I'm trying to learn python - but new to OOP. I'd like to make the functions fA, fB, fC operate on the whole r-theta space at once, instead of one point at a time. My problem is the conditional (r<=1). The code below is quite ugly (!) but it works.
How can I make this more pythonesque? Thanks!
(in this simplified example, note the math for (r>1) diverges when r goes to zero)
from math import pi, sin, cos, exp
import numpy as np
import matplotlib.pyplot as plt
def fA(rr,th,a,b,c):
if (rr<=1):
fx = a * sin(th)
fy = b * rr * cos(th)
fz = c * rr
else:
fx = (a / rr) * sin(th)
fy = (b / rr) * cos(th)
fz = (c / rr)
return(fx,fy,fz)
def fB(rr,th,a,b,c):
if (rr<=1):
fx = b * sin(2.*th)
fy = a * rr * cos(2.*th)
fz = c * rr
else:
fx = (b / rr) * sin(2.*th)
fy = (a / rr) * cos(2.*th)
fz = c
return(fx,fy,fz)
def fC(rr,th,a,b,c):
if (rr<=1):
fx = exp(rr - 1.) * cos(th)
fy = exp(rr - 1.) * sin(th)
fz = c
else:
fx = exp(1. - rr) * cos(th)
fy = exp(1. - rr) * sin(th)
fz = c / rr
return(fx,fy,fz)
nx = 101
ny = 101
dx = 4. / (nx-1)
dy = 4. / (ny-1)
X = np.zeros((ny,nx))
Y = np.zeros((ny,nx))
for ix in range(nx):
for iy in range(ny):
X[iy,ix] = dx*(ix - (nx-1)/2)
Y[iy,ix] = dy*(iy - (ny-1)/2)
r = np.sqrt(X**2. + Y**2.)
theta = np.arctan2(Y,X)
Ax = np.zeros((ny,nx))
Ay = np.zeros((ny,nx))
Az = np.zeros((ny,nx))
Bx = np.zeros((ny,nx))
By = np.zeros((ny,nx))
Bz = np.zeros((ny,nx))
Cx = np.zeros((ny,nx))
Cy = np.zeros((ny,nx))
Cz = np.zeros((ny,nx))
for ix in range (nx):
for iy in range(ny):
Ax[iy,ix], Ay[iy,ix], Az[iy,ix] = fA(r[iy,ix], theta[iy,ix], 1.0, 1.0, 1.5)
Bx[iy,ix], By[iy,ix], Bz[iy,ix] = fB(r[iy,ix], theta[iy,ix], 1.5, 0.8, 1.0)
Cx[iy,ix], Cy[iy,ix], Cz[iy,ix] = fC(r[iy,ix], theta[iy,ix], 0.9, 1.1, 1.2)
plt.figure()
plt.subplot(3,3,1)
plt.imshow(Ax)
plt.colorbar()
plt.title('Ax')
plt.subplot(3,3,2)
plt.imshow(Ay)
plt.colorbar()
plt.title('Ay')
plt.subplot(3,3,3)
plt.imshow(Az)
plt.colorbar()
plt.title('Az')
plt.subplot(3,3,4)
plt.imshow(Bx)
plt.colorbar()
plt.title('Bx')
plt.subplot(3,3,5)
plt.imshow(By)
plt.colorbar()
plt.title('By')
plt.subplot(3,3,6)
plt.imshow(Bz)
plt.colorbar()
plt.title('Bz')
plt.subplot(3,3,7)
plt.imshow(Cx)
plt.colorbar()
plt.title('Cx')
plt.subplot(3,3,8)
plt.imshow(Cy)
plt.colorbar()
plt.title('Cy')
plt.subplot(3,3,9)
plt.imshow(Cz)
plt.colorbar()
plt.title('Cz')
plt.show()
Like #mdurant said np.where and np.meshgrid will be useful. Here, let me reorganize your code and provide another way to avoid Python looping by using numpy advanced indexing:
import sys
from math import pi, sin, cos, exp
import numpy as np
import matplotlib.pyplot as plt
def _generate_coordinate(nx, ny):
"""
Generate coordinate data points in a function to prevent namespace
pollution.
"""
dx = 4. / (nx-1)
dy = 4. / (ny-1)
X = np.zeros((ny,nx))
Y = np.zeros((ny,nx))
for ix in range(nx):
for iy in range(ny):
X[iy,ix] = dx*(ix - (nx-1)/2)
Y[iy,ix] = dy*(iy - (ny-1)/2)
return np.sqrt(X**2 + Y**2), np.arctan2(Y,X)
nx = ny = 101
r, theta = _generate_coordinate(101, 101)
def calculate_numpy():
# Helper methods for vector-based calculator.
def fA(rr, th, a, b, c):
# Calculate every value because mulplication doesn't give NaN.
arrx = a * np.sin(th)
arry = b * rr * np.cos(th)
arrz = c * rr
# Override value with a certain condition.
slct = rr > 1
rr = rr[slct]
th = th[slct]
arrx[slct] = a / rr * np.sin(th)
arry[slct] = b / rr * np.cos(th)
arrz[slct] = c / rr
return arrx, arry, arrz
def fB(rr, th, a, b, c):
# Calculate every value because mulplication doesn't give NaN.
arrx = b * np.sin(2.*th)
arry = a * rr * np.cos(2.*th)
arrz = c * rr
# Override value with a certain condition.
slct = rr > 1
rr = rr[slct]
th = th[slct]
arrx[slct] = b / rr * np.sin(2.*th)
arry[slct] = a / rr * np.cos(2.*th)
arrz[slct] = c
return arrx, arry, arrz
def fC(rr,th,a,b,c):
# Calculate every value because mulplication doesn't give NaN.
arrx = np.exp(rr-1) * np.cos(th)
arry = np.exp(rr-1) * np.sin(th)
arrz = np.empty_like(rr)
arrz.fill(c)
# Override value with a certain condition.
slct = rr > 1
rr = rr[slct]
th = th[slct]
arrx[slct] = np.exp(1.-rr) * np.cos(th)
arry[slct] = np.exp(1.-rr) * np.sin(th)
arrz[slct] = c / rr
return arrx, arry, arrz
# Carry out calculation.
Ax, Ay, Az = fA(r, theta, 1.0, 1.0, 1.5)
Bx, By, Bz = fB(r, theta, 1.5, 0.8, 1.0)
Cx, Cy, Cz = fC(r, theta, 0.9, 1.1, 1.2)
return Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz
def calculate_loop():
# Helper methods for loop calculator.
def fA(rr,th,a,b,c):
if (rr<=1):
fx = a * sin(th)
fy = b * rr * cos(th)
fz = c * rr
else:
fx = (a / rr) * sin(th)
fy = (b / rr) * cos(th)
fz = (c / rr)
return(fx,fy,fz)
def fB(rr,th,a,b,c):
if (rr<=1):
fx = b * sin(2.*th)
fy = a * rr * cos(2.*th)
fz = c * rr
else:
fx = (b / rr) * sin(2.*th)
fy = (a / rr) * cos(2.*th)
fz = c
return(fx,fy,fz)
def fC(rr,th,a,b,c):
if (rr<=1):
fx = exp(rr - 1.) * cos(th)
fy = exp(rr - 1.) * sin(th)
fz = c
else:
fx = exp(1. - rr) * cos(th)
fy = exp(1. - rr) * sin(th)
fz = c / rr
return(fx,fy,fz)
# Create buffer arrays for loops.
Ax = np.zeros((ny,nx))
Ay = np.zeros((ny,nx))
Az = np.zeros((ny,nx))
Bx = np.zeros((ny,nx))
By = np.zeros((ny,nx))
Bz = np.zeros((ny,nx))
Cx = np.zeros((ny,nx))
Cy = np.zeros((ny,nx))
Cz = np.zeros((ny,nx))
# Carry out calculation with Python loops. This is slow.
for ix in range (nx):
for iy in range(ny):
Ax[iy,ix], Ay[iy,ix], Az[iy,ix] = fA(r[iy,ix], theta[iy,ix], 1.0, 1.0, 1.5)
Bx[iy,ix], By[iy,ix], Bz[iy,ix] = fB(r[iy,ix], theta[iy,ix], 1.5, 0.8, 1.0)
Cx[iy,ix], Cy[iy,ix], Cz[iy,ix] = fC(r[iy,ix], theta[iy,ix], 0.9, 1.1, 1.2)
return Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz
def main():
calculate = globals()["calculate_" + sys.argv[1]]
Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz = calculate()
plt.figure()
plt.subplot(3,3,1)
plt.imshow(Ax)
plt.colorbar()
plt.title('Ax')
plt.subplot(3,3,2)
plt.imshow(Ay)
plt.colorbar()
plt.title('Ay')
plt.subplot(3,3,3)
plt.imshow(Az)
plt.colorbar()
plt.title('Az')
plt.subplot(3,3,4)
plt.imshow(Bx)
plt.colorbar()
plt.title('Bx')
plt.subplot(3,3,5)
plt.imshow(By)
plt.colorbar()
plt.title('By')
plt.subplot(3,3,6)
plt.imshow(Bz)
plt.colorbar()
plt.title('Bz')
plt.subplot(3,3,7)
plt.imshow(Cx)
plt.colorbar()
plt.title('Cx')
plt.subplot(3,3,8)
plt.imshow(Cy)
plt.colorbar()
plt.title('Cy')
plt.subplot(3,3,9)
plt.imshow(Cz)
plt.colorbar()
plt.title('Cz')
plt.show()
if __name__ == '__main__':
main()
The function calculate_numpy() is where I demonstrate the advanced indexing. If you want to totally avoid duplicated calculation, you will need to create buffers like what you did in calculate_loop(). But I would say in terms of runtime, the duplication calculation is OK.
Let's say the program is saved in a file draw.py. We have both numpy ndarray and loop versions of the code, and can use timeit to benchmark them:
$ python -m timeit -s "import draw" "draw.calculate_loop()"
10 loops, best of 3: 95.2 msec per loop
$ python -m timeit -s "import draw" "draw.calculate_numpy()"
100 loops, best of 3: 2.11 msec per loop
As you can see, the numpy version is 45 times faster than your loop version. Most of the cases it's good enough.
Choosing one of your relations at random, you can use numpy.where instead of the if... semantics:
fx = where( rr<=1, exp(rr - 1.) * cos(th), exp(1. - rr) * cos(th))
This effectively does if/else for a set of arrays rather than one at a time individual numbers. You would then be able to do Ax, Ay, Az = fA(...) without the looping.
X and Y you can make using meshgrid or mgrid.
To not evaluate all elements, you could use slice notation
fx = empty_like(rr)
fx[rr<=1] = exp(rr[rr<=1] - 1.) * cos(th[rr<=1])
fx[rr>1] = exp(1. - rr[rr>1]) * cos(th[rr>1]))
Related
I have the following code:
import numpy as np
import scipy.stats as si
import sympy as sy
def price(S, K, T, r, vol, call=True):
d1 = (np.log(S / K) + (r + 0.5 * vol ** 2) * T) / (vol * np.sqrt(T))
d2 = (np.log(S / K) + (r - 0.5 * vol ** 2) * T) / (vol * np.sqrt(T))
if call:
price = (S * si.norm.cdf(d1, 0.0, 1.0) - K * np.exp(-r * T) * si.norm.cdf(d2, 0.0, 1.0))
else:
price = (K * np.exp(-r * T) * si.norm.cdf(-d2, 0.0, 1.0) - S * si.norm.cdf(-d1, 0.0, 1.0))
return price
p,S,K,T,r, vol, call = sy.symbols('p S K T r vol call')
exp = p - price(S, K, T, r, vol, call)
When i run this i get the following error: loop of ufunc does not support argument 0 of type Mul which has no callable log method
When i checked online there was mention of not scoping my log function but I have done this so this is not the problem. Can anyone see what I am doing wrong?
My current implementation looks like this:
if (shapesCollide) {
if (velocity.y > 0) entity.position.y = other.position.y - entity.size.y;
else entity.position.y = other.position.y + other.size.y;
velocity.y = 0;
if (velocity.x > 0) entity.position.x = other.position.x - entity.size.x;
else entity.position.x = other.position.x + other.size.x;
velocity.x = 0;
}
However, this leads to weird handling when movement is happening on both axes - for example, having entity moving downward to the left of object, and then moving it to collide with object, will correctly resolve the horizontal collision, but will break the vertical movement.
I previously simply went
if (shapesCollide) {
position = oldPosition;
velocity = { 0, 0 };
}
But this lead to another multi-axis issue: if I have my entity resting atop the object, it will be unable to move, as the gravity-induced movement will constantly cancel out both velocities. I also tried considering both axes separately, but this lead to issues whenever the collision only occurs when both velocities are taken into account.
What is the best solution to resolving collision on two axes?
I assume that the entities can be considered to be more or less round and that size is the radius of the entities?
We probably need a little vector math to resolve this. (I don't know the square-root function in c++, so be aware at sqrt.) Try replacing your code inside if(shapesCollide) with this and see how it works for you.
float rEntity = sqrt(entity.size.x * entity.size.x + entity.size.y * entity.size.y);
float rOther = sqrt(other.size.x * other.size.x + other.size.y * other.size.y);
float midX = (entity.position.x + other.position.x) / 2.0;
float midY = (entity.position.y + other.position.y) / 2.0;
float dx = entity.position.x - midX;
float dy = entity.position.y - midY;
float D = sqrt(dx * dx + dy * dy);
rEntity and rOther are the radii of the objects, and midX and midY are their center coordinates. dx and dy are the distances to the center from the entity.
Then do:
entity.position.x = midX + dx * rEntity / D;
entity.position.y = midY + dy * rEntity / D;
other.position.x = midX - dx * rOther / D;
other.position.y = midY - dy * rOther / D;
You should probably check that D is not 0, and if it is, just set dx = 1, dy = 0, D = 1 or something like that.
You should also still do:
velocity.x = 0;
velocity.y = 0;
if you want the entities to stop.
For more accurate modelling, you could also try the following:
float rEntity = sqrt(entity.size.x * entity.size.x + entity.size.y * entity.size.y);
float rOther = sqrt(other.size.x * other.size.x + other.size.y * other.size.y);
float midX = (entity.position.x * rOther + other.position.x * rEntity) / (rEntity + rOther);
float midY = (entity.position.y * rOther + other.position.y * rEntity) / (rEntity + rOther);
float dxEntity = entity.position.x - midX;
float dyEntity = entity.position.y - midY;
float dEntity = sqrt(dxEntity * dxEntity + dyEntity * dyEntity);
float dxOther = other.position.x - midX;
float dyOther = other.position.y - midY;
float dOther = sqrt(dxOther * dxOther + dyOther * dyOther);
entity.position.x = midX + dxEntity * rEntity / dEntity;
entity.position.y = midY + dyEntity * rEntity / dEntity;
other.position.x = midX + dxOther * rOther / dOther;
other.position.y = midY + dyOther * rOther / dOther;
which finds the midpoints when the radii are taken into account. But I won't guarantee that that works. Also, the signs on the last additions are important.
I hope this helps (and works). Let me know if something is unclear.
I have that piece of code that is responsible for lighting a pyramid.
float Geometric3D::calculateLight(int vert1, int vert2, int vert3) {
float ax = tabX[vert2] - tabX[vert1];
float ay = tabY[vert2] - tabY[vert1];
float az = tabZ[vert2] - tabZ[vert1];
float bx = tabX[vert3] - tabX[vert1];
float by = tabY[vert3] - tabY[vert1];
float bz = tabZ[vert3] - tabZ[vert1];
float Nx = (ay * bz) - (az * by);
float Ny = (az * bx) - (ax * bz);;
float Nz = (ax * by) - (ay * bx);;
float Lx = -300.0f;
float Ly = -300.0f;
float Lz = -1000.0f;
float lenN = sqrtf((Nx * Nx) + (Ny * Ny) + (Nz * Nz));
float lenL = sqrtf((Lx * Lx) + (Ly * Ly) + (Lz * Lz));
float res = ((Nx * Lx) + (Ny * Ly) + (Nz * Lz)) / (lenN * lenL);
if (res < 0.0f)
res = -res;
return res;
}
I cannot understand calculations at the end. Can someone explain me the maths that is behind them? I know that firstly program calculates two vectors of a plane to compute the normal of it (which goes for vector N). Vector L stand for lighting but what happens next? Why do we calculate length of normal and light then multiply it and divide by their sizes?
I am trying to implement a gradient descent algorithm for simple linear regression. For some reason it doesn't seem to be working.
from __future__ import division
import random
def error(x_i,z_i, theta0,theta1):
return z_i - theta0 - theta1 * x_i
def squared_error(x_i,z_i,theta0,theta1):
return error(x_i,z_i,theta0,theta1)**2
def mse_fn(x, z, theta0,theta1):
m = 2 * len(x)
return sum(squared_error(x_i,z_i,theta0,theta1) for x_i,z_i in zip(x,z)) / m
def mse_gradient(x, z, theta0,theta1):
m = 2 * len(x)
grad_0 = sum(error(x_i,z_i,theta0,theta1) for x_i,z_i in zip(x,z)) / m
grad_1 = sum(error(x_i,z_i,theta0,theta1) * x_i for x_i,z_i in zip(x,z)) / m
return grad_0, grad_1
def minimize_batch(x, z, mse_fn, mse_gradient_fn, theta0,theta1,tolerance=0.000001):
step_sizes = 0.01
theta0 = theta0
theta1 = theta1
value = mse_fn(x,z,theta0,theta1)
while True:
grad_0, grad_1 = mse_gradient(x,z,theta0,theta1)
next_theta0 = theta0 - step_sizes * grad_0
next_theta1 = theta1 - step_sizes * grad_1
next_value = mse_fn(x,z,next_theta0,theta1)
if abs(value - next_value) < tolerance:
return theta0, theta1
else:
theta0, theta1, value = next_theta0, next_theta1, next_value
#The data
x = [i + 1 for i in range(40)]
y = [random.randrange(1,30) for i in range(40)]
z = [2*x_i + y_i + (y_i/7) for x_i,y_i in zip(x,y)]
theta0, theta1 = [random.randint(-10,10) for i in range(2)]
q = minimize_batch(x,z,mse_fn, mse_gradient, theta0,theta1,tolerance=0.000001)
When I run I get the following error:
return error(x_i,z_i,theta0,theta1)**2 OverflowError: (34, 'Result too large')
I am working on a home project where I need to closely solve an equation by iteration.
M = E - e* sin(E) or another way (E - e*sin(E))/M = 1.
M is previously solved for and e is given in the data message.
So would you plug in a number for E and check to see how close the value ends up to 1, then continue to adjust the plug in value of E untill the expression is within a set value to 1.00000?
Is there an "ideal" method to solving something like this in software?
The rest of my calculation function is shown as
FP64 is defined as double
bool SV_pos_GAL_L1(int chan, FP64* x, FP64* y, FP64* z) //finds SV ECEF position in orbit at ref GAL system time
{
FP64 smaxis = pow(GALChannel[chan].L1galData.sqrrtA, 2); //semi major axis
FP64 nc = sqrt( MU/(pow(smaxis, 3)) ) + GALChannel[chan].L1galData.delta_n; //n corrected
FP64 Tk = GALChannel[chan].L1galData.TOW - GALChannel[chan].L1galData.Toe; //time since ephemeris
FP64 M = GALChannel[chan].L1galData.M0 + nc * Tk; //mean anomaly
FP64 E;
FP64 v = atan( ((sqrt(1-pow(GALChannel[chan].L1galData.e,2)) * sin(E)) / (1-(GALChannel[chan].L1galData.e*cos(E)))) / ((cos(E)-GALChannel[chan].L1galData.e) / (1-(cos(E)*GALChannel[chan].L1galData.e))) );//true anomaly
FP64 Omega = GALChannel[chan].L1galData.Omega0 + (Tk * (GALChannel[chan].L1galData.dot_Omega - GALChannel[chan].L1galData.w)) - ( GALChannel[chan].L1galData.w * GALChannel[chan].L1galData.Toe); //corrected longitude of ascinding node
FP64 ArgLat = v + Omega; //argument of latitude
FP64 Su = (GALChannel[chan].L1galData.Cus * sin(2*ArgLat)) + ( GALChannel[chan].L1galData.Cuc * cos(2*ArgLat)); //argument of latitude correction
FP64 Sr = (GALChannel[chan].L1galData.Crs * sin(2*ArgLat)) + ( GALChannel[chan].L1galData.Crc * cos(2*ArgLat)); //radius correction
FP64 Si = (GALChannel[chan].L1galData.Cis * sin(2*ArgLat)) + ( GALChannel[chan].L1galData.Cic * cos(2*ArgLat)); //inclination correction
FP64 u = ArgLat + Su; //corrected arg latitude
FP64 r = smaxis * (1 - (GALChannel[chan].L1galData.e * cos(E))) + Sr; //corrected radius
FP64 i = GALChannel[chan].L1galData.i0 + Si + (GALChannel[chan].L1galData.dot_i * Tk); //corrected inclination
FP64 x1 = r * cos(u);
FP64 y1 = r * sin(u);
x = (x1 * cos(Omega)) - (y1 * cos(i) * sin(Omega));
y = (x1 * sin(Omega)) - (y1 * cos(i) * cos(Omega));
z = y1 * sin(i);
return true;
}