0

Say I have orthogonal vectors of dimension n. I have two questions:

  1. How to create/initialize n such orthogonal vectors in python using the existing packages (numpy, scipy, pytorch etc)? Ideally these basis vectors should be as random as possible given the constraints, that is avoiding values such as 1,0,-1 as much as possible.
  2. How can I rotate them by an angle alpha so that they remain orthogonal in high dimensional space? Again, I would like to do this in python, preferably using existing implementation in some of the packages.
sanjas
  • 125
  • 1
  • 8
  • Just create an n dimensional rotation matrix and multiply your basis vectors with it. What exactly is unclear about this? – Nils Werner Jul 25 '20 at 14:33
  • The question about initialization is very broad. There are many ways to construct an orthogonal matrix, it just depends on your needs. What is the goal? – bnaecker Jul 25 '20 at 16:50
  • @NilsWerner I am familiar with the rotation matrix for `n=2` and `n=3`. I am asking how to do this for a general `n`. – sanjas Jul 25 '20 at 18:19
  • @bnaecker I edited the question to answer your comment – sanjas Jul 25 '20 at 18:20

3 Answers3

1

You could do a QR decomposition of a random matrix, and set the R-component to zero. This will yield a random orthogonal matrix.

Vary one of the Givens angles in the Q components and you get a random rotation.

Nils Werner
  • 28,291
  • 6
  • 62
  • 82
  • thanks for your answer. Can you explain what do you mean by "Vary one of the Givens angles in the Q components"? Also, I actually don't need a random rotation, but one with angle `alpha`. Is this feasible? – sanjas Jul 25 '20 at 19:47
1

I have an answer to your first question and some thoughts on how to approach the second.

1.

import numpy as np

#let's say we're working in 5-D space
n = 5

#set of orthogonal basis vectors
basis_vectors = []

for _ in range(n):
    vector = np.random.randn(n)
    for basis_vector in basis_vectors:
        vector -= basis_vector.dot(vector) * vector
    #uncomment following to make basis orthonormal
    #vector /= np.linalg.norm(rotation_axis)
    basis_vectors.append(vector)

for a_i in range(n):
    for b_i (a_i + 1, n):
        assert np.allclose(basis_vectors[a_i].dot(basis_vectors[b_i]), 0)

Because you want to rotate both vectors in the same manner, there must be a way to preserve information on the way each rotation is carried out (e.g. rotation matrix, rotation quaternion).

Preexisting implementations of 3D Rotation matrices include the Scipy function scipy.spatial.transform.Rotation.from_rotvec and Python's quaternion module (see henneray's answer), but these are only for 3D vectors. Unless I've overlooked something, it'd be necessary to implement ND rotation from scratch.

Here's a general outline of the steps I would take:

  • Find 2 linearly independent ND basis vectors of the 2D plane in which you want to rotate the two vectors. (the vectors you want to rotate, a and b, aren't necessarily on this plane)
  • Find the remaining (N-2)D basis vectors that are linearly independent to these first 2 vectors. Combined the N basis vectors should span the ND space.
  • Break up each of the two N-D orthogonal vectors you want to rotate into the sum of two vectors: 1) the vectors' projections onto the 2D plane you've constructed and 2) the "remainder" of the vector that doesn't fall on the 2D plane. Set this "remainder" aside for now.
  • Perform a change of basis on the projected N-D vectors so that they can be expressed as the product of a 2D vector and an Nx2 matrix, which has its columns set to each of the corresponding basis vectors calculated. Keep in mind that the 2D vector is now in a modified coordinate space, not the original.
  • Construct the 2D rotation matrix corresponding to the desired rotation within the 2D plane identified in the first step. Perform the rotation transformation on the 2D vectors.
  • Transform the rotated 2D vectors back into ND vectors in the main coordinate system by multiplying the by the Nx2 matrix.
  • Add the "remainder" set aside earlier back to the mapped ND vector.
  • The resulting two vectors have been rotated by an arbitrary angle on a particular 2D plane, but maintain orthogonality.

I hope these ideas help you. Take care.

  • Thanks for your answer! I think it wasn't clear in my original question, but I need an orthogonal (potentially orthonormal basis), so that would be a square matrix of dimension n. I found a scipy function that can do 1, though it seems 2 is not easy. – sanjas Jul 25 '20 at 20:37
  • 1
    @sanjas Ah I see. I just updated the answer for consistency with providing n basis vectors. Good luck! – Ravit Sharma Jul 25 '20 at 22:17
0

I found a scipy function that can do 1, ortho_group, still wondering about 2.

>>> from scipy.stats import ortho_group
>>> m = ortho_group.rvs(dim=4)
>>> m
array([[-0.25952499,  0.435163  ,  0.04561972,  0.86092902],
       [-0.44123728, -0.38814758, -0.80217271,  0.10568846],
       [ 0.16909943, -0.80707234,  0.35548632,  0.44007851],
       [-0.8422362 , -0.0927839 ,  0.47756387, -0.23229737]])
>>> m.dot(m.T)
array([[ 1.00000000e+00, -1.68203864e-16,  1.75471554e-16,
         9.74154717e-17],
       [-1.68203864e-16,  1.00000000e+00, -1.18506045e-16,
        -1.81879209e-16],
       [ 1.75471554e-16, -1.18506045e-16,  1.00000000e+00,
         1.16692720e-16],
       [ 9.74154717e-17, -1.81879209e-16,  1.16692720e-16,
         1.00000000e+00]])

sanjas
  • 125
  • 1
  • 8