How to rotate a numpy array? - python

I have some numpy/scipy issue. I have a 3D array that represent an ellipsoid in a binary way [ 0 out of the ellipsoid].
The thing is I would like to rotate my shape of a certain degree. Do you think it's possible ?
Or is there an efficient way to write directly the ellipsoid equation with the rotation ?

Just a short answer. If you need more informations or you don't know how to do it, then I will edit this post and add a small example.
The right way to rotate your matrix of data points is to do a matrix multiplication. Your rotation matrix would be probably an n*n-matrix and you have to multiply it with every point. If you have your 3d-matrix you have some thing like i*j*k-points for plotting. This means for your case you have to do it i*j*k-times to find the new points. Maybe you should consider an other matrix for plotting which is just a 2D matrix and just store the plotting points and no zero values.
There are some algorithm to calculate faster the results for low valued matrix, but just google for this.
Did you understood me or do you still have some questions? Sorry for this rough overview.
Best regards

Take a look at the command numpy.shape
I used it once to transpose an array, but I don't know if it might fit your needs.
Cheers!

rotating by a non rectangular degree is tricky, because the rotated square does no longer fit in the matrix.
The simplest way would be to transpose a 2D array/matrix by:
import numpy as np
... x = np.array([[1,2,3],[4,5,6],[7,8,9]])
x
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
x.T # transpose the array
array([[1, 4, 7],
[2, 5, 8],
[3, 6, 9]])
if you require an explicit array rotation check the ndimage package from scipy library:
from scipy import ndimage, datasets
img = datasets.ascent()
img_45 = ndimage.rotate(img, 45, reshape=False)

Related

What is the most efficient way to handle conversion from full to symmetric second order tensors using numpy?

I am processing symmetric second order tensors (of stress) using numpy. In order to transform the tensors I have to generate a fully populated tensor, do the transformation and then recover the symmetric tensor in the rotated frame.
My input is a 2D numpy array of symmetric tensors (nx6). The code below works, but I'm pretty sure there must be a more efficient and/or elegant way to manipulate the arrays but I can't seem to figure it out.
I anyone can anyone suggest an improvement I'd be very grateful? The sample input is just 2 symmetric tensors but in use this could be millions of tensors, hence the concernr with efficiency
Thanks,
Doug
# Sample symmetric input (S11, S22, S33, S12, S23, S13)
sym_tens_in=np.array([[0,9], [1,10], [2,11], [3,12], [4,13], [5,14]])
# Expand to full tensor
tens_full=np.array([[sym_tens_in[0], sym_tens_in[3], sym_tens_in[4]],
[sym_tens_in[3], sym_tens_in[1], sym_tens_in[5]],
[sym_tens_in[4], sym_tens_in[5], sym_tens_in[2]]])
# Transpose and reshape to n x 3 x 3
tens_full=np.transpose(tens_full, axes=(2, 0, 1))
# This where the work on the full tensor will go....
# Reshape for extraction of the symmetric tensor
tens_full=np.reshape(tens_full, (2,9))
# Create an array for the test ouput symmetric tensor
sym_tens_out=np.empty((2,6), dtype=np.int32)
# Extract the symmetric components
sym_tens_out[:,0]=tens_full[:,0]
sym_tens_out[:,1]=tens_full[:,4]
sym_tens_out[:,2]=tens_full[:,8]
sym_tens_out[:,3]=tens_full[:,2]
sym_tens_out[:,4]=tens_full[:,3]
sym_tens_out[:,5]=tens_full[:,5]
# Transpose....
sym_tens_out=np.transpose(sym_tens_out)
This won't be any faster, but it's more compact:
In [166]: idx=np.array([0,3,4,3,1,5,4,5,2]).reshape(3,3)
In [167]: sym_tens_in[idx].transpose(2,0,1)
Out[167]:
array([[[ 0, 3, 4],
[ 3, 1, 5],
[ 4, 5, 2]],
[[ 9, 12, 13],
[12, 10, 14],
[13, 14, 11]]])
The transpose could be done first:
sym_tens_in.T[:,idx]
Similarly the reverse mapping can be done with:
In [168]: idx1 = [0,4,8,1,2,5]
In [171]: tens_full.reshape(2,-1)[:,idx1]
Out[171]:
array([[ 0, 1, 2, 3, 4, 5],
[ 9, 10, 11, 12, 13, 14]])
with the optional transpose.
OK - Based on the answers provided here I found a really cool solution. Now, I have to say that in my original question I omitted the actual reason that I was trying to get the full tensor into nx3x3 form. Basically, I'm implementing a function to rotate 2nd order stress tensors which requires solution of σ′=R⋅σ⋅RT.
I was planning to use numpy.matmul for the matrix multiplication but to transform multiple stress tensors, matmul requires the 3x3 tensors to be in the last two indices of the nx3x3 matrix - hence the effort to get the data into nx3x3 from from the original 3x3xn form....
However, after I let go of numpy.matmul as my target solution and embraced numpy.einsum instead....... everything became much easier....
# Sample symmetric input (S11, S22, S33, S12, S23, S13)
sym_tens_in=np.array([[0,9], [1,10], [2,11], [3,12], [4,13], [5,14]])
idx=np.array([0,3,5,3,1,4,5,4,2]).reshape(3,3)
full=sym_tens_in[idx]
full_transformed=np.einsum('ij, jkn, lk->nil', rot_mat, full, rot_mat)
Thanks for the inspiration!!!!

Find the numpy 2d array use customized index in python

