use crate::cv::subset_vec;
use crate::error::FdarError;
use crate::explain::subsample_rows;
use crate::matrix::FdMatrix;
use crate::scalar_on_function::{fregre_lm, fregre_np_mixed, predict_fregre_lm, predict_fregre_np};
use super::{
build_regression_result, conformal_split, validate_split_inputs, ConformalMethod,
ConformalRegressionResult,
};
#[must_use = "expensive computation whose result should not be discarded"]
pub fn conformal_fregre_lm(
data: &FdMatrix,
y: &[f64],
test_data: &FdMatrix,
scalar_train: Option<&FdMatrix>,
scalar_test: Option<&FdMatrix>,
ncomp: usize,
cal_fraction: f64,
alpha: f64,
seed: u64,
) -> Result<ConformalRegressionResult, FdarError> {
let n = data.nrows();
validate_split_inputs(n, test_data.nrows(), cal_fraction, alpha)?;
if y.len() != n {
return Err(FdarError::InvalidDimension {
parameter: "y",
expected: format!("{n}"),
actual: format!("{}", y.len()),
});
}
if data.ncols() != test_data.ncols() {
return Err(FdarError::InvalidDimension {
parameter: "test_data",
expected: format!("{} columns", data.ncols()),
actual: format!("{} columns", test_data.ncols()),
});
}
let (proper_idx, cal_idx) = conformal_split(n, cal_fraction, seed);
if proper_idx.len() < ncomp + 2 {
return Err(FdarError::InvalidParameter {
parameter: "ncomp",
message: format!(
"proper training set size {} too small for ncomp={}",
proper_idx.len(),
ncomp
),
});
}
let proper_data = subsample_rows(data, &proper_idx);
let proper_y = subset_vec(y, &proper_idx);
let proper_sc = scalar_train.map(|sc| subsample_rows(sc, &proper_idx));
let refit = fregre_lm(&proper_data, &proper_y, proper_sc.as_ref(), ncomp)?;
let cal_data = subsample_rows(data, &cal_idx);
let cal_sc = scalar_train.map(|sc| subsample_rows(sc, &cal_idx));
let cal_preds = predict_fregre_lm(&refit, &cal_data, cal_sc.as_ref());
let cal_residuals: Vec<f64> = cal_idx
.iter()
.enumerate()
.map(|(i, &orig)| (y[orig] - cal_preds[i]).abs())
.collect();
let test_preds = predict_fregre_lm(&refit, test_data, scalar_test);
Ok(build_regression_result(
cal_residuals,
test_preds,
alpha,
ConformalMethod::Split,
))
}
#[must_use = "expensive computation whose result should not be discarded"]
pub fn conformal_fregre_np(
data: &FdMatrix,
y: &[f64],
test_data: &FdMatrix,
argvals: &[f64],
scalar_train: Option<&FdMatrix>,
scalar_test: Option<&FdMatrix>,
h_func: f64,
h_scalar: f64,
cal_fraction: f64,
alpha: f64,
seed: u64,
) -> Result<ConformalRegressionResult, FdarError> {
let n = data.nrows();
validate_split_inputs(n, test_data.nrows(), cal_fraction, alpha)?;
if y.len() != n {
return Err(FdarError::InvalidDimension {
parameter: "y",
expected: format!("{n}"),
actual: format!("{}", y.len()),
});
}
if data.ncols() != test_data.ncols() {
return Err(FdarError::InvalidDimension {
parameter: "test_data",
expected: format!("{} columns", data.ncols()),
actual: format!("{} columns", test_data.ncols()),
});
}
let (proper_idx, cal_idx) = conformal_split(n, cal_fraction, seed);
let proper_data = subsample_rows(data, &proper_idx);
let proper_y = subset_vec(y, &proper_idx);
let proper_sc = scalar_train.map(|sc| subsample_rows(sc, &proper_idx));
let _fit = fregre_np_mixed(
&proper_data,
&proper_y,
argvals,
proper_sc.as_ref(),
h_func,
h_scalar,
)?;
let cal_data = subsample_rows(data, &cal_idx);
let cal_sc = scalar_train.map(|sc| subsample_rows(sc, &cal_idx));
let cal_preds = predict_fregre_np(
&proper_data,
&proper_y,
proper_sc.as_ref(),
&cal_data,
cal_sc.as_ref(),
argvals,
h_func,
h_scalar,
);
let cal_residuals: Vec<f64> = cal_idx
.iter()
.enumerate()
.map(|(i, &orig)| (y[orig] - cal_preds[i]).abs())
.collect();
let test_preds = predict_fregre_np(
&proper_data,
&proper_y,
proper_sc.as_ref(),
test_data,
scalar_test,
argvals,
h_func,
h_scalar,
);
Ok(build_regression_result(
cal_residuals,
test_preds,
alpha,
ConformalMethod::Split,
))
}