How to scatter randomly points on a sphere - python

using PyPlot
n = 50
u = range(0,stop=2*π,length=n);
v = range(0,stop=π,length=n);
x = cos.(u) * sin.(v)';
y = sin.(u) * sin.(v)';
z = ones(n) * cos.(v)';
scatter3D(vec(x),vec(y),vec(z);c="red",s=1)
However, if I multiply vec(x), vec(y), vec(z) with rand() ,
I still get the same plot with the only difference being that the axis change or in other words that the sphere gets "squished".
using PyPlot
n = 50
u = range(0,stop=2*π,length=n);
v = range(0,stop=π,length=n);
x = cos.(u) * sin.(v)';
y = sin.(u) * sin.(v)';
z = ones(n) * cos.(v)';
scatter3D(rand()*vec(x),rand()*vec(y),rand()*vec(z);c="red",s=1)

The simplest approach seems to be sampling a Gaussian for each dimension and then normalizing the length of the resulting vector as described in this answer. There's a very slight possibility of getting a vector with zero length, which can be handled with rejection sampling. Putting that together you would do this:
points = map(1:n) do _
while true
x = randn()
y = randn()
z = randn()
l = hypot(x, y, z)
l ≠ 0 && return (x, y, z) ./ l
end
end
This gives a vector of 3-tuples each representing x, y and z coordinates of points, which you can plot as before. Separate vectors of coordinates can be extracted using comprehensions:
xs = [p[1] for p in points]
ys = [p[2] for p in points]
zs = [p[3] for p in points]
This approach can readily be generalized to any number of dimensions.

Related

What is the formula for creating an n-dimensional grid from a 1-dimensional loop?

