Skip to content

Commit 06c77c0

Browse files
bring tests from RcppParallelTests
1 parent 477d80b commit 06c77c0

File tree

10 files changed

+392
-11
lines changed

10 files changed

+392
-11
lines changed

.travis.yml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,19 @@ before_install:
55
- chmod 755 ./travis-tool.sh
66
- ./travis-tool.sh bootstrap
77
- ./travis-tool.sh github_package testthat
8-
- ./travis-tool.sh github_package Rcpp11/Rcpp11
9-
- ./travis-tool.sh github_package Rcpp11/attributes
10-
- ./travis-tool.sh r_binary_install Rcpp
11-
12-
script:
13-
- R CMD INSTALL RcppParallel
14-
- cd ..
15-
- git clone https://github.com/romainfrancois/RcppParallelTests.git
16-
- cd RcppParallelTests
8+
- if [ "$RCPP" = "Rcpp" ]; then ./travis-tool.sh github_package RcppCore/Rcpp; fi
9+
- if [ "$RCPP" = "Rcpp11" ]; then ./travis-tool.sh github_package Rcpp11/Rcpp11; ./travis-tool.sh github_package Rcpp11/attributes; fi
10+
11+
script:
12+
- R CMD INSTALL .
13+
- cd tests
1714
- Rscript testthat.R
18-
- cd ../RcppParallel
19-
15+
2016
notifications:
2117
email:
2218
on_success: change
2319
on_failure: change
2420

21+
env:
22+
- RCPP=Rcpp
23+
- RCPP=Rcpp11

tests/testthat.R

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require(methods)
2+
require(RcppParallel)
3+
require(testthat)
4+
5+
RCPP <- Sys.getenv( "RCPP" )
6+
if( RCPP == "Rcpp" ){
7+
message( "testing against Rcpp" )
8+
require(Rcpp)
9+
} else if( RCPP == "Rcpp11" ){
10+
message( "testing against Rcpp11" )
11+
require(attributes)
12+
} else {
13+
stop( "Rcpp implementation not setup, please set the $RCPP environment variable" )
14+
}
15+
16+
test_dir("testthat")
17+

