Sparse Matrix Cholesky decomposition Rcpp Eigen - sparse-matrix

I'm dealing with a big sparse matrix (10k x 10k variance/covariance matrix, so symmetric and positive definite) in R. I need a fast way to find the Cholesky decomposition of that matrix. I understand that using SparseLU from RcppEigen package can be a solution but I can't figure out how it works.
In the next script, I put the example of my function in R. It loads a SparseMatrix SS, of which I need the Cholesky decomposition. I'd like to have the same output as chol(SS), with typical R function chol.
cholScript<-'using Eigen::Map;
using Eigen::SparseMatrix;
const SparseMatrix<double> Sigma(as<SparseMatrix<double> >(Sigma));
using namespace Rcpp;
// compute C, the Cholesky decomposition of Sigma
return wrap(C);'
cxxfunction(signature(Sigma = "dgCMatrix"), cholScript, plugin = "RcppEigen")
Thank you very much.

I think that this can be a solution:
CholeskyCppSparse<-'using Eigen::Map;
using Eigen::SparseMatrix;
using Eigen::LLT;
const SparseMatrix<double> SS(as<SparseMatrix<double> >(Sigma));
typedef Eigen::SimplicialLLT<SparseMatrix<double> > SpChol;
const SpChol Ch(SS);
return wrap(Ch.matrixL());'
CholSparse <- cxxfunction(signature(Sigma = "dgCMatrix"), CholeskyCppSparse, plugin = "RcppEigen")
Change matrixL for matrixU if you want the upper triangular part of the decomposition (as for chol() function in R).

Related

remove empty rows of an Eigen::SparseMatrix

I have built a sparse matrix mat from a list of triplets
Eigen::SparseMatrix<double, Eigen::RowMajor> mat(Nbins,Ndata);
mat.setFromTriplets(tripletList.begin(), tripletList.end());
Now I would like to create a new matrix ret, which only contains the rows of the previous matrix which are not empty. I do it as follows
Eigen::SparseMatrix<double, Eigen::RowMajor> ret(Nbins,Ndata);
unsigned Nrow=0;
for (unsigned i=0; i<Nbins; ++i) {
auto mrow = mat.row(i);
if (mrow.sum()>0) {
ret.row(Nrow++) = mrow;
}
}
ret.conservativeResize(Nrow,Ndata);
However, doing it this way is slow and inefficient. Slow because quick profiling suggests it spends most of its time on ret.row(Nrow++) = mrow;. Inefficient because we are also copying all the data twice.
Is there a better solution? I feel one has to fiddle with the inner vectors but I get confused by them and I don't know how user-proof it is to play with them.
EDIT: In my application, matrices are row major, and I want to remove empty rows. mat is not needed, just ret. All coefficients are positive hence the way I check for nonzero rows. The triplets are sorted but column-major. There are no duplicate triplets.
Found it! Instead of writing a hand-made setFromTriplets, I went with a modification of the tripletList. The interface of Eigen::Triplet makes it very easy.
//get which rows are empty
std::vector<bool> has_value(Nbins,false);
for (auto tr : tripletList) has_value[tr.row()] = true;
//create map from old to new indices
std::map<unsigned,unsigned> row_map;
unsigned new_idx=0;
for (unsigned old_idx=0; old_idx<Nbins; old_idx++)
if(has_value[old_idx])
row_map[old_idx]=new_idx++;
//make new triplet list, dropping empty rows
std::vector<Eigen::Triplet<double> > newTripletList;
newTripletList.reserve(Ndata);
for (auto tr : tripletList)
newTripletList.push_back(
Eigen::Triplet<double>(row_map[tr.row()],tr.col(),tr.value()));
//form new matrix and return
Eigen::SparseMatrix<double, Eigen::RowMajor> ret(new_idx,Ndata);
ret.setFromTriplets(newTripletList.begin(), newTripletList.end());

Error using linsolve: Matrix must be positive definite

