tests/testthat/test_SOManifold.R

# devtools::load_all()
library(testthat)


test_that('Helper functions for SO(n) works', {
  
  # isSkewSym
  expect_true(isSkewSym(0))
  expect_false(isSkewSym(1))
  expect_true(isSkewSym(matrix(c(0, 1, -1, 0), 2, 2)))
  expect_false(isSkewSym(matrix(c(0, 1, 1, 0), 2, 2)))
  expect_true(isSkewSym(0.01, tol=0.1))
  expect_false(isSkewSym(0.1, tol=0.01))

  # isOrth
  expect_true(isOrth(1))
  expect_false(isOrth(0))
  expect_true(isOrth(diag(2)))
  expect_true(isOrth(diag(c(1, -1))))
  expect_false(isOrth(diag(2) + 0.1))

  # isSO
  expect_true(isSO(diag(2)))
  expect_false(isSO(diag(c(1, -1))))

  # NearestOrth
  set.seed(1)
  d <- 3
  A <- matrix(rnorm(d^2), d, d)
  O1 <- NearestOrth(A)
  expect_true(isOrth(O1))

  # NearestSO
  set.seed(1)
  d <- 3
  A <- matrix(rnorm(d^2), d, d)
  B <- diag(d)
  SO1 <- project.SO(p=cbind(c(A), c(B)))
  expect_true(isSO(matrix(SO1[, 1], d, d)))
  expect_equal(SO1[, 2], c(B))

  # MakeSkewSym
  set.seed(1)
  v <- c(1, 2, 3) / 10
  A <- matrix(c(0, -v[1], -v[2],
                v[1], 0, -v[3],
                v[2], v[3], 0), 3, 3, byrow=TRUE)
  SSv <- MakeSkewSym(v)

  expect_equal(SSv, A)
  expect_equal(SSv + t(SSv), matrix(0, 3, 3))

  m <- 5
  pts <- seq(0, 1, length.out=m)
  v0 <- function(x) rep(0, length(x))
  v1 <- function(x) x * 2 
  v2 <- function(x) exp(- (x * 2 - 1/4)^2 * 3) - exp(- 3 / 16)
  F1 <- MakeSkewSymFunc(list(v1))
  F2 <- MakeSkewSymFunc(list(v0, v1, v2))
  Fpts1 <- sapply(F1, function(f) f(pts))
  Fpts2 <- sapply(F2, function(f) f(pts))
  Fmat1 <- lapply(seq_len(m), function(i) matrix(Fpts1[i, ], 2, 2))
  Fmat2 <- lapply(seq_len(m), function(i) matrix(Fpts2[i, ], 3, 3))

  # MakeSkewSymFunc
  expect_equal(sapply(Fmat1, `[`, 2, 1), v1(pts))
  expect_equal(sapply(Fmat1, `[`, 1, 2), -v1(pts))
  expect_equal(sapply(Fmat2, `[`, 3, 1), v1(pts))
  expect_equal(sapply(Fmat2, `[`, 1, 3), -v1(pts))
  expect_equal(sapply(Fmat2, `[`, 3, 2), v2(pts))
  expect_equal(sapply(Fmat2, `[`, 2, 3), -v2(pts))
  # Output is skew symmetric
  expect_true(all(sapply(Fmat1, isSkewSym)))
  expect_true(all(sapply(Fmat2, isSkewSym)))

  R1 <- MakeSOMat(v)
  # R2 <- MakeSOMat(c(0, 0, 0))
  R2 <- MakeSOMat(rep(0, 3))
  R3 <- MakeSOMat(rnorm(3))

  # MakeSOMat
  expect_equal(R1, ExpM(A)) # Make SO(n) matrix works
  expect_equal(R2, diag(3))
  expect_equal(crossprod(MakeSOMat(rnorm(6))), diag(4)) # orthogonal
  expect_equal(crossprod(MakeSOMat(rnorm(10))), diag(5)) # orthonormal

  # distSO
  # expect_equal(distSO(matrix(R1), matrix(R3)), 
  #              rotations::rot.dist(rotations::as.SO3(R1), 
  #                                  rotations::as.SO3(R3), 
  #                                  method='intrinsic'))
  expect_equal(distSO(matrix(R2), matrix(R2)), 0)
  # A <- crossprod(R1)
  # LogM(A, 'Eigen')
})


