Skip to content

Commit 100192d

Browse files
author
NightlordTW
committed
Refactor repeated code
1 parent 4d00f10 commit 100192d

File tree

4 files changed

+237
-77
lines changed

4 files changed

+237
-77
lines changed

R/RcppExports.R

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,51 @@ ptvdf <- function(x, df, lower) {
3535
.Call(`_SimTOST_ptvdf`, x, df, lower)
3636
}
3737

38+
#' @title Check Equivalence
39+
#'
40+
#' @description
41+
#' This function evaluates whether equivalence criteria are met.
42+
#' It first checks whether all primary endpoints satisfy
43+
#' equivalence (if sequential testing is enabled). Then, it determines whether the
44+
#' required number of endpoints (`k`) meet the equivalence threshold.
45+
#' The function returns a structured matrix that includes equivalence decisions,
46+
#' test results, mean estimates, and standard deviations.
47+
#'
48+
#' @param typey An unsigned integer vector (`arma::uvec`) indicating the type of each endpoint:
49+
#' - `1` = Primary endpoint
50+
#' - `2` = Secondary endpoint
51+
#' @param adseq A boolean flag (`TRUE` if sequential testing is enabled).
52+
#' - If `TRUE`, all primary endpoints must pass equivalence for secondary endpoints to be evaluated.
53+
#' - If `FALSE`, primary and secondary endpoints are evaluated independently.
54+
#' @param tbioq A matrix (`arma::mat`) indicating the equivalence test results:
55+
#' - `1` = Equivalence met
56+
#' - `0` = Equivalence not met
57+
#' @param k An integer specifying the minimum number of endpoints required to establish equivalence.
58+
#' @param mu0 A matrix (`arma::mat`) containing the estimated means for the reference treatment group.
59+
#' @param mu1 A matrix (`arma::mat`) containing the estimated means for the treatment under evaluation.
60+
#' @param sd0 A matrix (`arma::mat`) containing the standard deviations for the reference treatment group.
61+
#' @param sd1 A matrix (`arma::mat`) containing the standard deviations for the treatment under evaluation.
62+
#'
63+
#' @details
64+
#' - **Sequential Adjustment (`adseq = TRUE`)**:
65+
#' - Ensures that all primary endpoints must meet equivalence before secondary endpoints are evaluated.
66+
#' - **Non-Sequential Testing (`adseq = FALSE`)**:
67+
#' - Evaluates all endpoints simultaneously without enforcing hierarchical constraints.
68+
#' - **Final Equivalence Decision (`totaly`)**:
69+
#' - `1` if at least `k` endpoints meet equivalence and (if sequential testing is enabled) all primary endpoints pass.
70+
#' - `0` otherwise.
71+
#'
72+
#' @return
73+
#' An `arma::mat` containing the final equivalence decision along with test statistics:
74+
#' - `totaly` (1 × 1 matrix): Binary indicator (1 = equivalence established, 0 = not established).
75+
#' - `tbioq` (m × n matrix): Equivalence test results for each endpoint.
76+
#' - `mu0, mu1` (m × n matrices): Mean estimates for the reference and treatment groups.
77+
#' - `sd0, sd1` (m × n matrices): Standard deviations for the reference and treatment groups.
78+
#' @expor
79+
check_equivalence <- function(typey, adseq, tbioq, k, mu0, mu1, sd0, sd1) {
80+
.Call(`_SimTOST_check_equivalence`, typey, adseq, tbioq, k, mu0, mu1, sd0, sd1)
81+
}
82+
3883
#' @title Simulate a 2x2 Crossover Design and Compute Difference of Means (DOM)
3984
#'
4085
#' @description

man/check_equivalence.Rd

