1use std::{
7 fmt::{Debug, Display, Formatter, Result as FmtResult},
8 ops::Add,
9 process::{Command, Stdio},
10 str::FromStr,
11};
12
13use approx::assert_relative_eq;
14use nalgebra::{DMatrix, Dim, IsContiguous, Matrix, Storage};
15use num::{complex::Complex64, Float, ToPrimitive};
16
17#[macro_export]
18macro_rules! r_assert_relative_equal {
19 ($lhs:expr, $rhs:expr, $max_relative:expr) => {{
20 $crate::r::r_assert_relative_equal_($lhs, $rhs, $max_relative)
21 }};
22 ($lhs:expr, $rhs:expr) => {{
23 r_assert_relative_equal!($lhs, $rhs, 1e-3)
24 }};
25}
26
27pub fn r_assert_relative_equal_(mut lhs: f64, mut rhs: f64, max_relative: f64) {
28 if lhs < 1e-30 {
29 lhs = 0.0;
30 }
31 if rhs < 1e-30 {
32 rhs = 0.0;
33 }
34 if lhs.is_finite() && rhs.is_finite() {
35 if (lhs - rhs).abs() / lhs > max_relative && (lhs - rhs).abs() / rhs > max_relative {
36 panic!(
37 "Test Failed: r_assert_relative_equal\n\n\tleft : {}\n\tright : {}\n\tdiff : {:e}\n\tmax_relative : {:e}\n\n",
38 lhs, rhs, (lhs - rhs).abs(), max_relative
39 )
40 }
41 } else if lhs.is_nan() && rhs.is_nan()
42 || lhs.is_nan() && !rhs.is_nan()
44 {
45 } else if (lhs.is_finite() && !rhs.is_finite())
46 || (!lhs.is_finite() && rhs.is_finite())
47 || (lhs.is_sign_negative() && rhs.is_sign_positive())
48 || (lhs.is_sign_positive() && rhs.is_sign_negative())
49 {
50 panic!(
51 "Test Failed: r_assert_relative_equal\n\n\tleft : {}\n\tright : {}\n\n",
52 lhs, rhs
53 )
54 }
55}
56
57#[macro_export]
58macro_rules! r_assert_relative_equal_result {
59 ($lhs:expr, $rhs:expr, $max_relative:expr) => {{
60 $crate::r::r_assert_relative_equal_result_(
61 $lhs,
62 Ok(num_traits::ToPrimitive::to_f64($rhs).unwrap()),
63 $max_relative,
64 )
65 }};
66 ($lhs:expr, $rhs:expr) => {{
67 r_assert_relative_equal_result!($lhs, $rhs, 1e-3)
68 }};
69}
70
71pub fn r_assert_relative_equal_result_(
72 lhs: Result<f64, Box<dyn std::error::Error>>,
73 rhs: Result<f64, Box<dyn std::error::Error>>,
74 max_relative: f64,
75) {
76 match (lhs, rhs) {
77 (Ok(o1), Ok(o2)) => {
78 if !(o1.is_nan() && o2.is_nan()) {
79 assert_relative_eq!(o1, o2, max_relative = max_relative)
80 }
81 }
82 (Err(e), Ok(o)) => {
83 if !o.is_nan() {
84 panic!("Test Failed: r_assert_relative_equal_result\n\n\tleft : Err({})\n\tright : Ok({})\n\n", e, o)
85 }
86 }
87 r => panic!("Unexpected: {:?}", r),
88 }
89}
90
91#[derive(Copy, Clone, Debug)]
92pub enum RTesterError {
93 NotFinished,
94}
95
96impl Display for RTesterError {
97 fn fmt(&self, f: &mut Formatter) -> FmtResult {
98 match self {
99 RTesterError::NotFinished => write!(f, "R Tester stopped before finishing"),
100 }
101 }
102}
103
104impl std::error::Error for RTesterError {}
105
106#[derive(Clone, Debug)]
107pub struct RTester {
108 seed: Option<RString>,
109 rand_type: Option<RString>,
110 libraries: RString,
111 script: RString,
112 display: RString,
113 done: RString,
114}
115
116#[derive(Clone, Debug)]
117pub struct RString(String);
118
119impl Display for RString {
120 fn fmt(&self, f: &mut Formatter) -> FmtResult {
121 write!(f, "{}", self.0)
122 }
123}
124
125impl Add for RString {
126 type Output = Self;
127
128 fn add(self, rhs: Self) -> Self::Output {
129 Self(self.0 + rhs.0.as_str())
130 }
131}
132
133impl FromStr for RString {
134 type Err = ();
135
136 fn from_str(s: &str) -> Result<Self, Self::Err> {
137 Ok(Self(s.to_string()))
138 }
139}
140
141impl RString {
142 pub fn from_string(string: String) -> Self {
143 Self(string)
144 }
145
146 pub fn empty() -> Self {
147 Self(String::new())
148 }
149
150 pub fn push(self, string: &str) -> Self {
151 Self(self.0 + string)
152 }
153
154 pub fn as_f64(&self) -> Result<f64, Box<dyn std::error::Error>> {
155 let string = self.0.as_str();
156
157 let string = if string.contains(']') {
158 string
159 .trim()
160 .split("] ")
161 .last()
162 .unwrap()
163 .replace(['<', '>'], "")
164 } else {
165 string.replace(['<', '>'], "")
166 };
167 match string.as_str() {
168 "Inf" => Ok(f64::infinity()),
169 "-Inf" => Ok(f64::NEG_INFINITY),
170 "NaN" | "NA" => Ok(f64::nan()),
171 _ => Ok(string.parse()?),
172 }
173 }
174
175 pub fn as_complex64(&self) -> Result<Complex64, Box<dyn std::error::Error>> {
176 let string = self.0.as_str();
177
178 let string = if string.contains(']') {
179 string
180 .trim()
181 .split("] ")
182 .last()
183 .unwrap()
184 .replace(['<', '>'], "")
185 } else {
186 string.replace(['<', '>'], "")
187 }
188 .replace('i', "");
189
190 let split_index = string
191 .rfind('+')
192 .filter(|i| *i != 0)
193 .unwrap_or(string.rfind('-').filter(|i| *i != 0).unwrap_or(0));
194 let split_string = string.split_at(split_index);
195
196 let real = RString::from_str(split_string.0).unwrap().as_f64()?;
197 let imaginary = RString::from_str(split_string.1).unwrap().as_f64()?;
198
199 Ok(Complex64::new(real, imaginary))
200 }
201
202 pub fn as_complex64_vec(&self) -> Result<Vec<Complex64>, Box<dyn std::error::Error>> {
203 let string = self.0.as_str();
204
205 Ok(string
206 .split_whitespace()
207 .filter(|i| !i.contains('['))
208 .filter_map(|s| RString::from_str(s).unwrap().as_complex64().ok())
209 .collect())
210 }
211
212 pub fn as_f64_vec(&self) -> Result<Vec<f64>, Box<dyn std::error::Error>> {
213 let string = self.0.as_str();
214
215 Ok(string
216 .split_whitespace()
217 .filter_map(|s| RString::from_str(s).unwrap().as_f64().ok())
218 .collect())
219 }
220
221 pub fn as_f64_matrix(&self) -> Result<DMatrix<f64>, Box<dyn std::error::Error>> {
222 let string = self.0.as_str();
223 let mut num_cols = 0;
224 string.lines().take(1).for_each(|s| {
225 num_cols = s.split_ascii_whitespace().count();
226 });
227 let num_rows = string.lines().skip(1).count();
228 let mut ret = DMatrix::from_iterator(
229 num_rows,
230 num_cols,
231 vec![0.0; num_rows * num_cols].into_iter(),
232 );
233 for (row, line) in string.lines().skip(1).enumerate() {
234 for (col, val) in line.split_ascii_whitespace().skip(1).enumerate() {
235 if let Some(x) = ret.get_mut((row, col)) {
236 *x = RString::from_str(val.trim()).unwrap().as_f64().unwrap();
237 }
238 }
239 }
240
241 Ok(ret)
242 }
243
244 pub fn as_bool(&self) -> Result<bool, Box<String>> {
245 let str = self.0.as_str();
246
247 if str.contains("TRUE") {
248 Ok(true)
249 } else if str.contains("FALSE") {
250 Ok(false)
251 } else {
252 Err(Box::new(format!("{str} is not a bool")))
253 }
254 }
255
256 pub fn as_lm_regression(&self) -> LMRegression {
257 let summary = self.0.as_str();
258
259 let mut coefficient_lines = Vec::new();
260 let mut r_squared_line = String::new();
261 let mut significance_line = String::new();
262
263 for line in summary
264 .trim()
265 .split('\n')
266 .skip_while(|line| !line.contains("Coefficients:"))
267 .skip(2)
268 .take_while(|line| !line.contains("---") && !line.is_empty())
269 {
270 coefficient_lines.push(line);
271 }
272
273 for line in summary.trim().split('\n') {
274 if line.starts_with("Multiple R-squared") {
275 r_squared_line = line.to_string();
276 }
277 if line.starts_with("F-statistic") {
278 significance_line = line.to_string();
279 }
280 }
281
282 let coefs = lm_summary_coefficients(&coefficient_lines);
283 let r_squared = r_r_squared(&r_squared_line);
284 let significance = r_significance(&significance_line);
285
286 LMRegression {
287 coefs: coefs
288 .into_iter()
289 .map(|(estimate, std_error, t, p)| LMCoefs {
290 estimate,
291 std_error,
292 t,
293 p,
294 })
295 .collect(),
296 r_squared,
297 f: significance.0,
298 p: significance.1,
299 }
300 }
301
302 pub fn as_rlm_regression(&self) -> RLMRegression {
303 let summary = self.0.as_str();
304
305 let mut coefficient_lines = Vec::new();
306
307 let mut on_coefficients = false;
308 for line in summary.trim().split('\n') {
309 if line.contains("Coefficients:") {
310 on_coefficients = true;
311 } else if line.contains("---") || line.is_empty() {
312 on_coefficients = false;
313 } else if on_coefficients {
314 coefficient_lines.push(line);
315 }
316 }
317
318 let coefs = rlm_summary_coefficients(&coefficient_lines);
319
320 RLMRegression {
321 coefs: coefs
322 .into_iter()
323 .map(|(estimate, std_error, t)| RLMCoefs {
324 estimate,
325 std_error,
326 t,
327 })
328 .collect(),
329 }
330 }
331
332 pub fn as_glm_regression(&self) -> GLMRegression {
333 let summary = self.0.as_str();
334
335 let mut coefficient_lines = Vec::new();
336 let mut null_dev_line = String::new();
337 let mut resid_dev_line = String::new();
338 let mut aic_line = String::new();
339
340 let mut on_coefficients = false;
341 for line in summary.trim().split('\n') {
342 if line.contains("Estimate") {
343 on_coefficients = true;
344 } else if line.is_empty() {
345 on_coefficients = false;
346 } else if on_coefficients {
347 coefficient_lines.push(line);
348 }
349 }
350
351 for line in summary.trim().split('\n') {
352 if line.trim().starts_with("Null deviance") {
353 null_dev_line = line.to_string();
354 }
355 if line.starts_with("Residual deviance") {
356 resid_dev_line = line.to_string();
357 }
358 if line.starts_with("AIC") {
359 aic_line = line.to_string();
360 }
361 }
362
363 let coefs = lm_summary_coefficients(&coefficient_lines);
364 let null_dev = r_null_deviance(&null_dev_line);
365 let resid_dev = r_residual_deviance(&resid_dev_line);
366 let aic = r_aic(&aic_line);
367
368 GLMRegression {
369 coefs: coefs
370 .into_iter()
371 .map(|(estimate, std_error, z, p)| GLMCoefs {
372 estimate,
373 std_error,
374 z,
375 p,
376 })
377 .collect(),
378 null_dev,
379 resid_dev,
380 aic,
381 }
382 }
383
384 pub fn as_r_fit(&self) -> RFitRegression {
385 let summary = self.0.as_str();
386
387 let mut coefficient_lines = Vec::new();
388 let mut r_squared_line = String::new();
389 let mut significance_line = String::new();
390 let mut wald_line = String::new();
391
392 for line in summary
393 .trim()
394 .split('\n')
395 .skip_while(|line| !line.contains("Coefficients:"))
396 .skip(2)
397 .take_while(|line| !line.contains("---") && !line.is_empty())
398 {
399 coefficient_lines.push(line);
400 }
401
402 for line in summary.trim().split('\n') {
403 if line.starts_with("Multiple R-squared (Robust)") {
404 r_squared_line = line.to_string();
405 }
406 if line.starts_with("Reduction in Dispersion") {
407 significance_line = line.to_string();
408 }
409 if line.starts_with("Overall Wald Test") {
410 wald_line = line.to_string();
411 }
412 }
413
414 let coefs = lm_summary_coefficients(&coefficient_lines);
415 let r_squared_robust = r_r_squared(&r_squared_line);
416 let red_dispersion = r_red_dispersion(&significance_line);
417 let wald_test = r_wald_test(&wald_line);
418
419 RFitRegression {
420 coefs: coefs
421 .into_iter()
422 .map(|(estimate, std_error, t, p)| LMCoefs {
423 estimate,
424 std_error,
425 t,
426 p,
427 })
428 .collect(),
429 r_squared_robust,
430 red_disp_test: red_dispersion.0,
431 disp_p: red_dispersion.1,
432 wald_test: wald_test.0,
433 wald_p: wald_test.1,
434 }
435 }
436
437 pub fn as_one_way_r_fit(&self) -> Vec<OneWayRFit> {
438 let summary = self.0.as_str();
439
440 let mut ret = Vec::new();
441 for line in summary
442 .trim()
443 .split('\n')
444 .skip_while(|line| !line.contains("Estimate"))
445 .skip(1)
446 {
447 let split = line.split_whitespace().collect::<Vec<_>>();
448 ret.push(OneWayRFit {
449 i: split[1].to_string(),
450 j: split[2].to_string(),
451 estimate: RString::from_str(split[3]).unwrap().as_f64().unwrap(),
452 std_err: RString::from_str(split[4]).unwrap().as_f64().unwrap(),
453 confidence_interval: (
454 RString::from_str(split[5]).unwrap().as_f64().unwrap(),
455 RString::from_str(split[6]).unwrap().as_f64().unwrap(),
456 ),
457 });
458 }
459
460 ret
461 }
462
463 pub fn as_raov(&self) -> Vec<RAOV> {
464 let summary = self.0.as_str();
465
466 let mut ret = Vec::new();
467 for line in summary
468 .trim()
469 .split('\n')
470 .skip_while(|line| !line.contains("Mean RD"))
471 .skip(1)
472 {
473 let mut line = line.to_string();
474 for i in 1..=20 {
475 line = line.replace(&format!("x[, {i}]"), &format!("x[,{i}]"));
476 }
477 let split = line.split_whitespace().collect::<Vec<_>>();
478 ret.push(RAOV {
479 name: split[0].to_string(),
480 df: RString::from_str(split[1]).unwrap().as_f64().unwrap(),
481 rd: RString::from_str(split[2]).unwrap().as_f64().unwrap(),
482 mean_rd: RString::from_str(split[3]).unwrap().as_f64().unwrap(),
483 f: RString::from_str(split[4]).unwrap().as_f64().unwrap(),
484 p: RString::from_str(split[5]).unwrap().as_f64().unwrap(),
485 });
486 }
487
488 ret
489 }
490
491 pub fn from_f64_slice(v: &[f64]) -> Self {
492 let length = v.len();
493
494 let mut ret = "c(".to_string();
495
496 for (i, v_i) in v.iter().take(length).enumerate() {
497 ret += &v_i.to_string();
498 if i < length - 1 {
499 ret += ", "
500 }
501 }
502
503 ret += ")";
504 Self(ret)
505 }
506
507 pub fn from_complex64_slice(v: &[Complex64]) -> Self {
508 let length = v.len();
509
510 let mut ret = "c(".to_string();
511
512 for (i, v_i) in v.iter().take(length).enumerate() {
513 ret += &v_i.re.to_string();
514 ret += "+";
515 ret += &v_i.re.to_string();
516 ret += "i";
517
518 if i < length - 1 {
519 ret += ", "
520 }
521 }
522
523 ret += ")";
524 Self(ret)
525 }
526
527 pub fn from_f64_matrix<R, C, S>(m: &Matrix<f64, R, C, S>) -> Self
528 where
529 R: Dim,
530 C: Dim,
531 S: Storage<f64, R, C> + IsContiguous,
532 {
533 let (row_size, col_size) = m.shape();
534 let slice_string = RString::from_f64_slice(m.as_slice());
535 let mut ret = "matrix(".to_string();
536 ret += &slice_string.to_string();
537 ret += &format!(", nrow={}, ncol={})", row_size, col_size);
538 Self(ret)
539 }
540
541 pub fn from_bool(b: bool) -> Self {
542 Self(match b {
543 true => "TRUE".to_string(),
544 false => "FALSE".to_string(),
545 })
546 }
547
548 pub fn from_f64<F: ToPrimitive + std::fmt::Debug>(num: F) -> Self {
549 let num = num.to_f64().unwrap_or(f64::nan());
550 Self(if num.is_infinite() && num.is_sign_positive() {
551 "Inf".to_string()
552 } else if num.is_infinite() && num.is_sign_negative() {
553 "-Inf".to_string()
554 } else if num.is_nan() {
555 "NaN".to_string()
556 } else {
557 format!("{}", num)
558 })
559 }
560
561 pub fn from_library_name(lib_name: &str) -> Self {
562 Self(String::from("library(\"") + lib_name + "\")")
563 }
564}
565
566pub fn print_mat<R, C, S>(x: &Matrix<f64, R, C, S>)
567where
568 R: Dim,
569 C: Dim,
570 S: Storage<f64, R, C>,
571{
572 print!(" ");
573 for i in 0..x.ncols() {
574 print!("{:4} ", i);
575 }
576 println!();
577 for i in 0..x.nrows() {
578 print!("{:4} ", i);
579 for j in 0..x.ncols() {
580 print!("{:4} ", x[(i, j)]);
581 }
582 println!();
583 }
584}
585
586const RSCRIPT: Option<&str> = option_env!("Rscript");
587
588impl Default for RTester {
589 fn default() -> Self {
590 Self {
591 seed: None,
592 rand_type: None,
593 libraries: RString::empty(),
594 script: RString::empty(),
595 display: RString::empty(),
596 done: RString::from_str("R_TESTER_DONE").unwrap(),
597 }
598 }
599}
600
601impl RTester {
602 pub fn new() -> Self {
603 Self::default()
604 }
605
606 pub fn add_library(mut self, library: &RString) -> Self {
607 self.libraries.0 += library.0.as_str();
608 self.libraries.0 += ";";
609 self
610 }
611
612 pub fn set_seed(mut self, seed: u16) -> Self {
613 self.seed = Some(RString::from_f64(seed));
614 self
615 }
616
617 pub fn set_rand_type(mut self, rand_type: &str) -> Self {
618 self.rand_type = Some(RString::from_str(rand_type).unwrap());
619 self
620 }
621
622 pub fn set_script(mut self, script: &RString) -> Self {
623 self.script = script.clone();
624 self
625 }
626
627 pub fn set_display(mut self, display: &RString) -> Self {
628 self.display = display.clone();
629 self
630 }
631
632 pub fn run(&self) -> Result<RString, Box<dyn std::error::Error>> {
633 let seed_piece = match (self.seed.clone(), self.rand_type.clone()) {
634 (Some(seed), Some(rand_type)) => {
635 RString::from_string(format!("set.seed({}, '{}');", seed, rand_type))
636 }
637 (None, Some(rand_type)) => {
638 RString::from_string(format!("set.seed(NULL, '{}');", rand_type))
639 }
640 (Some(seed), None) => {
641 RString::from_string(format!("set.seed({}, 'Marsaglia-Multicarry');", seed))
642 }
643 (None, None) => RString::from_str("").unwrap(),
644 };
645
646 let script = format!(
647 "options(warn=-1, show.error.messages=FALSE, digits=14, width=1e4, scipen=1);{}{}{}print({}, digits=14, dig.tst=14);cat('{}');",
648 self.libraries.0, seed_piece.0, self.script.0, self.display.0, self.done.0,
649 );
650 let mut ret_string = String::from_utf8(
651 Command::new(
652 RSCRIPT
653 .ok_or("")
654 .expect("Environment variable `Rscript` not set"),
655 )
656 .args(["-e", &script])
657 .stdout(Stdio::piped())
658 .spawn()?
659 .wait_with_output()?
660 .stdout,
661 )?;
662
663 let done_message = (0..self.done.0.len())
664 .filter_map(|_| ret_string.pop())
665 .collect::<String>()
666 .chars()
667 .rev()
668 .collect::<String>();
669 if done_message == self.done.0 {
670 Ok(RString(ret_string))
671 } else {
672 let error_script = format!(
673 "options(digits=14, width=1e4);{}{}{}print({});cat('{}');",
674 self.libraries.0, seed_piece.0, self.script.0, self.display.0, self.done.0,
675 );
676 let ret = Command::new(
677 RSCRIPT
678 .ok_or("")
679 .expect("Environment variable `Rscript` not set"),
680 )
681 .args(["-e", &error_script])
682 .stdout(Stdio::piped())
683 .stderr(Stdio::piped())
684 .spawn()?
685 .wait_with_output()?;
686 let output = String::from_utf8(ret.stdout)?;
687 let error = String::from_utf8(ret.stderr)?;
688 println!("Input:\n{}", script);
689 println!("Output:\n{}", output);
690 println!("Error:\n{}", error);
691 Err(Box::new(RTesterError::NotFinished))
692 }
693 }
694}
695
696fn lm_summary_coefficients(lines: &[&str]) -> Vec<(f64, f64, f64, f64)> {
697 lines
698 .iter()
699 .take_while(|s| !s.trim().is_empty())
700 .filter_map(|line| {
701 let nums = line
702 .split_whitespace()
703 .filter_map(|s| RString::from_str(s).unwrap().as_f64().ok())
704 .collect::<Vec<_>>();
705 if nums.len() == 4 {
706 Some((nums[0], nums[1], nums[2], nums[3]))
707 } else {
708 None
709 }
710 })
711 .collect()
712}
713
714fn rlm_summary_coefficients(lines: &[&str]) -> Vec<(f64, f64, f64)> {
715 lines
716 .iter()
717 .skip(1)
718 .filter(|l| l.split_ascii_whitespace().count() == 4)
719 .map(|line| {
720 let nums = line
721 .split_whitespace()
722 .filter_map(|s| RString::from_str(s).unwrap().as_f64().ok())
723 .collect::<Vec<_>>();
724 (nums[0], nums[1], nums[2])
725 })
726 .collect()
727}
728
729fn r_r_squared(line: &str) -> f64 {
730 RString::from_str(line.split_whitespace().last().unwrap_or("0.0"))
731 .unwrap()
732 .as_f64()
733 .expect("R^2 error")
734}
735
736fn r_significance(line: &str) -> (f64, f64) {
737 let split_line = line.split_whitespace().collect::<Vec<_>>();
738 (
739 RString::from_str(split_line[1])
740 .unwrap()
741 .as_f64()
742 .expect("F-statistic error"),
743 RString::from_str(split_line.last().unwrap())
744 .unwrap()
745 .as_f64()
746 .expect("P-value error"),
747 )
748}
749
750fn r_null_deviance(line: &str) -> f64 {
751 let split_line = line.split_whitespace().collect::<Vec<_>>();
752 RString::from_str(split_line[2])
753 .unwrap()
754 .as_f64()
755 .expect("Null deviance error")
756}
757
758fn r_residual_deviance(line: &str) -> f64 {
759 let split_line = line.split_whitespace().collect::<Vec<_>>();
760 RString::from_str(split_line[2])
761 .unwrap()
762 .as_f64()
763 .expect("Residual deviance error")
764}
765
766fn r_aic(line: &str) -> f64 {
767 let split_line = line.split_whitespace().collect::<Vec<_>>();
768 RString::from_str(split_line[1])
769 .unwrap()
770 .as_f64()
771 .expect("AIC deviance error")
772}
773
774fn r_red_dispersion(line: &str) -> (f64, f64) {
775 let split_line = line.split_whitespace().collect::<Vec<_>>();
776 (
777 RString::from_str(split_line.get(4).unwrap_or(&"0.0"))
778 .unwrap()
779 .as_f64()
780 .expect("Reduction in Dispersion Test"),
781 RString::from_str(split_line.last().unwrap_or(&"0.0"))
782 .unwrap()
783 .as_f64()
784 .expect("P Value"),
785 )
786}
787
788fn r_wald_test(line: &str) -> (f64, f64) {
789 let split_line = line.split_whitespace().collect::<Vec<_>>();
790 (
791 RString::from_str(split_line.get(3).unwrap_or(&"0.0"))
792 .unwrap()
793 .as_f64()
794 .expect("Overall Wald Test"),
795 RString::from_str(split_line.last().unwrap_or(&"0.0"))
796 .unwrap()
797 .as_f64()
798 .expect("P Value"),
799 )
800}
801
802#[derive(Copy, Clone, Debug, Default)]
803pub struct RGenerator {
804 seed: u16,
805}
806
807impl RGenerator {
808 pub fn new() -> Self {
809 Self::default()
810 }
811
812 pub fn set_seed(self, seed: u16) -> Self {
813 Self { seed, ..self }
814 }
815
816 pub fn generate_uniform<T1: ToPrimitive + Debug, T2: ToPrimitive + Debug>(
817 &self,
818 len: T1,
819 (lower_bound, upper_bound): (T2, T2),
820 ) -> Vec<f64> {
821 RTester::new()
822 .set_seed(self.seed)
823 .set_script(&RString::from_string(format!(
824 "ret = runif({}, {}, {});",
825 RString::from_f64(len),
826 RString::from_f64(lower_bound),
827 RString::from_f64(upper_bound),
828 )))
829 .set_display(&RString::from_str("ret").unwrap())
830 .run()
831 .expect("R running error")
832 .as_f64_vec()
833 .expect("R running error")
834 }
835
836 pub fn generate_uniform_matrix<
837 T1: ToPrimitive + Debug,
838 T2: ToPrimitive + Debug,
839 T3: ToPrimitive + Debug + Clone,
840 >(
841 &self,
842 num_rows: T1,
843 num_columns: T2,
844 (lower_bound, upper_bound): (T3, T3),
845 ) -> DMatrix<f64> {
846 let mut x = RTester::new()
847 .set_seed(self.seed)
848 .set_display(&RString::from_string(format!(
849 "matrix(runif({0}*{1}, {2}, {3}), nrow={0}, ncol={1})",
850 RString::from_f64(num_rows),
851 RString::from_f64(num_columns),
852 RString::from_f64(lower_bound.clone()),
853 RString::from_f64(upper_bound.clone()),
854 )))
855 .run()
856 .expect("R error")
857 .as_f64_matrix()
858 .expect("R array error");
859 x.iter_mut().for_each(|x_i| {
860 if x_i.is_nan() {
861 *x_i = lower_bound.to_f64().unwrap()
862 + ((upper_bound.clone().to_f64().unwrap()
863 - lower_bound.clone().to_f64().unwrap())
864 / 2.0)
865 }
866 });
867 x
868 }
869
870 pub fn generate_errors<
871 T1: ToPrimitive + Debug,
872 T2: ToPrimitive + Debug + Clone,
873 T3: ToPrimitive + Debug,
874 >(
875 &self,
876 len: T1,
877 (lower_bound, upper_bound): (T2, T2),
878 fuzz_amount: T3,
879 ) -> Vec<f64> {
880 let mut errors = RTester::new()
881 .set_seed(self.seed)
882 .set_display(&RString::from_string(format!(
883 "rnorm({0}, {1}, {2}) + runif({0}, -{3}, {3})",
884 RString::from_f64(len),
885 RString::from_f64(lower_bound.clone()),
886 RString::from_f64(upper_bound.clone()),
887 RString::from_f64(fuzz_amount)
888 )))
889 .run()
890 .expect("R error")
891 .as_f64_vec()
892 .expect("R array error");
893 errors.iter_mut().for_each(|e| {
894 if e.is_nan() {
895 *e = lower_bound.clone().to_f64().unwrap()
896 + ((upper_bound.to_f64().unwrap() - lower_bound.clone().to_f64().unwrap())
897 / 2.0)
898 }
899 });
900 errors
901 }
902}
903
904#[derive(Clone, Debug)]
905pub struct LMCoefs {
906 pub estimate: f64,
907 pub std_error: f64,
908 pub t: f64,
909 pub p: f64,
910}
911
912#[derive(Clone, Debug)]
913pub struct RLMCoefs {
914 pub estimate: f64,
915 pub std_error: f64,
916 pub t: f64,
917}
918
919#[derive(Clone, Debug)]
920pub struct GLMCoefs {
921 pub estimate: f64,
922 pub std_error: f64,
923 pub z: f64,
924 pub p: f64,
925}
926
927#[derive(Clone, Debug)]
928pub struct LMRegression {
929 pub coefs: Vec<LMCoefs>,
930 pub r_squared: f64,
931 pub f: f64,
932 pub p: f64,
933}
934
935#[derive(Clone, Debug)]
936pub struct RLMRegression {
937 pub coefs: Vec<RLMCoefs>,
938}
939
940#[derive(Clone, Debug)]
941pub struct GLMRegression {
942 pub coefs: Vec<GLMCoefs>,
943 pub null_dev: f64,
944 pub resid_dev: f64,
945 pub aic: f64,
946}
947
948#[derive(Clone, Debug)]
949pub struct RFitRegression {
950 pub coefs: Vec<LMCoefs>,
951 pub r_squared_robust: f64,
952 pub red_disp_test: f64,
953 pub disp_p: f64,
954 pub wald_test: f64,
955 pub wald_p: f64,
956}
957
958#[derive(Clone, Debug)]
959pub struct OneWayRFit {
960 pub i: String,
961 pub j: String,
962 pub estimate: f64,
963 pub std_err: f64,
964 pub confidence_interval: (f64, f64),
965}
966
967#[derive(Clone, Debug)]
968pub struct RAOV {
969 pub name: String,
970 pub df: f64,
971 pub rd: f64,
972 pub mean_rd: f64,
973 pub f: f64,
974 pub p: f64,
975}