Thank you for your interest.
My specific use case is that I have an auto-encoder whose bottleneck embedding layer is hyperbolic. I’m adding noise to that embedding as a regularizer.
I have a specific kind of noise in mind which is very straight forward to describe. Grab a point, drag it either toward the middle of the disk or out toward the edge. Don’t change the angle or sign.
I’ve made progress on this problem in the two-dimensional case. I convert euclidian coordinates to polar coordinates, which give a radius and an angle. I then add/substract to the radius, and then convert back.
That was a very straightforward hack in 2d, but it may not have been the most efficient. I also don’t know how to generalize it to N-dimensions.
Here’s the functions I found for doing the conversion

  
      github.com
  
  
    PyAbel/PyAbel/blob/master/abel/tools/polar.py 5
# -*- coding: utf-8 -*-

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import numpy as np
from scipy.ndimage import map_coordinates
from scipy.ndimage.interpolation import shift
from scipy.optimize import curve_fit, minimize


def reproject_image_into_polar(data, origin=None, Jacobian=False,
                               dr=1, dt=None):
    """
    Reprojects a 2D numpy array (``data``) into a polar coordinate system.
    "origin" is a tuple of (x0, y0) relative to the bottom-left image corner,
    and defaults to the center of the image.



  This file has been truncated. show original

  
  
    
    
  
  


def cart2polar(x, y):
r = torch.sqrt(x2 + y2).to(device)
theta = torch.atan2(y, x).to(device)
return r, theta
def polar2cart(r, theta):
y = r * torch.cos(theta).to(device)   # θ referenced to vertical
x = r * torch.sin(theta).to(device)
return x, y
And here’s the code in the forward pass that applies the noise
if self.training:
            new= cart2polar(x[:, 0], x[:, 1])
            r=new[0]
            angle=new[1]          
            distribution = torch.distributions.uniform.Uniform(torch.tensor([0.0]).to(device) , torch.tensor([1.0]).to(device) ) #reducing it to .5 noise
            r_new =  torch.sqrt( ( r - torch.t(distribution.sample(torch.Size([len(r)]))) ) **2).to(device)            
            converted = polar2cart(r_new,angle) #It returns x1 first and then x1
            x_new=x.clone()
            x_new[:,0]=converted[1] #these need to be inverted
            x_new[:,1]=converted[0]