Lines changed: 65 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/RcppExports.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,24 @@ BEGIN_RCPP
3737
return rcpp_result_gen;
3838
END_RCPP
3939
}
40+
// check_equivalence
41+
arma::mat check_equivalence(const arma::uvec& typey, bool adseq, const arma::mat& tbioq, int k, const arma::mat& mu0, const arma::mat& mu1, const arma::mat& sd0, const arma::mat& sd1);
42+
RcppExport SEXP _SimTOST_check_equivalence(SEXP typeySEXP, SEXP adseqSEXP, SEXP tbioqSEXP, SEXP kSEXP, SEXP mu0SEXP, SEXP mu1SEXP, SEXP sd0SEXP, SEXP sd1SEXP) {
43+
BEGIN_RCPP
44+
Rcpp::RObject rcpp_result_gen;
45+
Rcpp::RNGScope rcpp_rngScope_gen;
46+
Rcpp::traits::input_parameter< const arma::uvec& >::type typey(typeySEXP);
47+
Rcpp::traits::input_parameter< bool >::type adseq(adseqSEXP);
48+
Rcpp::traits::input_parameter< const arma::mat& >::type tbioq(tbioqSEXP);
49+
Rcpp::traits::input_parameter< int >::type k(kSEXP);
50+
Rcpp::traits::input_parameter< const arma::mat& >::type mu0(mu0SEXP);
51+
Rcpp::traits::input_parameter< const arma::mat& >::type mu1(mu1SEXP);
52+
Rcpp::traits::input_parameter< const arma::mat& >::type sd0(sd0SEXP);
53+
Rcpp::traits::input_parameter< const arma::mat& >::type sd1(sd1SEXP);
54+
rcpp_result_gen = Rcpp::wrap(check_equivalence(typey, adseq, tbioq, k, mu0, mu1, sd0, sd1));
55+
return rcpp_result_gen;
56+
END_RCPP
57+
}
4058
// test_2x2_dom
4159
arma::mat test_2x2_dom(int n, arma::vec muT, arma::vec muR, arma::mat SigmaW, arma::rowvec lequi_tol, arma::rowvec uequi_tol, arma::rowvec alpha, double sigmaB, arma::vec dropout, arma::vec Eper, arma::vec Eco, arma::uvec typey, bool adseq, int k, int arm_seed);
4260
RcppExport SEXP _SimTOST_test_2x2_dom(SEXP nSEXP, SEXP muTSEXP, SEXP muRSEXP, SEXP SigmaWSEXP, SEXP lequi_tolSEXP, SEXP uequi_tolSEXP, SEXP alphaSEXP, SEXP sigmaBSEXP, SEXP dropoutSEXP, SEXP EperSEXP, SEXP EcoSEXP, SEXP typeySEXP, SEXP adseqSEXP, SEXP kSEXP, SEXP arm_seedSEXP) {
@@ -147,6 +165,7 @@ RcppExport SEXP _rcpp_module_boot_test();
147165
static const R_CallMethodDef CallEntries[] = {
148166
{"_SimTOST_ptv", (DL_FUNC) &_SimTOST_ptv, 3},
149167
{"_SimTOST_ptvdf", (DL_FUNC) &_SimTOST_ptvdf, 3},
168+
{"_SimTOST_check_equivalence", (DL_FUNC) &_SimTOST_check_equivalence, 8},
150169
{"_SimTOST_test_2x2_dom", (DL_FUNC) &_SimTOST_test_2x2_dom, 15},
151170
{"_SimTOST_test_2x2_rom", (DL_FUNC) &_SimTOST_test_2x2_rom, 15},
152171
{"_SimTOST_test_par_dom", (DL_FUNC) &_SimTOST_test_par_dom, 17},

src/module.cpp

Lines changed: 108 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,90 @@ arma::mat ptvdf(arma::mat x, arma::mat df, bool lower) {
6060
return arma::reshape(y, 1, n);
6161
}
6262

63+
//' @title Check Equivalence
64+
//'
65+
//' @description
66+
//' This function evaluates whether equivalence criteria are met.
67+
//' It first checks whether all primary endpoints satisfy
68+
//' equivalence (if sequential testing is enabled). Then, it determines whether the
69+
//' required number of endpoints (`k`) meet the equivalence threshold.
70+
//' The function returns a structured matrix that includes equivalence decisions,
71+
//' test results, mean estimates, and standard deviations.
72+
//'
73+
//' @param typey An unsigned integer vector (`arma::uvec`) indicating the type of each endpoint:
74+
//' - `1` = Primary endpoint
75+
//' - `2` = Secondary endpoint
76+
//' @param adseq A boolean flag (`TRUE` if sequential testing is enabled).
77+
//' - If `TRUE`, all primary endpoints must pass equivalence for secondary endpoints to be evaluated.
78+
//' - If `FALSE`, primary and secondary endpoints are evaluated independently.
79+
//' @param tbioq A matrix (`arma::mat`) indicating the equivalence test results:
80+
//' - `1` = Equivalence met
81+
//' - `0` = Equivalence not met
82+
//' @param k An integer specifying the minimum number of endpoints required to establish equivalence.
83+
//' @param mu0 A matrix (`arma::mat`) containing the estimated means for the reference treatment group.
84+
//' @param mu1 A matrix (`arma::mat`) containing the estimated means for the treatment under evaluation.
85+
//' @param sd0 A matrix (`arma::mat`) containing the standard deviations for the reference treatment group.
86+
//' @param sd1 A matrix (`arma::mat`) containing the standard deviations for the treatment under evaluation.
87+
//'
88+
//' @details
89+
//' - **Sequential Adjustment (`adseq = TRUE`)**:
90+
//' - Ensures that all primary endpoints must meet equivalence before secondary endpoints are evaluated.
91+
//' - **Non-Sequential Testing (`adseq = FALSE`)**:
92+
//' - Evaluates all endpoints simultaneously without enforcing hierarchical constraints.
93+
//' - **Final Equivalence Decision (`totaly`)**:
94+
//' - `1` if at least `k` endpoints meet equivalence and (if sequential testing is enabled) all primary endpoints pass.
95+
//' - `0` otherwise.
96+
//'
97+
//' @return
98+
//' An `arma::mat` containing the final equivalence decision along with test statistics:
99+
//' - `totaly` (1 × 1 matrix): Binary indicator (1 = equivalence established, 0 = not established).
100+
//' - `tbioq` (m × n matrix): Equivalence test results for each endpoint.
101+
//' - `mu0, mu1` (m × n matrices): Mean estimates for the reference and treatment groups.
102+
//' - `sd0, sd1` (m × n matrices): Standard deviations for the reference and treatment groups.
103+
//' @export
104+
// [[Rcpp::export]]
105+
arma::mat check_equivalence(const arma::uvec& typey, bool adseq,
106+
const arma::mat& tbioq, int k,
107+
const arma::mat& mu0, const arma::mat& mu1,
108+
const arma::mat& sd0, const arma::mat& sd1) {
109+
// primary endpoints in case of sequencial adjustment
110+
int sumtypey;
111+
// in case no primary endpoint is added.
112+
if( accu(typey) >= 0) {
113+
sumtypey = accu(tbioq.cols(typey)); // sum of primary endpoint rejected
114+
}else{
115+
sumtypey = 1;
116+
}
117+
118+
// Total number of primary endpoints
119+
int lentypey = typey.n_elem;
120+
121+
// Determine if all primary endpoints meet the equivalence criteria under sequential adjustment.
122+
//
123+
// If `adseq` (sequential testing) is disabled (`false`), equivalence is not required for all primary endpoints,
124+
// so `sumpe` is automatically set to `true`.
125+
//
126+
// If `adseq` is enabled (`true`), `sumpe` is set to `true` only if all primary endpoints (`sumtypey`) meet
127+
// the required equivalence criteria (`lentypey`), meaning all must pass.
128+
bool sumpe = !adseq || (sumtypey == lentypey);
129+
130+
// Check if at least `k` endpoints meet equivalence criteria
131+
bool sumt = accu(tbioq) >= k;
132+
133+
// Store final equivalence decision
134+
arma::mat totaly(1,1);
135+
totaly(0, 0) = (sumt && sumpe) ? 1 : 0;
136+
137+
// Combine results into a response matrix
138+
arma::mat response0 = join_rows(totaly, tbioq);
139+
arma::mat response1 = join_rows(mu0, mu1);
140+
arma::mat response2 = join_rows(sd0, sd1);
141+
arma::mat response3 = join_rows(response0, response1);
142+
143+
return join_rows(response3, response2);
144+
}
145+
146+
63147
//' @title Simulate a 2x2 Crossover Design and Compute Difference of Means (DOM)
64148
//'
65149
//' @description
@@ -168,9 +252,6 @@ arma::mat test_2x2_dom(int n, arma::vec muT, arma::vec muR,
168252
mat alpha0 = conv_to<mat>::from(alpha);
169253
mat tbioq = conv_to<mat>::from((ptost < alpha0));
170254

171-
// Initialize `sumpe` (Sequential Pass Status) to `true` (assume success by default)
172-
bool sumpe = true;
173-
174255
// `sumtypey` stores the number of primary endpoints that meet equivalence criteria.
175256
// Default to 1 in case no primary endpoints are specified.
176257
int sumtypey = 1;
@@ -184,10 +265,16 @@ arma::mat test_2x2_dom(int n, arma::vec muT, arma::vec muR,
184265
// Store the total number of primary endpoints
185266
int lentypey = typey.n_elem;
186267

187-
// If sequential adjustment (`adseq`) is enabled, ensure all primary endpoints meet equivalence
188-
if (adseq) {
189-
sumpe = (sumtypey == lentypey); // `true` if all primary endpoints pass, `false` otherwise
190-
}
268+
// Determine if all primary endpoints meet the equivalence criteria under sequential adjustment.
269+
//
270+
// If `adseq` (sequential testing) is disabled (`false`), equivalence is not required for all primary endpoints,
271+
// so `sumpe` is automatically set to `true`.
272+
//
273+
// If `adseq` is enabled (`true`), `sumpe` is set to `true` only if all primary endpoints (`sumtypey`) meet
274+
// the required equivalence criteria (`lentypey`), meaning all must pass.
275+
//
276+
// This ensures that secondary endpoints are tested only if all primary endpoints demonstrate equivalence.
277+
bool sumpe = !adseq || (sumtypey == lentypey);
191278

192279
// Check the Total Number of Endpoints Meeting Equivalence Criteria
193280
bool sumt = accu(tbioq) >= k;
@@ -330,7 +417,6 @@ arma::mat test_2x2_rom(int n, arma::vec muT, arma::vec muR,
330417
mat tbioq = conv_to<mat>::from((ptost < alpha0));
331418

332419
// primary endpoints in case of sequencial adjustment
333-
bool sumpe = true;
334420
int sumtypey;
335421
// in case no primary endpoint is added.
336422
if( accu(typey) >= 0) {
@@ -342,9 +428,16 @@ arma::mat test_2x2_rom(int n, arma::vec muT, arma::vec muR,
342428

343429
int lentypey = typey.n_elem;
344430

345-
if(adseq == true){
346-
sumpe = sumtypey == lentypey;
347-
}
431+
// Determine if all primary endpoints meet the equivalence criteria under sequential adjustment.
432+
//
433+
// If `adseq` (sequential testing) is disabled (`false`), equivalence is not required for all primary endpoints,
434+
// so `sumpe` is automatically set to `true`.
435+
//
436+
// If `adseq` is enabled (`true`), `sumpe` is set to `true` only if all primary endpoints (`sumtypey`) meet
437+
// the required equivalence criteria (`lentypey`), meaning all must pass.
438+
//
439+
// This ensures that secondary endpoints are tested only if all primary endpoints demonstrate equivalence.
440+
bool sumpe = !adseq || (sumtypey == lentypey);
348441

349442
bool sumt = accu(tbioq) >= k;
350443

@@ -476,39 +569,8 @@ arma::mat test_par_dom(int n, arma::vec muT, arma::vec muR,
476569
mat alpha0 = conv_to<mat>::from(alpha);
477570
mat tbioq = conv_to<mat>::from((ptost < alpha0));
478571

479-
// primary endpoints in case of sequencial adjustment
480-
// primary endpoints in case of sequencial adjustment
481-
bool sumpe = true;
482-
int sumtypey;
483-
// in case no primary endpoint is added.
484-
if( accu(typey) >= 0) {
485-
sumtypey = accu(tbioq.cols(typey)); // sum of primary endpoint rejected
486-
}else{
487-
sumtypey = 1;
488-
}
489-
// total number of primary endpoints
490-
int lentypey = typey.n_elem;
491-
492-
if(adseq == true){
493-
sumpe = sumtypey == lentypey;
494-
}
495-
496-
bool sumt = accu(tbioq) >= k;
497-
498-
mat totaly(1,1);
499-
500-
if(sumt&sumpe){
501-
totaly(0, 0) = 1;
502-
}else{
503-
totaly(0, 0) = 0;
504-
}
505-
506-
mat response0 = join_rows<mat>(totaly,tbioq);
507-
mat response1 = join_rows<mat>(mu0,mu1);
508-
mat response2 = join_rows<mat>(sd0,sd1);
509-
mat response3 = join_rows<mat>(response0,response1);
510-
511-
return join_rows<mat>(response3,response2);
572+
// Call the check_equivalence function
573+
return check_equivalence(typey, adseq, tbioq, k, mu0, mu1, sd0, sd1);
512574
}
513575

514576
//' @title Simulate a Parallel Design and Compute Ratio of Means (ROM)
@@ -611,39 +673,8 @@ arma::mat test_par_rom(int n, arma::vec muT, arma::vec muR,
611673
mat alpha0 = conv_to<mat>::from(alpha);
612674
mat tbioq = conv_to<mat>::from((ptost < alpha0));
613675

614-
// primary endpoints in case of sequencial adjustment
615-
bool sumpe = true;
616-
int sumtypey;
617-
// in case no primary endpoint is added.
618-
if( accu(typey) >= 0) {
619-
sumtypey = accu(tbioq.cols(typey)); // sum of primary endpoint rejected
620-
}else{
621-
sumtypey = 1;
622-
}
623-
624-
// total number of primary endpoints
625-
int lentypey = typey.n_elem;
626-
if(adseq == true){
627-
sumpe = sumtypey == lentypey;
628-
}
629-
630-
bool sumt = accu(tbioq) >= k;
631-
632-
mat totaly(1,1);
633-
634-
if(sumt&sumpe){
635-
totaly(0, 0) = 1;
636-
}else{
637-
totaly(0, 0) = 0;
638-
}
639-
640-
641-
mat response0 = join_rows<mat>(totaly,tbioq);
642-
mat response1 = join_rows<mat>(mu0,mu1);
643-
mat response2 = join_rows<mat>(sd0,sd1);
644-
mat response3 = join_rows<mat>(response0,response1);
645-
646-
return join_rows<mat>(response3,response2);
676+
// Call the check_equivalence function
677+
return check_equivalence(typey, adseq, tbioq, k, mu0, mu1, sd0, sd1);
647678
}
648679

649680

0 commit comments

Comments
 (0)