Skip to content

Commit 1cbfefb

Browse files
committed
re-add implicit conversion from int matrix to dbl matrix
1 parent 3431074 commit 1cbfefb

File tree

7 files changed

+109
-19
lines changed

7 files changed

+109
-19
lines changed

extended-tests/Rcppbenchmark/DESCRIPTION

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
Package: Rcppbenchmark
22
Type: Package
33
Title: Checking speed improvement/worsening with different C++ standards for Rcpp
4-
Description: A benchmark package to test the speed of various C++ implementations using the Rcpp package.
5-
The benchmarks include operations such as cumulative sums, outer products, pairwise distances, grouped
6-
means, and bootstrap resampling.
4+
Description: Benchmark adapted from the official Armadillo documentation to test the speed of different C++ standards
5+
when using the cpp4r package. The idea is to check how compiling with GCC or Clang using C++11, C++14, C++17, C++20
6+
or C++23 affects the speed of various linear algebra operations.
77
Version: 0.1
88
Authors@R:
99
person("Mauricio", "Vargas Sepulveda", role = c("aut","cre","cph"),
@@ -16,8 +16,6 @@ Suggests:
1616
Depends: R(>= 4.0.0)
1717
Imports: Rcpp
1818
License: Apache License (>= 2)
19-
BugReports: https://github.com/USERNAME/PKGNAME/issues
20-
URL: https://WEBSITE.COM
2119
RoxygenNote: 7.3.3
2220
Encoding: UTF-8
2321
NeedsCompilation: yes

extended-tests/cpp11benchmark/DESCRIPTION

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
Package: cpp11benchmark
22
Type: Package
33
Title: Checking speed improvement/worsening with different C++ standards for cpp11
4-
Description: A benchmark package to test the speed of various C++ implementations using the cpp11 package.
5-
The benchmarks include operations such as cumulative sums, outer products, pairwise distances, grouped
6-
means, and bootstrap resampling.
4+
Description: Benchmark adapted from the official Armadillo documentation to test the speed of different C++ standards
5+
when using the cpp4r package. The idea is to check how compiling with GCC or Clang using C++11, C++14, C++17, C++20
6+
or C++23 affects the speed of various linear algebra operations.
77
Version: 0.1
88
Authors@R:
99
person("Mauricio", "Vargas Sepulveda", role = c("aut","cre","cph"),
@@ -15,8 +15,6 @@ Suggests:
1515
testthat (>= 3.0.0)
1616
Depends: R(>= 4.0.0)
1717
License: Apache License (>= 2)
18-
BugReports: https://github.com/USERNAME/PKGNAME/issues
19-
URL: https://WEBSITE.COM
2018
RoxygenNote: 7.3.3
2119
Encoding: UTF-8
2220
LinkingTo: cpp11

extended-tests/cpp4rbenchmark/DESCRIPTION

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
Package: cpp4rbenchmark
22
Type: Package
33
Title: Checking speed improvement/worsening with different C++ standards for cpp4r
4-
Description: A benchmark package to test the speed of various C++ implementations using the cpp4r package.
5-
The benchmarks include operations such as cumulative sums, outer products, pairwise distances, grouped
6-
means, and bootstrap resampling.
4+
Description: Benchmark adapted from the official Armadillo documentation to test the speed of different C++ standards
5+
when using the cpp4r package. The idea is to check how compiling with GCC or Clang using C++11, C++14, C++17, C++20
6+
or C++23 affects the speed of various linear algebra operations.
77
Version: 0.1
88
Authors@R:
99
person("Mauricio", "Vargas Sepulveda", role = c("aut","cre","cph"),
@@ -15,8 +15,6 @@ Suggests:
1515
testthat (>= 3.0.0)
1616
Depends: R(>= 4.0.0)
1717
License: Apache License (>= 2)
18-
BugReports: https://github.com/USERNAME/PKGNAME/issues
19-
URL: https://WEBSITE.COM
2018
RoxygenNote: 7.3.3
2119
Encoding: UTF-8
2220
LinkingTo: cpp4r

extended-tests/cpp4rtest/DESCRIPTION

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
Package: cpp4rtest
22
Title: A Test Suite and Benchmark Code for 'cpp4r'
3+
Description: To check cpp4r correctness. The headers are vendored to check which lines of
4+
the C++ code are covered by the unit tests.
35
Version: 0.1.0
46
Authors@R:
57
person(
@@ -9,7 +11,6 @@ Authors@R:
911
email = "[email protected]",
1012
comment = c(ORCID = "0000-0003-1017-7574")
1113
)
12-
Description: Provides a test suite and benchmarking code for the 'cpp4r' package.
1314
License: Apache License (>= 2)
1415
Encoding: UTF-8
1516
LinkingTo: testthat

extended-tests/cpp4rtest/src/test-logicals-extended.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ context("logicals-extended-C++") {
213213
}
214214

215215
test_that("r_bool NA handling") {
216-
cpp4r::writable::logicals x({NA_LOGICAL});
216+
cpp4r::writable::logicals x{NA_LOGICAL};
217217

218218
cpp4r::r_bool rb = x[0];
219219
expect_true(rb == NA_LOGICAL);
@@ -567,7 +567,7 @@ context("logicals-extended-C++") {
567567

568568
test_that("logicals get_sexptype returns LGLSXP") {
569569
// Verify the SEXPTYPE by creating and checking
570-
cpp4r::writable::logicals x({TRUE});
570+
cpp4r::writable::logicals x{TRUE};
571571
SEXP s = x.data();
572572
expect_true(TYPEOF(s) == LGLSXP);
573573
}

extended-tests/cpp4rtest/src/test-r_vector_fwd-extended.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -905,7 +905,7 @@ context("r_vector_fwd-extended-C++") {
905905
}
906906

907907
test_that("logicals multiple assignments to same element") {
908-
cpp4r::writable::logicals x({TRUE});
908+
cpp4r::writable::logicals x{TRUE};
909909

910910
// Repeated assignments to exercise set_elt
911911
x[0] = TRUE;

inst/include/cpp4r/matrix.hpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,101 @@ using strings_matrix = matrix<r_vector<r_string>, r_string, S>;
318318
template <typename S = by_column>
319319
using complexes_matrix = matrix<r_vector<r_complex>, r_complex, S>;
320320

321+
// Implicit coercion from integer/logical to double
322+
template <typename S = by_column>
323+
class numeric_matrix {
324+
private:
325+
r_vector<double> vector_;
326+
int nrow_;
327+
int ncol_;
328+
329+
// Convert integer SEXP to double r_vector
330+
static r_vector<double> convert_integer(SEXP x, int nrow, int ncol) {
331+
R_xlen_t size = static_cast<R_xlen_t>(nrow) * ncol;
332+
SEXP result = PROTECT(Rf_allocMatrix(REALSXP, nrow, ncol));
333+
const int* CPP4R_RESTRICT x_ptr = INTEGER(x);
334+
double* CPP4R_RESTRICT ret_ptr = REAL(result);
335+
336+
for (R_xlen_t i = 0; i < size; ++i) {
337+
int val = x_ptr[i];
338+
ret_ptr[i] = CPP4R_LIKELY(val != NA_INTEGER) ? static_cast<double>(val) : NA_REAL;
339+
}
340+
341+
// Preserve dimnames
342+
SEXP dimnames = Rf_getAttrib(x, R_DimNamesSymbol);
343+
if (CPP4R_UNLIKELY(dimnames != R_NilValue)) {
344+
Rf_setAttrib(result, R_DimNamesSymbol, dimnames);
345+
}
346+
347+
UNPROTECT(1);
348+
return r_vector<double>(result);
349+
}
350+
351+
// Convert logical SEXP to double r_vector
352+
static r_vector<double> convert_logical(SEXP x, int nrow, int ncol) {
353+
R_xlen_t size = static_cast<R_xlen_t>(nrow) * ncol;
354+
SEXP result = PROTECT(Rf_allocMatrix(REALSXP, nrow, ncol));
355+
const int* CPP4R_RESTRICT x_ptr = LOGICAL(x);
356+
double* CPP4R_RESTRICT ret_ptr = REAL(result);
357+
358+
for (R_xlen_t i = 0; i < size; ++i) {
359+
int val = x_ptr[i];
360+
ret_ptr[i] = CPP4R_LIKELY(val != NA_LOGICAL) ? static_cast<double>(val) : NA_REAL;
361+
}
362+
363+
// Preserve dimnames
364+
SEXP dimnames = Rf_getAttrib(x, R_DimNamesSymbol);
365+
if (CPP4R_UNLIKELY(dimnames != R_NilValue)) {
366+
Rf_setAttrib(result, R_DimNamesSymbol, dimnames);
367+
}
368+
369+
UNPROTECT(1);
370+
return r_vector<double>(result);
371+
}
372+
373+
// Coerce SEXP to double r_vector (zero-copy if already double)
374+
static r_vector<double> coerce_to_double(SEXP x, int nrow, int ncol) {
375+
SEXPTYPE type = detail::r_typeof(x);
376+
if (type == REALSXP) {
377+
return r_vector<double>(x); // Zero-copy
378+
} else if (type == INTSXP) {
379+
return convert_integer(x, nrow, ncol);
380+
} else if (type == LGLSXP) {
381+
return convert_logical(x, nrow, ncol);
382+
}
383+
throw type_error(REALSXP, type);
384+
}
385+
386+
public:
387+
using underlying_type = double;
388+
389+
numeric_matrix(SEXP x)
390+
: nrow_(Rf_nrows(x)),
391+
ncol_(Rf_ncols(x)),
392+
vector_(coerce_to_double(x, nrow_, ncol_)) {}
393+
394+
// Allow construction from doubles_matrix (zero-copy)
395+
numeric_matrix(const doubles_matrix<S>& m)
396+
: vector_(m.vector()), nrow_(m.nrow()), ncol_(m.ncol()) {}
397+
398+
CPP4R_ALWAYS_INLINE int nrow() const noexcept { return nrow_; }
399+
CPP4R_ALWAYS_INLINE int ncol() const noexcept { return ncol_; }
400+
R_xlen_t size() const { return vector_.size(); }
401+
SEXP data() const { return vector_.data(); }
402+
operator SEXP() const { return SEXP(vector_); }
403+
404+
// Convert to doubles_matrix for full matrix functionality
405+
operator doubles_matrix<S>() const { return doubles_matrix<S>(vector_.data()); }
406+
407+
CPP4R_ALWAYS_INLINE double operator()(int row, int col) const {
408+
return vector_[row + (col * nrow_)];
409+
}
410+
411+
CPP4R_ALWAYS_INLINE const double* CPP4R_RESTRICT data_ptr() const noexcept {
412+
return vector_.data_ptr();
413+
}
414+
};
415+
321416
namespace writable {
322417
template <typename S = by_column>
323418
using doubles_matrix = matrix<r_vector<double>, typename r_vector<double>::reference, S>;

0 commit comments

Comments
 (0)