Skip to main content

oxilean_std/range/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4use super::functions::*;
5
6/// A closed floating-point interval `[lo, hi]` with outward-rounded arithmetic.
7///
8/// Implements a simplified version of Moore interval arithmetic.
9#[allow(dead_code)]
10#[derive(Clone, Copy, Debug, PartialEq)]
11pub struct FloatInterval {
12    pub(super) lo: f64,
13    pub(super) hi: f64,
14}
15impl FloatInterval {
16    /// Create a new interval. Panics if `lo > hi`.
17    pub fn new(lo: f64, hi: f64) -> Self {
18        assert!(
19            lo <= hi,
20            "FloatInterval: lo ({}) must be <= hi ({})",
21            lo,
22            hi
23        );
24        Self { lo, hi }
25    }
26    /// Try to create a new interval, returning `None` if `lo > hi`.
27    pub fn try_new(lo: f64, hi: f64) -> Option<Self> {
28        if lo <= hi {
29            Some(Self { lo, hi })
30        } else {
31            None
32        }
33    }
34    /// The lower bound.
35    pub fn lo(self) -> f64 {
36        self.lo
37    }
38    /// The upper bound.
39    pub fn hi(self) -> f64 {
40        self.hi
41    }
42    /// The width `hi - lo`.
43    pub fn width(self) -> f64 {
44        self.hi - self.lo
45    }
46    /// The midpoint `(lo + hi) / 2`.
47    pub fn midpoint(self) -> f64 {
48        self.lo + (self.hi - self.lo) / 2.0
49    }
50    /// Check if `x` is contained in `[lo, hi]`.
51    pub fn contains(self, x: f64) -> bool {
52        x >= self.lo && x <= self.hi
53    }
54    /// Moore addition: `[a,b] + [c,d] = [a+c, b+d]`.
55    pub fn add(self, other: Self) -> Self {
56        Self::new(self.lo + other.lo, self.hi + other.hi)
57    }
58    /// Moore subtraction: `[a,b] - [c,d] = [a-d, b-c]`.
59    pub fn sub(self, other: Self) -> Self {
60        Self::new(self.lo - other.hi, self.hi - other.lo)
61    }
62    /// Moore multiplication (four-product rule).
63    pub fn mul(self, other: Self) -> Self {
64        let products = [
65            self.lo * other.lo,
66            self.lo * other.hi,
67            self.hi * other.lo,
68            self.hi * other.hi,
69        ];
70        let lo = products.iter().cloned().fold(f64::INFINITY, f64::min);
71        let hi = products.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
72        Self::new(lo, hi)
73    }
74    /// Interval negation: `-[a,b] = [-b, -a]`.
75    pub fn neg(self) -> Self {
76        Self::new(-self.hi, -self.lo)
77    }
78    /// Intersection of two intervals, returning `None` if disjoint.
79    pub fn intersect(self, other: Self) -> Option<Self> {
80        let lo = f64::max(self.lo, other.lo);
81        let hi = f64::min(self.hi, other.hi);
82        Self::try_new(lo, hi)
83    }
84    /// Convex hull (smallest enclosing interval).
85    pub fn hull(self, other: Self) -> Self {
86        Self::new(f64::min(self.lo, other.lo), f64::max(self.hi, other.hi))
87    }
88    /// Check if `self` is a subset of `other`.
89    pub fn is_subset_of(self, other: Self) -> bool {
90        other.lo <= self.lo && self.hi <= other.hi
91    }
92    /// Absolute value interval: `|[a,b]|`.
93    pub fn abs(self) -> Self {
94        if self.lo >= 0.0 {
95            self
96        } else if self.hi <= 0.0 {
97            self.neg()
98        } else {
99            Self::new(0.0, f64::max(-self.lo, self.hi))
100        }
101    }
102    /// Square: `[a,b]^2`.
103    pub fn square(self) -> Self {
104        self.mul(self)
105    }
106    /// Mignitude: `min |x|` for `x ∈ [lo, hi]`.
107    pub fn mignitude(self) -> f64 {
108        if self.lo >= 0.0 {
109            self.lo
110        } else if self.hi <= 0.0 {
111            -self.hi
112        } else {
113            0.0
114        }
115    }
116    /// Magnitude: `max |x|` for `x ∈ [lo, hi]`.
117    pub fn magnitude(self) -> f64 {
118        f64::max(self.lo.abs(), self.hi.abs())
119    }
120}
121/// A segment tree for range-minimum queries over a fixed array.
122#[allow(dead_code)]
123pub struct RangeMinSegTree {
124    n: usize,
125    data: Vec<i64>,
126}
127impl RangeMinSegTree {
128    /// Sentinel value for empty nodes.
129    const INF: i64 = i64::MAX;
130    /// Build a segment tree from a slice of values.
131    pub fn build(values: &[i64]) -> Self {
132        let n = values.len();
133        let mut data = vec![Self::INF; 4 * (n + 1)];
134        if n > 0 {
135            Self::build_rec(&mut data, values, 1, 0, n - 1);
136        }
137        Self { n, data }
138    }
139    fn build_rec(data: &mut Vec<i64>, values: &[i64], node: usize, lo: usize, hi: usize) {
140        if lo == hi {
141            data[node] = values[lo];
142            return;
143        }
144        let mid = (lo + hi) / 2;
145        Self::build_rec(data, values, 2 * node, lo, mid);
146        Self::build_rec(data, values, 2 * node + 1, mid + 1, hi);
147        data[node] = data[2 * node].min(data[2 * node + 1]);
148    }
149    /// Query the minimum in the range `[l, r]`.
150    pub fn query_min(&self, l: usize, r: usize) -> Option<i64> {
151        if self.n == 0 || l > r || r >= self.n {
152            return None;
153        }
154        Some(self.query_rec(1, 0, self.n - 1, l, r))
155    }
156    fn query_rec(&self, node: usize, lo: usize, hi: usize, l: usize, r: usize) -> i64 {
157        if r < lo || hi < l {
158            return Self::INF;
159        }
160        if l <= lo && hi <= r {
161            return self.data[node];
162        }
163        let mid = (lo + hi) / 2;
164        let left = self.query_rec(2 * node, lo, mid, l, r);
165        let right = self.query_rec(2 * node + 1, mid + 1, hi, l, r);
166        left.min(right)
167    }
168    /// Update the value at index `i`.
169    pub fn update(&mut self, i: usize, val: i64) {
170        if i < self.n {
171            self.update_rec(1, 0, self.n - 1, i, val);
172        }
173    }
174    fn update_rec(&mut self, node: usize, lo: usize, hi: usize, i: usize, val: i64) {
175        if lo == hi {
176            self.data[node] = val;
177            return;
178        }
179        let mid = (lo + hi) / 2;
180        if i <= mid {
181            self.update_rec(2 * node, lo, mid, i, val);
182        } else {
183            self.update_rec(2 * node + 1, mid + 1, hi, i, val);
184        }
185        self.data[node] = self.data[2 * node].min(self.data[2 * node + 1]);
186    }
187    /// Number of elements.
188    pub fn len(&self) -> usize {
189        self.n
190    }
191    /// Whether the tree is empty.
192    pub fn is_empty(&self) -> bool {
193        self.n == 0
194    }
195}
196/// A validated interval: a `FloatInterval` together with a proof obligation tag.
197///
198/// In a real verified system this would carry a kernel proof; here we store a
199/// human-readable certificate string.
200#[allow(dead_code)]
201#[derive(Clone, Debug)]
202pub struct ValidatedInterval {
203    interval: FloatInterval,
204    certificate: String,
205    is_verified: bool,
206}
207impl ValidatedInterval {
208    /// Create a verified validated interval.
209    pub fn verified(interval: FloatInterval, certificate: impl Into<String>) -> Self {
210        Self {
211            interval,
212            certificate: certificate.into(),
213            is_verified: true,
214        }
215    }
216    /// Create an unverified validated interval (e.g., computed, not proved).
217    pub fn unverified(interval: FloatInterval) -> Self {
218        Self {
219            interval,
220            certificate: String::new(),
221            is_verified: false,
222        }
223    }
224    /// Return the underlying interval.
225    pub fn interval(&self) -> FloatInterval {
226        self.interval
227    }
228    /// Return whether this interval has been formally verified.
229    pub fn is_verified(&self) -> bool {
230        self.is_verified
231    }
232    /// The certificate string.
233    pub fn certificate(&self) -> &str {
234        &self.certificate
235    }
236    /// Compute the addition of two validated intervals.
237    /// Result is verified only if both inputs are.
238    pub fn add(&self, other: &Self) -> Self {
239        Self {
240            interval: self.interval.add(other.interval),
241            certificate: format!("add({}, {})", self.certificate, other.certificate),
242            is_verified: self.is_verified && other.is_verified,
243        }
244    }
245    /// Compute the multiplication of two validated intervals.
246    pub fn mul(&self, other: &Self) -> Self {
247        Self {
248            interval: self.interval.mul(other.interval),
249            certificate: format!("mul({}, {})", self.certificate, other.certificate),
250            is_verified: self.is_verified && other.is_verified,
251        }
252    }
253}
254/// Weighted interval scheduling solver using dynamic programming.
255#[allow(dead_code)]
256pub struct IntervalScheduler {
257    jobs: Vec<ScheduledJob>,
258}
259impl IntervalScheduler {
260    /// Create a new scheduler with the given jobs.
261    pub fn new(jobs: Vec<ScheduledJob>) -> Self {
262        Self { jobs }
263    }
264    /// Find the latest job that finishes before `start`.
265    fn latest_compatible(&self, idx: usize) -> Option<usize> {
266        let start = self.jobs[idx].start;
267        let mut result = None;
268        for i in 0..idx {
269            if self.jobs[i].finish <= start {
270                result = Some(i);
271            }
272        }
273        result
274    }
275    /// Solve weighted interval scheduling via DP. Returns the maximum total weight.
276    pub fn max_weight_schedule(&mut self) -> u64 {
277        self.jobs.sort_by_key(|j| j.finish);
278        let n = self.jobs.len();
279        if n == 0 {
280            return 0;
281        }
282        let mut dp = vec![0u64; n + 1];
283        for i in 0..n {
284            let weight = self.jobs[i].weight;
285            let p = self.latest_compatible(i).map(|j| j + 1).unwrap_or(0);
286            dp[i + 1] = dp[i].max(dp[p] + weight);
287        }
288        dp[n]
289    }
290    /// Return the number of jobs.
291    pub fn job_count(&self) -> usize {
292        self.jobs.len()
293    }
294}
295/// A simple Krawczyk-method interval root solver.
296///
297/// Given a function `f` and its derivative `df`, approximates a root using
298/// the Krawczyk operator `K(x, X) = m - f(m)/df(X)`.
299#[allow(dead_code)]
300pub struct KrawczykSolver {
301    max_iters: usize,
302    tolerance: f64,
303}
304impl KrawczykSolver {
305    /// Create a new solver with given maximum iterations and tolerance.
306    pub fn new(max_iters: usize, tolerance: f64) -> Self {
307        Self {
308            max_iters,
309            tolerance,
310        }
311    }
312    /// Attempt to find a root of `f` in `x0` using the Krawczyk operator.
313    ///
314    /// `f` and `df` take the midpoint as a Float and the interval for the derivative.
315    /// Returns the tightest enclosing interval if converged, otherwise `None`.
316    pub fn solve<F, DF>(&self, mut x: FloatInterval, f: F, df: DF) -> Option<FloatInterval>
317    where
318        F: Fn(f64) -> f64,
319        DF: Fn(FloatInterval) -> FloatInterval,
320    {
321        for _ in 0..self.max_iters {
322            let m = x.midpoint();
323            let fm = f(m);
324            let dfx = df(x);
325            if dfx.mignitude() < 1e-15 {
326                return None;
327            }
328            let (lo, hi) = if dfx.lo > 0.0 {
329                (m - fm / dfx.lo, m - fm / dfx.hi)
330            } else if dfx.hi < 0.0 {
331                (m - fm / dfx.hi, m - fm / dfx.lo)
332            } else {
333                return None;
334            };
335            let k = FloatInterval::try_new(lo, hi)?;
336            let next = k.intersect(x)?;
337            if next.width() < self.tolerance {
338                return Some(next);
339            }
340            x = next;
341        }
342        None
343    }
344}
345/// A job for interval scheduling, defined by a start time, finish time, and weight.
346#[allow(dead_code)]
347#[derive(Clone, Debug)]
348pub struct ScheduledJob {
349    /// Job identifier.
350    pub id: usize,
351    /// Start time (inclusive).
352    pub start: u64,
353    /// Finish time (exclusive).
354    pub finish: u64,
355    /// Non-negative weight/value.
356    pub weight: u64,
357}
358impl ScheduledJob {
359    /// Create a new job.
360    pub fn new(id: usize, start: u64, finish: u64, weight: u64) -> Self {
361        Self {
362            id,
363            start,
364            finish,
365            weight,
366        }
367    }
368    /// Check if this job overlaps with `other`.
369    pub fn overlaps(&self, other: &Self) -> bool {
370        self.start < other.finish && other.start < self.finish
371    }
372    /// Check if this job is compatible with `other` (non-overlapping).
373    pub fn compatible(&self, other: &Self) -> bool {
374        !self.overlaps(other)
375    }
376}