relmath-rs 0.7.0

Relation-first mathematics and scientific computing in Rust.
Documentation
//! Deterministic explicit finite carrier foundations.

use std::collections::BTreeSet;

use super::UnaryRelation;

/// A deterministic explicit finite carrier.
///
/// `FiniteCarrier<T>` is the first executable G7 carrier boundary. It records
/// admissible values explicitly, even when some values are disconnected from
/// the support of stored tuples. This keeps an explicit carrier semantically
/// distinct from exact support inferred from relations such as
/// [`crate::BinaryRelation::carrier`].
/// Empty and singleton carriers are ordinary first-class values rather than
/// special cases hidden behind relation support.
///
/// The starter implementation stores carrier members in a `BTreeSet`, so
/// membership and iteration are deterministic.
///
/// # Examples
///
/// ```rust
/// use relmath::{BinaryRelation, FiniteCarrier};
///
/// let states = FiniteCarrier::from_values(["Draft", "Review", "Archived"]);
/// let step = BinaryRelation::from_pairs([("Draft", "Review")]);
///
/// assert!(states.contains(&"Archived"));
/// assert_eq!(states.to_vec(), vec!["Archived", "Draft", "Review"]);
/// assert_eq!(step.carrier().to_vec(), vec!["Draft", "Review"]);
/// ```
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FiniteCarrier<T: Ord> {
    values: BTreeSet<T>,
}

impl<T: Ord> FiniteCarrier<T> {
    /// Creates an empty explicit finite carrier.
    #[must_use]
    pub fn new() -> Self {
        Self {
            values: BTreeSet::new(),
        }
    }

    /// Creates an explicit finite carrier from the provided values.
    ///
    /// Duplicate values are coalesced into one stored member.
    #[must_use]
    pub fn from_values<I>(values: I) -> Self
    where
        I: IntoIterator<Item = T>,
    {
        values.into_iter().collect()
    }

    /// Creates an explicit finite carrier containing exactly one value.
    #[must_use]
    pub fn singleton(value: T) -> Self {
        let mut values = BTreeSet::new();
        values.insert(value);
        Self { values }
    }

    /// Returns the number of values in the explicit carrier.
    #[must_use]
    pub fn len(&self) -> usize {
        self.values.len()
    }

    /// Returns `true` when the explicit carrier contains no values.
    #[must_use]
    pub fn is_empty(&self) -> bool {
        self.values.is_empty()
    }

    /// Inserts a value into the explicit carrier.
    ///
    /// Returns `true` when the value was not already present.
    pub fn insert(&mut self, value: T) -> bool {
        self.values.insert(value)
    }

    /// Returns `true` when the explicit carrier contains the given value.
    #[must_use]
    pub fn contains(&self, value: &T) -> bool {
        self.values.contains(value)
    }

    /// Returns an iterator over carrier values in deterministic order.
    pub fn iter(&self) -> impl Iterator<Item = &T> {
        self.values.iter()
    }

    /// Materializes this explicit carrier as a unary relation.
    ///
    /// This is an explicit bridge to the published exact APIs and generic code
    /// paths that still take `UnaryRelation<T>` carrier arguments, such as
    /// [`crate::BinaryRelation::identity`] and older call sites of
    /// [`crate::BinaryRelation::reflexive_transitive_closure`].
    ///
    /// The conversion is intentionally explicit because it forgets the
    /// semantic distinction between an explicitly declared carrier and ordinary
    /// unary relation support. For direct carrier-aware exact operations, prefer
    /// methods such as [`crate::BinaryRelation::identity_on`] and
    /// [`crate::BinaryRelation::reflexive_transitive_closure_on`].
    ///
    /// # Examples
    ///
    /// ```rust
    /// use relmath::{BinaryRelation, FiniteCarrier};
    ///
    /// let step = BinaryRelation::from_pairs([("Draft", "Review")]);
    /// let states = FiniteCarrier::from_values(["Draft", "Review", "Archived"]);
    ///
    /// assert_eq!(
    ///     step.reflexive_transitive_closure(&states.to_unary_relation())
    ///         .to_vec(),
    ///     step.reflexive_transitive_closure_on(&states).to_vec()
    /// );
    /// ```
    #[must_use]
    pub fn to_unary_relation(&self) -> UnaryRelation<T>
    where
        T: Clone,
    {
        self.values.iter().cloned().collect()
    }

    /// Converts the explicit carrier into a sorted vector of values.
    #[must_use]
    pub fn to_vec(&self) -> Vec<T>
    where
        T: Clone,
    {
        self.values.iter().cloned().collect()
    }
}

impl<T: Ord> Default for FiniteCarrier<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<T: Ord> FromIterator<T> for FiniteCarrier<T> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        Self {
            values: iter.into_iter().collect(),
        }
    }
}

impl<T: Ord> Extend<T> for FiniteCarrier<T> {
    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
        self.values.extend(iter);
    }
}

impl<T: Ord> IntoIterator for FiniteCarrier<T> {
    type Item = T;
    type IntoIter = std::collections::btree_set::IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        self.values.into_iter()
    }
}

impl<'a, T: Ord> IntoIterator for &'a FiniteCarrier<T> {
    type Item = &'a T;
    type IntoIter = std::collections::btree_set::Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.values.iter()
    }
}