tests/testthat/cpp/distance.cpp

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/**
2+
* @title Parallel Distance Matrix Calculation with RcppParallel
3+
* @author JJ Allaire and Jim Bullard
4+
* @license GPL (>= 2)
5+
*/
6+
7+
#include <Rcpp.h>
8+
using namespace Rcpp;
9+
10+
#include <cmath>
11+
#include <algorithm>
12+
13+
// generic function for kl_divergence
14+
template <typename InputIterator1, typename InputIterator2>
15+
inline double kl_divergence(InputIterator1 begin1, InputIterator1 end1,
16+
InputIterator2 begin2) {
17+
18+
// value to return
19+
double rval = 0;
20+
21+
// set iterators to beginning of ranges
22+
InputIterator1 it1 = begin1;
23+
InputIterator2 it2 = begin2;
24+
25+
// for each input item
26+
while (it1 != end1) {
27+
28+
// take the value and increment the iterator
29+
double d1 = *it1++;
30+
double d2 = *it2++;
31+
32+
// accumulate if appropirate
33+
if (d1 > 0 && d2 > 0)
34+
rval += std::log(d1 / d2) * d1;
35+
}
36+
return rval;
37+
}
38+
39+
// helper function for taking the average of two numbers
40+
inline double average(double val1, double val2) {
41+
return (val1 + val2) / 2;
42+
}
43+
44+
// [[Rcpp::export]]
45+
NumericMatrix rcpp_js_distance(NumericMatrix mat) {
46+
47+
// allocate the matrix we will return
48+
NumericMatrix rmat(mat.nrow(), mat.nrow());
49+
50+
for (int i = 0; i < rmat.nrow(); i++) {
51+
for (int j = 0; j < i; j++) {
52+
53+
// rows we will operate on
54+
NumericMatrix::Row row1 = mat.row(i);
55+
NumericMatrix::Row row2 = mat.row(j);
56+
57+
// compute the average using std::tranform from the STL
58+
std::vector<double> avg(row1.size());
59+
std::transform(row1.begin(), row1.end(), // input range 1
60+
row2.begin(), // input range 2
61+
avg.begin(), // output range
62+
average); // function to apply
63+
64+
// calculate divergences
65+
double d1 = kl_divergence(row1.begin(), row1.end(), avg.begin());
66+
double d2 = kl_divergence(row2.begin(), row2.end(), avg.begin());
67+
68+
// write to output matrix
69+
rmat(i,j) = std::sqrt(.5 * (d1 + d2));
70+
}
71+
}
72+
73+
return rmat;
74+
}
75+
76+
// [[Rcpp::depends(RcppParallel)]]
77+
#include <RcppParallel.h>
78+
using namespace RcppParallel;
79+
80+
struct JsDistance : public Worker {
81+
82+
// input matrix to read from
83+
const RMatrix<double> mat;
84+
85+
// output matrix to write to
86+
RMatrix<double> rmat;
87+
88+
// initialize from Rcpp input and output matrixes (the RMatrix class
89+
// can be automatically converted to from the Rcpp matrix type)
90+
JsDistance(const NumericMatrix mat, NumericMatrix rmat)
91+
: mat(mat), rmat(rmat) {}
92+
93+
// function call operator that work for the specified range (begin/end)
94+
void operator()(std::size_t begin, std::size_t end) {
95+
for (std::size_t i = begin; i < end; i++) {
96+
for (std::size_t j = 0; j < i; j++) {
97+
98+
// rows we will operate on
99+
RMatrix<double>::Row row1 = mat.row(i);
100+
RMatrix<double>::Row row2 = mat.row(j);
101+
102+
// compute the average using std::tranform from the STL
103+
std::vector<double> avg(row1.length());
104+
std::transform(row1.begin(), row1.end(), // input range 1
105+
row2.begin(), // input range 2
106+
avg.begin(), // output range
107+
average); // function to apply
108+
109+
// calculate divergences
110+
double d1 = kl_divergence(row1.begin(), row1.end(), avg.begin());
111+
double d2 = kl_divergence(row2.begin(), row2.end(), avg.begin());
112+
113+
// write to output matrix
114+
rmat(i,j) = sqrt(.5 * (d1 + d2));
115+
}
116+
}
117+
}
118+
};
119+
120+
// [[Rcpp::export]]
121+
NumericMatrix rcpp_parallel_js_distance(NumericMatrix mat) {
122+
123+
// allocate the matrix we will return
124+
NumericMatrix rmat(mat.nrow(), mat.nrow());
125+
126+
// create the worker
127+
JsDistance jsDistance(mat, rmat);
128+
129+
// call it with parallelFor
130+
parallelFor(0, mat.nrow(), jsDistance);
131+
132+
return rmat;
133+
}
134+
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* @title Computing an Inner Product with RcppParallel
3+
* @author JJ Allaire
4+
* @license GPL (>= 2)
5+
*/
6+
7+
#include <Rcpp.h>
8+
using namespace Rcpp;
9+
10+
#include <algorithm>
11+
12+
// [[Rcpp::export]]
13+
double innerProduct(NumericVector x, NumericVector y) {
14+
return std::inner_product(x.begin(), x.end(), y.begin(), 0.0);
15+
}
16+
17+
// [[Rcpp::depends(RcppParallel)]]
18+
#include <RcppParallel.h>
19+
using namespace RcppParallel;
20+
21+
struct InnerProduct : public Worker
22+
{
23+
// source vectors
24+
const RVector<double> x;
25+
const RVector<double> y;
26+
27+
// product that I have accumulated
28+
double product;
29+
30+
// constructors
31+
InnerProduct(const NumericVector x, const NumericVector y)
32+
: x(x), y(y), product(0) {}
33+
InnerProduct(const InnerProduct& innerProduct, Split)
34+
: x(innerProduct.x), y(innerProduct.y), product(0) {}
35+
36+
// process just the elements of the range I have been asked to
37+
void operator()(std::size_t begin, std::size_t end) {
38+
product += std::inner_product(x.begin() + begin,
39+
x.begin() + end,
40+
y.begin() + begin,
41+
0.0);
42+
}
43+
44+
// join my value with that of another InnerProduct
45+
void join(const InnerProduct& rhs) {
46+
product += rhs.product;
47+
}
48+
};
49+
50+
// [[Rcpp::export]]
51+
double parallelInnerProduct(NumericVector x, NumericVector y) {
52+
53+
// declare the InnerProduct instance that takes a pointer to the vector data
54+
InnerProduct innerProduct(x, y);
55+
56+
// call paralleReduce to start the work
57+
parallelReduce(0, x.length(), innerProduct);
58+
59+
// return the computed product
60+
return innerProduct.product;
61+
}
62+