I'm trying to create a 3D grid of Node types (a custom data-type).
To create a 2D grid, I usually use this formula:
where i is the current iteration in 1D loop, and gridsize is size of one axis of grid
x = i % gridsize,
y = floor(i / gridsize)
For example, in Python:
from math import floor
grid = list()
gridsize = 3 # 3x3 grid
for i in range(gridsize**2):
x = i % gridsize
y = floor(i / gridsize)
grid.append( Node(x, y) )
How can I alter this formula to find x, y, and z coordinates for a 3D grid, and is there a general rule for finding coordinates for nD grids?
x ticks up the fastest, incrementing by 1 every time i increments, and wraps around when it reaches gridsize:
x = i % gridsize
y ticks up more slowly, incrementing by 1 every time i increases by gridsize, but also wraps around when it reaches gridsize:
y = (i // gridsize) % gridsize
z ticks up the slowest, incrementing by 1 every time i increases by gridsize**2, and we don't need it to wrap around:
z = i // gridsize**2
We can generalize this:
x = (i // gridsize**0) % gridsize
y = (i // gridsize**1) % gridsize
z = (i // gridsize**2) % gridsize
I'm sure you see the pattern here.
Afer writing out a table of x, y and z values for a 3x3x3 grid, I figured this out:
For a cubic 3D¹ grid
x = i % gs
y = floor(i / gs) % gs
z = floor(i / gs²)
where i is the current iteration, and gs is length of one axis.
With a bit of extrapolation, here's a formula2 for an nD grid:
cn = floor(i / gsn-1) % gs
For example:
x = floor( i / gs⁰ ) % gs # 1D
y = floor( i / gs¹ ) % gs # 2D
z = floor( i / gs² ) % gs # 3D
a = floor( i / gs³ ) % gs # 4D
etc.
NOTE:
The x value can be simplified to i % gs because
i/gs0 % gs => i/1 % gs => i % gs. Likewise, we can remove the % gs from the calculation of the z value, because the loop should never go over gs3
This formula only works for cubic grids (ie. grids whose axes all have the same number of points on them - 2x2x2x2, 5x5x5, etc.). 3x4x5 grids, for example, require a different formula.
I wouldn't use a formula but just this:
r = range(gridsize)
grid = [Node(x, y, z) for z in r for y in r for x in r]
Or with an arbitrary dimension, using itertools.product:
grid = [Node(*p[::-1]) for p in product(range(gridsize), repeat=griddim)]
If you don't mind the order of the nodes, you can leave out the [::-1] or also use itertools.starmap:
grid = list(starmap(Node, product(range(gridsize), repeat=griddim)))

How to calculate the divergent of a vector in sympy?

I want to calculate the divergent of a given vector with sympy. Is there any function in python responsible for this? I looked for something in the functions of einsteinpy, but I still haven't found any that help.
Basically I want to calculate \nabla_\mu (n v^\mu)=0 from a given vector v; n being a constant number.
\nabla_\mu (nv^\mu)=0 represents a divergence where \mu will take the derivative with respect to x, y or z of the vector element corresponding to the component. For example:
\nabla_\mu (n v^\mu) = \partial_x (u^x) + \partial_y(u^y) + \partial_z(u^z)
u can be something like (2x,4y,6z)
I appreciate any help.
As shown by #mikuszefski, you can use the module sympy.vector such that you have the implementation of the divergence in a space.
Another way to do what you want is to use the function derive_by_array to get a tensor and do einsten contraction.
import sympy as sp
x, y, z = sp.symbols("x y z") # dim = 3
# Now the functions that you want:
u, v, w = 2*x, 4*y, 6*z
# In a more general way, you can do:
u = sp.Function("u")(x, y, z)
v = sp.Function("v")(x, y, z)
w = sp.Function("w")(x, y, z)
U = sp.Array([u, v, w]) # U is a vector of dim = 3 (or sympy.Array)
X = sp.Array([x, y, z]) # X is a vector of dim = 3 (or sympy.Array)
dUdX = sp.derive_by_array(U, X) # dUdX is a tensor of dim = 3 and order = 2
# Frist way:
divU = sp.trace(sp.Matrix(sp.derive_by_array(U, X))) # Limited
# Second way:
divU = sp.tensorcontraction(sp.derive_by_array(U, X), (0, 1)) # More general
This solution works fine when dim = 2 for example, but you must have that len(X) == len(U)

Is there a quick method to project points onto an certain grid?

I am now trying to project n points with 3 dimensional coordinates (x,y,z) onto a xy-grid with a certain size (like 64*64), of course the coordinate of such n points is restricted in this grid.
The goal is to print z coordinate of points which are projected onto each of grid elements. I write two for-loops, but is there any better method to avoid using for-loop to run it more quickly?
for i in range(XY_grid.shape[0]):
x = np.where((X_coordinate > i) & (X_coordinate <= i + 1), 1, 0)
for j in range(XY_grid.shape[1]):
y = np.where(( Y_coordinate > j) & (Y_coordinate <= j + 1), 1, 0)
print(x * y * Z_coordinate)
I think what you want is a 2D histogram:
import numpy as np
# generate some data (x, y, z)
x = np.arange(100)
y = np.random.rand(100)
z = np.arange(100)[::-1] * 1.5
# grid (x, y) onto a defined grid (0-127) in x and y
grid, xe, ye = np.histogram2d(x, y, bins=(np.arange(128), np.arange(128)), weights=None)
grid.sum()
>>> 100.0 # all data is in the grid (was only 100 points)
You can use the weight argument to add z values:
# grid (x, y) onto a defined grid (0-127) in x and y
grid, xe, ye = np.histogram2d(x, y, bins=(np.arange(128), np.arange(128)), weights=z)
grid.sum()
>>> 7425.0
z.sum()
>>> 7425.0 # all z values are in the produced grid
You can change the bins widths etc. to make them nonuniform, or keep them evenly spaced for a regular grid.
The resulting grid is a 2D numpy array which contains all of the z information that falls into each bin. You can easily just print it or loop over it to get every element in turn.
To print all the entries of Z_coordinate that coorespond to a specific point in X_coordinate and Y_coordinate you can do:
for i in range(XY_grid.shape[0]):
for j in range(XY_grid.shape[1]):
print(Z_coordinate[np.logical_and(X_coordinate==i, Y_coordinate==j)])

How to draw the best ellipse given number of points?

Given the vectors p,q and number of points n I want to approximate shape of the ellipse with these n points as best as possible. To do this I use parametric equation of ellipse and change radius and angle in a double for loop:
n = 10000
points = []
p = [300, 0]
q = [0, 200]
root = int(math.sqrt(n))
for a in range(root):
for b in range(root):
x = 400 + (a/root)*(p[0] - q[0])*math.cos(2*math.pi*b/root)
y = 300 - (a/root)*(p[1] - q[1])*math.sin(2*math.pi*b/root)
points.append([x, y])
for w in points:
pygame.draw.circle(screen, (200, 50, 75), (int(w[0]), int(w[1])), 1)
Here I'm using pygame to draw but it doesn't really matter. Given these parameters my ellipse looks like this:
with n = 100000. It looks like this:
Given the nature of the ellipse there are more points in the middle using basic parametrization of the radious and angle. Because of that I need very large n to get good picture. How can I change parameterization to make points better spread on the whole area?
Perhaps create the points uniformly and then filter out the ones outside the ellipse?
import numpy as np
from math import sqrt
import matplotlib.pyplot as plt
def filter_points(h, k, a, b, x, y):
mask = ((x-h)**2)/(a**2) + ((y-k)**2)/(b**2) <= 1
return x[mask], y[mask]
h = 0
k = 0
a = 4
b = 5
N = 10000
n = int(sqrt(N))
X, Y = np.meshgrid(
np.linspace(-a,a,n),
np.linspace(-b,b,n)
)
X, Y = filter_points(h, k, a, b, X[:], Y[:])
points = np.asarray([X, Y]).T
plt.figure
plt.plot(X,Y,'.')

How can I get data for a quiver plot in torch?

I have some function z(x, y) and I would like to generate a quiver plot (a 2D plot of the gradients). Something like this:
In order to do it, I have to run gradient over a linear mesh and adjust data to the format that matplotlib.quiver does.
A naive way is to iterate forward and backward in a loop:
for i in range(10):
for j in range(10):
x = torch.tensor(1. * i, requires_grad=True)
y = torch.tensor(1. * j, requires_grad=True)
z = x ** 2 + y ** 2
z.backward()
print(x.grad, y.grad)
This is obviously very inefficient. There are some examples on how to generate a linear mesh from x, y but I would need later change the mesh back to the format of the forward formula, get vectors of gradient and put them back, etc..
A simple example in numpy would be:
import matplotlib.pyplot as plt
n = 25
x_range = np.linspace(-25, 25, n)
y_range = np.linspace(-25, 25, n)
X, Y = np.meshgrid(x_range, y_range)
Z = X**2 + Y**2
U, V = 2*X, 2*Y
plt.quiver(X, Y, U, V, Z, alpha=.9)
What would be the standard way of doing this with pytorch? Are there some simple examples available?
You can compute gradients of non-scalars by passing torch.Tensors of ones.
import matplotlib.pyplot as plt
import torch
# create meshgrid
n = 25
a = torch.linspace(-25, 25, n)
b = torch.linspace(-25, 25, n)
x = a.repeat(n)
y = b.repeat(n, 1).t().contiguous().view(-1)
x.requires_grad = True
y.requires_grad=True
z = x**2 + y**2
# this line will compute the gradients
torch.autograd.backward([z], [torch.ones(x.size()), torch.ones(y.size())])
# detach to plot
plt.quiver(x.detach(), y.detach(), x.grad, y.grad, z.detach(), alpha=.9)
plt.show()
If you need to do this repeatedly you need to zero the gradients (set x.grad = y.grad = None).

Categories

Resources