BoundTypeChecks

Trait BoundTypeChecks 

Source
pub trait BoundTypeChecks {
    // Required method
    fn includes_boundary(&self) -> bool;

    // Provided methods
    fn is_open(&self) -> bool { ... }
    fn is_closed(&self) -> bool { ... }
}
Expand description

Runtime queries for boundary inclusion semantics (open vs closed bounds).

BoundTypeChecks provides a unified interface for determining whether a bound includes or excludes its boundary value at runtime. This trait enables generic programming over different boundary inclusion semantics while maintaining mathematical correctness and type safety.

§Design Philosophy

§Runtime Type Detection

Unlike the compile-time BoundType trait that provides static type information, BoundTypeChecks operates on bound instances to determine their inclusion semantics:

use grid1d::bounds::*;
use try_create::New;

fn analyze_bound_inclusion<B: BoundTypeChecks>(bound: &B) -> String {
    if bound.is_closed() {
        "This bound includes its boundary value".to_string()
    } else {
        "This bound excludes its boundary value".to_string()
    }
}

let closed = LowerBoundClosed::new(0.0);
let open = UpperBoundOpen::new(10.0);

assert_eq!(analyze_bound_inclusion(&closed), "This bound includes its boundary value");
assert_eq!(analyze_bound_inclusion(&open), "This bound excludes its boundary value");

§Complement Relationship

The two derived methods in this trait are logical complements:

is_closed() == includes_boundary()
is_open() == !includes_boundary()

This relationship is enforced by the default implementations of BoundTypeChecks::is_closed() and BoundTypeChecks::is_open(), ensuring mathematical consistency across all implementations.

§Mathematical Semantics

§Closed Bounds (Inclusive)

Closed bounds include their boundary values in the constraint:

Bound TypeMathematical ConstraintNotationMeaning
LowerBoundClosedx ≥ bound_value[aIncludes minimum
UpperBoundClosedx ≤ bound_valueb]Includes maximum

§Open Bounds (Exclusive)

Open bounds exclude their boundary values from the constraint:

Bound TypeMathematical ConstraintNotationMeaning
LowerBoundOpenx > bound_value(aExcludes minimum
UpperBoundOpenx < bound_valueb)Excludes maximum

§Core Methods

§BoundTypeChecks::includes_boundary()

The fundamental method that determines whether the boundary value is part of the constraint. This is the only method implementors must provide:

use grid1d::bounds::*;
use try_create::New;

let closed_lower = LowerBoundClosed::new(5.0);
let open_lower = LowerBoundOpen::new(5.0);
let closed_upper = UpperBoundClosed::new(10.0);
let open_upper = UpperBoundOpen::new(10.0);

// Closed bounds include their boundary
assert!(closed_lower.includes_boundary());
assert!(closed_upper.includes_boundary());

// Open bounds exclude their boundary
assert!(!open_lower.includes_boundary());
assert!(!open_upper.includes_boundary());

§BoundTypeChecks::is_closed()

Returns true if this bound includes its boundary value. This is a convenience method that delegates to BoundTypeChecks::includes_boundary():

use grid1d::bounds::*;
use try_create::New;

assert!(LowerBoundClosed::new(0.0).is_closed());
assert!(!LowerBoundClosed::new(1.0).is_open());

assert!(UpperBoundClosed::new(2.0).is_closed());
assert!(!UpperBoundClosed::new(3.0).is_open());

assert!(!LowerBoundOpen::new(4.0).is_closed());
assert!(LowerBoundOpen::new(5.0).is_open());

assert!(!UpperBoundOpen::new(6.0).is_closed());
assert!(UpperBoundOpen::new(7.0).is_open());

§BoundTypeChecks::is_open()

Returns true if this bound excludes its boundary value. This is implemented as the logical negation of BoundTypeChecks::includes_boundary():

use grid1d::bounds::*;
use try_create::New;

let open_lower = LowerBoundOpen::new(1.0);
let open_upper = UpperBoundOpen::new(2.0);
let closed_lower = LowerBoundClosed::new(1.0);
let closed_upper = UpperBoundClosed::new(2.0);

// Open bounds return true
assert!(open_lower.is_open());
assert!(open_upper.is_open());
assert!(!open_lower.is_closed());
assert!(!open_upper.is_closed());

// Closed bounds return false
assert!(!closed_lower.is_open());
assert!(!closed_upper.is_open());
assert!(closed_lower.is_closed());
assert!(closed_upper.is_closed());

§Generic Programming Applications

§Constraint Analysis

