ruvector_mincut/instance/traits.rs
1//! Core traits for bounded-range minimum cut instances
2//!
3//! This module defines the `ProperCutInstance` trait that all bounded-range
4//! minimum cut solvers must implement. The trait provides a unified interface
5//! for maintaining minimum proper cuts under dynamic edge updates.
6//!
7//! # Overview
8//!
9//! A **proper cut instance** maintains the minimum proper cut for a graph
10//! under the assumption that the minimum cut value λ ∈ [λ_min, λ_max].
11//! This bounded assumption enables more efficient algorithms than maintaining
12//! the exact minimum cut for arbitrary λ values.
13//!
14//! # Guarantees
15//!
16//! - **Correctness**: If λ ∈ [λ_min, λ_max], the instance returns correct results
17//! - **Undefined behavior**: If λ < λ_min, behavior is undefined
18//! - **Detection**: If λ > λ_max, the instance reports `AboveRange`
19//!
20//! # Update Model
21//!
22//! Updates follow a two-phase protocol:
23//! 1. **Insert phase**: Call `apply_inserts()` with new edges
24//! 2. **Delete phase**: Call `apply_deletes()` with removed edges
25//!
26//! This ordering ensures graph connectivity is maintained during updates.
27
28use crate::graph::{VertexId, EdgeId, DynamicGraph};
29use super::witness::WitnessHandle;
30
31/// Result from a bounded-range instance query
32///
33/// Represents the outcome of querying a minimum proper cut instance.
34/// The instance either finds a cut within the bounded range [λ_min, λ_max]
35/// or determines that the minimum cut exceeds λ_max.
36#[derive(Debug, Clone)]
37pub enum InstanceResult {
38 /// Cut value is within [λ_min, λ_max], with witness
39 ///
40 /// The witness certifies that a proper cut exists with the given value.
41 /// The value is guaranteed to be in the range [λ_min, λ_max].
42 ///
43 /// # Fields
44 ///
45 /// - `value`: The cut value |δ(U)| where U is the witness set
46 /// - `witness`: A witness handle certifying the cut
47 ValueInRange {
48 /// The minimum proper cut value
49 value: u64,
50 /// Witness certifying the cut
51 witness: WitnessHandle,
52 },
53
54 /// Cut value exceeds λ_max
55 ///
56 /// The instance has detected that the minimum proper cut value
57 /// is strictly greater than λ_max. No witness is provided because
58 /// maintaining witnesses above the range is not required.
59 ///
60 /// This typically triggers a range adjustment in the outer algorithm.
61 AboveRange,
62}
63
64impl InstanceResult {
65 /// Check if result is in range
66 ///
67 /// # Examples
68 ///
69 /// ```
70 /// use ruvector_mincut::instance::traits::InstanceResult;
71 /// use ruvector_mincut::instance::witness::WitnessHandle;
72 /// use roaring::RoaringBitmap;
73 ///
74 /// let witness = WitnessHandle::new(0, RoaringBitmap::from_iter([0, 1]), 5);
75 /// let result = InstanceResult::ValueInRange { value: 5, witness };
76 /// assert!(result.is_in_range());
77 ///
78 /// let result = InstanceResult::AboveRange;
79 /// assert!(!result.is_in_range());
80 /// ```
81 pub fn is_in_range(&self) -> bool {
82 matches!(self, InstanceResult::ValueInRange { .. })
83 }
84
85 /// Check if result is above range
86 ///
87 /// # Examples
88 ///
89 /// ```
90 /// use ruvector_mincut::instance::traits::InstanceResult;
91 ///
92 /// let result = InstanceResult::AboveRange;
93 /// assert!(result.is_above_range());
94 /// ```
95 pub fn is_above_range(&self) -> bool {
96 matches!(self, InstanceResult::AboveRange)
97 }
98
99 /// Get the cut value if in range
100 ///
101 /// # Examples
102 ///
103 /// ```
104 /// use ruvector_mincut::instance::traits::InstanceResult;
105 /// use ruvector_mincut::instance::witness::WitnessHandle;
106 /// use roaring::RoaringBitmap;
107 ///
108 /// let witness = WitnessHandle::new(0, RoaringBitmap::from_iter([0]), 7);
109 /// let result = InstanceResult::ValueInRange { value: 7, witness };
110 /// assert_eq!(result.value(), Some(7));
111 ///
112 /// let result = InstanceResult::AboveRange;
113 /// assert_eq!(result.value(), None);
114 /// ```
115 pub fn value(&self) -> Option<u64> {
116 match self {
117 InstanceResult::ValueInRange { value, .. } => Some(*value),
118 InstanceResult::AboveRange => None,
119 }
120 }
121
122 /// Get the witness if in range
123 ///
124 /// # Examples
125 ///
126 /// ```
127 /// use ruvector_mincut::instance::traits::InstanceResult;
128 /// use ruvector_mincut::instance::witness::WitnessHandle;
129 /// use roaring::RoaringBitmap;
130 ///
131 /// let witness = WitnessHandle::new(0, RoaringBitmap::from_iter([0]), 7);
132 /// let result = InstanceResult::ValueInRange { value: 7, witness: witness.clone() };
133 /// assert!(result.witness().is_some());
134 ///
135 /// let result = InstanceResult::AboveRange;
136 /// assert!(result.witness().is_none());
137 /// ```
138 pub fn witness(&self) -> Option<&WitnessHandle> {
139 match self {
140 InstanceResult::ValueInRange { witness, .. } => Some(witness),
141 InstanceResult::AboveRange => None,
142 }
143 }
144}
145
146/// A bounded-range proper cut instance
147///
148/// This trait defines the interface for maintaining minimum proper cuts
149/// over a dynamic graph, assuming the cut value λ remains within a
150/// bounded range [λ_min, λ_max].
151///
152/// # Proper Cuts
153///
154/// A **proper cut** is a partition (U, V \ U) where both U and V \ U
155/// induce connected subgraphs. This is stricter than a general cut.
156///
157/// # Bounded Range Assumption
158///
159/// The instance assumes λ ∈ [λ_min, λ_max]:
160/// - If λ < λ_min: Undefined behavior
161/// - If λ ∈ [λ_min, λ_max]: Returns `ValueInRange` with witness
162/// - If λ > λ_max: Returns `AboveRange`
163///
164/// # Update Protocol
165///
166/// Updates must follow this order:
167/// 1. Call `apply_inserts()` with batch of insertions
168/// 2. Call `apply_deletes()` with batch of deletions
169/// 3. Call `query()` to get updated result
170///
171/// # Thread Safety
172///
173/// Implementations must be `Send + Sync` for use in parallel algorithms.
174pub trait ProperCutInstance: Send + Sync {
175 /// Initialize instance on graph with given bounds
176 ///
177 /// Creates a new instance that maintains minimum proper cuts
178 /// for the given graph, assuming λ ∈ [λ_min, λ_max].
179 ///
180 /// # Arguments
181 ///
182 /// * `graph` - The dynamic graph to operate on
183 /// * `lambda_min` - Minimum bound on the cut value
184 /// * `lambda_max` - Maximum bound on the cut value
185 ///
186 /// # Panics
187 ///
188 /// May panic if λ_min > λ_max or if the graph is invalid.
189 fn init(graph: &DynamicGraph, lambda_min: u64, lambda_max: u64) -> Self
190 where
191 Self: Sized;
192
193 /// Apply batch of edge insertions
194 ///
195 /// Inserts a batch of edges into the maintained structure.
196 /// Must be called **before** `apply_deletes()` in each update round.
197 ///
198 /// # Arguments
199 ///
200 /// * `edges` - Slice of (edge_id, source, target) tuples to insert
201 fn apply_inserts(&mut self, edges: &[(EdgeId, VertexId, VertexId)]);
202
203 /// Apply batch of edge deletions
204 ///
205 /// Deletes a batch of edges from the maintained structure.
206 /// Must be called **after** `apply_inserts()` in each update round.
207 ///
208 /// # Arguments
209 ///
210 /// * `edges` - Slice of (edge_id, source, target) tuples to delete
211 fn apply_deletes(&mut self, edges: &[(EdgeId, VertexId, VertexId)]);
212
213 /// Query current minimum proper cut
214 ///
215 /// Returns the current minimum proper cut value and witness,
216 /// or indicates that the cut value exceeds the maximum bound.
217 ///
218 /// # Returns
219 ///
220 /// - `ValueInRange { value, witness }` if λ ∈ [λ_min, λ_max]
221 /// - `AboveRange` if λ > λ_max
222 ///
223 /// # Complexity
224 ///
225 /// Typically O(1) to O(log n) depending on the data structure.
226 fn query(&mut self) -> InstanceResult;
227
228 /// Get the lambda bounds for this instance
229 ///
230 /// Returns the [λ_min, λ_max] bounds this instance was initialized with.
231 ///
232 /// # Returns
233 ///
234 /// A tuple (λ_min, λ_max)
235 fn bounds(&self) -> (u64, u64);
236}