I am trying to use compressed sensing for a 2D matrix. I am trying to run the following piece of code -
Nf=800;
N=401;
E=E(Nf,N); %matrix of signal(this only for sampling) real matrix E is 2D matrix with size of Nf and N
% compressive sensing
M=ceil(0.3*N);
psi=fft(eye(N));
phi=randi(M,N);
EE = permute(E,[2 1]);
theta=phi*psi;
for k=1:Nf
y(:,k)=phi*EE(:,k);
end
x0 = theta.'*y;
for p=1:Nf
X_hat(:,p) = l1eq_pd(x0(:,p), theta, [], y(:,p), 1e-5); %l1eq_pd=l1-magic
end
X1_hat=psi*X_hat;
XX_hat=permute(X1_hat,[2 1]);
but while running the code I get the following error.
Error using linsolve
Matrix must be positive definite.
Error in l1eq_pd (line 77)
[w, hcond] = linsolve(A*A', b, opts);
Error in simulation_mono_SAR (line 91)
X_hat(:,p) = l1eq_pd(x0(:,p), theta, [], y(:,p), 1e-5);
Could someone point me, what is the problem? Is it a problem inherent to l1-magic? shall I use another solver?

Converting matrix_float3x3 rotation to SceneKit

I was experimenting with GameplayKit’s GKAgent3D class to move a SCNNode within a scene. I was able to update the SCNNode with the agent’s position, but not rotation. The issue being the agent’s rotation is stored as a matrix_float3x3, which doesn’t match any of data types SceneKit uses for storing rotational information.
So what I’d like to know is if there’s a simple function or method that could convert a rotation stored as matrix_float3x3 to any SceneKit data types?
To expand on #rickster 's answer, here's a nice way to take the top-left 3x3 of a 4x4 matrix in Swift, taking advantage of the expanded simd support in the iOS 11/ tvOS 11/ High Sierra version of SceneKit:
extension float4 {
var xyz: float3 {
return float3(x, y, z)
}
init(_ vec3: float3, _ w: Float) {
self = float4(vec3.x, vec3.y, vec3.z, w)
}
}
extension float4x4 {
var upperLeft3x3: float3x3 {
let (a,b,c,_) = columns
return float3x3(a.xyz, b.xyz, c.xyz)
}
init(rotation: float3x3, position: float3) {
let (a,b,c) = rotation.columns
self = float4x4(float4(a, 0),
float4(b, 0),
float4(c, 0),
float4(position, 1))
}
}
Then, to update your agent to match your node's orientation, you'd write:
agent.rotation = node.simdTransform.upperLeft3x3
Or, if the node in question is not at the "root" level (as in, a direct child of the rootNode), you might want to use the node's worldTransform:
agent.rotation = node.simdWorldTransform.upperLeft3x3
EDIT: If the node in question has a dynamic physics body attached, or is being animated with an SCNTransaction block, the node's presentation node will more accurately reflect its current position on screen:
agent.position = node.presentation.simdWorldPosition
agent.rotation = node.presentation.simdWorldTransform.upperLeft3x3
EDIT: added code above for going in the other direction, moving the node to match the agent.
node.simdTransform = float4x4(rotation: agent3d.rotation, position: agent3d.position)
Note that if you have a physics body attached to the node, it should be kinematic rather than dynamic if you're going to be directly modifying the node's transform in this way.
SceneKit takes transform matrices as SCNMatrix4, and provides utilities for converting from SIMD matrix_float4x4: init(_ m: float4x4) for Swift and SCNMatrix4FromMat4 for ObjC/C++.
Sadly, I don't see a built-in way to convert between SIMD 3x3 and 4x4 matrices using the assumption that the 3x3 is the upper left of the 4x4. (Seems like you'd expect that in the SIMD library, so it's worth filing a bug to Apple about.)
But it's not too hard to provide one yourself: just construct a 4x4 from column vectors, using the three column vectors of the 3x3 (padded out to float4 vectors with zero for the w component) and identity for the fourth column (0,0,0,1). (Implementation code left for the reader, partly because I don't want to write it for three languages.) After converting float3x3 to float4x4 you can convert to SCNMatrix4.
Edit: In iOS 11 / tvOS 11 / macOS 10.13 (why didn't they just call this year's macOS version 11, too?), SceneKit has a whole parallel set of APIs for using SIMD types like float4x4 directly; e.g. simdTransform. However, you still need to convert a 3x3 to a 4x4 matrix.

R parallel code for two arrays

I'm trying to process two 3d arrays using parallel computing in R. I have a function that takes two vectors as input, so I need to loop through the rows and columns of my arrays. Doing this in serial code is simply too slow and R gets stuck as the arrays are large.
I've not found a solution for doing this with parallel functions and would appreciate any suggestions. I've tried parApply but do not know how to incorporate a second input, and mcmapply but it is hard to use over rows/cols. Ideally the output should also be an array of the same dimension.
Below is a reproducible example of what I'm trying to do in serial code. Any help on how this could be written in parallel code would be much appreciated!
fun <- function(a,b)
{
a*b
}
input1 <- array(data=1:1000, dim=c(10,10,10))
input2 <- array(data=2:1001, dim=c(10,10,10))
result <- array(data=NA, dim=c(10,10,10))
for(i in 1:nrow(mat1))
{ for(j in 1:ncol(mat1)) {
result[,i,j] <- fun(input1[,i,j], input2[,i,j])
}}
Here's one way to do it with the foreach package:
library(doSNOW)
library(abind)
cl <- makeSOCKcluster(parallel::detectCores())
registerDoSNOW(cl)
fun <- function(a,b) a*b
input1 <- array(rnorm(60), dim=c(4,5,3))
input2 <- array(rnorm(60), dim=c(4,5,3))
rdim <- dim(input1)[1:2]
comb <- function(...) abind(..., along=3)
result <-
foreach(i1=iapply(input1, 3), i2=iapply(input2, 3),
.multicombine=TRUE, .combine='comb') %dopar% {
r <- array(data=NA, dim=rdim)
for (i in 1:ncol(i1)) {
r[,i] <- fun(i1[,i], i2[,i])
}
r
}
The "iapply" function from the iterators package is used to split the 3D input arrays into 2D matrices. The result matrices are combined into a 3D array using the "abind" function from the abind package.
Note that I'm specifically using the "doSNOW" parallel backend because it sends data from the two "iapply" iterators to the workers and processes the results on-the-fly. This reduces the memory needed by the master process. The "doParallel" backend can't work on-the-fly because the "parallel" package doesn't export the necessary functions.

Any example of matrix operations with JavaCV?

I need to convert an image into an matrix to do math with it, like what is done with Matlab (imadd, imsubtract, immultiply, imdivide).
I only managed to do this:
CvMat mtx = new CvMat(iplUltima);
opencv_core.cvTranspose(mtx,mtx);
iplUltima = new IplImage(mtx);
pbxImagenTransformada.setIcon(new ImageIcon(iplUltima.getBufferedImage()));
but when I try to do the same with cvSum or cvAdd I got errors. Can you give me an example of use? I tried to replace cvTranspose by cvAdd but it is an error.

Resources