Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can two parametrizations be used in the same tensor? #42

Open
dherrera1911 opened this issue Feb 12, 2024 · 1 comment
Open

Can two parametrizations be used in the same tensor? #42

dherrera1911 opened this issue Feb 12, 2024 · 1 comment

Comments

@dherrera1911
Copy link

dherrera1911 commented Feb 12, 2024

Hello,

I am wondering whether two parametrizations can be used on a same tensor. In particular, I want to parametrize a matrix to be both positive definite and in the SL group.

In the example below, I create a class with a matrix that should be both PSD and SLN:

class PrNorm(torch.nn.Module):
    def __init__(self, nDim):
        super().__init__()
        self.B = nn.Parameter(torch.eye(nDim, requires_grad=True))
        geotorch.positive_semidefinite(self, "B")
        geotorch.sln(self, "B")

    def forward(self, x):
        quadratic = torch.einsum('i,ij,j->', x, self.B, x)
        return quadratic

prnorm = PrNorm(nDim)

However, I get the following error when I initialize the class:

InManifoldError: Tensor not contained in PSSD(
  n=7
  (0): Stiefel(n=7, k=7, triv=linalg_matrix_exp)
  (1): Rn(n=7)
). Got

I think that the parametrized tensor gets re-initialized by SLN, and so it is no longer PSD, leading to the error. Is there some way to do something as intended here with geotorch?

@lezcano
Copy link
Owner

lezcano commented Feb 13, 2024

Alas, these parametrisations are not compositional as-is, but it shouldn't be too difficult to implement your own.
Note that the class PSD is implemented in terms of the class PSSDFixedRank by fixing the rank to be the highest and choosing a particular transformation like softplus

class PSD(PSSDFixedRank):

On the other hand, sl(n) is implemented in a similar way, but tweaking the function that's used to define the eigenvalues (we normalise them so that their product is one):

geotorch/geotorch/sl.py

Lines 31 to 42 in ba38d40

@staticmethod
def parse_f(f_name):
if f_name in FixedRank.fs.keys():
f, inv = FixedRank.parse_f(f_name)
def f_sl(x):
y = f(x)
return y / y.prod(dim=-1, keepdim=True).pow(1.0 / y.shape[-1])
return (f_sl, inv)
else:
return f_name

As such, you can inherit from PSD and implement your own class where you pass in a normalised function like we do in SL(n) to the parent class. You'll also need to implement the method in_manifold_eigen and sample, similar to how SL(n) does it.

Please reach out if there is anything that's not clear :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants