ellalgo_rs/ell_calc.rs
1// mod lib;
2use crate::cutting_plane::CutStatus;
3
4/// The `EllCalcCore` struct represents the parameters for calculating the new Ellipsoid Search Space.
5///
6/// Properties:
7///
8/// * `n_f`: The `n_f` property represents the number of variables in the ellipsoid search space.
9/// * `n_plus_1`: The `n_plus_1` property represents the value of `n + 1`, where `n` is the dimension of
10/// the search space. It is used in calculations related to the ellipsoid search space.
11/// * `half_n`: The `half_n` property represents half of the dimension of the ellipsoid search space. It
12/// is used in the calculation of the parameters for the ellipsoid search space.
13/// * `cst1`: The `cst1` property is a constant used in the calculation of the parameters for the new
14/// Ellipsoid Search Space. Its specific purpose and value are not provided in the code snippet.
15/// * `cst2`: The `cst2` property is a constant used in the calculation of the parameters for the new
16/// Ellipsoid Search Space. It is not specified what exactly it represents or how it is used in the
17/// calculation.
18/// * `cst3`: The `cst3` property is a constant value used in the calculation of the parameters for the
19/// new Ellipsoid Search Space. It is not specified what exactly this constant represents or how it is
20/// used in the calculations.
21#[derive(Debug, Clone)]
22pub struct EllCalcCore {
23 pub n_f: f64,
24 pub n_plus_1: f64,
25 pub half_n: f64,
26 pub inv_n: f64,
27 cst1: f64,
28 cst2: f64,
29}
30
31impl EllCalcCore {
32 /// Constructs a new EllCalcCore instance, initializing its fields based on the provided dimension n_f.
33 ///
34 /// This is a constructor function for the EllCalcCore struct. It takes in the dimension n_f and uses
35 /// it to calculate and initialize the other fields of EllCalcCore that depend on n_f.
36 ///
37 /// Being a constructor function, it is part of the public API of the EllCalcCore struct. The
38 /// documentation follows the conventions and style of the other documentation in this crate.
39 ///
40 /// Arguments:
41 ///
42 /// * `n_f`: The parameter `n_f` represents the value of `n` in the calculations. It is a floating-point
43 /// number.
44 ///
45 /// Returns:
46 ///
47 /// The `new` function returns an instance of the `EllCalcCore` struct.
48 ///
49 /// # Examples:
50 ///
51 /// ```rust
52 /// use approx_eq::assert_approx_eq;
53 /// use ellalgo_rs::ell_calc::EllCalcCore;
54 ///
55 /// let ell_calc_core = EllCalcCore::new(4.0);
56 ///
57 /// assert_approx_eq!(ell_calc_core.n_f, 4.0);
58 /// assert_approx_eq!(ell_calc_core.half_n, 2.0);
59 /// assert_approx_eq!(ell_calc_core.n_plus_1, 5.0);
60 /// ```
61 pub fn new(n_f: f64) -> EllCalcCore {
62 let n_plus_1 = n_f + 1.0;
63 let half_n = n_f / 2.0;
64 let inv_n = 1.0 / n_f;
65 let n_sq = n_f * n_f;
66 let cst0 = 1.0 / (n_f + 1.0);
67 let cst1 = n_sq / (n_sq - 1.0);
68 let cst2 = 2.0 * cst0;
69
70 EllCalcCore {
71 n_f,
72 n_plus_1,
73 half_n,
74 inv_n,
75 cst1,
76 cst2,
77 }
78 }
79
80 #[doc = svgbobdoc::transform!(
81 /// The function calculates the core values for updating an ellipsoid with either a parallel-cut or
82 /// a deep-cut.
83 ///
84 /// Arguments:
85 ///
86 /// * `beta0`: The parameter `beta0` represents the semi-minor axis of the ellipsoid before the cut. It is
87 /// a floating-point number.
88 /// * `beta1`: The parameter `beta1` represents the length of the semi-minor axis of the ellipsoid.
89 /// * `tsq`: tsq is a reference to a f64 value, which represents the square of the semi-major axis
90 /// of the ellipsoid.
91 ///
92 /// ```svgbob
93 /// _.-'''''''-._
94 /// ,' | `.
95 /// / | | \
96 /// . | | .
97 /// | | | |
98 /// | | |. |
99 /// | | | |
100 /// :\ | | /:
101 /// | `._ | _.' |
102 /// | |'-.......-' |
103 /// | | | |
104 /// "-τ" "-β" "-β" +τ
105 /// 1 0
106 ///
107 /// β + β
108 /// 0 1
109 /// β = ───────
110 /// 2
111 ///
112 /// 1 ⎛ 2 ⎞ 2
113 /// h = ─ ⋅ ⎜τ + β ⋅ β ⎟ + n ⋅ β
114 /// 2 ⎝ 0 1⎠
115 /// _____________________
116 /// ╱ 2 2
117 /// k = h + ╲╱ h - (n + 1) ⋅ η ⋅ β
118 ///
119 /// 1 η
120 /// σ = ───── = ─
121 /// μ + 1 k
122 ///
123 /// 1 η
124 /// ─ = ─────
125 /// μ k - η
126 ///
127 /// ϱ = β ⋅ σ
128 ///
129 /// 2 2 1 ⎛ 2 ⎞
130 /// δ ⋅ τ = τ + ─ ⋅ ⎜β ⋅ σ - β ⋅ β ⎟
131 /// μ ⎝ 0 1⎠
132 /// ```
133 ///
134 /// # Examples
135 ///
136 /// ```
137 /// use approx_eq::assert_approx_eq;
138 /// use ellalgo_rs::ell_calc::EllCalcCore;
139 ///
140 /// let ell_calc_core = EllCalcCore::new(4.0);
141 /// let (rho, sigma, delta) = ell_calc_core.calc_parallel_bias_cut_fast(1.0, 2.0, 4.0, 2.0, 12.0);
142 /// assert_approx_eq!(rho, 1.2);
143 /// assert_approx_eq!(sigma, 0.8);
144 /// assert_approx_eq!(delta, 0.8);
145 /// ```
146 )]
147 pub fn calc_parallel_bias_cut_fast(
148 &self,
149 beta0: f64,
150 beta1: f64,
151 tsq: f64,
152 b0b1: f64,
153 eta: f64,
154 ) -> (f64, f64, f64) {
155 let bavg = (beta0 + beta1) * 0.5;
156 let bavgsq = bavg * bavg;
157 let h = (tsq + b0b1) * 0.5 + self.n_f * bavgsq;
158 let k = h + (h * h - eta * self.n_plus_1 * bavgsq).sqrt();
159 let inv_mu_plus_1 = eta / k;
160 let inv_mu = eta / (k - eta);
161 let rho = bavg * inv_mu_plus_1;
162 let sigma = inv_mu_plus_1;
163 let delta = (tsq + inv_mu * (bavgsq * inv_mu_plus_1 - b0b1)) / tsq;
164
165 (rho, sigma, delta)
166 }
167
168 #[doc = svgbobdoc::transform!(
169 /// The function calculates the core values for updating an ellipsoid with either a parallel-cut or
170 /// a deep-cut.
171 ///
172 /// Arguments:
173 ///
174 /// * `beta0`: The parameter `beta0` represents the semi-minor axis of the ellipsoid before the cut. It is
175 /// a floating-point number.
176 /// * `beta1`: The parameter `beta1` represents the length of the semi-minor axis of the ellipsoid.
177 /// * `tsq`: tsq is a reference to a f64 value, which represents the square of the semi-major axis
178 /// of the ellipsoid.
179 ///
180 /// ```svgbob
181 /// _.-'''''''-._
182 /// ,' | `.
183 /// / | | \
184 /// . | | .
185 /// | | | |
186 /// | | |. |
187 /// | | | |
188 /// :\ | | /:
189 /// | `._ | _.' |
190 /// | |'-.......-' |
191 /// | | | |
192 /// "-τ" "-β" "-β" +τ
193 /// 1 0
194 ///
195 /// 2
196 /// η = τ + n ⋅ β ⋅ β
197 /// 0 1
198 /// β + β
199 /// 0 1
200 /// β = ───────
201 /// 2
202 ///
203 /// 1 ⎛ 2 ⎞ 2
204 /// h = ─ ⋅ ⎜τ + β ⋅ β ⎟ + n ⋅ β
205 /// 2 ⎝ 0 1⎠
206 /// _____________________
207 /// ╱ 2 2
208 /// k = h + ╲╱ h - (n + 1) ⋅ η ⋅ β
209 ///
210 /// 1 η
211 /// σ = ───── = ─
212 /// μ + 1 k
213 ///
214 /// 1 η
215 /// ─ = ─────
216 /// μ k - η
217 ///
218 /// ϱ = β ⋅ σ
219 ///
220 /// 2 2 1 ⎛ 2 ⎞
221 /// δ ⋅ τ = τ + ─ ⋅ ⎜β ⋅ σ - β ⋅ β ⎟
222 /// μ ⎝ 0 1⎠
223 /// ```
224 ///
225 /// # Examples
226 ///
227 /// ```rust
228 /// use approx_eq::assert_approx_eq;
229 /// use ellalgo_rs::ell_calc::EllCalcCore;
230 ///
231 /// let ell_calc_core = EllCalcCore::new(4.0);
232 /// let (rho, sigma, delta) = ell_calc_core.calc_parallel_bias_cut(1.0, 2.0, 4.0);
233 /// assert_approx_eq!(rho, 1.2);
234 /// assert_approx_eq!(sigma, 0.8);
235 /// assert_approx_eq!(delta, 0.8);
236 /// ```
237 )]
238 #[inline]
239 pub fn calc_parallel_bias_cut(&self, beta0: f64, beta1: f64, tsq: f64) -> (f64, f64, f64) {
240 let b0b1 = beta0 * beta1;
241 let eta = tsq + self.n_f * b0b1;
242 self.calc_parallel_bias_cut_fast(beta0, beta1, tsq, b0b1, eta)
243 }
244
245 #[doc = svgbobdoc::transform!(
246 /// The function calculates the core values for updating an ellipsoid with the parallel-cut method.
247 ///
248 /// Arguments:
249 ///
250 /// * `beta1`: The parameter `beta1` represents the semi-minor axis of the ellipsoid. It is a floating-point
251 /// number.
252 /// * `tsq`: The parameter `tsq` represents the square of the gamma semi-axis length of the ellipsoid.
253 ///
254 /// ```svgbob
255 /// _.-'''''''-._
256 /// ,' | `.
257 /// / | | \
258 /// . | | .
259 /// | | |
260 /// | | . |
261 /// | | |
262 /// :\ | | /:
263 /// | `._ | _.' |
264 /// | |'-.......-' |
265 /// | | | |
266 /// "-τ" "-β" 0 +τ
267 /// 1
268 ///
269 /// 2 2 2
270 /// α = β / τ
271 ///
272 /// n 2
273 /// h = ─ ⋅ α
274 /// 2
275 /// ___________
276 /// ╱ 2 2
277 /// r = h + ╲╱ h + 1 - α
278 ///
279 /// β
280 /// ϱ = ─────
281 /// r + 1
282 ///
283 /// 2
284 /// σ = ─────
285 /// r + 1
286 ///
287 /// r
288 /// δ = ─────────
289 /// r - 1 / n
290 /// ```
291 ///
292 /// # Example
293 ///
294 /// ```
295 /// use approx_eq::assert_approx_eq;
296 /// use ellalgo_rs::ell_calc::EllCalcCore;
297 ///
298 /// let ell_calc_core = EllCalcCore::new(4.0);
299 /// let (rho, sigma, delta) = ell_calc_core.calc_parallel_central_cut(1.0, 4.0);
300 /// assert_approx_eq!(rho, 0.4);
301 /// assert_approx_eq!(sigma, 0.8);
302 /// assert_approx_eq!(delta, 1.2);
303 /// ```
304 )]
305 pub fn calc_parallel_central_cut(&self, beta1: f64, tsq: f64) -> (f64, f64, f64) {
306 let b1sq = beta1 * beta1;
307 let a1sq = b1sq / tsq;
308 let h = self.half_n * a1sq;
309 let r = h + (1.0 - a1sq + h * h).sqrt();
310 let r_plus_1 = r + 1.0;
311 let rho = beta1 / r_plus_1;
312 let sigma = 2.0 / r_plus_1;
313 let delta = r / (r - self.inv_n);
314
315 (rho, sigma, delta)
316 }
317
318 #[doc = svgbobdoc::transform!(
319 /// The function calculates the core values needed for updating an ellipsoid with the deep-cut method.
320 ///
321 /// Arguments:
322 ///
323 /// * `beta`: The `beta` parameter represents a value used in the calculation of the core of updating
324 /// the ellipsoid with the deep-cut. It is of type `f64`, which means it is a 64-bit floating-point
325 /// number.
326 /// * `tau`: The parameter `tau` represents the time constant of the system. It is a measure of how
327 /// quickly the system responds to changes.
328 /// * `eta`: The parameter `eta` represents the deep-cut factor. It is a measure of how much the
329 /// ellipsoid is being updated or modified.
330 ///
331 /// ```svgbob
332 /// _.-'''''''-._
333 /// ,' | `.
334 /// / | \
335 /// . | .
336 /// | | |
337 /// | | . |
338 /// | | |
339 /// :\ | /:
340 /// | `._ | _.' |
341 /// | '-.......-' |
342 /// | | |
343 /// "-τ" "-β" +τ
344 ///
345 /// η
346 /// ϱ = ─────
347 /// n + 1
348 ///
349 /// 2 ⋅ ϱ
350 /// σ = ─────
351 /// "τ + β"
352 ///
353 /// 2 2 2
354 /// n τ - β
355 /// δ = ────── ⋅ ───────
356 /// 2 2
357 /// n - 1 τ
358 /// ```
359 ///
360 /// # Example
361 ///
362 /// ```
363 /// use approx_eq::assert_approx_eq;
364 /// use ellalgo_rs::ell_calc::EllCalcCore;
365 ///
366 /// let ell_calc_core = EllCalcCore::new(4.0);
367 /// let (rho, sigma, delta) = ell_calc_core.calc_bias_cut_fast(1.0, 2.0, 6.0);
368 /// assert_approx_eq!(rho, 1.2);
369 /// assert_approx_eq!(sigma, 0.8);
370 /// assert_approx_eq!(delta, 0.8);
371 /// ```
372 )]
373 pub fn calc_bias_cut_fast(&self, beta: f64, tau: f64, eta: f64) -> (f64, f64, f64) {
374 let rho = eta / self.n_plus_1;
375 let sigma = 2.0 * rho / (tau + beta);
376 let alpha = beta / tau;
377 let delta = self.cst1 * (1.0 - alpha * alpha);
378 (rho, sigma, delta)
379 }
380
381 #[doc = svgbobdoc::transform!(
382 /// The function calculates the core values needed for updating an ellipsoid with the deep-cut method.
383 ///
384 /// Arguments:
385 ///
386 /// * `beta`: The `beta` parameter represents a value used in the calculation of the core of updating
387 /// the ellipsoid with the deep-cut. It is of type `f64`, which means it is a 64-bit floating-point
388 /// number.
389 /// * `tau`: The parameter `tau` represents the time constant of the system. It is a measure of how
390 /// quickly the system responds to changes.
391 /// * `eta`: The parameter `eta` represents the deep-cut factor. It is a measure of how much the
392 /// ellipsoid is being updated or modified.
393 ///
394 /// ```svgbob
395 /// _.-'''''''-._
396 /// ,' | `.
397 /// / | \
398 /// . | .
399 /// | | |
400 /// | | . |
401 /// | | |
402 /// :\ | /:
403 /// | `._ | _.' |
404 /// | '-.......-' |
405 /// | | |
406 /// "-τ" "-β" +τ
407 ///
408 /// η = τ + n ⋅ β
409 ///
410 /// η
411 /// ϱ = ─────
412 /// n + 1
413 ///
414 /// 2 ⋅ ϱ
415 /// σ = ─────
416 /// "τ + β"
417 ///
418 /// 2 2 2
419 /// n τ - β
420 /// δ = ────── ⋅ ───────
421 /// 2 2
422 /// n - 1 τ
423 /// ```
424 ///
425 /// # Example
426 ///
427 /// ```
428 /// use approx_eq::assert_approx_eq;
429 /// use ellalgo_rs::ell_calc::EllCalcCore;
430 ///
431 /// let ell_calc_core = EllCalcCore::new(4.0);
432 /// let (rho, sigma, delta) = ell_calc_core.calc_bias_cut(1.0, 2.0);
433 /// assert_approx_eq!(rho, 1.2);
434 /// assert_approx_eq!(sigma, 0.8);
435 /// assert_approx_eq!(delta, 0.8);
436 /// ```
437 )]
438 #[inline]
439 pub fn calc_bias_cut(&self, beta: f64, tau: f64) -> (f64, f64, f64) {
440 let eta = tau + self.n_f * beta;
441 self.calc_bias_cut_fast(beta, tau, eta)
442 }
443
444 #[doc = svgbobdoc::transform!(
445 /// The `calc_central_cut_core` function calculates the core values needed for updating an ellipsoid with the
446 /// central-cut.
447 ///
448 /// Arguments:
449 ///
450 /// * `tsq`: The parameter `tsq` represents the square of the time taken to update the ellipsoid with
451 /// the central-cut.
452 ///
453 /// ```svgbob
454 /// _.-'''''''-._
455 /// ,' | `.
456 /// / | \
457 /// . | .
458 /// | |
459 /// | . |
460 /// | |
461 /// :\ | /:
462 /// | `._ | _.' |
463 /// | '-.......-' |
464 /// | | |
465 /// "-τ" 0 +τ
466 ///
467 /// 2
468 /// σ = ─────
469 /// n + 1
470 ///
471 /// τ
472 /// ϱ = ─────
473 /// n + 1
474 ///
475 /// 2
476 /// n
477 /// δ = ──────
478 /// 2
479 /// n - 1
480 /// ```
481 ///
482 /// # Example
483 ///
484 /// ```rust
485 /// use approx_eq::assert_approx_eq;
486 /// use ellalgo_rs::ell_calc::EllCalcCore;
487 /// let ell_calc_core = EllCalcCore::new(4.0);
488 /// let (rho, sigma, delta) = ell_calc_core.calc_central_cut(4.0);
489 /// assert_approx_eq!(rho, 0.4);
490 /// assert_approx_eq!(sigma, 0.4);
491 /// assert_approx_eq!(delta, 16.0/15.0);
492 /// ```
493 )]
494 pub fn calc_central_cut(&self, tsq: f64) -> (f64, f64, f64) {
495 // self.mu = self.half_n_minus_1;
496 let sigma = self.cst2;
497 let rho = tsq.sqrt() / self.n_plus_1;
498 let delta = self.cst1;
499 (rho, sigma, delta)
500 }
501}
502
503/// The `EllCalc` struct represents an ellipsoid search space in Rust.
504///
505/// EllCalc = {x | (x - xc)^T mq^-1 (x - xc) \le \kappa}
506///
507/// Properties:
508///
509/// * `n_f`: The `n_f` property is a floating-point number that represents the dimensionality of the
510/// search space. It indicates the number of variables or dimensions in the ellipsoid search space.
511/// * `helper`: The `helper` property is of type `EllCalcCore` and is used to perform
512/// calculations related to the ellipsoid search space. It is a separate struct that contains the
513/// necessary methods and data for these calculations.
514/// * `use_parallel_cut`: A boolean flag indicating whether to use parallel cut or not.
515#[derive(Debug, Clone)]
516pub struct EllCalc {
517 n_f: f64,
518 pub helper: EllCalcCore,
519 pub use_parallel_cut: bool,
520}
521
522impl EllCalc {
523 /// The `new` function constructs a new [`EllCalc`] object with a given value for `n_f` and sets the
524 /// `use_parallel_cut` flag to `true`.
525 ///
526 /// Arguments:
527 ///
528 /// * `n_f`: The parameter `n_f` is a floating-point number that is used to initialize the `EllCalc`
529 /// struct.
530 ///
531 /// Returns:
532 ///
533 /// The `new` function is returning an instance of the `EllCalc` struct.
534 ///
535 /// # Examples:
536 ///
537 /// ```rust
538 /// use ellalgo_rs::ell_calc::EllCalc;
539 /// let ell_calc = EllCalc::new(4);
540 /// assert!(ell_calc.use_parallel_cut);
541 /// ```
542 pub fn new(n: usize) -> EllCalc {
543 let n_f = n as f64;
544 let helper = EllCalcCore::new(n_f);
545
546 EllCalc {
547 n_f,
548 helper,
549 use_parallel_cut: true,
550 }
551 }
552
553 // pub fn update_cut(&mut self, beta: f64) -> CutStatus { self.calc_bias_cut(beta) }
554
555 /// The function calculates the updating of an ellipsoid with a single or parallel-cut.
556 ///
557 /// Arguments:
558 ///
559 /// * `beta`: The `beta` parameter is a tuple containing two values: `beta0` and `beta1_opt`. `beta0` is of type
560 /// `f64` and `beta1_opt` is an optional value of type `Option<f64>`.
561 /// * `tsq`: The `tsq` parameter is a reference to a `f64` value.
562 pub fn calc_single_or_parallel_bias_cut(
563 &self,
564 beta: &(f64, Option<f64>),
565 tsq: f64,
566 ) -> (CutStatus, (f64, f64, f64)) {
567 let (beta0, beta1_opt) = *beta;
568 if let Some(beta1) = beta1_opt {
569 self.calc_parallel_bias_cut(beta0, beta1, tsq)
570 } else {
571 self.calc_bias_cut(beta0, tsq)
572 }
573 }
574
575 /// The function calculates the updating of an ellipsoid with a single or parallel-cut (one of them is central-cut).
576 ///
577 /// Arguments:
578 ///
579 /// * `beta`: The `beta` parameter is a tuple containing two values: `f64` and `Option<f64>`.
580 /// The first value, denoted as `_b0`, is of type `f64`. The second value, `beta1_opt`, is of type `Option<f64>`.
581 /// * `tsq`: The `tsq` parameter is a reference to a `f64` value.
582 pub fn calc_single_or_parallel_central_cut(
583 &self,
584 beta: &(f64, Option<f64>),
585 tsq: f64,
586 ) -> (CutStatus, (f64, f64, f64)) {
587 let (_b0, beta1_opt) = *beta;
588 if let Some(beta1) = beta1_opt {
589 self.calc_parallel_central_cut(beta1, tsq)
590 } else {
591 self.calc_central_cut(tsq)
592 }
593 }
594
595 /// The function calculates the updating of an ellipsoid with a single or parallel-cut (discrete version).
596 ///
597 /// Arguments:
598 ///
599 /// * `beta`: The `beta` parameter is a tuple containing two values: `beta0` and `beta1_opt`. `beta0` is of type
600 /// `f64` and `beta1_opt` is an optional value of type `Option<f64>`.
601 /// * `tsq`: The `tsq` parameter is a reference to a `f64` value.
602 pub fn calc_single_or_parallel_q(
603 &self,
604 beta: &(f64, Option<f64>),
605 tsq: f64,
606 ) -> (CutStatus, (f64, f64, f64)) {
607 let (beta0, beta1_opt) = *beta;
608 if let Some(beta1) = beta1_opt {
609 self.calc_parallel_q(beta0, beta1, tsq)
610 } else {
611 self.calc_bias_cut_q(beta0, tsq)
612 }
613 }
614
615 /// Parallel Deep Cut
616 ///
617 /// # Examples:
618 ///
619 /// ```rust
620 /// use approx_eq::assert_approx_eq;
621 /// use ellalgo_rs::ell_calc::EllCalc;
622 /// use ellalgo_rs::cutting_plane::CutStatus;
623 ///
624 /// let ell_calc = EllCalc::new(4);
625 /// let (status, _result) = ell_calc.calc_parallel_bias_cut(0.07, 0.03, 0.01);
626 /// assert_eq!(status, CutStatus::NoSoln);
627 ///
628 /// let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_bias_cut(0.0, 0.05, 0.01);
629 /// assert_eq!(status, CutStatus::Success);
630 /// assert_approx_eq!(sigma, 0.8);
631 /// assert_approx_eq!(rho, 0.02);
632 /// assert_approx_eq!(delta, 1.2);
633 ///
634 /// let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_bias_cut(0.05, 0.11, 0.01);
635 /// assert_eq!(status, CutStatus::Success);
636 /// assert_approx_eq!(sigma, 0.8);
637 /// assert_approx_eq!(rho, 0.06);
638 /// assert_approx_eq!(delta, 0.8);
639 ///
640 /// let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_bias_cut(0.01, 0.04, 0.01);
641 /// assert_eq!(status, CutStatus::Success);
642 /// assert_approx_eq!(sigma, 0.928);
643 /// assert_approx_eq!(rho, 0.0232);
644 /// assert_approx_eq!(delta, 1.232);
645 /// ```
646 pub fn calc_parallel_bias_cut(
647 &self,
648 beta0: f64,
649 beta1: f64,
650 tsq: f64,
651 ) -> (CutStatus, (f64, f64, f64)) {
652 if beta1 < beta0 {
653 return (CutStatus::NoSoln, (0.0, 0.0, 0.0)); // no sol'n
654 }
655
656 let b1sqn = beta1 * (beta1 / tsq);
657 let t1n = 1.0 - b1sqn;
658 if t1n < 0.0 || !self.use_parallel_cut {
659 return self.calc_bias_cut(beta0, tsq);
660 }
661
662 (
663 CutStatus::Success,
664 self.helper.calc_parallel_bias_cut(beta0, beta1, tsq),
665 )
666 }
667
668 /// Discrete Parallel Deep Cut
669 ///
670 /// # Examples:
671 ///
672 /// ```rust
673 /// use approx_eq::assert_approx_eq;
674 /// use ellalgo_rs::ell_calc::EllCalc;
675 /// use ellalgo_rs::cutting_plane::CutStatus;
676 ///
677 /// let ell_calc = EllCalc::new(4);
678 /// let (status, _result) = ell_calc.calc_parallel_q(-0.07, 0.07, 0.01);
679 /// assert_eq!(status, CutStatus::NoEffect);
680 ///
681 /// let (status, _result) = ell_calc.calc_parallel_q(-0.04, 0.0625, 0.01);
682 /// assert_eq!(status, CutStatus::NoEffect);
683 /// ```
684 pub fn calc_parallel_q(
685 &self,
686 beta0: f64,
687 beta1: f64,
688 tsq: f64,
689 ) -> (CutStatus, (f64, f64, f64)) {
690 if beta1 < beta0 {
691 return (CutStatus::NoSoln, (0.0, 0.0, 0.0)); // no sol'n
692 }
693
694 if (beta1 > 0.0) && beta1 * beta1 >= tsq || !self.use_parallel_cut {
695 return self.calc_bias_cut_q(beta0, tsq);
696 }
697
698 let b0b1 = beta0 * beta1;
699 let eta = tsq + self.n_f * b0b1;
700 if eta <= 0.0 {
701 return (CutStatus::NoEffect, (0.0, 0.0, 1.0)); // no effect
702 }
703
704 (
705 CutStatus::Success,
706 self.helper
707 .calc_parallel_bias_cut_fast(beta0, beta1, tsq, b0b1, eta),
708 )
709 }
710
711 /// Parallel Central Cut
712 ///
713 /// # Examples:
714 ///
715 /// ```rust
716 /// use approx_eq::assert_approx_eq;
717 /// use ellalgo_rs::ell_calc::EllCalc;
718 /// use ellalgo_rs::cutting_plane::CutStatus;
719 ///
720 /// let ell_calc = EllCalc::new(4);
721 /// let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_central_cut(0.11, 0.01);
722 /// assert_eq!(status, CutStatus::Success);
723 /// assert_approx_eq!(sigma, 0.4);
724 /// assert_approx_eq!(rho, 0.02);
725 /// assert_approx_eq!(delta, 16.0 / 15.0);
726 ///
727 /// let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_central_cut(0.05, 0.01);
728 /// assert_eq!(status, CutStatus::Success);
729 /// assert_approx_eq!(sigma, 0.8);
730 /// assert_approx_eq!(rho, 0.02);
731 /// assert_approx_eq!(delta, 1.2);
732 /// ```
733 pub fn calc_parallel_central_cut(&self, beta1: f64, tsq: f64) -> (CutStatus, (f64, f64, f64)) {
734 if beta1 < 0.0 {
735 return (CutStatus::NoSoln, (0.0, 0.0, 0.0)); // no solution
736 }
737 if tsq <= beta1 * beta1 || !self.use_parallel_cut {
738 return self.calc_central_cut(tsq);
739 }
740 (
741 CutStatus::Success,
742 self.helper.calc_parallel_central_cut(beta1, tsq),
743 )
744 }
745
746 /// Deep Cut
747 ///
748 /// # Examples:
749 ///
750 /// ```rust
751 /// use approx_eq::assert_approx_eq;
752 /// use ellalgo_rs::ell_calc::EllCalc;
753 /// use ellalgo_rs::cutting_plane::CutStatus;
754 ///
755 /// let ell_calc = EllCalc::new(4);
756 /// let (status, _result) = ell_calc.calc_bias_cut(0.11, 0.01);
757 /// assert_eq!(status, CutStatus::NoSoln);
758 /// let (status, _result) = ell_calc.calc_bias_cut(0.0, 0.01);
759 /// assert_eq!(status, CutStatus::Success);
760 ///
761 /// let (status, (rho, sigma, delta)) = ell_calc.calc_bias_cut(0.05, 0.01);
762 /// assert_eq!(status, CutStatus::Success);
763 /// assert_approx_eq!(sigma, 0.8);
764 /// assert_approx_eq!(rho, 0.06);
765 /// assert_approx_eq!(delta, 0.8);
766 /// ```
767 pub fn calc_bias_cut(&self, beta: f64, tsq: f64) -> (CutStatus, (f64, f64, f64)) {
768 if tsq < beta * beta {
769 return (CutStatus::NoSoln, (0.0, 0.0, 0.0)); // no sol'n
770 }
771
772 let tau = tsq.sqrt();
773 (CutStatus::Success, self.helper.calc_bias_cut(beta, tau))
774 }
775
776 /// Discrete Deep Cut
777 ///
778 /// # Examples:
779 ///
780 /// ```rust
781 /// use approx_eq::assert_approx_eq;
782 /// use ellalgo_rs::ell_calc::EllCalc;
783 /// use ellalgo_rs::cutting_plane::CutStatus;
784 ///
785 /// let ell_calc = EllCalc::new(4);
786 /// let (status, _result) = ell_calc.calc_bias_cut_q(-0.05, 0.01);
787 /// assert_eq!(status, CutStatus::NoEffect);
788 /// ```
789 pub fn calc_bias_cut_q(&self, beta: f64, tsq: f64) -> (CutStatus, (f64, f64, f64)) {
790 let tau = tsq.sqrt();
791
792 if tau < beta {
793 return (CutStatus::NoSoln, (0.0, 0.0, 0.0)); // no sol'n
794 }
795
796 let eta = tau + self.n_f * beta;
797 if eta < 0.0 {
798 return (CutStatus::NoEffect, (0.0, 0.0, 1.0)); // no effect
799 }
800
801 (
802 CutStatus::Success,
803 self.helper.calc_bias_cut_fast(beta, tau, eta),
804 )
805 }
806
807 /// Central Cut
808 ///
809 /// # Examples:
810 ///
811 /// ```rust
812 /// use approx_eq::assert_approx_eq;
813 /// use ellalgo_rs::ell_calc::EllCalc;
814 /// use ellalgo_rs::cutting_plane::CutStatus;
815 ///
816 /// let ell_calc = EllCalc::new(4);
817 /// let (status, (rho, sigma, delta)) = ell_calc.calc_central_cut(0.01);
818 ///
819 /// assert_eq!(status, CutStatus::Success);
820 /// assert_approx_eq!(sigma, 0.4);
821 /// assert_approx_eq!(rho, 0.02);
822 /// assert_approx_eq!(delta, 16.0 / 15.0);
823 /// ```
824 #[inline]
825 pub fn calc_central_cut(&self, tsq: f64) -> (CutStatus, (f64, f64, f64)) {
826 // self.mu = self.half_n_minus_1;
827 (CutStatus::Success, self.helper.calc_central_cut(tsq))
828 }
829}
830
831// pub trait UpdateByCutChoice {
832// fn update_by(self, ell: &mut EllCalc) -> CutStatus;
833// }
834#[cfg(test)]
835mod tests {
836 use super::*;
837 use approx_eq::assert_approx_eq;
838
839 #[test]
840 pub fn test_construct() {
841 let helper = EllCalcCore::new(4.0);
842 assert_eq!(helper.n_f, 4.0);
843 assert_eq!(helper.half_n, 2.0);
844 assert_approx_eq!(helper.cst1, 16.0 / 15.0);
845 assert_approx_eq!(helper.cst2, 0.4);
846 }
847
848 #[test]
849 pub fn test_calc_parallel_bias_cut_fast() {
850 let ell_calc_core = EllCalcCore::new(4.0);
851 let (rho, sigma, delta) =
852 ell_calc_core.calc_parallel_bias_cut_fast(1.0, 2.0, 4.0, 2.0, 12.0);
853 assert_approx_eq!(rho, 1.2);
854 assert_approx_eq!(sigma, 0.8);
855 assert_approx_eq!(delta, 0.8);
856 }
857
858 #[test]
859 pub fn test_calc_bias_cut_fast() {
860 let ell_calc_core = EllCalcCore::new(4.0);
861 let (rho, sigma, delta) = ell_calc_core.calc_bias_cut_fast(1.0, 2.0, 6.0);
862 assert_approx_eq!(rho, 1.2);
863 assert_approx_eq!(sigma, 0.8);
864 assert_approx_eq!(delta, 0.8);
865 }
866
867 #[test]
868 pub fn test_calc_central_cut() {
869 let ell_calc = EllCalc::new(4);
870 // ell_calc.tsq = 0.01;
871 let (status, (rho, sigma, delta)) = ell_calc.calc_central_cut(0.01);
872 assert_eq!(status, CutStatus::Success);
873 assert_approx_eq!(sigma, 0.4);
874 assert_approx_eq!(rho, 0.02);
875 assert_approx_eq!(delta, 16.0 / 15.0);
876 }
877
878 #[test]
879 pub fn test_calc_bias_cut() {
880 let ell_calc = EllCalc::new(4);
881 // ell_calc.tsq = 0.01;
882 let (status, _result) = ell_calc.calc_bias_cut(0.11, 0.01);
883 assert_eq!(status, CutStatus::NoSoln);
884 let (status, _result) = ell_calc.calc_bias_cut(0.0, 0.01);
885 assert_eq!(status, CutStatus::Success);
886 let (status, _result) = ell_calc.calc_bias_cut_q(-0.05, 0.01);
887 assert_eq!(status, CutStatus::NoEffect);
888
889 // ell_calc.tsq = 0.01;
890 let (status, (rho, sigma, delta)) = ell_calc.calc_bias_cut(0.05, 0.01);
891 assert_eq!(status, CutStatus::Success);
892 assert_approx_eq!(sigma, 0.8);
893 assert_approx_eq!(rho, 0.06);
894 assert_approx_eq!(delta, 0.8);
895 }
896
897 #[test]
898 pub fn test_calc_parallel_central_cut() {
899 let ell_calc = EllCalc::new(4);
900 let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_central_cut(0.11, 0.01);
901 assert_eq!(status, CutStatus::Success);
902 assert_approx_eq!(sigma, 0.4);
903 assert_approx_eq!(rho, 0.02);
904 assert_approx_eq!(delta, 16.0 / 15.0);
905
906 let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_central_cut(0.05, 0.01);
907 assert_eq!(status, CutStatus::Success);
908 assert_approx_eq!(sigma, 0.8);
909 assert_approx_eq!(rho, 0.02);
910 assert_approx_eq!(delta, 1.2);
911 }
912
913 #[test]
914 pub fn test_calc_parallel() {
915 let ell_calc = EllCalc::new(4);
916 // ell_calc.tsq = 0.01;
917 let (status, _result) = ell_calc.calc_parallel_bias_cut(0.07, 0.03, 0.01);
918 assert_eq!(status, CutStatus::NoSoln);
919
920 let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_bias_cut(0.0, 0.05, 0.01);
921 assert_eq!(status, CutStatus::Success);
922 assert_approx_eq!(sigma, 0.8);
923 assert_approx_eq!(rho, 0.02);
924 assert_approx_eq!(delta, 1.2);
925
926 let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_bias_cut(0.05, 0.11, 0.01);
927 assert_eq!(status, CutStatus::Success);
928 assert_approx_eq!(sigma, 0.8);
929 assert_approx_eq!(rho, 0.06);
930 assert_approx_eq!(delta, 0.8);
931
932 let (status, _result) = ell_calc.calc_parallel_q(-0.07, 0.07, 0.01);
933 assert_eq!(status, CutStatus::NoEffect);
934
935 let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_bias_cut(0.01, 0.04, 0.01);
936 assert_eq!(status, CutStatus::Success);
937 assert_approx_eq!(sigma, 0.928);
938 assert_approx_eq!(rho, 0.0232);
939 assert_approx_eq!(delta, 1.232);
940
941 let (status, _result) = ell_calc.calc_parallel_q(-0.04, 0.0625, 0.01);
942 assert_eq!(status, CutStatus::NoEffect);
943 }
944
945 #[test]
946 fn test_construct2() {
947 let ell_calc = EllCalc::new(4);
948 assert!(ell_calc.use_parallel_cut);
949 assert_eq!(ell_calc.n_f, 4.0);
950 }
951
952 #[test]
953 fn test_calc_central_cut2() {
954 let ell_calc = EllCalc::new(4);
955 let (status, result) =
956 ell_calc.calc_single_or_parallel_central_cut(&(0.0, Some(0.05)), 0.01);
957 assert_eq!(status, CutStatus::Success);
958 let (rho, sigma, delta) = result;
959 assert_approx_eq!(sigma, 0.8);
960 assert_approx_eq!(rho, 0.02);
961 assert_approx_eq!(delta, 1.2);
962 }
963
964 #[test]
965 fn test_calc_bias_cut2() {
966 let ell_calc = EllCalc::new(4);
967 let (status, _result) = ell_calc.calc_bias_cut(0.11, 0.01);
968 assert_eq!(status, CutStatus::NoSoln);
969 let (status, _result) = ell_calc.calc_bias_cut(0.01, 0.01);
970 assert_eq!(status, CutStatus::Success);
971
972 let (status, result) = ell_calc.calc_bias_cut(0.05, 0.01);
973 assert_eq!(status, CutStatus::Success);
974 let (rho, sigma, delta) = result;
975 assert_approx_eq!(rho, 0.06);
976 assert_approx_eq!(sigma, 0.8);
977 assert_approx_eq!(delta, 0.8);
978 }
979
980 #[test]
981 fn test_calc_parallel_central_cut2() {
982 let ell_calc = EllCalc::new(4);
983 let (status, result) =
984 ell_calc.calc_single_or_parallel_central_cut(&(0.0, Some(0.05)), 0.01);
985 assert_eq!(status, CutStatus::Success);
986 let (rho, sigma, delta) = result;
987 assert_approx_eq!(rho, 0.02);
988 assert_approx_eq!(sigma, 0.8);
989 assert_approx_eq!(delta, 1.2);
990 }
991
992 #[test]
993 fn test_calc_parallel2() {
994 let ell_calc = EllCalc::new(4);
995 let (status, _result) = ell_calc.calc_parallel_bias_cut(0.07, 0.03, 0.01);
996 assert_eq!(status, CutStatus::NoSoln);
997 let (status, result) = ell_calc.calc_parallel_bias_cut(0.0, 0.05, 0.01);
998 assert_eq!(status, CutStatus::Success);
999 let (rho, sigma, delta) = result;
1000 assert_approx_eq!(rho, 0.02);
1001 assert_approx_eq!(sigma, 0.8);
1002 assert_approx_eq!(delta, 1.2);
1003 let (status, result) = ell_calc.calc_parallel_bias_cut(0.05, 0.11, 0.01);
1004 assert_eq!(status, CutStatus::Success);
1005 let (rho, sigma, delta) = result;
1006 assert_approx_eq!(rho, 0.06);
1007 assert_approx_eq!(sigma, 0.8);
1008 assert_approx_eq!(delta, 0.8);
1009 let (status, result) = ell_calc.calc_parallel_bias_cut(0.01, 0.04, 0.01);
1010 assert_eq!(status, CutStatus::Success);
1011 let (rho, sigma, delta) = result;
1012 assert_approx_eq!(rho, 0.0232);
1013 assert_approx_eq!(sigma, 0.928);
1014 assert_approx_eq!(delta, 1.232);
1015 }
1016
1017 #[test]
1018 fn test_calc_bias_cut_q2() {
1019 let ell_calc_q = EllCalc::new(4);
1020 let (status, _result) = ell_calc_q.calc_bias_cut_q(0.11, 0.01);
1021 assert_eq!(status, CutStatus::NoSoln);
1022 let (status, _result) = ell_calc_q.calc_bias_cut_q(0.01, 0.01);
1023 assert_eq!(status, CutStatus::Success);
1024 let (status, _result) = ell_calc_q.calc_bias_cut_q(-0.05, 0.01);
1025 assert_eq!(status, CutStatus::NoEffect);
1026 let (status, result) = ell_calc_q.calc_bias_cut_q(0.05, 0.01);
1027 assert_eq!(status, CutStatus::Success);
1028 let (rho, sigma, delta) = result;
1029 assert_approx_eq!(rho, 0.06);
1030 assert_approx_eq!(sigma, 0.8);
1031 assert_approx_eq!(delta, 0.8);
1032 }
1033
1034 #[test]
1035 fn test_calc_parallel_q2() {
1036 let ell_calc = EllCalc::new(4);
1037 let (status, _result) = ell_calc.calc_parallel_q(0.07, 0.03, 0.01);
1038 assert_eq!(status, CutStatus::NoSoln);
1039 let (status, _result) = ell_calc.calc_parallel_q(-0.04, 0.0625, 0.01);
1040 assert_eq!(status, CutStatus::NoEffect);
1041 let (status, result) = ell_calc.calc_parallel_q(0.0, 0.05, 0.01);
1042 assert_eq!(status, CutStatus::Success);
1043 let (rho, sigma, delta) = result;
1044 assert_approx_eq!(rho, 0.02);
1045 assert_approx_eq!(sigma, 0.8);
1046 assert_approx_eq!(delta, 1.2);
1047 let (status, result) = ell_calc.calc_parallel_q(0.05, 0.11, 0.01);
1048 assert_eq!(status, CutStatus::Success);
1049 let (rho, sigma, delta) = result;
1050 assert_approx_eq!(rho, 0.06);
1051 assert_approx_eq!(sigma, 0.8);
1052 assert_approx_eq!(delta, 0.8);
1053 let (status, result) = ell_calc.calc_parallel_q(0.01, 0.04, 0.01);
1054 assert_eq!(status, CutStatus::Success);
1055 let (rho, sigma, delta) = result;
1056 assert_approx_eq!(rho, 0.0232);
1057 assert_approx_eq!(sigma, 0.928);
1058 assert_approx_eq!(delta, 1.232);
1059 }
1060}