Skip to main content

copp\copp/
general.rs

1//! General shared definitions and numeric utilities for TOPP/COPP flows.
2//!
3//! # Method identity
4//! This module hosts lightweight, cross-cutting primitives that are reused by
5//! multiple solver/formulation layers, including:
6//! - interpolation policy descriptors for output trajectory sampling;
7//! - tolerant floating-point comparison helpers used by feasibility and
8//!   convergence checks.
9//!
10//! # Design notes
11//! - Types here are intentionally small and dependency-free.
12//! - Approximate comparison uses a mixed tolerance
13//!   $\max(\text{abs\_tol},\ \text{rel\_tol}\cdot\max(|x_1|,|x_2|))$.
14//! - `approx_order()` is preferred over direct equality checks when decisions
15//!   depend on floating-point values near boundaries.
16
17/// Time-grid policy used when interpolating path-parameterization outputs.
18///
19/// This enum describes how target sample times are provided to interpolation
20/// routines after a trajectory has been parameterized.
21pub enum InterpolationMode<'a> {
22    /// Uniform sampling grid.
23    ///
24    /// # Tuple fields
25    /// - `t0`: time stamp of the first path station (`s[0]`).
26    /// - `dt`: constant sampling period (`dt > 0` expected by callers).
27    /// - `include_final`: handling of non-integer final step.
28    ///
29    /// # Final-sample policy
30    /// If final time `t_final` is not an integer multiple of `dt` from `t0`:
31    /// - `include_final = true`: append one final sample exactly at `t_final`.
32    /// - `include_final = false`: stop at `t0 + n\,dt`, where `n` is the
33    ///   largest integer satisfying `t0 + n\,dt \le t_final`.
34    UniformTimeGrid(f64, f64, bool),
35
36    /// User-provided non-uniform sampling grid.
37    ///
38    /// # Tuple fields
39    /// - `t_samples`: strictly increasing time stamps.
40    ///
41    /// # Contract
42    /// Callers should provide an increasing grid and ensure the first sample is
43    /// not earlier than the interpolation start time.
44    NonUniformTimeGrid(&'a [f64]),
45}
46
47/// Approximate ordering relation for two floating-point values.
48///
49/// Returned by [`approx_order()`] when comparing `x1` and `x2` under mixed
50/// absolute/relative tolerance.
51pub(crate) enum ApproxOrdering {
52    /// `x1 < x2` under tolerance-aware comparison.
53    Less,
54    /// `x1 \approx x2` within tolerance band.
55    Equal,
56    /// `x1 > x2` under tolerance-aware comparison.
57    Greater,
58}
59
60/// Compute the mixed absolute/relative comparison threshold.
61///
62/// # Formula
63/// `threshold = max(abs_tol, rel_tol * max(|x1|, |x2|))`
64///
65/// # Parameters
66/// - `x1`, `x2`: values to be compared.
67/// - `abs_tol`: absolute tolerance component.
68/// - `rel_tol`: relative tolerance component.
69///
70/// # Returns
71/// A non-negative scalar used as symmetric comparison band around zero for
72/// `dx = x1 - x2`.
73///
74#[inline(always)]
75pub(crate) fn threshold_approx(x1: f64, x2: f64, abs_tol: f64, rel_tol: f64) -> f64 {
76    abs_tol.max(rel_tol * x1.abs().max(x2.abs()))
77}
78
79/// Compare two floating-point values with mixed tolerance and return ordering.
80///
81/// # Decision rule
82/// Let `dx = x1 - x2` and
83/// `threshold = threshold_approx(x1, x2, abs_tol, rel_tol)`.
84///
85/// - return [`ApproxOrdering::Greater`] if `dx > threshold`;
86/// - return [`ApproxOrdering::Less`] if `dx < -threshold`;
87/// - otherwise return [`ApproxOrdering::Equal`].
88///
89/// # Parameters
90/// - `x1`, `x2`: values to compare.
91/// - `abs_tol`: absolute tolerance.
92/// - `rel_tol`: relative tolerance.
93///
94/// # Returns
95/// Tolerance-aware ordering relation between `x1` and `x2`.
96#[inline(always)]
97pub(crate) fn approx_order(x1: f64, x2: f64, abs_tol: f64, rel_tol: f64) -> ApproxOrdering {
98    let threshold = threshold_approx(x1, x2, abs_tol, rel_tol);
99    let dx = x1 - x2;
100    if dx > threshold {
101        ApproxOrdering::Greater
102    } else if dx < -threshold {
103        ApproxOrdering::Less
104    } else {
105        ApproxOrdering::Equal
106    }
107}