use grid1d::bounds::*;
use try_create::New;

fn analyze_constraint_strictness<B: BoundTypeChecks + AsRef<f64>>(bounds: &[B]) -> (usize, usize) {
    let (strict, inclusive): (Vec<_>, Vec<_>) = bounds.iter()
        .partition(|bound| bound.is_open());
    (strict.len(), inclusive.len())
}

let mixed_lower_bounds: Vec<LowerBoundRuntime<f64>> = vec![
    LowerBoundClosed::new(0.0).into(),   // Inclusive
    LowerBoundOpen::new(1.0).into(),     // Strict
];
let mixed_upper_bounds: Vec<UpperBoundRuntime<f64>> = vec![
    UpperBoundClosed::new(10.0).into(),  // Inclusive
    UpperBoundOpen::new(9.0).into(),     // Strict
    UpperBoundOpen::new(8.0).into(),     // Strict
];

let (strict_count, inclusive_count) = analyze_constraint_strictness(&mixed_lower_bounds);
assert_eq!(strict_count, 1);     // One open bounds
assert_eq!(inclusive_count, 1);  // One closed bounds

let (strict_count, inclusive_count) = analyze_constraint_strictness(&mixed_upper_bounds);
assert_eq!(strict_count, 2);     // Two open bounds
assert_eq!(inclusive_count, 1);  // One closed bounds

§Boundary Behavior Validation

use grid1d::bounds::*;
use try_create::New;

fn validate_boundary_consistency<B>(bound: &B, test_value: f64) -> bool
where
    B: BoundTypeChecks + ValueWithinBound<RealType = f64> + AsRef<f64>,
{
    let boundary_value = *bound.as_ref();
    let at_boundary = (test_value - boundary_value).abs() < f64::EPSILON;
     
    if at_boundary {
        // At the boundary, constraint should match inclusion semantics
        bound.value_within_bound(&test_value) == bound.includes_boundary()
    } else {
        // Away from boundary, inclusion type shouldn't matter for this test
        true
    }
}

let closed_bound = LowerBoundClosed::new(5.0);
let open_bound = LowerBoundOpen::new(5.0);

// Test boundary value behavior
assert!(validate_boundary_consistency(&closed_bound, 5.0)); // Should include 5.0
assert!(validate_boundary_consistency(&open_bound, 5.0));   // Should exclude 5.0

// Test non-boundary values
assert!(validate_boundary_consistency(&closed_bound, 6.0)); // Both should include 6.0
assert!(validate_boundary_consistency(&open_bound, 6.0));

§Dynamic Interval Construction

use grid1d::bounds::*;
use try_create::New;

fn describe_interval_boundary<L, U>(lower: &L, upper: &U) -> String
where
    L: BoundTypeChecks + AsRef<f64>,
    U: BoundTypeChecks + AsRef<f64>,
{
    let left_bracket = if lower.is_closed() { "[" } else { "(" };
    let right_bracket = if upper.is_closed() { "]" } else { ")" };
     
    format!("{}{}, {}{}",
        left_bracket, lower.as_ref(),
        upper.as_ref(), right_bracket)
}

let bounds_combinations: Vec<(LowerBoundRuntime<f64>, UpperBoundRuntime<f64>)> = vec![
    (LowerBoundClosed::new(0.0).into(), UpperBoundClosed::new(1.0).into()),   // [0, 1]
    (LowerBoundOpen::new(0.0).into(), UpperBoundOpen::new(1.0).into()),       // (0, 1)
    (LowerBoundClosed::new(0.0).into(), UpperBoundOpen::new(1.0).into()),     // [0, 1)
    (LowerBoundOpen::new(0.0).into(), UpperBoundClosed::new(1.0).into()),     // (0, 1]
];

let descriptions: Vec<String> = bounds_combinations.iter()
    .map(|(l, u)| describe_interval_boundary(l, u))
    .collect();

assert_eq!(descriptions, vec!["[0, 1]", "(0, 1)", "[0, 1)", "(0, 1]"]);

§Integration with Runtime Bounds

The trait works seamlessly with runtime bound types:

use grid1d::bounds::*;
use try_create::New;

fn analyze_runtime_bound_types(
    lower: &LowerBoundRuntime<f64>,
    upper: &UpperBoundRuntime<f64>
) -> String {
    let lower_type = if lower.is_closed() { "closed" } else { "open" };
    let upper_type = if upper.is_closed() { "closed" } else { "open" };
     
    format!("Lower: {} ({}), Upper: {} ({})",
        lower.as_ref(), lower_type,
        upper.as_ref(), upper_type)
}

