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 let b1sqn = beta1 * (beta1 / tsq);
738 let t1n = 1.0 - b1sqn;
739 if t1n < 0.0 || !self.use_parallel_cut {
740 return self.calc_central_cut(tsq);
741 }
742 (
743 CutStatus::Success,
744 self.helper.calc_parallel_central_cut(beta1, tsq),
745 )
746 }
747
748 /// Deep Cut
749 ///
750 /// # Examples:
751 ///
752 /// ```rust
753 /// use approx_eq::assert_approx_eq;
754 /// use ellalgo_rs::ell_calc::EllCalc;
755 /// use ellalgo_rs::cutting_plane::CutStatus;
756 ///
757 /// let ell_calc = EllCalc::new(4);
758 /// let (status, _result) = ell_calc.calc_bias_cut(0.11, 0.01);
759 /// assert_eq!(status, CutStatus::NoSoln);
760 /// let (status, _result) = ell_calc.calc_bias_cut(0.0, 0.01);
761 /// assert_eq!(status, CutStatus::Success);
762 ///
763 /// let (status, (rho, sigma, delta)) = ell_calc.calc_bias_cut(0.05, 0.01);
764 /// assert_eq!(status, CutStatus::Success);
765 /// assert_approx_eq!(sigma, 0.8);
766 /// assert_approx_eq!(rho, 0.06);
767 /// assert_approx_eq!(delta, 0.8);
768 /// ```
769 pub fn calc_bias_cut(&self, beta: f64, tsq: f64) -> (CutStatus, (f64, f64, f64)) {
770 if tsq < beta * beta {
771 return (CutStatus::NoSoln, (0.0, 0.0, 0.0)); // no sol'n
772 }
773
774 let tau = tsq.sqrt();
775 (CutStatus::Success, self.helper.calc_bias_cut(beta, tau))
776 }
777
778 /// Discrete Deep Cut
779 ///
780 /// # Examples:
781 ///
782 /// ```rust
783 /// use approx_eq::assert_approx_eq;
784 /// use ellalgo_rs::ell_calc::EllCalc;
785 /// use ellalgo_rs::cutting_plane::CutStatus;
786 ///
787 /// let ell_calc = EllCalc::new(4);
788 /// let (status, _result) = ell_calc.calc_bias_cut_q(-0.05, 0.01);
789 /// assert_eq!(status, CutStatus::NoEffect);
790 /// ```
791 pub fn calc_bias_cut_q(&self, beta: f64, tsq: f64) -> (CutStatus, (f64, f64, f64)) {
792 let tau = tsq.sqrt();
793
794 if tau < beta {
795 return (CutStatus::NoSoln, (0.0, 0.0, 0.0)); // no sol'n
796 }
797
798 let eta = tau + self.n_f * beta;
799 if eta < 0.0 {
800 return (CutStatus::NoEffect, (0.0, 0.0, 1.0)); // no effect
801 }
802
803 (
804 CutStatus::Success,
805 self.helper.calc_bias_cut_fast(beta, tau, eta),
806 )
807 }
808
809 /// Central Cut
810 ///
811 /// # Examples:
812 ///
813 /// ```rust
814 /// use approx_eq::assert_approx_eq;
815 /// use ellalgo_rs::ell_calc::EllCalc;
816 /// use ellalgo_rs::cutting_plane::CutStatus;
817 ///
818 /// let ell_calc = EllCalc::new(4);
819 /// let (status, (rho, sigma, delta)) = ell_calc.calc_central_cut(0.01);
820 ///
821 /// assert_eq!(status, CutStatus::Success);
822 /// assert_approx_eq!(sigma, 0.4);
823 /// assert_approx_eq!(rho, 0.02);
824 /// assert_approx_eq!(delta, 16.0 / 15.0);
825 /// ```
826 #[inline]
827 pub fn calc_central_cut(&self, tsq: f64) -> (CutStatus, (f64, f64, f64)) {
828 // self.mu = self.half_n_minus_1;
829 (CutStatus::Success, self.helper.calc_central_cut(tsq))
830 }
831}
832
833// pub trait UpdateByCutChoice {
834// fn update_by(self, ell: &mut EllCalc) -> CutStatus;
835// }
836#[cfg(test)]
837mod tests {
838 use super::*;
839 use approx_eq::assert_approx_eq;
840
841 #[test]
842 pub fn test_construct() {
843 let helper = EllCalcCore::new(4.0);
844 assert_eq!(helper.n_f, 4.0);
845 assert_eq!(helper.half_n, 2.0);
846 assert_approx_eq!(helper.cst1, 16.0 / 15.0);
847 assert_approx_eq!(helper.cst2, 0.4);
848 }
849
850 #[test]
851 pub fn test_calc_parallel_bias_cut_fast() {
852 let ell_calc_core = EllCalcCore::new(4.0);
853 let (rho, sigma, delta) =
854 ell_calc_core.calc_parallel_bias_cut_fast(1.0, 2.0, 4.0, 2.0, 12.0);
855 assert_approx_eq!(rho, 1.2);
856 assert_approx_eq!(sigma, 0.8);
857 assert_approx_eq!(delta, 0.8);
858 }
859
860 #[test]
861 pub fn test_calc_bias_cut_fast() {
862 let ell_calc_core = EllCalcCore::new(4.0);
863 let (rho, sigma, delta) = ell_calc_core.calc_bias_cut_fast(1.0, 2.0, 6.0);
864 assert_approx_eq!(rho, 1.2);
865 assert_approx_eq!(sigma, 0.8);
866 assert_approx_eq!(delta, 0.8);
867 }
868
869 #[test]
870 pub fn test_calc_central_cut() {
871 let ell_calc = EllCalc::new(4);
872 // ell_calc.tsq = 0.01;
873 let (status, (rho, sigma, delta)) = ell_calc.calc_central_cut(0.01);
874 assert_eq!(status, CutStatus::Success);
875 assert_approx_eq!(sigma, 0.4);
876 assert_approx_eq!(rho, 0.02);
877 assert_approx_eq!(delta, 16.0 / 15.0);
878 }
879
880 #[test]
881 pub fn test_calc_bias_cut() {
882 let ell_calc = EllCalc::new(4);
883 // ell_calc.tsq = 0.01;
884 let (status, _result) = ell_calc.calc_bias_cut(0.11, 0.01);
885 assert_eq!(status, CutStatus::NoSoln);
886 let (status, _result) = ell_calc.calc_bias_cut(0.0, 0.01);
887 assert_eq!(status, CutStatus::Success);
888 let (status, _result) = ell_calc.calc_bias_cut_q(-0.05, 0.01);
889 assert_eq!(status, CutStatus::NoEffect);
890
891 // ell_calc.tsq = 0.01;
892 let (status, (rho, sigma, delta)) = ell_calc.calc_bias_cut(0.05, 0.01);
893 assert_eq!(status, CutStatus::Success);
894 assert_approx_eq!(sigma, 0.8);
895 assert_approx_eq!(rho, 0.06);
896 assert_approx_eq!(delta, 0.8);
897 }
898
899 #[test]
900 pub fn test_calc_parallel_central_cut() {
901 let ell_calc = EllCalc::new(4);
902 let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_central_cut(0.11, 0.01);
903 assert_eq!(status, CutStatus::Success);
904 assert_approx_eq!(sigma, 0.4);
905 assert_approx_eq!(rho, 0.02);
906 assert_approx_eq!(delta, 16.0 / 15.0);
907
908 let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_central_cut(0.05, 0.01);
909 assert_eq!(status, CutStatus::Success);
910 assert_approx_eq!(sigma, 0.8);
911 assert_approx_eq!(rho, 0.02);
912 assert_approx_eq!(delta, 1.2);
913 }
914
915 #[test]
916 pub fn test_calc_parallel() {
917 let ell_calc = EllCalc::new(4);
918 // ell_calc.tsq = 0.01;
919 let (status, _result) = ell_calc.calc_parallel_bias_cut(0.07, 0.03, 0.01);
920 assert_eq!(status, CutStatus::NoSoln);
921
922 let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_bias_cut(0.0, 0.05, 0.01);
923 assert_eq!(status, CutStatus::Success);
924 assert_approx_eq!(sigma, 0.8);
925 assert_approx_eq!(rho, 0.02);
926 assert_approx_eq!(delta, 1.2);
927
928 let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_bias_cut(0.05, 0.11, 0.01);
929 assert_eq!(status, CutStatus::Success);
930 assert_approx_eq!(sigma, 0.8);
931 assert_approx_eq!(rho, 0.06);
932 assert_approx_eq!(delta, 0.8);
933
934 let (status, _result) = ell_calc.calc_parallel_q(-0.07, 0.07, 0.01);
935 assert_eq!(status, CutStatus::NoEffect);
936
937 let (status, (rho, sigma, delta)) = ell_calc.calc_parallel_bias_cut(0.01, 0.04, 0.01);
938 assert_eq!(status, CutStatus::Success);
939 assert_approx_eq!(sigma, 0.928);
940 assert_approx_eq!(rho, 0.0232);
941 assert_approx_eq!(delta, 1.232);
942
943 let (status, _result) = ell_calc.calc_parallel_q(-0.04, 0.0625, 0.01);
944 assert_eq!(status, CutStatus::NoEffect);
945 }
946
947 #[test]
948 fn test_construct2() {
949 let ell_calc = EllCalc::new(4);
950 assert!(ell_calc.use_parallel_cut);
951 assert_eq!(ell_calc.n_f, 4.0);
952 }
953
954 #[test]
955 fn test_calc_central_cut2() {
956 let ell_calc = EllCalc::new(4);
957 let (status, result) =
958 ell_calc.calc_single_or_parallel_central_cut(&(0.0, Some(0.05)), 0.01);
959 assert_eq!(status, CutStatus::Success);
960 let (rho, sigma, delta) = result;
961 assert_approx_eq!(sigma, 0.8);
962 assert_approx_eq!(rho, 0.02);
963 assert_approx_eq!(delta, 1.2);
964 }
965
966 #[test]
967 fn test_calc_bias_cut2() {
968 let ell_calc = EllCalc::new(4);
969 let (status, _result) = ell_calc.calc_bias_cut(0.11, 0.01);
970 assert_eq!(status, CutStatus::NoSoln);
971 let (status, _result) = ell_calc.calc_bias_cut(0.01, 0.01);
972 assert_eq!(status, CutStatus::Success);
973
974 let (status, result) = ell_calc.calc_bias_cut(0.05, 0.01);
975 assert_eq!(status, CutStatus::Success);
976 let (rho, sigma, delta) = result;
977 assert_approx_eq!(rho, 0.06);
978 assert_approx_eq!(sigma, 0.8);
979 assert_approx_eq!(delta, 0.8);
980 }
981
982 #[test]
983 fn test_calc_parallel_central_cut2() {
984 let ell_calc = EllCalc::new(4);
985 let (status, result) =
986 ell_calc.calc_single_or_parallel_central_cut(&(0.0, Some(0.05)), 0.01);
987 assert_eq!(status, CutStatus::Success);
988 let (rho, sigma, delta) = result;
989 assert_approx_eq!(rho, 0.02);
990 assert_approx_eq!(sigma, 0.8);
991 assert_approx_eq!(delta, 1.2);
992 }
993
994 #[test]
995 fn test_calc_parallel2() {
996 let ell_calc = EllCalc::new(4);
997 let (status, _result) = ell_calc.calc_parallel_bias_cut(0.07, 0.03, 0.01);
998 assert_eq!(status, CutStatus::NoSoln);
999 let (status, result) = ell_calc.calc_parallel_bias_cut(0.0, 0.05, 0.01);
1000 assert_eq!(status, CutStatus::Success);
1001 let (rho, sigma, delta) = result;
1002 assert_approx_eq!(rho, 0.02);
1003 assert_approx_eq!(sigma, 0.8);
1004 assert_approx_eq!(delta, 1.2);
1005 let (status, result) = ell_calc.calc_parallel_bias_cut(0.05, 0.11, 0.01);
1006 assert_eq!(status, CutStatus::Success);
1007 let (rho, sigma, delta) = result;
1008 assert_approx_eq!(rho, 0.06);
1009 assert_approx_eq!(sigma, 0.8);
1010 assert_approx_eq!(delta, 0.8);
1011 let (status, result) = ell_calc.calc_parallel_bias_cut(0.01, 0.04, 0.01);
1012 assert_eq!(status, CutStatus::Success);
1013 let (rho, sigma, delta) = result;
1014 assert_approx_eq!(rho, 0.0232);
1015 assert_approx_eq!(sigma, 0.928);
1016 assert_approx_eq!(delta, 1.232);
1017 }
1018
1019 #[test]
1020 fn test_calc_bias_cut_q2() {
1021 let ell_calc_q = EllCalc::new(4);
1022 let (status, _result) = ell_calc_q.calc_bias_cut_q(0.11, 0.01);
1023 assert_eq!(status, CutStatus::NoSoln);
1024 let (status, _result) = ell_calc_q.calc_bias_cut_q(0.01, 0.01);
1025 assert_eq!(status, CutStatus::Success);
1026 let (status, _result) = ell_calc_q.calc_bias_cut_q(-0.05, 0.01);
1027 assert_eq!(status, CutStatus::NoEffect);
1028 let (status, result) = ell_calc_q.calc_bias_cut_q(0.05, 0.01);
1029 assert_eq!(status, CutStatus::Success);
1030 let (rho, sigma, delta) = result;
1031 assert_approx_eq!(rho, 0.06);
1032 assert_approx_eq!(sigma, 0.8);
1033 assert_approx_eq!(delta, 0.8);
1034 }
1035
1036 #[test]
1037 fn test_calc_parallel_q2() {
1038 let ell_calc = EllCalc::new(4);
1039 let (status, _result) = ell_calc.calc_parallel_q(0.07, 0.03, 0.01);
1040 assert_eq!(status, CutStatus::NoSoln);
1041 let (status, _result) = ell_calc.calc_parallel_q(-0.04, 0.0625, 0.01);
1042 assert_eq!(status, CutStatus::NoEffect);
1043 let (status, result) = ell_calc.calc_parallel_q(0.0, 0.05, 0.01);
1044 assert_eq!(status, CutStatus::Success);
1045 let (rho, sigma, delta) = result;
1046 assert_approx_eq!(rho, 0.02);
1047 assert_approx_eq!(sigma, 0.8);
1048 assert_approx_eq!(delta, 1.2);
1049 let (status, result) = ell_calc.calc_parallel_q(0.05, 0.11, 0.01);
1050 assert_eq!(status, CutStatus::Success);
1051 let (rho, sigma, delta) = result;
1052 assert_approx_eq!(rho, 0.06);
1053 assert_approx_eq!(sigma, 0.8);
1054 assert_approx_eq!(delta, 0.8);
1055 let (status, result) = ell_calc.calc_parallel_q(0.01, 0.04, 0.01);
1056 assert_eq!(status, CutStatus::Success);
1057 let (rho, sigma, delta) = result;
1058 assert_approx_eq!(rho, 0.0232);
1059 assert_approx_eq!(sigma, 0.928);
1060 assert_approx_eq!(delta, 1.232);
1061 }
1062}