Download rust/crates/hyperkitty-nand/src/conflicts.rs from Snapkitty/hyperkitty-constraint-dsl: direct link, hf CLI and curl.
- Browser
- Download file 5.61 kB
-
https://huggingface.co/Snapkitty/hyperkitty-constraint-dsl/resolve/main/rust/crates/hyperkitty-nand/src/conflicts.rs
- Command line
-
hf download hf://Snapkitty/hyperkitty-constraint-dsl/rust/crates/hyperkitty-nand/src/conflicts.rs
-
curl -L -o conflicts.rs https://huggingface.co/Snapkitty/hyperkitty-constraint-dsl/resolve/main/rust/crates/hyperkitty-nand/src/conflicts.rs
5.61 kB
| //! Conflict Registry — expert conflict declaration and querying. | |
| //! | |
| //! Stores pairwise conflicts between experts. When two experts are declared | |
| //! conflicting, at most one may be active at any time. | |
| use std::collections::HashSet; | |
| /// Expert identifier — a unique 64-bit tag for each expert in the system. | |
| pub struct ExpertId(pub u64); | |
| impl ExpertId { | |
| /// Create a new ExpertId | |
| pub fn new(id: u64) -> Self { | |
| ExpertId(id) | |
| } | |
| } | |
| /// Registry of pairwise conflicts between experts. | |
| /// | |
| /// A conflict between A and B means at most one of {A, B} may be active | |
| /// in any valid route configuration. | |
| pub struct ConflictRegistry { | |
| /// Stored as canonical pairs (min, max) to avoid duplicates | |
| conflicts: HashSet<(ExpertId, ExpertId)>, | |
| } | |
| impl ConflictRegistry { | |
| /// Create an empty conflict registry | |
| pub fn new() -> Self { | |
| ConflictRegistry { | |
| conflicts: HashSet::new(), | |
| } | |
| } | |
| /// Canonicalize a pair so (min, max) is always stored | |
| fn canonical(a: ExpertId, b: ExpertId) -> (ExpertId, ExpertId) { | |
| if a.0 <= b.0 { | |
| (a, b) | |
| } else { | |
| (b, a) | |
| } | |
| } | |
| /// Register a conflict between two experts. | |
| /// | |
| /// Declaring a conflict with oneself is a no-op. | |
| pub fn register_conflict(&mut self, a: ExpertId, b: ExpertId) { | |
| if a == b { | |
| return; | |
| } | |
| let pair = Self::canonical(a, b); | |
| self.conflicts.insert(pair); | |
| } | |
| /// Check whether two experts are in conflict. | |
| pub fn are_conflicting(&self, a: ExpertId, b: ExpertId) -> bool { | |
| if a == b { | |
| return false; | |
| } | |
| let pair = Self::canonical(a, b); | |
| self.conflicts.contains(&pair) | |
| } | |
| /// Find all conflicting pairs within a set of experts. | |
| /// | |
| /// Returns pairs in deterministic order (sorted by canonical pair). | |
| pub fn find_conflicts(&self, experts: &[ExpertId]) -> Vec<(ExpertId, ExpertId)> { | |
| let mut found = Vec::new(); | |
| let n = experts.len(); | |
| for i in 0..n { | |
| for j in (i + 1)..n { | |
| if self.are_conflicting(experts[i], experts[j]) { | |
| let pair = Self::canonical(experts[i], experts[j]); | |
| found.push(pair); | |
| } | |
| } | |
| } | |
| found.sort(); | |
| found.dedup(); | |
| found | |
| } | |
| /// Return the number of registered conflicts | |
| pub fn len(&self) -> usize { | |
| self.conflicts.len() | |
| } | |
| /// Check if the registry is empty | |
| pub fn is_empty(&self) -> bool { | |
| self.conflicts.is_empty() | |
| } | |
| } | |
| impl Default for ConflictRegistry { | |
| fn default() -> Self { | |
| Self::new() | |
| } | |
| } | |
| mod tests { | |
| use super::*; | |
| fn test_register_and_query() { | |
| let mut reg = ConflictRegistry::new(); | |
| let a = ExpertId(1); | |
| let b = ExpertId(2); | |
| let c = ExpertId(3); | |
| reg.register_conflict(a, b); | |
| assert!(reg.are_conflicting(a, b)); | |
| assert!(reg.are_conflicting(b, a)); // symmetric | |
| assert!(!reg.are_conflicting(a, c)); | |
| assert!(!reg.are_conflicting(b, c)); | |
| } | |
| fn test_self_conflict_is_noop() { | |
| let mut reg = ConflictRegistry::new(); | |
| let a = ExpertId(1); | |
| reg.register_conflict(a, a); | |
| assert!(!reg.are_conflicting(a, a)); | |
| assert_eq!(reg.len(), 0); | |
| } | |
| fn test_find_conflicts_in_set() { | |
| let mut reg = ConflictRegistry::new(); | |
| let a = ExpertId(1); | |
| let b = ExpertId(2); | |
| let c = ExpertId(3); | |
| let d = ExpertId(4); | |
| reg.register_conflict(a, b); | |
| reg.register_conflict(c, d); | |
| let experts = vec![a, b, c, d]; | |
| let conflicts = reg.find_conflicts(&experts); | |
| assert_eq!(conflicts.len(), 2); | |
| assert!(conflicts.contains(&(a, b))); | |
| assert!(conflicts.contains(&(c, d))); | |
| } | |
| fn test_find_conflicts_subset() { | |
| let mut reg = ConflictRegistry::new(); | |
| let a = ExpertId(1); | |
| let b = ExpertId(2); | |
| let c = ExpertId(3); | |
| reg.register_conflict(a, b); | |
| reg.register_conflict(a, c); | |
| reg.register_conflict(b, c); | |
| // Only query subset {a, c} | |
| let conflicts = reg.find_conflicts(&[a, c]); | |
| assert_eq!(conflicts.len(), 1); | |
| assert!(conflicts.contains(&(a, c))); | |
| } | |
| fn test_no_conflicts() { | |
| let reg = ConflictRegistry::new(); | |
| let experts = vec![ExpertId(1), ExpertId(2), ExpertId(3)]; | |
| let conflicts = reg.find_conflicts(&experts); | |
| assert!(conflicts.is_empty()); | |
| } | |
| fn test_duplicate_registration() { | |
| let mut reg = ConflictRegistry::new(); | |
| let a = ExpertId(1); | |
| let b = ExpertId(2); | |
| reg.register_conflict(a, b); | |
| reg.register_conflict(a, b); | |
| reg.register_conflict(b, a); | |
| assert_eq!(reg.len(), 1); | |
| assert!(reg.are_conflicting(a, b)); | |
| } | |
| fn test_many_conflicts() { | |
| let mut reg = ConflictRegistry::new(); | |
| // Register conflicts between consecutive experts | |
| for i in 0..10 { | |
| reg.register_conflict(ExpertId(i), ExpertId(i + 1)); | |
| } | |
| assert_eq!(reg.len(), 10); | |
| assert!(reg.are_conflicting(ExpertId(0), ExpertId(1))); | |
| assert!(reg.are_conflicting(ExpertId(9), ExpertId(10))); | |
| assert!(!reg.are_conflicting(ExpertId(0), ExpertId(2))); | |
| } | |
| } | |