pub trait Contains<RealType: RealScalar>: GetIntervalBound<BoundType = RealType> {
// Required method
fn contains_point(&self, x: &RealType) -> bool;
// Provided method
fn contains_interval<IntervalType: IntervalTrait<RealType = RealType>>(
&self,
other: &IntervalType,
) -> bool { ... }
}
Expand description
Core trait for point containment testing in mathematical intervals.
The Contains
trait provides the fundamental operation for testing whether a specific
point belongs to an interval. This trait forms the foundation for all point-based queries
and is complemented by the contains_interval
method
for interval-to-interval containment testing.
§Mathematical Foundation
Point containment is the most basic operation in interval mathematics. For any interval I
and point x
, the containment test x ∈ I
determines whether the point lies within the
interval according to its boundary conditions:
- Closed intervals
[a,b]
:x ∈ [a,b] ⟺ a ≤ x ≤ b
- Open intervals
(a,b)
:x ∈ (a,b) ⟺ a < x < b
- Half-open intervals
[a,b)
:x ∈ [a,b) ⟺ a ≤ x < b
- Half-open intervals
(a,b]
:x ∈ (a,b] ⟺ a < x ≤ b
- Singleton intervals
{a}
:x ∈ {a} ⟺ x = a
- Unbounded intervals: Various combinations with infinite extents
§Design Philosophy
The Contains
trait is intentionally minimal and focused:
- Single Responsibility: Only handles point containment, not interval containment
- Generic Design: Works with any scalar type implementing
RealScalar
- Performance First: Designed for O(1) operations with minimal overhead
- Type Safety: Prevents containment queries with incompatible types
- Mathematical Correctness: Respects boundary semantics exactly
§Relationship with Interval Containment
Point containment (contains_point
) and interval containment
(contains_interval
) are related but distinct operations:
Point Containment: x ∈ I (scalar ∈ interval)
Interval Containment: A ⊆ B (interval ⊆ interval)
§Key Differences
Aspect | Point Containment | Interval Containment |
---|---|---|
Input | Single scalar value | Another interval |
Output | bool | bool |
Complexity | O(1) - at most 2 comparisons | O(1) - boundary logic |
Use Cases | Point queries, evaluation domains | Set operations, subset testing |
Mathematical Basis | Element membership x ∈ I | Subset relation A ⊆ B |
§Mathematical Relationship
Interval containment can be expressed in terms of point containment:
A ⊆ B ⟺ ∀x ∈ A: x ∈ B
However, for efficiency, interval containment is implemented by comparing boundaries rather than testing all points.
§Core Operation
§contains_point
Tests whether a specific point belongs to the interval.
Signature: fn contains_point(&self, point: &RealType) -> bool
Behavior:
- Returns
true
if the point is within the interval - Returns
false
if the point is outside the interval - Respects boundary inclusion/exclusion semantics
- Always O(1) complexity regardless of interval type
§Usage Examples
§Basic Point Containment
use grid1d::intervals::*;
use num_valid::RealNative64StrictFiniteInDebug;
use try_create::{New, TryNew};
type Real = RealNative64StrictFiniteInDebug;
let closed = IntervalClosed::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap()
);
let open = IntervalOpen::new(
Real::try_new(0.0).unwrap(),
Real::try_new(1.0).unwrap()
);
let singleton = IntervalSingleton::new(Real::try_new(0.5).unwrap());
// Closed interval includes boundaries
assert!(closed.contains_point(&Real::try_new(0.0).unwrap())); // Lower bound
assert!(closed.contains_point(&Real::try_new(0.5).unwrap())); // Interior
assert!(closed.contains_point(&Real::try_new(1.0).unwrap())); // Upper bound
// Open interval excludes boundaries
assert!(!open.contains_point(&Real::try_new(0.0).unwrap())); // Lower bound excluded
assert!(open.contains_point(&Real::try_new(0.5).unwrap())); // Interior
assert!(!open.contains_point(&Real::try_new(1.0).unwrap())); // Upper bound excluded
// Singleton contains only exact match
assert!(singleton.contains_point(&Real::try_new(0.5).unwrap())); // Exact match
assert!(!singleton.contains_point(&Real::try_new(0.4).unwrap())); // Any other value
§Comparison with Interval Containment
use grid1d::intervals::*;
use try_create::New;
let outer = IntervalClosed::new(0.0, 2.0); // [0, 2]
let inner = IntervalClosed::new(0.5, 1.5); // [0.5, 1.5]
let point_interval = IntervalSingleton::new(1.0); // {1}
// Point containment: test specific values
assert!(outer.contains_point(&1.0)); // Point 1.0 ∈ [0, 2] ✓
assert!(inner.contains_point(&1.0)); // Point 1.0 ∈ [0.5, 1.5] ✓
// Interval containment: test subset relationships
assert!(outer.contains_interval(&inner)); // [0, 2] ⊇ [0.5, 1.5] ✓
assert!(outer.contains_interval(&point_interval)); // [0, 2] ⊇ {1} ✓
assert!(inner.contains_interval(&point_interval)); // [0.5, 1.5] ⊇ {1} ✓
assert!(!inner.contains_interval(&outer)); // [0.5, 1.5] ⊉ [0, 2] ✗
§Generic Programming with Point Containment
use grid1d::intervals::*;
use num_valid::RealScalar;
/// Count how many test points are contained in an interval
fn count_contained_points<I, T>(interval: &I, test_points: &[T]) -> usize
where
I: Contains<T>,
T: RealScalar,
{
test_points.iter()
.filter(|&point| interval.contains_point(point))
.count()
}
/// Filter points to only those contained in an interval
fn filter_points_in_interval<I, T>(interval: &I, points: Vec<T>) -> Vec<T>
where
I: Contains<T>,
T: RealScalar,
{
points.into_iter()
.filter(|point| interval.contains_point(point))
.collect()
}
let interval = IntervalClosed::new(-1.0, 1.0);
let test_points = vec![-2.0, -1.0, -0.5, 0.0, 0.5, 1.0, 2.0];
let count = count_contained_points(&interval, &test_points);
assert_eq!(count, 5); // -1.0, -0.5, 0.0, 0.5, 1.0
let filtered = filter_points_in_interval(&interval, test_points);
assert_eq!(filtered, vec![-1.0, -0.5, 0.0, 0.5, 1.0]);
§Performance Characteristics
§Time Complexity
- All interval types: O(1) regardless of interval size or type
- Bounded intervals: At most 2 comparisons (lower ≤ x ≤ upper)
- Semi-bounded intervals: 1 comparison (x ≥ lower or x ≤ upper)
- Unbounded intervals: Constant time (always true)
- Singletons: 1 equality comparison (x == value)
§Space Complexity
- Memory usage: O(1) - no additional allocation
- Stack usage: Minimal - simple comparison operations
- Cache efficiency: Excellent - operates on interval bounds directly
§Scalar Type Performance Impact
use grid1d::intervals::*;
use num_valid::{RealNative64StrictFiniteInDebug, RealNative64StrictFinite, RealScalar};
// All these have nearly identical performance for point containment:
type FastInterval = IntervalClosed<f64>;
type OptimalInterval = IntervalClosed<RealNative64StrictFiniteInDebug>;
type SafeInterval = IntervalClosed<RealNative64StrictFinite>;
fn benchmark_point_containment<T: RealScalar>(
interval: &IntervalClosed<T>,
test_point: &T
) -> bool {
// This compiles to identical assembly for f64 and RealNative64StrictFiniteInDebug
// Slight overhead for RealNative64StrictFinite due to validation
interval.contains_point(test_point)
}
§Boundary Semantics and Edge Cases
§Boundary Inclusion Rules
use grid1d::intervals::*;
use num_valid::RealScalar;
// Demonstrate different boundary behaviors
let closed = IntervalClosed::new(0.0, 1.0); // [0, 1]
let open = IntervalOpen::new(0.0, 1.0); // (0, 1)
let left_open = IntervalLowerOpenUpperClosed::new(0.0, 1.0); // (0, 1]
let right_open = IntervalLowerClosedUpperOpen::new(0.0, 1.0); // [0, 1)
let lower_bound = 0.0;
let upper_bound = 1.0;
let interior = 0.5;
// Lower boundary behavior
assert!(closed.contains_point(&lower_bound)); // [0,1] includes 0
assert!(!open.contains_point(&lower_bound)); // (0,1) excludes 0
assert!(!left_open.contains_point(&lower_bound)); // (0,1] excludes 0
assert!(right_open.contains_point(&lower_bound)); // [0,1) includes 0
// Upper boundary behavior
assert!(closed.contains_point(&upper_bound)); // [0,1] includes 1
assert!(!open.contains_point(&upper_bound)); // (0,1) excludes 1
assert!(left_open.contains_point(&upper_bound)); // (0,1] includes 1
assert!(!right_open.contains_point(&upper_bound)); // [0,1) excludes 1
// Interior points (always included for positive-length intervals)
assert!(closed.contains_point(&interior));
assert!(open.contains_point(&interior));
assert!(left_open.contains_point(&interior));
assert!(right_open.contains_point(&interior));
§Floating-Point Precision Considerations
use grid1d::intervals::*;
let interval = IntervalClosed::new(0.0, 1.0);
// Exact boundary values
assert!(interval.contains_point(&0.0));
assert!(interval.contains_point(&1.0));
// Values very close to boundaries
assert!(interval.contains_point(&f64::EPSILON)); // Just above 0
assert!(interval.contains_point(&(1.0 - f64::EPSILON))); // Just below 1
assert!(!interval.contains_point(&-f64::EPSILON)); // Just below 0
assert!(!interval.contains_point(&(1.0 + f64::EPSILON))); // Just above 1
// For very small intervals, be aware of precision limits
let tiny = IntervalClosed::new(1.0, 1.0 + f64::EPSILON);
assert!(tiny.contains_point(&1.0));
assert!(tiny.contains_point(&(1.0 + f64::EPSILON)));
assert_eq!(tiny.length().into_inner(), f64::EPSILON);
§Implementation Requirements
Types implementing Contains
must guarantee:
§Mathematical Correctness
use grid1d::intervals::*;
use num_valid::RealScalar;
// These properties must hold for all implementations:
fn verify_contains_properties<I, T>(interval: &I, point: &T)
where
I: Contains<T>,
T: RealScalar,
{
let result = interval.contains_point(point);
// Consistency: repeated calls must give same result
assert_eq!(result, interval.contains_point(point));
// The result should be deterministic for the same inputs
assert_eq!(result, interval.contains_point(&point.clone()));
}
§Performance Requirements
- O(1) time complexity: All implementations must be constant time
- No allocation: Point containment should not allocate memory
- Minimal computation: Use the most efficient boundary checks possible
§Type Safety Requirements
- Scalar type consistency: Point type must match interval’s scalar type
- Reference semantics: Accept points by reference to avoid unnecessary copies
- Generic compatibility: Work with any
RealScalar
implementation
§Advanced Usage Patterns
§Predicate Functions and Filtering
use grid1d::intervals::*;
use num_valid::RealScalar;
/// Create a predicate function from an interval
fn interval_predicate<I, T>(interval: I) -> impl Fn(&T) -> bool
where
I: Contains<T>,
T: RealScalar,
{
move |point: &T| interval.contains_point(point)
}
/// Filter a dataset based on multiple interval constraints
fn filter_by_intervals<T>(
data: Vec<T>,
constraints: &[impl Contains<T>]
) -> Vec<T>
where
T: RealScalar,
{
data.into_iter()
.filter(|point| {
constraints.iter().all(|interval| interval.contains_point(point))
})
.collect()
}
§Statistical Analysis
use grid1d::intervals::*;
/// Compute statistics for points within an interval
fn interval_statistics<I>(
interval: &I,
data: &[f64]
) -> Option<(f64, f64, usize)>
where
I: Contains<f64>,
{
let contained_points: Vec<f64> = data.iter()
.filter(|&x| interval.contains_point(x))
.cloned()
.collect();
if contained_points.is_empty() {
return None;
}
let count = contained_points.len();
let sum: f64 = contained_points.iter().sum();
let mean = sum / count as f64;
let variance = contained_points.iter()
.map(|x| (x - mean).powi(2))
.sum::<f64>() / count as f64;
Some((mean, variance, count))
}
let interval = IntervalClosed::new(-1.0, 1.0);
let data = vec![-2.0, -0.5, 0.0, 0.5, 2.0];
if let Some((mean, variance, count)) = interval_statistics(&interval, &data) {
println!("Points in interval: count={}, mean={}, variance={}", count, mean, variance);
}
§Common Pitfalls and Best Practices
§Avoiding Common Mistakes
use grid1d::intervals::*;
// WRONG: Assuming all intervals include their "endpoints"
fn naive_endpoint_test<I>(interval: &I) -> bool
where
I: Contains<f64> + HasLowerBound<LowerBoundValue = f64> + HasUpperBound<UpperBoundValue = f64>,
{
let lower = *interval.lower_bound_value();
let upper = *interval.upper_bound_value();
// This fails for open intervals!
interval.contains_point(&lower) && interval.contains_point(&upper)
}
// CORRECT: Test boundary inclusion explicitly
fn proper_boundary_test<I>(interval: &I) -> (bool, bool)
where
I: Contains<f64> + HasLowerBound<LowerBoundValue = f64> + HasUpperBound<UpperBoundValue = f64>,
{
let lower = *interval.lower_bound_value();
let upper = *interval.upper_bound_value();
(interval.contains_point(&lower), interval.contains_point(&upper))
}
let closed = IntervalClosed::new(0.0, 1.0);
let open = IntervalOpen::new(0.0, 1.0);
assert!(naive_endpoint_test(&closed)); // Works for closed
assert!(!naive_endpoint_test(&open)); // Fails for open (correct behavior)
assert_eq!(proper_boundary_test(&closed), (true, true)); // Both included
assert_eq!(proper_boundary_test(&open), (false, false)); // Both excluded
§Performance Best Practices
use grid1d::intervals::*;
// GOOD: Reuse intervals for multiple point tests
fn efficient_batch_testing(interval: &IntervalClosed<f64>, points: &[f64]) -> Vec<bool> {
points.iter()
.map(|point| interval.contains_point(point))
.collect()
}
// AVOID: Creating intervals repeatedly for the same bounds
fn inefficient_testing(lower: f64, upper: f64, points: &[f64]) -> Vec<bool> {
points.iter()
.map(|point| {
let interval = IntervalClosed::new(lower, upper); // Wasteful!
interval.contains_point(point)
})
.collect()
}
§Mathematical Properties and Guarantees
The Contains
trait implementations maintain these essential properties:
§Consistency Properties
- Deterministic: Same input always produces same output
- Reflexive: For any point in the interval, containment is stable
- Boundary Correct: Respects mathematical interval notation exactly
§Performance Properties
- Constant Time: O(1) for all interval types and point queries
- Memory Efficient: No allocation, minimal stack usage
- Cache Friendly: Operations on compact data structures
§Type Safety Properties
- Scalar Consistency: Point and interval scalar types must match
- Generic Correctness: Works with any
RealScalar
implementation - Reference Safety: Accepts points by reference safely
These guarantees are preserved across all interval types and scalar types, ensuring that point containment testing is both mathematically correct and computationally efficient throughout the library.
Required Methods§
Sourcefn contains_point(&self, x: &RealType) -> bool
fn contains_point(&self, x: &RealType) -> bool
Tests whether a point is contained within this interval.
This is the fundamental operation that all interval types must implement. The behavior depends on the specific interval type and its boundary conditions.
§Boundary Behavior
- Closed intervals
[a, b]
: Include both endpoints - Open intervals
(a, b)
: Exclude both endpoints - Half-open intervals: Include one endpoint, exclude the other
- Unbounded intervals: Have infinite extent in one or both directions
- Singleton intervals: Contain exactly one point
§Examples
use grid1d::intervals::*;
use try_create::New;
let closed = IntervalClosed::new(0.0, 1.0);
assert!(closed.contains_point(&0.0)); // Endpoints included
assert!(closed.contains_point(&1.0)); // Endpoints included
assert!(closed.contains_point(&0.5)); // Interior point
let open = IntervalOpen::new(0.0, 1.0);
assert!(!open.contains_point(&0.0)); // Endpoints excluded
assert!(!open.contains_point(&1.0)); // Endpoints excluded
assert!(open.contains_point(&0.5)); // Interior point
let half_open = IntervalLowerOpenUpperClosed::new(0.0, 1.0);
assert!(!half_open.contains_point(&0.0)); // Lower bound excluded
assert!(half_open.contains_point(&1.0)); // Upper bound included
let singleton = IntervalSingleton::new(42.0);
assert!(singleton.contains_point(&42.0)); // Exact match
assert!(!singleton.contains_point(&41.0)); // No match
§Performance
This operation is O(1) for all interval types, involving at most two comparisons.
Provided Methods§
Sourcefn contains_interval<IntervalType: IntervalTrait<RealType = RealType>>(
&self,
other: &IntervalType,
) -> bool
fn contains_interval<IntervalType: IntervalTrait<RealType = RealType>>( &self, other: &IntervalType, ) -> bool
Tests whether this interval completely contains another interval.
Returns true
if and only if every point in other
is also contained in self
.
This includes proper handling of boundary conditions - for example, the closed
interval [0., 1.]
contains the open interval (0., 1.)
, but not vice versa.
§Mathematical Definition
For intervals A and B, A contains B (A ⊇ B) if and only if:
- The lower bound of A is ≤ the lower bound of B (with proper boundary handling)
- The upper bound of A is ≥ the upper bound of B (with proper boundary handling)
§Boundary Rules
- Closed bounds can contain open bounds at the same value
- Open bounds cannot contain closed bounds at the same value
- Unbounded sides always contain any bounded side
§Examples
use grid1d::intervals::*;
let outer = IntervalClosed::new(0.0, 2.0); // [0, 2]
let inner = IntervalOpen::new(0.5, 1.5); // (0.5, 1.5)
let boundary = IntervalClosed::new(0.0, 1.0); // [0, 1]
let open_boundary = IntervalOpen::new(0.0, 1.0); // (0, 1)
assert!(outer.contains_interval(&inner)); // [0, 2] ⊇ (0.5, 1.5) ✓
assert!(outer.contains_interval(&boundary)); // [0, 2] ⊇ [0, 1] ✓
assert!(boundary.contains_interval(&open_boundary)); // [0, 1] ⊇ (0, 1) ✓
assert!(!open_boundary.contains_interval(&boundary)); // (0, 1) ⊉ [0, 1] ✗
§Performance
This operation is O(1) and involves only bound comparisons.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.