docstr: Test that it is possible to initialize a parametrization when it
  implements a `right_inverse` method
docstr_tok: ["Test","that","it","is","possible","to","initialize","a","parametrization","when","it","implements","a","`","right_inverse","`","method"]
code: def test_initialization_parametrization(self):
      r"""Test that it is possible to initialize a parametrization when it
      implements a `right_inverse` method
      """
  
      class Skew(nn.Module):
          def forward(self, X):
              A = X.triu(1)
              return A - A.T
  
          def is_skew(self, A):
              return torch.allclose(A, -A.T, atol=1e-6)
  
          def right_inverse(self, X):
              if not self.is_skew(X):
                  raise ValueError("The matrix is not skew-symmetric.")
              return X.triu(1)
  
      # Implements a Cayley map where right_inverse is not quite the inverse of forward
      class Orthogonal(nn.Module):
          def __init__(self, n):
              super().__init__()
              self.register_buffer("B", torch.eye(n))
  
          def forward(self, X):
              Id = torch.eye(X.size(0))
              return self.B @ torch.linalg.solve(Id + X, Id - X)
  
          def is_orthogonal(self, X):
              Id = torch.eye(X.size(0))
              return torch.allclose(X.T @ X, Id, atol=1e-4)
  
          def right_inverse(self, X):
              if not self.is_orthogonal(X):
                  raise ValueError("The input is not orthogonal.")
              # cayley(0) == Id, so B @ cayley(0) == B
              self.B = X
              return torch.zeros_like(X)
  
      N = 5
      model = nn.Linear(N, N)
      # Register the skew-symmetric constraint. The result is now skew-symmetric
      skew = Skew()
      # Make the weight skew-symmetric before registering the parametrization
      with torch.no_grad():
          model.weight.set_(skew(model.weight))
      parametrize.register_parametrization(model, "weight", skew)
      X = torch.rand(N, N)
      # X is not skew-symmetric, so it throws an error
      with self.assertRaises(ValueError):
          model.weight = X
      # Make X skew-symmetric
      X = X - X.T
      model.weight = X
      self.assertEqual(
          model.parametrizations.weight.original, X.triu(1)
      )
      self.assertEqual(model.weight, X)
  
      # Having several parametrizations registered should work in the same way
      parametrize.register_parametrization(
          model, "weight", Orthogonal(N)
      )
      # Register now the Cayley map. The result is now orthogonal
      X = torch.rand(N, N)
      # X is not orthogonal, so it throws an error
      with self.assertRaises(ValueError):
          model.weight = X
      init.orthogonal_(X)
      model.weight = X
      self.assertEqual(model.weight, X)
      self.assertEqual(
          model.parametrizations.weight.original, torch.zeros_like(X)
      )
  
imports: from copy import deepcopy
  from itertools import product
  import pickle
  import torch
  import torch.nn
  import torch.nn.functional
  import torch.nn.init
  import torch.nn.utils.parametrize
  from torch.nn import Parameter
  from torch.testing._internal.common_utils import run_tests, skipIfNoLapack, TemporaryFileName, instantiate_parametrized_tests, set_default_dtype
  from torch.testing._internal.common_device_type import instantiate_device_type_tests
  from torch.testing._internal.common_cuda import TEST_MULTIGPU
  from torch.testing._internal.common_nn import NNTestCase
  from torch.testing._internal.common_utils import gradcheck
label_desc: Use image node_id 5 for calling the TestNNParametrization obj's underlying member method code with example usage: obj.test_initialization_parametrization() and returns: unknown, torch, X, unknown, torch, torch