tests/testthat/cpp/sum.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @title Summing a Vector in Parallel with RcppParallel
3+
* @author JJ Allaire
4+
* @license GPL (>= 2)
5+
*/
6+
7+
#include <Rcpp.h>
8+
#include <RcppParallel.h>
9+
10+
// [[Rcpp::depends(RcppParallel)]]
11+
using namespace RcppParallel;
12+
using namespace Rcpp;
13+
14+
struct Sum : public Worker
15+
{
16+
// source vector
17+
const RVector<double> input;
18+
19+
// accumulated value
20+
double value;
21+
22+
// constructors
23+
Sum(const NumericVector input) : input(input), value(0) {}
24+
Sum(const Sum& sum, Split) : input(sum.input), value(0) {}
25+
26+
// accumulate just the element of the range I have been asked to
27+
void operator()(std::size_t begin, std::size_t end) {
28+
value += std::accumulate(input.begin() + begin, input.begin() + end, 0.0);
29+
}
30+
31+
// join my value with that of another Sum
32+
void join(const Sum& rhs) {
33+
value += rhs.value;
34+
}
35+
};
36+
37+
// [[Rcpp::export]]
38+
double parallelVectorSum(NumericVector x) {
39+
40+
// declare the SumBody instance
41+
Sum sum(x);
42+
43+
// call parallel_reduce to start the work
44+
parallelReduce(0, x.length(), sum);
45+
46+
// return the computed sum
47+
return sum.value;
48+
}
49+
50+
// [[Rcpp::export]]
51+
double vectorSum(NumericVector x) {
52+
return std::accumulate(x.begin(), x.end(), 0.0);
53+
}
54+
55+

tests/testthat/cpp/transform.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @title Transforming a Matrix in Parallel using RcppParallel
3+
* @author JJ Allaire
4+
* @license GPL (>= 2)
5+
*/
6+
7+
#include <Rcpp.h>
8+
using namespace Rcpp;
9+
10+
#include <cmath>
11+
#include <algorithm>
12+
13+
// [[Rcpp::export]]
14+
NumericMatrix matrixSqrt(NumericMatrix orig) {
15+
16+
// allocate the matrix we will return
17+
NumericMatrix mat(orig.nrow(), orig.ncol());
18+
19+
// transform it
20+
std::transform(orig.begin(), orig.end(), mat.begin(), ::sqrt);
21+
22+
// return the new matrix
23+
return mat;
24+
}
25+
// [[Rcpp::depends(RcppParallel)]]
26+
#include <RcppParallel.h>
27+
using namespace RcppParallel;
28+
29+
struct SquareRoot : public Worker
30+
{
31+
// source matrix
32+
const RMatrix<double> input;
33+
34+
// destination matrix
35+
RMatrix<double> output;
36+
37+
// initialize with source and destination
38+
SquareRoot(const NumericMatrix input, NumericMatrix output)
39+
: input(input), output(output) {}
40+
41+
// take the square root of the range of elements requested
42+
void operator()(std::size_t begin, std::size_t end) {
43+
std::transform(input.begin() + begin,
44+
input.begin() + end,
45+
output.begin() + begin,
46+
::sqrt);
47+
}
48+
};
49+
50+
// [[Rcpp::export]]
51+
NumericMatrix parallelMatrixSqrt(NumericMatrix x) {
52+
53+
// allocate the output matrix
54+
NumericMatrix output(x.nrow(), x.ncol());
55+
56+
// SquareRoot functor (pass input and output matrixes)
57+
SquareRoot squareRoot(x, output);
58+
59+
// call parallelFor to do the work
60+
parallelFor(0, x.nrow() * x.ncol(), squareRoot);
61+
62+
// return the output matrix
63+
return output;
64+
}
65+

tests/testthat/test-distance.R

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
context( "distance" )
2+
3+
test_that( "distance works with Rcpp", {
4+
sourceCpp( "cpp/distance.cpp" )
5+
6+
n = 1000
7+
m = matrix(runif(n*10), ncol = 10)
8+
m = m/rowSums(m)
9+
10+
expect_equal(
11+
rcpp_js_distance(m),
12+
rcpp_parallel_js_distance(m)
13+
)
14+
})
15+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
context( "inner product" )
2+
3+
test_that( "parallelInnerProduct works with Rcpp", {
4+
sourceCpp( "cpp/innerproduct.cpp" )
5+
6+
x <- runif(1000000)
7+
y <- runif(1000000)
8+
9+
expect_equal(innerProduct(x, y), parallelInnerProduct(x, y))
10+
})
11+

0 commit comments

Comments
 (0)