code: def trRV(X=None, V=None):
      """
      If V is None it defaults to identity.
  
      If X is None, it defaults to the 0-dimensional subspace,
      i.e. R is the identity.
  
      >>> import numpy as np
      >>> from numpy.random import standard_normal
      >>>
      >>> X = standard_normal((100, 4))
      >>> np.allclose(trRV(X), (96.0, 96.0))
      True
      >>> V = np.identity(100)
      >>> np.allclose(trRV(X), (96.0, 96.0))
      True
      >>>
      >>> X[:,3] = X[:,1] + X[:,2]
      >>> np.allclose(trRV(X), (97.0, 97.0))
      True
      >>>
      >>> u = orth(X)
      >>> V = np.dot(u, u.T)
      >>> print(np.allclose(trRV(X, V), 0))
      True
      """
      n, p = X.shape
  
      if V is None:
          V = np.identity(n)
  
      if X is None:
          if V is None:
              trRV = trRVRV = n
          else:
              trRV = _trace(V)
              trRVRV = _frobenius(V, V)
      else:
          u = orth(X)
          if V is None:
              trRV = trRVRV = n - u.shape[1]
          else:
              Vu = np.dot(V, u)
              utVu = np.dot(u.T, Vu)
              trRV = _trace(V) - _frobenius(u, Vu)
              trRVRV = (
                  _frobenius(V, V)
                  - 2 * _frobenius(Vu, Vu)
                  + _frobenius(utVu, utVu)
              )
  
      return trRV, trRVRV
  
imports: import numpy
  from numpy.linalg import svd
  from .reml import orth
label_desc: Use image node_id 3 for calling a global function with example usage: trRV(X, V) and returns: trRV,  trRVRV