Recently, I am trying to work on the Rcpp package to improve efficiency of computation in my work. However,I am not deep knowledged about C++, there are some strange behavoirs I can not understand. The below example show a simple tasks about derving weight of NumericVector, there are several questions:
When I use WAP=rev(WAP), it results in an incorrect output, I have to introduce a new variable to store the result so that I get the right output. I do not know why, should it NEVER use a 'x=f(x)' operation in C++ and Rcpp (must copy by clone instead) ?
About the CharacterVector method="eq", exactly I want to use a char or string type, however, it does not work with strncmp function (now I have to use method[0]), but I do not know how to look up the API of Rcpp functions in Rstudio?
I wonder whether there is a R-style grep, tolower function for conditions in Rcpp, I do not know which document I should refer to except for Rcpp suger, so that I can find the availiable base functions. Otherwise, I am thinking about calling R functions with Rcpp::function R_grep("grep"), but I do know whether this is the best way and recommended.
Any suggestions would be greatly appreciated.
#include <Rcpp.h>
#include <string>
#include <math.h>
#include <algorithm>
using namespace std;
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector cppweight(int N, CharacterVector method="eq", const bool reverse=false, const bool test=false){
NumericVector W(N);
NumericVector WAP(N);
NumericVector revWAP(N);
//method=tolower(method); //function not exists
if(strncmp(method[0],"eq",2)==0){
W=rep(1,N)/1.0*N;//convert int to float by multiplying 1.0
WAP=W/sum(W);
Rcout<< sum(W) << "\n";
} else if(strncmp(method[0],"ln",2)==0){
W=rev(seq(1,N))/1.0*N;
WAP=W/sum(W);
}
if(reverse){
if(test){
WAP=rev(WAP);//Why this result in incorrect result
revWAP=WAP;
}else{
revWAP=rev(WAP);
}
}else{
revWAP=WAP;
}
return(round(revWAP,3));
}
/*** R
cppweight(6,"ln",reverse=F,test=F)
cppweight(6,"ln",reverse=T,test=F)
cppweight(6,"ln",reverse=T,test=T)
*/
Related
Is this the only solution when there is a pointer that points to a vector and we would like to use accumulate to sum up numbers?
Is there any simpler solution rather than writing a lambda function and using a four argument type of accumulating?
Also, for using std::sort, will the situation be the same?
Here is the code:
#include <random>
#include <vector>
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int main() {
const int N=3;
auto p=make_unique<array<int,N>> ();
(*p)[0]=3;
(*p)[1]=4;
(*p)[2]=5;
sum=accumulate(p,?,0);
return 0;
}
To answer your immediate question:
std::accumulate(p->begin(), p->end(), 0);
The same syntax will work for other STL algorithms as well.
Other improvements to your code snippet:
Avoid using #include<bits/stdc++.h>, see this post. Similarly for using namespace std, it's considered bad practise.
const N=3 -> const auto N=3
std::array is not a vector and you can initialise it directly using initializer-list syntax:
const auto* obj = new std::array<int,3>{3,4,5};
What is the appropriate way to apply log1p() to an entire arma::vec? It seems that there are vectorized versions of log() and exp(), but not log1p(). I found that there's syntactic sugar for NumericVector, so I end up converting arma::vec to NumericVector, applying log1p(), then converting back:
#include <RcppArmadillo.h>
using namespace Rcpp;
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
arma::vec test_log1p( arma::vec v )
{
// arma::vec res = log1p(v); // results in a compilation error
NumericVector v1 = log1p( wrap(v) );
arma::vec res = as<arma::vec>(v1);
return res;
}
Is there a more elegant way of doing this?
The devil is, once again, in the detail.
For starters, RcppArmadillo does not have 'Sugar' so your reasoning is flawed--you can't just look at the Rcpp Sugar functions that are working on Rcpp::NumericVector.
Then again, one can convert as you did. But you chose an expensive conversion. Look into the advanced constructors explicitly reusing memory -- no copies needed.
A much simpler and more direct (yet local) approach would just be to add a little local inlined function. That's what I would do :) Done in a few minutes.
Lastly, we have some sibbling projects that generalized Rcpp Sugar over anything that can take iterators. That is "the high road" and it could do with some fresh development. Maybe start at this repo.
Use the .transform() or .for_each() facilities available for Armadillo vectors and matrices. Example:
v.transform( [](double val) { return log1p(val); } );
or
v.for_each( [](double& val) { val = log1p(val); } ); // note the & character
You may need to use the std prefix: std::log1p() instead of log1p().
I am brand new to Rcpp. I am trying to using the R package RcppEigen to get the determinant of a matrix. The following code is saved in a file and I use sourceCpp to use it. There is no compilation error when I use sourceCpp. When using getDeterminant(A) in R, A is a matrix. It always complains the following error.
"Error: could not find function "getDeterminant""
However, the getEigenValues works well.
I appreciate a lot if anybody is happy to help me with this.
Thanks a lot!
#include <RcppEigen.h>
// [[Rcpp::depends(RcppEigen)]]
using Eigen::Map; // 'maps' rather than copies
using Eigen::MatrixXd; // variable size matrix, double precision
using Eigen::VectorXd; // variable size vector, double precision
using Eigen::SelfAdjointEigenSolver; // one of the eigenvalue solvers
using Eigen::MatrixXi;
using Eigen::MatrixBase;
// [[Rcpp::export]]
VectorXd getEigenValues(Map<MatrixXd> M) {
SelfAdjointEigenSolver<MatrixXd> es(M);
return es.eigenvalues();
}
// [[Rcpp:export]]
double getDeterminant(Map<MatrixXd> AA){
return AA.determinant();
}
You are missing a : in the second Rcpp Attributes tag: Rcpp::export is the form the regular expression looks for.
If you add it, the functions becomes accessible:
R> Rcpp::sourceCpp("/tmp/crystal.cpp")
R> M <- matrix(1:9,3,3)*1.0
R> getEigenValues(M)
[1] 2.80689e-16 6.99265e-01 1.43007e+01
R> getDeterminant(M)
[1] 0
R>
I would like to get the weighted_median of an unsorted, variable
length, eigen c++ vectorXf object. It seems i can use the boost
weighted_median function from boost's statistical accumulators
library to do that efficiently [?].
In essence, i'm trying to do something very similar to what is done
here. I'm not sure boost's accumulator are the right framework
for this task (if not please advice!), but i've not found another
out the shelf implementation of the O(n) weighted median out there.
My question at this point is whether there a way to replace the
"for(int i=0;i<100;i++)" loop below by a more elegant construct?
P.S. i've seen this SO question, but it's not
really clear how to turn the answer there unto an
operation-able solution.
#include <Eigen/Dense>
#include <iostream>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/median.hpp>
#include <boost/accumulators/statistics/weighted_median.hpp>
using namespace boost::accumulators;
using namespace Eigen;
int main(){
accumulator_set<float, stats<tag::median > > acc1;
accumulator_set<float, stats<tag::median >,int> acc2;
VectorXi rw=VectorXi::Random(100);
VectorXf rn=VectorXf::Random(100);
rw=rw.cwiseAbs();
for(int i=0;i<100;i++){
acc1(rn(i));
acc2(rn(i),weight=rw(i));
}
std::cout << " Median: " << median(acc1) << std::endl;
std::cout << "Weighted Median: " << median(acc2) << std::endl;
return 0;
}
What you're trying to do is to use the boost accumulators to accumulate values in a container of some sort. You'll notice that even passing std::vector<float> to an accumulator won't work. Accumulators are simply not meant to be used that way. You can use accumulators to accumulate vector- or matrix-valued values, of course - but that's not what you're after here.
You can use std::for_each to get rid of the explicit loop, and that's about it:
// median
using boost::bind;
using boost::ref;
std::for_each(rn.data(), rn.data()+rn.rows(), bind<void>( ref(acc1), _1 ) );
The question you link to is not relevant anymore in the latest release version of Eigen3. The code given there runs just fine and produces correct results.
How can I initialize a SparseVector in Eigen ? The following code:
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
#include <Eigen/Sparse>
using namespace Eigen;
SparseVector<float> vec(3);
main()
{
vec(0)=1.0;
}
gives me the following error
error: call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type
vec(0)=1.0;
by the way, vec[0]=1.0 doesn't work either.
Looking at the documentation I noticed Scalar& coeffRef(Index i), and it says:
Returns a reference to the coefficient value at given index i. This operation involes a log(rho*size) binary search. If the coefficient does not exist yet, then a sorted insertion into a sequential buffer is performed. (This insertion might be very costly if the number of nonzeros above i is large.)
So the following should work:
#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
#include <Eigen/Sparse>
using namespace Eigen;
SparseVector<float> vec(3);
main()
{
vec.coeffRef(0)=1.0;
}
Not sure why they did it that way instead of using array overloading. Perhaps when it becomes IS_STABLE then they'll do it in a more typical C++ way?