I am wondering what is the most convenient way for finding the numpy array value with customized coordinates.
For example, I create a numpy array like
[[1,2,3,4]
[5,6,7,8]]
The x coordinate is[1, 3, 5, 7], and the y coordinate is [1,1.5].
I hope to get the value '8' by using the coordinate (7,1.5) rather than using numpy index (3,1).
What is the most elegant way to do that?

Sum pattern across array

I'm having trouble finding the proper way to do something I think should be trivial using numpy. I have an array (1000x1000) and I want to calculate the sum of a specific pattern across the array.
For example:
If I have this array and want to calculate the sum of a two-cell-right diagonal I would expect [7,12,11,8,12,6,11,7] (a total of 8 sums).
How can I do this?
This operation is called a 2-dimensional convolution:
>>> import numpy as np
>>> from scipy.signal import convolve2d
>>> kernel = np.eye(2, dtype=int)
>>> a = np.array([[5,3,7,1,2],[3,2,9,4,7],[8,9,4,2,3]])
>>> convolve2d(a, kernel, mode='valid')
array([[ 7, 12, 11, 8],
[12, 6, 11, 7]])
Should you want to generalize it to arbitrary dimensions, there is also scipy.ndimage.convolve available. It will also work for this 2d case, but does not offer the mode='valid' convenience.
l = [[5,3,7,1,2],[3,2,9,4,7],[8,9,4,2,3]]
[q+l[w+1][t+1] for w,i in enumerate(l[:-1]) for t,q in enumerate(i[:-1])]
then you can avoid using numpy :) and the output is
[7,12,11,8,12,6,11,7]

Matrix norm in TensorFlow

I need to compute the Frobenius norm in order to achieve this formula using the TensorFlow framework:
where w is a matrix with 50 rows and 100 columns.
I tried to write something, but I don't understand how to fill out the axis argument.
tf.pow(
tf.norm(x, ord='fro', axis=?), 2
)
According to the TensorFlow docs I have to use a 2-tuple (or a 2-list) because it determines the axies in tensor over which to compute a matrix norm, but I simply need a plain Frobenius norm. In SciPy, for example, I can do it without specify any axis.
So, what should I use as axis to emulate the SciPy function?
So the Frobenius norm is a sum over a nxm matrix, but tf.norm allows to process several vectors and matrices in batch.
To better understand, imagine you have a rank 3 tensor:
t = [[[2], [4], [6]], [[8], [10], [12]], [[14], [16], [18]]]
It can be seen as several matrices aligned over one direction, but the function can't figure by itself which one. It could be either a batch of the following matrices:
[2, 4, 6] , [8 ,10, 12], [14, 16, 18]
or
[2 8 14], [4, 10, 16], [6, 12, 18]
So basically axis tells which directions you want to consider when doing the summation in the Frobenius norm.
In your case, any of [1,2] or [-2,-1] would do the trick.
Independent of the number of dimensions of the tensor,
tf.sqrt(tf.reduce_sum(tf.square(w)))
should do the trick.
Negative indices are supported. Example: If you are passing a tensor that can be either a matrix or a batch of matrices at runtime, pass axis=[-2,-1] instead of axis=None to make sure that matrix norms are computed.
I just tested and [-2,-1] works.
It seems to me you are better off simply calling
tf.reduce_sum(tf.multiply(x, x))
Calling norm which square-roots the above result, then pow which work for any power and therefore potentially uses an elaborate algorithm, is overkill.
Try axis=(0,1). I think, it will solve your problem!!
Frobenius norm does not work for matrix. You need to create vectors.
reshape your array to the batchsize,-1.
Use tf.norm(reshaped_data, ord= 'fro', axis = (0, 1))
Using reshape on the tensorflow eager execution may through an error. from version = 2.5 onwards use
import tensorflow.python.ops.numpy_ops.np_config as np_config np_config.enable_numpy_behavior()
for example of how I am using this :
heat_difference = gt_hm - pd_hm
heat_difference = heat_difference.reshape(batch_size, -1)
hm_loss = tf.square(tf.norm(heat_difference, ord='fro', axis=(0, 1)) / batch_size)

Python numpy array indexing. How is this working?

I came across this python code (which works) and to me it seems amazing. However, I am unable to figure out what this code is doing. To replicate it, I sort of wrote a test code:
import numpy as np
# Create a random array which represent the 6 unique coeff.
# of a symmetric 3x3 matrix
x = np.random.rand(10, 10, 6)
So, I have 100 symmetric 3x3 matrices and I am only storing the unique components. Now, I want to generate the full 3x3 matrix and this is where the magic happens.
indices = np.array([[0, 1, 3],
[1, 2, 4],
[3, 4, 5]])
I see what this is doing. This is how the 0-5 index components should be arranged in the 3x3 matrix to have a symmetric matrix.
mat = x[..., indices]
This line has me lost. So, it is working on the last dimension of the x array but it is not at all clear to me how the rearrangement and reshaping is done but this indeed returns an array of shape (10, 10, 3, 3). I am amazed and confused!
From the advanced indexing documentation - bi rico's link.
Example
Suppose x.shape is (10,20,30) and ind is a (2,3,4)-shaped indexing intp array, thenresult = x[...,ind,:] has shape (10,2,3,4,30) because the (20,)-shaped subspace has been replaced with a (2,3,4)-shaped broadcasted indexing subspace. If we let i, j, kloop over the (2,3,4)-shaped subspace then result[...,i,j,k,:] =x[...,ind[i,j,k],:]. This example produces the same result as x.take(ind, axis=-2).

Categories