diff --git a/inst/include/ComboGroups/ComboGroupsClass.h b/inst/include/ComboGroups/ComboGroupsClass.h index c85cd28..07365b4 100644 --- a/inst/include/ComboGroups/ComboGroupsClass.h +++ b/inst/include/ComboGroups/ComboGroupsClass.h @@ -11,8 +11,11 @@ class ComboGroupsClass : public Combo { cpp11::writable::list dimNames; cpp11::writable::strings myNames; + std::string grpSizeDesc; + bool IsArray; - int r; // Number of groups + int rDisp; // This will differ in the General case when OneGrp = true + int r; // Number of groups const std::unique_ptr CmbGrp; SEXP SingleReturn(); diff --git a/inst/include/ComboGroups/ComboGroupsGeneral.h b/inst/include/ComboGroups/ComboGroupsGeneral.h index 6aae18f..18ace97 100644 --- a/inst/include/ComboGroups/ComboGroupsGeneral.h +++ b/inst/include/ComboGroups/ComboGroupsGeneral.h @@ -6,7 +6,6 @@ class ComboGroupsGeneral : public ComboGroupsTemplate { private: const GroupHelper MyGrp; - const bool OneGrp; public: diff --git a/inst/include/ComboGroups/ComboGroupsTemplate.h b/inst/include/ComboGroups/ComboGroupsTemplate.h index 4231c3f..d9374ec 100644 --- a/inst/include/ComboGroups/ComboGroupsTemplate.h +++ b/inst/include/ComboGroups/ComboGroupsTemplate.h @@ -33,6 +33,9 @@ class ComboGroupsTemplate { std::string GroupType; + bool OneGrp; // Used only for General case, but we need to be able to + // to access it, so that we can properly name the output + // when using iterables (e.g. nextIter method) const int n; // Size of vector which is also the size of z (i.e. z.size()) const int r; // Number of groups @@ -68,6 +71,7 @@ class ComboGroupsTemplate { bool GetIsGmp() const {return IsGmp;} int GetNumGrps() const {return r;} std::string GetType() const {return GroupType;} + bool GetOneGrp() const {return OneGrp;} SEXP GetCount() const { return CppConvert::GetCount(IsGmp, computedRowsMpz, computedRows); diff --git a/inst/include/ComboGroups/GetComboGroups.h b/inst/include/ComboGroups/GetComboGroups.h index b4919fc..ec14060 100644 --- a/inst/include/ComboGroups/GetComboGroups.h +++ b/inst/include/ComboGroups/GetComboGroups.h @@ -20,7 +20,7 @@ SEXP GetComboGroups( SEXP Rv, nextGrpFunc nextCmbGrp, nthFuncDbl nthCmbGrp, nthFuncGmp nthCmbGrpGmp, finalTouchFunc FinalTouch, const std::vector &vNum, const std::vector &vInt, - std::vector &startZ, const VecType &myType, + std::vector startZ, const VecType &myType, const std::vector &mySample, const std::vector &myVec, mpz_class lowerMpz, double lower, int n, int numResults, int nThreads, bool IsArray, bool IsNamed, bool Parallel, bool IsSample, bool IsGmp diff --git a/src/ComboGroupsClass.cpp b/src/ComboGroupsClass.cpp index d1893f0..32440eb 100644 --- a/src/ComboGroupsClass.cpp +++ b/src/ComboGroupsClass.cpp @@ -24,7 +24,6 @@ SEXP ComboGroupsClass::GeneralReturn(int numResults) { SetThreads(LocalPar, maxThreads, numResults, myType, nThreads, sexpNThreads, limit); - CmbGrpClsFuncs f = GetClassFuncs(CmbGrp); cpp11::sexp res = GetComboGroups( @@ -33,6 +32,7 @@ SEXP ComboGroupsClass::GeneralReturn(int numResults) { numResults, nThreads, IsArray, false, LocalPar, false, IsGmp ); + zUpdateIndex(vNum, vInt, z, sexpVec, res, m, numResults); return res; } @@ -46,6 +46,7 @@ ComboGroupsClass::ComboGroupsClass( RmaxThreads, RnumThreads, Rparallel), CmbGrp(GroupPrep(Rv, RNumGroups, RGrpSize, n)) { + prevIterAvailable = false; CmbGrp->SetCount(); IsGmp = CmbGrp->GetIsGmp(); computedRows = CmbGrp->GetDblCount(); @@ -68,6 +69,7 @@ ComboGroupsClass::ComboGroupsClass( IsArray = (retType == "3Darray"); r = CmbGrp->GetNumGrps(); + rDisp = r; const int grpSize = n / r; std::vector myColNames(r, "Grp"); @@ -76,6 +78,10 @@ ComboGroupsClass::ComboGroupsClass( myColNames[j] += std::to_string(j + 1); } + for (auto g: CmbGrp->GetGroupSizes()) { + grpSizeDesc += (std::to_string(g) + ", "); + } + if (IsArray) { myNames.resize(r); @@ -96,6 +102,33 @@ ComboGroupsClass::ComboGroupsClass( myNames[k] = myColNames[i].c_str(); } } + } else if (CmbGrp->GetOneGrp()) { + myNames.resize(n); + std::vector vGrpSizes(CmbGrp->GetGroupSizes()); + + const int numOneGrps = vGrpSizes.front(); + std::vector realGrps(vGrpSizes); + realGrps.erase(realGrps.begin()); + realGrps.insert(realGrps.begin(), numOneGrps, 1); + + rDisp = realGrps.size(); + std::vector myColNamesOne(rDisp, "Grp"); + + for (int j = 0; j < rDisp; ++j) { + myColNamesOne[j] += std::to_string(j + 1); + } + + for (int i = 0, k = 0; i < rDisp; ++i) { + for (int j = 0; j < realGrps[i]; ++j, ++k) { + myNames[k] = myColNamesOne[i].c_str(); + } + } + + grpSizeDesc.clear(); + + for (auto g: realGrps) { + grpSizeDesc += (std::to_string(g) + ", "); + } } else { myNames.resize(n); std::vector vGrpSizes(CmbGrp->GetGroupSizes()); @@ -106,6 +139,10 @@ ComboGroupsClass::ComboGroupsClass( } } } + + // Remove the last space and comma + grpSizeDesc.pop_back(); + grpSizeDesc.pop_back(); } void ComboGroupsClass::startOver() { @@ -308,19 +345,9 @@ SEXP ComboGroupsClass::back() { SEXP ComboGroupsClass::summary() { - std::string grpSizeDesc; - - for (auto g: CmbGrp->GetGroupSizes()) { - grpSizeDesc += (std::to_string(g) + ", "); - } - - // Remove the last space and comma - grpSizeDesc.pop_back(); - grpSizeDesc.pop_back(); - const std::string gtype = CmbGrp->GetType(); const std::string prefix = "Partition of v of length " + - std::to_string(n) + " into " + std::to_string(r); + std::to_string(n) + " into " + std::to_string(rDisp); const std::string suffix = (gtype == "Uniform") ? " uniform groups" : " groups of sizes: " + grpSizeDesc; diff --git a/src/ComboGroupsGeneral.cpp b/src/ComboGroupsGeneral.cpp index 754447c..ab8e321 100644 --- a/src/ComboGroupsGeneral.cpp +++ b/src/ComboGroupsGeneral.cpp @@ -96,8 +96,9 @@ ComboGroupsGeneral::ComboGroupsGeneral( int n_, int numGroups, int i1, int i2, int bnd, GroupHelper MyGrp_, bool OneGrp_ ) : ComboGroupsTemplate(n_, numGroups, i1, i2, bnd), - MyGrp(MyGrp_), OneGrp(OneGrp_) { + MyGrp(MyGrp_) { + OneGrp = OneGrp_; GroupType = "General"; } diff --git a/src/ComboGroupsTemplate.cpp b/src/ComboGroupsTemplate.cpp index 1938ed2..f6a918f 100644 --- a/src/ComboGroupsTemplate.cpp +++ b/src/ComboGroupsTemplate.cpp @@ -7,7 +7,10 @@ ComboGroupsTemplate::ComboGroupsTemplate( int n_, int numGroups, int i1, int i2, int bnd -) : n(n_), r(numGroups), idx1(i1), idx2(i2), curr_bnd(bnd) {} +) : n(n_), r(numGroups), idx1(i1), idx2(i2), curr_bnd(bnd) { + + OneGrp = false; +} void ComboGroupsTemplate::SetCount() { computedRows = numGroupCombs(); diff --git a/src/GetComboGroups.cpp b/src/GetComboGroups.cpp index 9540c16..03e3b71 100644 --- a/src/GetComboGroups.cpp +++ b/src/GetComboGroups.cpp @@ -293,7 +293,7 @@ SEXP GetComboGroups( SEXP Rv, nextGrpFunc nextCmbGrp, nthFuncDbl nthCmbGrp, nthFuncGmp nthCmbGrpGmp, finalTouchFunc FinalTouch, const std::vector &vNum, const std::vector &vInt, - std::vector &startZ, const VecType &myType, + std::vector startZ, const VecType &myType, const std::vector &mySample, const std::vector &myBigSamp, mpz_class lowerMpz, double lower, int n, int numResults, int nThreads, diff --git a/tests/testthat/testComboGroupsClass.R b/tests/testthat/testComboGroupsClass.R new file mode 100644 index 0000000..2bb6a94 --- /dev/null +++ b/tests/testthat/testComboGroupsClass.R @@ -0,0 +1,209 @@ +test_that("comboGroupsIter produces correct results", { + + comboGroupsClassTest <- function( + v_pass, n_grps = NULL, grp_sizes = NULL, + ret = "matrix", testRand = TRUE + ) { + + myResults <- vector(mode = "logical") + + myRows <- comboGroupsCount(v_pass, n_grps, grp_sizes) + a <- comboGroupsIter(v_pass, n_grps, grp_sizes, ret) + b <- comboGroups(v_pass, n_grps, grp_sizes, ret) + + myResults <- c(myResults, isTRUE(all.equal( + a@summary()$totalResults, myRows) + )) + + if (length(v_pass) == 1 && v_pass == 0) { + myResults <- c(myResults, v_pass == a@sourceVector()) + } else if (length(v_pass) == 1) { + myResults <- c(myResults, isTRUE( + all.equal(abs(v_pass), length(a@sourceVector())) + )) + } else { + myResults <- c(myResults, isTRUE( + all.equal(sort(v_pass), a@sourceVector()) + )) + } + + if (testRand) { + myResults <- c(myResults, isTRUE( + all.equal(a@front(), b[1 ,]) + )) + myResults <- c(myResults, isTRUE(all.equal(a@currIter(), + b[1 ,]))) + myResults <- c(myResults, isTRUE(all.equal(a@back(), + b[myRows, ]))) + myResults <- c(myResults, isTRUE(all.equal(a@currIter(), + b[myRows, ]))) + } + + a@startOver() + msg <- capture.output(noMore <- a@currIter()) + myResults <- c(myResults, is.null(noMore)) + myResults <- c(myResults, grepl("Iterator Initialized. To see the first", msg[1])) + a1 <- b + + if (myRows) { + for (i in 1:myRows) { + a1[i, ] <- a@nextIter() + } + + myResults <- c(myResults, isTRUE(all.equal(a1, b))) + a@startOver() + num_iters <- if (myRows > 10) 3L else 1L + numTest <- as.integer(myRows / num_iters); + + s <- 1L + e <- numTest + + for (i in 1:num_iters) { + myResults <- c(myResults, isTRUE(all.equal(a@nextNIter(numTest), + b[s:e, , drop = FALSE]))) + s <- e + 1L + e <- e + numTest + } + + a@startOver() + myResults <- c(myResults, isTRUE(all.equal(a@nextRemaining(), b))) + msg <- capture.output(noMore <- a@nextIter()) + myResults <- c(myResults, is.null(noMore)) + + if (testRand) { + a@back() + msg <- capture.output(noMore <- a@nextNIter(1)) + myResults <- c(myResults, is.null(noMore)) + myResults <- c(myResults, "No more results." == msg[1]) + msg <- capture.output(noMore <- a@currIter()) + myResults <- c(myResults, "No more results." == msg[1]) + + a@startOver() + a@back() + msg <- capture.output(noMore <- a@nextRemaining()) + myResults <- c(myResults, is.null(noMore)) + myResults <- c(myResults, "No more results." == msg[1]) + + a@startOver() + a@back() + msg <- capture.output(noMore <- a@nextIter()) + myResults <- c(myResults, is.null(noMore)) + myResults <- c(myResults, "No more results." == msg[1]) + + samp <- sample(myRows, numTest) + myResults <- c(myResults, isTRUE(all.equal(a[[samp]], b[samp, ]))) + one_samp <- sample(myRows, 1) + myResults <- c(myResults, isTRUE(all.equal(a[[one_samp]], b[one_samp, ]))) + } + } else { + a@startOver() + msg <- capture.output(noMore <- a@nextNIter(1)) + myResults <- c(myResults, is.null(noMore)) + myResults <- c(myResults, "No more results." == msg[1]) + msg <- capture.output(noMore <- a@currIter()) + myResults <- c(myResults, "No more results." == msg[1]) + + a@startOver() + msg <- capture.output(noMore <- a@nextIter()) + myResults <- c(myResults, is.null(noMore)) + myResults <- c(myResults, "No more results." == msg[1]) + + a@startOver() + msg <- capture.output(noMore <- a@nextRemaining()) + myResults <- c(myResults, is.null(noMore)) + myResults <- c(myResults, "No more results." == msg[1]) + } + + rm(a, a1, b) + gc() + all(myResults) + } + + expect_true(comboGroupsClassTest(12, 3)) + # expect_true(comboGroupsClassTest(12, 3, ret = "3Darray")) + expect_true(comboGroupsClassTest(12, grp_sizes = c(3, 3, 6))) + expect_true(comboGroupsClassTest(12, grp_sizes = c(3, 4, 5))) + expect_true(comboGroupsClassTest(11, grp_sizes = c(1, 2, 2, 3, 3))) + expect_true(comboGroupsClassTest(4, grp_sizes = c(1, 1, 1, 1))) + expect_true(comboGroupsClassTest(4, grp_sizes = c(1, 1, 2))) + expect_true(comboGroupsClassTest(3, grp_sizes = c(1, 2))) + expect_true(comboGroupsClassTest(3, 1)) + expect_true(comboGroupsClassTest(1, 1)) + + ##******** BIG TESTS *********## + comboGroupsClassBigZTest <- function( + v_pass, n_grps = NULL, grp_sizes = NULL, + ret = "matrix", lenCheck = 1000, testRand = TRUE + ) { + + myResults <- vector(mode = "logical") + + myRows <- comboGroupsCount(v_pass, n_grps, grp_sizes) + a <- comboGroupsIter(v_pass, n_grps, grp_sizes, ret) + b1 <- comboGroups(v_pass, n_grps, grp_sizes, ret, upper = lenCheck) + b2 <- comboGroups(v_pass, n_grps, grp_sizes, ret, + lower = gmp::sub.bigz(myRows, lenCheck - 1)) + + myResults <- c(myResults, isTRUE(all.equal( + a@summary()$totalResults, myRows) + )) + + if (length(v_pass) == 1) { + myResults <- c(myResults, isTRUE( + all.equal(v_pass, length(a@sourceVector())) + )) + } else { + myResults <- c(myResults, isTRUE( + all.equal(sort(v_pass), a@sourceVector()) + )) + } + + myResults <- c(myResults, isTRUE( + all.equal(a@front(), b1[1 ,]) + )) + myResults <- c(myResults, isTRUE(all.equal(a@currIter(), + b1[1 ,]))) + myResults <- c(myResults, isTRUE(all.equal(a@back(), + b2[lenCheck, ]))) + myResults <- c(myResults, isTRUE(all.equal(a@currIter(), + b2[lenCheck, ]))) + + a@startOver() + a1 <- b1 + + for (i in 1:lenCheck) { + a1[i, ] <- a@nextIter() + } + + myResults <- c(myResults, isTRUE(all.equal(a1, b1))) + a@startOver() + numTest <- as.integer(lenCheck / 3); + s <- 1L + e <- numTest + + for (i in 1:3) { + myResults <- c(myResults, isTRUE(all.equal(a@nextNIter(numTest), + b1[s:e, ]))) + s <- e + 1L + e <- e + numTest + } + + a@startOver() + a[[gmp::sub.bigz(myRows, lenCheck)]] + myResults <- c(myResults, isTRUE(all.equal(a@nextRemaining(), b2))) + + t <- capture.output(a@nextIter()) + myResults <- c(myResults, is.null(a@nextIter())) + myResults <- c(myResults, is.null(a@nextNIter(1))) + myResults <- c(myResults, is.null(a@nextRemaining())) + + samp1 <- sample(lenCheck, 5) + samp2 <- gmp::sub.bigz(myRows, lenCheck) + gmp::as.bigz(samp1) + myResults <- c(myResults, isTRUE(all.equal(a[[samp1]], b1[samp1, ]))) + myResults <- c(myResults, isTRUE(all.equal(a[[samp2]], b2[samp1, ]))) + rm(a, a1, b1, b2) + gc() + all(myResults) + } + +})