test_that('rieLog.SO, rieExp.SO, distance.SO works', {
  
  mfd <- structure(list(), class='SO')
  x <- c(1, 2, 1) / 5         
  y <- c(-2, 1, -1) / 5
  X <- MakeSOMat(x)
  Y <- MakeSOMat(y)

  # Example from matlab
  z <- matrix(c(1, 1, 0, 0, 0, 2, 0, 0, -1), 3, 3)
  Z <- matrix(c(2.718281828459046, 1.718281828459045, 1.086161269630488, 0, 1, 1.264241117657115, 0, 0, 0.367879441171442), 3, 3)
  A <- cbind(as.numeric(X), as.numeric(Y))

  w <- matrix(c(0, 1, 0, -1, 0, 2, 0, -2, 0) / 5, 3, 3, byrow=TRUE)
  W <- matrix(c(0.980331119030009, 0.193399683419916, 0.039337761939982, -0.193399683419915, 0.901655595150045, 0.386799366839831, 0.039337761939982, -0.386799366839831, 0.921324476120036), 3, 3, byrow=TRUE)

  expect_equal(ExpM(z), Z)
  # expect_equal(ExpM_old(z), Z)
  expect_equal(LogM(Z), z)
  # expect_equal(LogM_old(Z), z)
  expect_equal(ExpM(w), W)
  # expect_equal(ExpM_old(w), W)
  expect_equal(ExpMSO3(w), W)
  expect_equal(LogM(W), w)
  # expect_equal(LogM_old(W), w)
  expect_equal(LogMSO3(W), w)
  expect_equal(ExpMSO3(matrix(0, 3, 3)), diag(3))

  # An SPD example
  Z <- cov(matrix(rnorm(200), 20, 10))
  expect_equal(LogMSPD(Z), LogM(Z))
  # expect_equal(ExpM_old(LogMSPD(Z)), Z)

  # microbenchmark::microbenchmark(
    # armaSPD = LogMSPD(Z), 
    # arma = LogM(Z),
    # old = LogM_old(Z),
    # times=100
    # )
  # Z1 <- Z
  # Z1[1, 2] <- Z1[1, 2] + 1e-5
  # microbenchmark::microbenchmark(
    # armaSPD = ExpM(Z), 
    # arma = ExpM(Z1),
    # old = ExpM_old(Z),
    # times=1000
    # )
 
  expect_equal(LogM(X), LogMSO3(X))
  expect_equal(LogM(Y), LogMSO3(Y))
  expect_equal(rieLog.SO(mfd, as.numeric(X), as.numeric(X)), 
               matrix(0, 3, 1))
  expect_equal(c(rieLog.SO(mfd, as.numeric(diag(3)), as.numeric(X))), 
               matrix(LogM(X), ncol=1)[lower.tri(diag(3))])
  expect_equal(rieLog.SO(mfd, as.numeric(diag(3)), A), unname(cbind(x, y)))

  v1 <- c(-1, -0.5, -1)
  expect_equal(rieExp.SO(V=as.numeric(v1)), 
               matrix(ExpM(MakeSkewSym(v1)), ncol=1))
  expect_equal(rieExp.SO(V=cbind(as.numeric(v1), as.numeric(v1)))[, 1, drop=FALSE], 
               matrix(ExpM(MakeSkewSym(v1)), ncol=1))

  expect_equal(rieExp.SO(V=rieLog.SO(X=A)), A)
  expect_equal(rieExp.SO(mfd, as.numeric(X), rieLog.SO(mfd, as.numeric(X), A)), A)
  expect_equal(rieLog.SO(X=rieExp.SO(V=rieLog.SO(X=A))), unname(cbind(x, y)))

  expect_equal(rieExp(mfd, V=as.numeric(w[lower.tri(w)])), rieExp.SO(V=as.numeric(w[lower.tri(w)])))
  expect_equal(rieLog(mfd, X=as.numeric(W)), rieLog.SO(X=as.numeric(W)))

  set.seed(1)
  for (d in 2:3) {
    p0 <- if (d == 2) 1 else if (d == 3) 3
  for (i in 1:10) {
    mu <- rieExp.SO(V=rnorm(p0))
    Z <- matrix(rieExp.SO(p=mu, V=rnorm(p0)), d, d)
    expect_true(isSO(Z))
    V <- rieLog.SO(p=mu, X=as.numeric(Z))
    expect_equal(nrow(V), p0)
  }
  }

  # distance.SO
  expect_equal(distance.SO(mfd, as.numeric(X), as.numeric(X)), 0)
  expect_equal(distance.SO(mfd, as.numeric(X), as.numeric(X)), 0)
  expect_equal(distance.SO(mfd, as.numeric(X), as.numeric(diag(3)))^2, sum(x^2))
  expect_equal(distance.SO(mfd, as.numeric(X), as.numeric(Y))^2, 
               sum(rieLog.SO(p=as.numeric(X), X=as.numeric(Y))^2))
})


test_that('calcIntDim.SO, calcGeomPar.SO, calcTanDim.SO work', {

  mfd <- structure(1, class='SO')
  for (n in 2:4) {
    X <- diag(n)
    ambient <- length(X)
    intrinsic <- n * (n - 1) / 2
    tangent <- intrinsic

    expect_equal(calcGeomPar(mfd, dimTangent=tangent), n)
    expect_equal(calcIntDim(mfd, dimAmbient=ambient), intrinsic)
    expect_equal(calcIntDim(mfd, dimTangent=tangent), intrinsic)
    expect_equal(calcTanDim(mfd, dimAmbient=ambient), tangent)
    expect_equal(calcTanDim(mfd, dimIntrinsic=intrinsic), tangent)
    expect_error(calcGeomPar(mfd, 1, 2))
    expect_error(calcIntDim(mfd, 1, 2))
    expect_error(calcTanDim(mfd, 1, 2))
  }
})


test_that('Axis-angle representation works', {
  
  mfd <- createM('SO')
  v1 <- c(0, 0, 0)
  v2 <- c(pi, 0, 0)
  v3 <- Normalize(c(1/3, 1/3, 1/3))

  x1 <- c(rieExp(mfd, V=v1))
  x2 <- rieExp(mfd, V=v2)
  x3 <- rieExp(mfd, V=v3)

  # results
  r1 <- axisAngleRep(mfd, x1)
  r2 <- axisAngleRep(mfd, x2)
  r3 <- axisAngleRep(mfd, x3)

  # expected
  e1 <- c(0, 1, 0, 0)
  e2 <- c(pi, 0, 0, 1)
  e3 <- c(1, v3[1], -v3[2], v3[3])

  expect_equivalent(r1, e1)
  expect_equivalent(r2, e2)
  expect_equivalent(r3, e3)
  expect_equivalent(axisAngleRep(mfd, cbind(x1, x2, x3)), cbind(e1, e2, e3))
})

Try the manifold package in your browser

Any scripts or data that you put into this service are public.

manifold documentation built on Oct. 4, 2022, 5:06 p.m.