1#![cfg(feature = "wasm")]
7
8use wasm_bindgen::prelude::*;
9
10use super::domain::check_domain;
11use crate::error::{error_json, error_to_json};
12use crate::linalg;
13use crate::regularized;
14
15#[wasm_bindgen]
31pub fn ols_prediction_intervals(
32 y_json: &str,
33 x_vars_json: &str,
34 new_x_json: &str,
35 alpha: f64,
36) -> String {
37 if let Err(e) = check_domain() {
38 return error_to_json(&e);
39 }
40
41 let y: Vec<f64> = match serde_json::from_str(y_json) {
42 Ok(v) => v,
43 Err(e) => return error_json(&format!("Failed to parse y: {}", e)),
44 };
45
46 let x_vars: Vec<Vec<f64>> = match serde_json::from_str(x_vars_json) {
47 Ok(v) => v,
48 Err(e) => return error_json(&format!("Failed to parse x_vars: {}", e)),
49 };
50
51 let new_x_vecs: Vec<Vec<f64>> = match serde_json::from_str(new_x_json) {
52 Ok(v) => v,
53 Err(e) => return error_json(&format!("Failed to parse new_x: {}", e)),
54 };
55
56 let new_x_refs: Vec<&[f64]> = new_x_vecs.iter().map(|v| v.as_slice()).collect();
57
58 match crate::prediction_intervals::prediction_intervals(&y, &x_vars, &new_x_refs, alpha) {
59 Ok(output) => serde_json::to_string(&output)
60 .unwrap_or_else(|_| error_json("Failed to serialize prediction intervals")),
61 Err(e) => error_json(&e.to_string()),
62 }
63}
64
65#[wasm_bindgen]
79pub fn ridge_prediction_intervals(
80 y_json: &str,
81 x_vars_json: &str,
82 new_x_json: &str,
83 alpha: f64,
84 lambda: f64,
85 standardize: bool,
86) -> String {
87 if let Err(e) = check_domain() {
88 return error_to_json(&e);
89 }
90
91 let y: Vec<f64> = match serde_json::from_str(y_json) {
92 Ok(v) => v,
93 Err(e) => return error_json(&format!("Failed to parse y: {}", e)),
94 };
95
96 let x_vars: Vec<Vec<f64>> = match serde_json::from_str(x_vars_json) {
97 Ok(v) => v,
98 Err(e) => return error_json(&format!("Failed to parse x_vars: {}", e)),
99 };
100
101 let new_x_vecs: Vec<Vec<f64>> = match serde_json::from_str(new_x_json) {
102 Ok(v) => v,
103 Err(e) => return error_json(&format!("Failed to parse new_x: {}", e)),
104 };
105
106 let (x, _n, _p) = build_design_matrix(&y, &x_vars);
108
109 let options = regularized::ridge::RidgeFitOptions {
110 lambda,
111 intercept: true,
112 standardize,
113 ..Default::default()
114 };
115
116 let fit = match regularized::ridge::ridge_fit(&x, &y, &options) {
117 Ok(f) => f,
118 Err(e) => return error_json(&e.to_string()),
119 };
120
121 let new_x_refs: Vec<&[f64]> = new_x_vecs.iter().map(|v| v.as_slice()).collect();
122
123 match crate::prediction_intervals::ridge_prediction_intervals(&fit, &x_vars, &new_x_refs, alpha) {
124 Ok(output) => serde_json::to_string(&output)
125 .unwrap_or_else(|_| error_json("Failed to serialize prediction intervals")),
126 Err(e) => error_json(&e.to_string()),
127 }
128}
129
130#[wasm_bindgen]
143#[allow(clippy::too_many_arguments)]
144pub fn lasso_prediction_intervals(
145 y_json: &str,
146 x_vars_json: &str,
147 new_x_json: &str,
148 alpha: f64,
149 lambda: f64,
150 standardize: bool,
151 max_iter: usize,
152 tol: f64,
153) -> String {
154 if let Err(e) = check_domain() {
155 return error_to_json(&e);
156 }
157
158 let y: Vec<f64> = match serde_json::from_str(y_json) {
159 Ok(v) => v,
160 Err(e) => return error_json(&format!("Failed to parse y: {}", e)),
161 };
162
163 let x_vars: Vec<Vec<f64>> = match serde_json::from_str(x_vars_json) {
164 Ok(v) => v,
165 Err(e) => return error_json(&format!("Failed to parse x_vars: {}", e)),
166 };
167
168 let new_x_vecs: Vec<Vec<f64>> = match serde_json::from_str(new_x_json) {
169 Ok(v) => v,
170 Err(e) => return error_json(&format!("Failed to parse new_x: {}", e)),
171 };
172
173 let (x, _n, _p) = build_design_matrix(&y, &x_vars);
174
175 let options = regularized::lasso::LassoFitOptions {
176 lambda,
177 intercept: true,
178 standardize,
179 max_iter,
180 tol,
181 ..Default::default()
182 };
183
184 let fit = match regularized::lasso::lasso_fit(&x, &y, &options) {
185 Ok(f) => f,
186 Err(e) => return error_json(&e.to_string()),
187 };
188
189 let new_x_refs: Vec<&[f64]> = new_x_vecs.iter().map(|v| v.as_slice()).collect();
190
191 match crate::prediction_intervals::lasso_prediction_intervals(&fit, &x_vars, &new_x_refs, alpha) {
192 Ok(output) => serde_json::to_string(&output)
193 .unwrap_or_else(|_| error_json("Failed to serialize prediction intervals")),
194 Err(e) => error_json(&e.to_string()),
195 }
196}
197
198#[wasm_bindgen]
212#[allow(clippy::too_many_arguments)]
213pub fn elastic_net_prediction_intervals(
214 y_json: &str,
215 x_vars_json: &str,
216 new_x_json: &str,
217 alpha: f64,
218 lambda: f64,
219 enet_alpha: f64,
220 standardize: bool,
221 max_iter: usize,
222 tol: f64,
223) -> String {
224 if let Err(e) = check_domain() {
225 return error_to_json(&e);
226 }
227
228 let y: Vec<f64> = match serde_json::from_str(y_json) {
229 Ok(v) => v,
230 Err(e) => return error_json(&format!("Failed to parse y: {}", e)),
231 };
232
233 let x_vars: Vec<Vec<f64>> = match serde_json::from_str(x_vars_json) {
234 Ok(v) => v,
235 Err(e) => return error_json(&format!("Failed to parse x_vars: {}", e)),
236 };
237
238 let new_x_vecs: Vec<Vec<f64>> = match serde_json::from_str(new_x_json) {
239 Ok(v) => v,
240 Err(e) => return error_json(&format!("Failed to parse new_x: {}", e)),
241 };
242
243 let (x, _n, _p) = build_design_matrix(&y, &x_vars);
244
245 let options = regularized::elastic_net::ElasticNetOptions {
246 lambda,
247 alpha: enet_alpha,
248 intercept: true,
249 standardize,
250 max_iter,
251 tol,
252 ..Default::default()
253 };
254
255 let fit = match regularized::elastic_net::elastic_net_fit(&x, &y, &options) {
256 Ok(f) => f,
257 Err(e) => return error_json(&e.to_string()),
258 };
259
260 let new_x_refs: Vec<&[f64]> = new_x_vecs.iter().map(|v| v.as_slice()).collect();
261
262 match crate::prediction_intervals::elastic_net_prediction_intervals(&fit, &x_vars, &new_x_refs, alpha) {
263 Ok(output) => serde_json::to_string(&output)
264 .unwrap_or_else(|_| error_json("Failed to serialize prediction intervals")),
265 Err(e) => error_json(&e.to_string()),
266 }
267}
268
269fn build_design_matrix(y: &[f64], x_vars: &[Vec<f64>]) -> (linalg::Matrix, usize, usize) {
271 let n = y.len();
272 let p = x_vars.len();
273
274 let mut x_data = vec![1.0; n * (p + 1)];
275 for (j, x_var) in x_vars.iter().enumerate() {
276 for (i, &val) in x_var.iter().enumerate() {
277 x_data[i * (p + 1) + j + 1] = val;
278 }
279 }
280
281 (linalg::Matrix::new(n, p + 1, x_data), n, p)
282}