R/rsvd_align.R

Defines functions rsvd_align

Documented in rsvd_align

#' Align singular vectors with majority of data vectors for randomized SVD.
#' @description Singular value decomposition is specified up to the sign (+/-) of the singular vectors.
#' This algorithm attempts to align the singular vectors with the majority of vectors of the input matrix.
#' @usage svd_align(x, r = NA)
#' @param x A data matrix.
#' @param r An integer; number of columns to include as a reduced rank SVD solution. Defaults to full rank.
#' @return \code{svd_flip} Aligned svd
#' @references Bro, R., Acar, E., & Kolda, T. G. (2008). Resolving the sign ambiguity in the singular value decomposition. Journal of Chemometrics: A Journal of the Chemometrics Society, 22(2), 135-140.
#' @examples
#' # Generate data
#' x <- cbind(runif(10, -0.5, 2), runif(10, -0.5, 2))
#'
#'
#' svd_flip <- svd_align(x)
#'
#' # Extract components of svd and plot
#' U <- svd_flip$u
#' Sigma <- svd_flip$d
#' VT <- t(svd_flip$v)
#'
#' # Plot data
#' plot(0, 0, xlim=c(-2,2), ylim=c(-2,2), type="n")
#'
#' for (i in 1:dim(x)[1]){
#'   arrows(0, 0, x[i,1], x[i,2], lwd=2)
#' }
#'
#' arrows(0, 0, VT[1, 1], VT[1, 2], col='red')
#'
#' @export
rsvd_align <- function(x, r = NA) {
  
  # Perform rsvd
  
  svd_flip <- rsvd::rsvd(x,k=r,nu=r, nv=r, p=10,q=2,sdist="normal")
  U <- svd_flip$u
  Sigma <- svd_flip$d
  VT <- t(svd_flip$v)
  Sigma_mat <- diag(Sigma)
  
  
  Y <- matrix(NA, dim(x))
  
  # Svd signflip algorithm
  for(k in 1:dim(Sigma_mat)[1]){
    k = 1
    Sigma_mat_k = diag(Sigma)
    Sigma_mat_k[k,k] = 0
    
    # Correction for correlations
    Y <- x - U %*% Sigma_mat_k %*% VT
    
    # Calculate left and right signs
    UY <- t(U[,k]) %*% Y
    VTY <- VT[k,] %*% t(Y)
    sleft <- sign(UY)%*%t(UY**2)
    sright <- sign(VTY)%*%t(VTY**2)
    
    if(sleft*sright < 0){
      if(sleft < sright){
        sleft <- -sleft
      }
      else{
        sleft <- -sright
      }
    }
    
    # Update the signs for the kth left and right singular vector
    U[,k] <- U[,k] %*% sign(sleft)
    VT[k,] <- VT[k,] %*% sign(sright)
  }
  
  # Modify signs in svd object and return
  svd_flip$u <- U
  svd_flip$v <- t(VT)
  svd_flip$d <- Sigma
  
  return(svd_flip)
}


# Copyright 2021 Robert Glenn Moulder Jr., Elena Martynova, & Shashwat Kumar
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
RobertGM111/havok documentation built on July 8, 2023, 8:23 p.m.