let lower = IntervalBoundRuntime::Closed(LowerBoundClosed::new(0.0));
let upper = IntervalBoundRuntime::Open(UpperBoundOpen::new(1.0));

assert_eq!(
    analyze_runtime_bound_types(&lower, &upper),
    "Lower: 0 (closed), Upper: 1 (open)"
);

§Mathematical Invariant Verification

The trait enables runtime validation of mathematical properties:

use grid1d::bounds::*;
use try_create::New;

fn verify_inclusion_consistency<B: BoundTypeChecks>(bound: &B) -> bool {
    // Verify the complement relationship holds
    bound.is_closed() == bound.includes_boundary() &&
    bound.is_open() == !bound.includes_boundary()
}

fn verify_boundary_semantics<B>(bound: &B, boundary_value: f64) -> Result<(), String>
where
    B: BoundTypeChecks + ValueWithinBound<RealType = f64> + AsRef<f64>,
{
    if !verify_inclusion_consistency(bound) {
        return Err("Bound inclusion consistency check failed".to_string());
    }
     
    // The boundary value itself should only satisfy the constraint if the bound is closed
    let boundary_satisfies = bound.value_within_bound(&boundary_value);
    if boundary_satisfies != bound.includes_boundary() {
        return Err("Boundary constraint behavior inconsistent with inclusion type".to_string());
    }
     
    Ok(())
}

let closed_bound = LowerBoundClosed::new(5.0);
let open_bound = LowerBoundOpen::new(5.0);

assert!(verify_boundary_semantics(&closed_bound, 5.0).is_ok());
assert!(verify_boundary_semantics(&open_bound, 5.0).is_ok());

§Performance Characteristics

§Runtime Complexity

  • includes_boundary(): O(1) - typically compiles to a constant or simple type check
  • is_closed(): O(1) - delegates to includes_boundary()
  • is_open(): O(1) - logical negation of includes_boundary()
  • Memory: No additional storage overhead beyond the underlying bound

§Optimization Notes

  • All methods are marked #[inline(always)] for zero-cost abstractions
  • The complement relationship enables compiler optimizations
  • For compile-time bounds, inclusion information is known statically and optimized away
  • Runtime bounds have small pattern matching overhead but maintain correctness

§Implementation Requirements

Implementors must provide:

  1. includes_boundary(): Core method that determines boundary inclusion semantics
  2. Consistency: The method must return consistent results for the lifetime of the object
  3. Mathematical Correctness: Return true for closed bounds, false for open bounds

§Example Implementation

use grid1d::bounds::*;

struct CustomBound {
    value: f64,
    is_inclusive: bool,
}

impl BoundTypeChecks for CustomBound {
    fn includes_boundary(&self) -> bool {
        self.is_inclusive
    }
}

let inclusive = CustomBound { value: 5.0, is_inclusive: true };
let exclusive = CustomBound { value: 5.0, is_inclusive: false };

assert!(inclusive.is_closed());
assert!(!inclusive.is_open());
assert!(inclusive.includes_boundary());

assert!(!exclusive.is_closed());
assert!(exclusive.is_open());
assert!(!exclusive.includes_boundary());

§Mathematical Guarantees

The BoundTypeChecks trait maintains mathematical correctness by:

  • Complement Relationship: Ensuring exactly one of is_open() or is_closed() is true
  • Consistency: Boundary inclusion semantics remain constant for the object’s lifetime
  • Type Safety: Preventing confusion between inclusive and exclusive constraints
  • Constraint Semantics: Properly reflecting the mathematical meaning of open vs closed bounds

Use BoundTypeChecks when you need to determine boundary inclusion behavior at runtime while maintaining mathematical correctness and type safety. For compile-time inclusion information, prefer the static BoundType trait and its associated types (Open, Closed).

Required Methods§

Source

fn includes_boundary(&self) -> bool

Returns whether the boundary value is included in the interval

Provided Methods§

Source

fn is_open(&self) -> bool

Returns whether this bound is open (excludes the boundary value)

Source

fn is_closed(&self) -> bool

Returns whether this bound is closed (includes the boundary value)

Implementors§

Source§

impl<RealType: RealScalar, Side: BoundSide> BoundTypeChecks for IntervalBoundRuntime<RealType, Side>

Source§

impl<RealType: RealScalar, Side: BoundSide, Type: BoundType> BoundTypeChecks for IntervalBound<RealType, Side, Type>