Related
I have a matrix whose shape is (TxK, and K << T). I want to extend it into shape TxT, and right shift the i-th row with i steps.
For an example:
inputs: T= 5, and K = 3
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
expected outputs:
1 2 3 0 0
0 1 2 3 0
0 0 1 2 3
0 0 0 1 2
0 0 0 0 1
My solutions:
right_pad = T - K + 1
output = F.pad(input, (0, right_pad), 'constant', value=0)
output = output.view(-1)[:-T].view(T, T)
My solution will cause the error -- gradient computation has been modified by an in-place operation. Is there an efficient and feasible way to achieve my purpose?
Your function is fine and is not a cause of your error (using PyTorch 1.6.0, if you are using other version, please update your dependencies).
Code below works fine:
import torch
import torch.nn as nn
import torch.nn.functional as F
T = 5
K = 3
inputs = torch.tensor(
[[1, 2, 3,], [1, 2, 3,], [1, 2, 3,], [1, 2, 3,], [1, 2, 3,],],
requires_grad=True,
dtype=torch.float,
)
right_pad = T - K + 1
output = F.pad(inputs, (0, right_pad), "constant", value=0)
output = output.flatten()[:-T].reshape(T, T)
output.sum().backward()
print(inputs.grad)
Please notice I have explicitly specified dtype as torch.float as you can't backprop integers.
view and slice will never break backpropagation, as the gradient is connected to single value, no matter whether it is viewed as 1D or unsqueezed 2D or whatever. Those are not modified in-place. In-place modification breaking gradient could be:
output[0, 3] = 15.
Also, your solution returns this:
tensor([[1., 2., 3., 0., 0.],
[0., 1., 2., 3., 0.],
[0., 0., 1., 2., 3.],
[0., 0., 0., 1., 2.],
[3., 0., 0., 0., 1.]], grad_fn=<ViewBackward>)
so you have a 3 in the bottom left corner. If that's not what you expect, you should add this line (multiplication by upper triangular matrix with 1) after output = output.flatten()[:-T].reshape(T,T):
output *= torch.triu(torch.ones_like(output))
which gives:
tensor([[1., 2., 3., 0., 0.],
[0., 1., 2., 3., 0.],
[0., 0., 1., 2., 3.],
[0., 0., 0., 1., 2.],
[0., 0., 0., 0., 1.]], grad_fn=<AsStridedBackward>)
And inputs.grad:
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 0.],
[1., 0., 0.]])
You can do this column by column with PyTorch.
# input is a T * K tensor
input = torch.ones((T, K))
index = torch.tensor(np.linspace(0, T - 1, num=T, dtype=np.int64))
output = torch.zeros((T, T))
output[index, index] = input[:, 0]
for k in range(1, K):
output[index[:-k], index[:-k] + k] = input[:-k, k]
print(output)
I'm attempting to create an array of matrices by multiplying a t = range(0,stop=2*pi,length=101) by a matrix [1, 0] as follows
A = t .* [1 ,0]
but this produces the error ERROR: LoadError: DimensionMismatch("arrays could not be broadcast to a common size"). I would like each scalar, or element of t to be multiplied elementwise (in terms of t) with the elements of the vector [1 , 0], essentially performing an elementwise scalar--matrix product.
The reason I'm doing this is because I would later like to be able to multiply another constant matrix M with each column vector found in A. How can this be done in Julia v1.1?
You have to wrap the element you do not want to be broadcasted over in a container. Here is a standard way to do it (I decreased length kwarg to 3 to make the example more clear):
julia> t = range(0,stop=2*pi,length=3)
0.0:3.141592653589793:6.283185307179586
julia> A = t .* Ref([1 ,0])
3-element Array{Array{Float64,1},1}:
[0.0, 0.0]
[3.141592653589793, 0.0]
[6.283185307179586, 0.0]
julia> Ref([1 2; 3 4]) .* A
3-element Array{Array{Float64,1},1}:
[0.0, 0.0]
[3.141592653589793, 9.42477796076938]
[6.283185307179586, 18.84955592153876]
Instead of Ref container you can also use a 1-element tuple or 1-element vector as wrappers:
julia> t .* ([1 ,0],)
3-element Array{Array{Float64,1},1}:
[0.0, 0.0]
[3.141592653589793, 0.0]
[6.283185307179586, 0.0]
julia> t .* [[1 ,0]]
3-element Array{Array{Float64,1},1}:
[0.0, 0.0]
[3.141592653589793, 0.0]
[6.283185307179586, 0.0]
The reason why Ref should be preferred is that it is 0-dimensional, so that it is the most neutral of these three methods (i.e. influences the output in the least way - retaining the broadcast style of the other argument). Here are some examples:
julia> f1(x) = x .* (2, )
f1 (generic function with 1 method)
julia> f2(x) = x .* [2]
f2 (generic function with 1 method)
julia> f3(x) = x .* Ref(2)
f3 (generic function with 1 method)
julia> f1(1)
(2,)
julia> f2(1)
1-element Array{Int64,1}:
2
julia> f3(1)
2
julia> f1((1,2))
(2, 4)
julia> f2((1,2))
2-element Array{Int64,1}:
2
4
julia> f3((1,2))
(2, 4)
I'm having a difficult time trying to figure out a general equation or function for some patterns generated using 4 variables C, x, y and z. M is a 3D matrix of shape (p, q, C) containing these values, where p and q are some large but likely irrelevant integers.
Shown below is a small selection of patterns. Can anyone see what the function f(C, x, y, z) might be like? Please note that the values of C, x, y and z are not limited to those below, but can be any integers.
C = 1
(x =) 0 0 0 0 0 0 0 0 0
(y =) 0 1 2 3 4 5 6 7 8
(z =) 0 0 0 0 0 0 0 0 0
M = [[[0]], [[1]], [[2]], [[3]], [[4]], [[5]], [[6]], [[7]], [[8]], ...]
---------------------------------------------------------------------------
(x =) 1 1 1 1 1 1 1 1 1
(y =) 0 1 2 3 4 5 6 7 8
(z =) 0 0 0 0 0 0 0 0 0
M = [[[0]], [[1]], [[2]], [[3]], [[4]], [[5]], [[6]], [[7]], [[8]], ...]
C = 2
(x =) 0 0 0 0 0 0 0 0 0 0
(y =) 0 0 1 1 2 2 3 3 4 4
(z =) 0 1 0 1 0 1 0 1 0 1
M = [[[0, 2], [1, 3]], [[4, 6], [5, 7]], [[8, 10], ...]
---------------------------------------------------------------------------------
(x =) 1 1 1 1 1 1 1 1 1 1
(y =) 0 0 1 1 2 2 3 3 4 4
(z =) 0 1 0 1 0 1 0 1 0 1
M = [[[0, 4], [1, 5]], [[2, 6], [3, 7]], [[8, 12], ...]
C = 3
(x =) 0 0 0 0 0 0 0 0 0 0 0 0
(y =) 0 0 0 1 1 1 2 2 2 3 3 3
(z =) 0 1 2 0 1 2 0 1 2 0 1 2
M = [[[0, 2, 4], [1, 3, 5]], [[6, 8, 10], [7, 9, 11]], ...]
-----------------------------------------------------------------------------------------------
(x =) 1 1 1 1 1 1 1 1 1 1 1 1
(y =) 0 0 0 1 1 1 2 2 2 3 3 3
(z =) 0 1 2 0 1 2 0 1 2 0 1 2
M = [[[0, 4, 8], [1, 5, 9]], [[2, 6, 10], [3, 7, 11]], ...]
C = 4
(x =) 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
(y =) 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3
(z =) 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
M = [[[0, 2, 4, 6], [1, 3, 5, 7]], [[8, 10, 12, 14], [9, 11, 13, 15], ...]
-------------------------------------------------------------------------------------------------------------------------
(x =) 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
(y =) 0 0 0 0 1 1 1 1 2 2 2 2 3 3 3 3
(z =) 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3
M = [[[0, 4, 8, 12], [1, 5, 9, 13]], [[2, 6, 10, 14], [3, 77, 11, 15], ...]
Quite clearly, when C > 1, there is some interleaving/skipping going on. For instance, when C == 2, M(1,1,1) == 0, M(1,2,1) == 1, M(1,1,2) == 2, etc. But it's not clear to me how the skipping across the values of C can be generalised.
I have a list or a vector V of n nonnegative integers. There are some positive integers that are equal and adjacent, say V=[2, 3, 3, 0, 0]. (I do not care about the zero integer.)
I would like to find all unique permutations of V such that all the same and positive integers remain adjacent. How to write an algorithm for this? (For an implementation, you can choose Python or Matlab or any other language.)
Under Matlab and for the example of V=[2, 3, 3, 0, 0], I get all the unique permuations as follows:
V = [2, 3, 3, 0, 0];
unique(perms([2, 3, 3, 0, 0]), 'rows')
and I get:
0 0 2 3 3
0 0 3 2 3
0 0 3 3 2
0 2 0 3 3
0 2 3 0 3
0 2 3 3 0
0 3 0 2 3
0 3 0 3 2
0 3 2 0 3
0 3 2 3 0
0 3 3 0 2
0 3 3 2 0
2 0 0 3 3
2 0 3 0 3
2 0 3 3 0
2 3 0 0 3
2 3 0 3 0
2 3 3 0 0
3 0 0 2 3
3 0 0 3 2
3 0 2 0 3
3 0 2 3 0
3 0 3 0 2
3 0 3 2 0
3 2 0 0 3
3 2 0 3 0
3 2 3 0 0
3 3 0 0 2
3 3 0 2 0
3 3 2 0 0
As you may know, I get 30 such permutations. Among these 30, there are 18 that do not respect the constraint of adjacency. For example, [3, 2, 3, 0, 0] can not be in the final result because 3 is no longer adjacent to 3. Finally, all unique permutations can be given by:
0 0 2 3 3
0 0 3 3 2
0 2 0 3 3
0 2 3 3 0
0 3 3 0 2
0 3 3 2 0
2 0 0 3 3
2 0 3 3 0
2 3 3 0 0
3 3 0 0 2
3 3 0 2 0
3 3 2 0 0
The first idea (and the simplest) that came to my mind is to generate all unique permutations like so and then, for each one, verify the constraint. But is there any other efficient algorithm?
We can first compress the given array so that there is just one entry for every positive number, while keeping a count of how many times each number occurred (the zeroes should be left as is).
Generate the permutations of the compressed array.
Decompress each of the permutation and retain only the unique ones.
To Compress
def compress(arr):
counts = {}
compressed = []
curr_ele = arr[0]
count_ele = 0
for ele in arr:
if ele != curr_ele or ele == 0:
counts[curr_ele] = count_ele
compressed.append(curr_ele)
count_ele = 1
curr_ele = ele
else:
count_ele += 1
counts[curr_ele] = count_ele
compressed.append(curr_ele)
return compressed, counts
To Uncompress
def uncompress(arr, counts):
res = []
for ele in arr:
if ele == 0:
res.append(0)
continue
num_reps = counts[ele]
for _ in range(num_reps):
res.append(ele)
return res
Putting it together: Compress, Permute, Uncompress and Retain Unique
import itertools
ip = [2, 3, 3, 0, 0]
ip_compressed, counts = compress(ip)
set([tuple(uncompress(perm, counts)) for perm in itertools.permutations(ip_compressed)])
Result:
{(0, 0, 2, 3, 3),
(0, 0, 3, 3, 2),
(0, 2, 0, 3, 3),
(0, 2, 3, 3, 0),
(0, 3, 3, 0, 2),
(0, 3, 3, 2, 0),
(2, 0, 0, 3, 3),
(2, 0, 3, 3, 0),
(2, 3, 3, 0, 0),
(3, 3, 0, 0, 2),
(3, 3, 0, 2, 0),
(3, 3, 2, 0, 0)}
A simple algorithm is:
1.traverse the initial table and make another table with two rows like:
input: V = [2, 3, 3, 0, 0];
new array: V2 = |2,3,0|
|1,2,2|
As you can see V2 comes from V keeping one time the elements and in second row counting how many times we have seen them.
Now generate all permutations of columns
And for every result e.g:
V2 = |3,2,0|
|2,1,2|
you have kept how many times the elements appear.
I have two 3D objects in space and i want to copy the points from one object to another. The problem is that these objects don't share a common coordinate system and i have to do coordinate transformations. I have the local transformation matrix for both objects and i have also access to the world transformation matrix. I know there's some calculations to be done using these transformation matrices but i don't know how.
How can i transform one point in the first object so that it has the same position(relative to the world coordinates) if i copy it in the other object( or its coordinate system )?
Thanks
Well, you have to apply the conversion operator that you have.
E.g., the relation between polar (r, t) and cartesian (x, y) coordinates is defined by:
x = rcost
y = rsint
I'm about 9 years late but I had to solve the same problem.
Use a homogeneous transformation matrix. To do this first calculate a 4x4 rotation matrix using the unit vectors describing the local cs using values with respect to the global cs. Then calculate a similar 4x4 translation matrix. Then the transformation matrix is simply the dot product of the translation and rotation matrices. Calculating the inverse of a homogeneous transformation matrix is not quite so simple. I found the University of Illinois robotics class notes helped me understand what was required. Of course the details can really trip you up so I feel compelled to render the details as python code.
Let's call the following code "transform_coord_sys.py":
# Functions to convert points etc from one coordinate system to another
#
# These functions are based on a 4x4 homogeneous matrices or
# homogeneous coordinates introduced by August Ferdinand Möbius
# See: https://en.wikipedia.org/wiki/Homogeneous_coordinates
#
# Other work I found useful in developing this code includes:
# University of Illinois Robotics course http://motion.cs.illinois.edu/RoboticSystems/CoordinateTransformations.html
import numpy as np
def unit_vector(xyz_array):
"""
Compute unit vector of vector from origin to specified xyz point
:param xyz_array: numpy array of length 3. x = 1st element, y = 2nd element, z = 3rd element
:return: xyz_unit : unit vector (ie ijk) in specified direction
"""
num_xyz = len(xyz_array)
if num_xyz != 3:
raise ValueError('Input array to "unit_vector" must have length of 3.')
xyz_unit = xyz_array / np.linalg.norm(xyz_array)
return xyz_unit
def create_rotation_matrix_from_points(local_origin, local_x_dir, local_xy_plane):
"""
Create a 4x4 homogeneous rotation matrix
:param local_origin: np_array of x,y,z wrt global cs
:param local_x_dir: np_array of x,y,z point. vector from local_origin to this point defines X
:param local_xy_plane: point in xy plane
:return: rot_matrix: homogeneous rotation matrix
"""
local_x_vec = local_x_dir - local_origin
local_unit_x = unit_vector(local_x_vec)
local_xy_vec = local_xy_plane - local_origin
local_z_vec = np.cross(local_x_vec, local_xy_vec)
local_unit_z = unit_vector(local_z_vec)
local_y_vec = np.cross(local_z_vec, local_x_vec)
local_unit_y = unit_vector(local_y_vec)
# print('local_unit_x = {}'.format(local_unit_x))
# print('local_unit_y = {}'.format(local_unit_y))
# print('local_unit_z = {}'.format(local_unit_z))
rot_matrix = np.zeros((4, 4))
rot_matrix[3, 3] = 1.0
rot_matrix[0:3, 0] = local_unit_x
rot_matrix[0:3, 1] = local_unit_y
rot_matrix[0:3, 2] = local_unit_z
determinant = np.linalg.det(rot_matrix)
assert np.isclose(determinant, 1.0)
# print('rot_matrix = \n{}'.format(rot_matrix))
# print('determinant = {}\n'.format(determinant))
return rot_matrix
def create_translation_matrix_from_point(point, origin=np.zeros(3)):
"""
Create a 4x4 homogeneous translation matrix
:param point: np_array of x,y,z wrt global cs
:param origin: np_array of x,y,z point. vector from local_origin to this point defines X
:return: translation_matrix : homogeneous translation matrix
"""
translation_matrix = np.identity(4)
deltas = point - origin
translation_matrix[0:3, 3] = deltas
# print('translation_matrix = \n{}'.format(translation_matrix))
return translation_matrix
def invert_homogeneous_transformation_matrix(transformation_matrix):
"""
Invert a homogeneous transformation matrix
:param transformation_matrix: homogeneous transformation matrix
:return: inverse_transform: inverted matrix
"""
rot_matrix = transformation_matrix[0:3, 0:3]
translation = transformation_matrix[0:3, 3]
# for orthogonal arrays the transpose is equal to the inverse
rot_inverse = rot_matrix.transpose()
trans_inv = -rot_inverse.dot(translation)
inverse_transform = np.identity(4)
inverse_transform[0:3, 0:3] = rot_inverse
inverse_transform[0:3, 3] = trans_inv
return inverse_transform
def calculate_homogeneous_transforms(local_origin, local_x_dir, local_xy_plane):
rot_matrix_4x4 = create_rotation_matrix_from_points(local_origin, local_x_dir, local_xy_plane)
translation_matrix = create_translation_matrix_from_point(local_origin)
# This is the key step showing how the transformation_matrix is created
# using matrix multiplication of the translation and rotation matrices.
# Order is CRITICAL:
# translation_matrix.dot(rot_matrix_4x4) IS NOT EQUAL TO rot_matrix_4x4.dot(translation_matrix)
# (except it trivial cases where it provides the correct answer but is still wrong)
transformation_matrix = translation_matrix.dot(rot_matrix_4x4)
inverse_transform = invert_homogeneous_transformation_matrix(transformation_matrix)
return transformation_matrix, inverse_transform
def test_pure_rotation():
print('{}'.format('-'*80))
print('testing test_pure_rotation')
local_origin = np.asarray([0.0, 0.0, .0])
local_x_dir = np.asarray([0.0, 1.0, 0.0])
local_xy_plane = np.asarray([-1.0, 1.0, 0.0])
print(' local_origin = {}'.format(local_origin))
print(' local_x_dir = {}'.format(local_x_dir))
print(' local_xy_plane = {}'.format(local_xy_plane))
transformation_matrix, inverse_transform = calculate_homogeneous_transforms(local_origin,
local_x_dir,
local_xy_plane)
tm_str = ' {}'.format(transformation_matrix)
tm_str = tm_str.replace('\n', '\n ')
print('\n transformation_matrix = \n{}'.format(tm_str))
point = np.asarray([1.0, 1.0, 2, 1.0])
point_local = inverse_transform.dot(point)
print('\n point {} in local cs = {}'.format(point, point_local))
point_global = transformation_matrix.dot(point_local)
print(' local point {} in global cs = {}\n'.format(point_local, point_global))
assert np.isclose(point, point_global).all()
assert np.isclose(point_local, [1.0, -1, 2, 1.]).all()
print(' Successfully completed test of test_pure_rotation\n')
return None
def test_pure_translation():
print('{}'.format('-'*80))
print('testing test_pure_translation')
local_origin = np.asarray([0.0, 0.0, 1.0])
local_x_dir = np.asarray([1.0, 0, 1.0])
local_xy_plane = np.asarray([0.0, 1.0, 1.0])
print(' local_origin = {}'.format(local_origin))
print(' local_x_dir = {}'.format(local_x_dir))
print(' local_xy_plane = {}'.format(local_xy_plane))
transformation_matrix, inverse_transform = calculate_homogeneous_transforms(local_origin,
local_x_dir,
local_xy_plane)
tm_str = ' {}'.format(transformation_matrix)
tm_str = tm_str.replace('\n', '\n ')
print('\n transformation_matrix = \n{}'.format(tm_str))
point = np.asarray([1.0, 1.0, 0, 1.0])
point_local = inverse_transform.dot(point)
print('\n point {} in local cs = {}'.format(point, point_local))
point_global = transformation_matrix.dot(point_local)
print(' local point {} in global cs = {}\n'.format(point_local, point_global))
assert np.isclose(point, point_global).all()
assert np.isclose(point_local, [1.0, 1, -1, 1.]).all()
print(' Successfully completed test of test_pure_translation\n')
return None
def test_rotation_and_translation():
print('{}'.format('-'*80))
print('testing test_rotation_and_translation')
local_origin = np.asarray([1.0, 1.0, 1.0])
local_x_dir = np.asarray([.0, 1, 1.0])
local_xy_plane = np.asarray([1.0, 2.0, 1.0])
print(' local_origin = {}'.format(local_origin))
print(' local_x_dir = {}'.format(local_x_dir))
print(' local_xy_plane = {}'.format(local_xy_plane))
transformation_matrix, inverse_transform = calculate_homogeneous_transforms(local_origin,
local_x_dir,
local_xy_plane)
tm_str = ' {}'.format(transformation_matrix)
tm_str = tm_str.replace('\n', '\n ')
print('\n transformation_matrix = \n{}'.format(tm_str))
point = np.asarray([-1.0, 2.0, 2, 1.0])
# point = np.asarray([1.0, 1.0, 1, 1.0])
# point = np.asarray([0.0, 0.0, 1, 1.0])
point_local = inverse_transform.dot(point)
print('\n point {} in local cs = {}'.format(point, point_local))
point_global = transformation_matrix.dot(point_local)
print(' local point {} in global cs = {}\n'.format(point_local, point_global))
assert np.isclose(point, point_global).all()
assert np.isclose(point_local, [2.0, 1, -1, 1.]).all()
print(' Successfully completed test of test_rotation_and_translation\n')
return None
if __name__ == '__main__':
test_pure_rotation()
test_pure_translation()
test_rotation_and_translation()
print('')
Now the test cases result in very simple output and show how a single point can be transformed from one coordinate system to the other.
--------------------------------------------------------------------------------
testing test_pure_rotation
local_origin = [0. 0. 0.]
local_x_dir = [0. 1. 0.]
local_xy_plane = [-1. 1. 0.]
transformation_matrix =
[[ 0. -1. 0. 0.]
[ 1. 0. 0. 0.]
[ 0. 0. 1. 0.]
[ 0. 0. 0. 1.]]
point [1. 1. 2. 1.] in local cs = [ 1. -1. 2. 1.]
local point [ 1. -1. 2. 1.] in global cs = [1. 1. 2. 1.]
Successfully completed test of test_pure_rotation
--------------------------------------------------------------------------------
testing test_pure_translation
local_origin = [0. 0. 1.]
local_x_dir = [1. 0. 1.]
local_xy_plane = [0. 1. 1.]
transformation_matrix =
[[1. 0. 0. 0.]
[0. 1. 0. 0.]
[0. 0. 1. 1.]
[0. 0. 0. 1.]]
point [1. 1. 0. 1.] in local cs = [ 1. 1. -1. 1.]
local point [ 1. 1. -1. 1.] in global cs = [1. 1. 0. 1.]
Successfully completed test of test_pure_translation
--------------------------------------------------------------------------------
testing test_rotation_and_translation
local_origin = [1. 1. 1.]
local_x_dir = [0. 1. 1.]
local_xy_plane = [1. 2. 1.]
transformation_matrix =
[[-1. 0. 0. 1.]
[ 0. 1. 0. 1.]
[ 0. 0. -1. 1.]
[ 0. 0. 0. 1.]]
point [-1. 2. 2. 1.] in local cs = [ 2. 1. -1. 1.]
local point [ 2. 1. -1. 1.] in global cs = [-1. 2. 2. 1.]
Successfully completed test of test_rotation_and_translation
To use the code for multiple points at a time we can call the following code "example_transform_cs.py".
import numpy as np
import matplotlib.pyplot as plt
import transform_coord_sys as tcs
if __name__ == '__main__':
local_origin = np.asarray([1.0, 1.0, 1.0])
local_x_dir = np.asarray([0, 1, 1.0])
# local_x_dir = np.asarray([-7, 2, -3])
local_xy_plane = np.asarray([1.0, 2.0, 1.0])
print(' local_origin = {}'.format(local_origin))
print(' local_x_dir = {}'.format(local_x_dir))
print(' local_xy_plane = {}'.format(local_xy_plane))
transformation_matrix, inverse_transform = tcs.calculate_homogeneous_transforms(local_origin,
local_x_dir,
local_xy_plane)
tm_str = ' {}'.format(transformation_matrix)
tm_str = tm_str.replace('\n', '\n ')
print('\n transformation_matrix = \n{}'.format(tm_str))
# all points have an extra dimension with the fourth item set to 1.0
# this is to make them compatible with homogeneous transforms
point = np.asarray([.4, 0.6, 0.7, 1.0])
point_local = inverse_transform.dot(point)
print('\n point {} in local cs = {}'.format(point, point_local))
point_global = transformation_matrix.dot(point_local)
print(' local point {} in global cs = {}\n'.format(point_local, point_global))
global_cs_line_x = np.asarray([0.0, 1.0, 0.0, 0.0, 0.0])
global_cs_line_y = np.asarray([0.0, 0.0, 1.0, 0.0, 0.0])
global_cs_line_z = np.asarray([0.0, 0.0, 0.0, 0.0, 1.0])
global_homogenous = np.ones(len(global_cs_line_x))
global_cs_3d = np.concatenate((global_cs_line_x, global_cs_line_y,
global_cs_line_z, global_homogenous)).reshape((4, 5))
local_cs_3d = transformation_matrix.dot(global_cs_3d)
ax = plt.figure().add_subplot(projection='3d')
ax.plot(global_cs_line_x, global_cs_line_y, global_cs_line_z, label='global_cs')
ax.plot(local_cs_3d[0, :], local_cs_3d[1, :], local_cs_3d[2, :], label='local_cs')
ax.plot(point[0], point[1], point[2], label='point', marker='x', markersize=14)
fig = plt.gcf()
text = 'Point\nGlobal CS {}\nLocal CS {}'.format(point[0:3], point_local[0:3])
fig.text(.1, .9, text, fontsize=8)
# ax.set_box_aspect((np.ptp(xs), np.ptp(ys), np.ptp(zs))) # aspect ratio is 1:1:1 in data space
ax.set_box_aspect((1., 1., 1.)) # aspect ratio is 1:1:1 in data space
ax.legend()
plt.show()
The code creates a simple line representation of the unit vectors representing the global coordinate system and then transforms the data to a local coordinate system. A single point is expressed in both the global and local coordinate systems. Of course a picture really helps me to understand what is happening and if it is working correctly.
Have a good day and pay it forward.