20 KiB
20 KiB
SPARC Phase 5: Completion - Integration & Deployment
Overview
This phase covers the final integration, deployment, documentation, and release preparation for the ruvector-mincut crate implementing subpolynomial-time dynamic minimum cut algorithms.
1. Integration with ruvector Ecosystem
1.1 Workspace Integration
Update root Cargo.toml:
[workspace]
members = [
"crates/ruvector",
"crates/ruvector-graph",
"crates/ruvector-mincut", # Add new crate
# ... other crates
]
[workspace.dependencies]
ruvector-mincut = { version = "0.1.0", path = "crates/ruvector-mincut" }
Create crates/ruvector-mincut/Cargo.toml:
[package]
name = "ruvector-mincut"
version = "0.1.0"
edition = "2021"
authors = ["RuVector Team"]
description = "Subpolynomial-time dynamic minimum cut algorithm"
license = "MIT OR Apache-2.0"
repository = "https://github.com/ruvnet/ruvector"
keywords = ["graph", "minimum-cut", "dynamic", "algorithms"]
categories = ["algorithms", "data-structures"]
[dependencies]
ruvector-graph = { workspace = true }
thiserror = "1.0"
smallvec = "1.11"
typed-arena = "2.0"
[dependencies.serde]
version = "1.0"
features = ["derive"]
optional = true
[dev-dependencies]
criterion = "0.5"
proptest = "1.4"
quickcheck = "1.0"
rand = "0.8"
[features]
default = ["monitoring"]
monitoring = ["serde", "serde_json"]
parallel = ["rayon"]
ffi = []
[[bench]]
name = "mincut_bench"
harness = false
[lib]
crate-type = ["lib", "cdylib", "staticlib"]
1.2 API Integration Points
Add to ruvector-graph:
// In ruvector-graph/src/algorithms/mod.rs
#[cfg(feature = "mincut")]
pub mod mincut {
pub use ruvector_mincut::*;
}
// Extension trait for Graph
#[cfg(feature = "mincut")]
impl Graph {
/// Compute dynamic minimum cut
pub fn dynamic_mincut(&self) -> DynamicMinCut {
DynamicMinCut::from_graph(self, MinCutConfig::default())
}
/// Compute minimum cut value (static)
pub fn min_cut_value(&self) -> usize {
let mincut = self.dynamic_mincut();
mincut.min_cut_value()
}
}
1.3 Feature Flag Configuration
# In ruvector-graph/Cargo.toml
[features]
mincut = ["ruvector-mincut"]
[dependencies]
ruvector-mincut = { workspace = true, optional = true }
2. Documentation
2.1 API Documentation
Create crates/ruvector-mincut/README.md:
# ruvector-mincut
Subpolynomial-time dynamic minimum cut algorithm for real-time graph monitoring.
## Features
- **Deterministic**: No probabilistic error
- **Fast**: Subpolynomial amortized update time O(n^{o(1)})
- **Exact**: For cuts up to 2^{Θ((log n)^{3/4})} edges
- **Approximate**: (1+ε)-approximate for larger cuts
- **Real-time**: Hundreds to thousands of updates/second
## Quick Start
```rust
use ruvector_mincut::*;
// Create dynamic min-cut structure
let mut mincut = DynamicMinCut::new(MinCutConfig::default());
// Insert edges
mincut.insert_edge(0, 1).unwrap();
mincut.insert_edge(1, 2).unwrap();
mincut.insert_edge(2, 3).unwrap();
// Query minimum cut (O(1))
let cut_value = mincut.min_cut_value();
println!("Minimum cut: {}", cut_value);
// Get partition
let result = mincut.min_cut();
println!("Partition A: {:?}", result.partition_a);
println!("Partition B: {:?}", result.partition_b);
```
## Performance
For graphs with n=10,000 vertices:
- **Update time**: ~1-5ms per operation
- **Query time**: ~10ns (O(1))
- **Throughput**: 1,000-10,000 updates/second
- **Memory**: ~12MB
## Algorithm
Based on breakthrough work achieving subpolynomial dynamic minimum cut:
- Hierarchical tree decomposition with O(log n) height
- Link-cut trees for efficient connectivity queries
- Sparsification for (1+ε)-approximate cuts
- Deterministic expander decomposition
## Examples
See `examples/` directory for:
- `basic_usage.rs` - Basic operations
- `monitoring.rs` - Real-time monitoring
- `integration.rs` - Integration with ruvector-graph
## Benchmarks
Run benchmarks:
```bash
cargo bench --package ruvector-mincut
```
## References
- Abboud et al. "Subpolynomial-Time Dynamic Minimum Cut" (2021+)
- Thorup. "Near-optimal fully-dynamic graph connectivity" (2000)
- Sleator & Tarjan. "A data structure for dynamic trees" (1983)
2.2 Module Documentation
Add to crates/ruvector-mincut/src/lib.rs:
//! # ruvector-mincut
//!
//! Dynamic minimum cut algorithm with subpolynomial amortized update time.
//!
//! ## Overview
//!
//! This crate implements a deterministic, fully-dynamic minimum-cut algorithm
//! that achieves O(n^{o(1)}) amortized time per edge insertion or deletion.
//!
//! ## Core Concepts
//!
//! ### Hierarchical Decomposition
//!
//! The algorithm maintains a hierarchical tree decomposition of the graph:
//! - Height: O(log n)
//! - Each level maintains local minimum cut information
//! - Updates propagate through O(log n / log log n) levels
//!
//! ### Link-Cut Trees
//!
//! Used for efficient dynamic connectivity:
//! - Link: Connect two vertices
//! - Cut: Disconnect two vertices
//! - Connected: Check if vertices in same component
//! - Time: O(log n) amortized
//!
//! ### Sparsification
//!
//! For (1+ε)-approximate cuts:
//! - Sample edges with probability ∝ 1/(ε²λ)
//! - Sparse graph has O(n log n / ε²) edges
//! - Guarantee: (1-ε)λ ≤ λ_H ≤ (1+ε)λ
//!
//! ## Examples
//!
//! ### Basic Usage
//!
//! ```rust
//! use ruvector_mincut::*;
//!
//! let mut mincut = DynamicMinCut::new(MinCutConfig::default());
//!
//! // Build path graph: 0-1-2-3
//! mincut.insert_edge(0, 1).unwrap();
//! mincut.insert_edge(1, 2).unwrap();
//! mincut.insert_edge(2, 3).unwrap();
//!
//! assert_eq!(mincut.min_cut_value(), 1);
//! ```
//!
//! ### With Monitoring
//!
//! ```rust
//! use ruvector_mincut::*;
//!
//! let config = MinCutConfig {
//! enable_monitoring: true,
//! ..Default::default()
//! };
//!
//! let mut mincut = DynamicMinCut::new(config);
//!
//! mincut.on_cut_change(Box::new(|old, new| {
//! println!("Cut changed: {} -> {}", old, new);
//! }));
//!
//! mincut.insert_edge(0, 1).unwrap();
//!
//! // View metrics
//! let metrics = mincut.metrics();
//! println!("P95 latency: {} ns", metrics.p95_update_time_ns);
//! ```
//!
//! ## Performance Characteristics
//!
//! | Operation | Time Complexity | Notes |
//! |-----------|----------------|-------|
//! | `insert_edge` | O(n^{o(1)}) amortized | Subpolynomial |
//! | `delete_edge` | O(n^{o(1)}) amortized | Subpolynomial |
//! | `min_cut_value` | O(1) | Cached |
//! | `min_cut` | O(k) | k = cut size |
//!
//! ## Safety
//!
//! This crate uses minimal `unsafe` code, only in performance-critical
//! sections that have been carefully verified.
#![warn(missing_docs)]
#![warn(clippy::all)]
pub mod core;
pub mod graph;
pub mod tree;
pub mod linkcut;
pub mod algorithm;
pub mod sparsify;
pub mod monitoring;
pub mod error;
pub use core::{DynamicMinCut, MinCutConfig, MinCutResult, MinCutMetrics};
pub use error::{MinCutError, Result};
// Re-export common types
pub use graph::{DynamicGraph, VertexId, Edge};
2.3 Examples
Create examples/basic_usage.rs:
use ruvector_mincut::*;
fn main() -> Result<()> {
println!("=== Basic Dynamic Minimum Cut ===\n");
// Create dynamic min-cut structure
let mut mincut = DynamicMinCut::new(MinCutConfig::default());
println!("Building path graph: 0-1-2-3");
mincut.insert_edge(0, 1)?;
mincut.insert_edge(1, 2)?;
mincut.insert_edge(2, 3)?;
let cut_value = mincut.min_cut_value();
println!("Minimum cut value: {}\n", cut_value);
println!("Building complete graph K4");
for i in 0..4 {
for j in i+1..4 {
mincut.insert_edge(i, j)?;
}
}
let result = mincut.min_cut();
println!("Minimum cut value: {}", result.value);
println!("Partition A: {:?}", result.partition_a);
println!("Partition B: {:?}", result.partition_b);
println!("Cut edges: {:?}", result.cut_edges);
Ok(())
}
Create examples/monitoring.rs:
use ruvector_mincut::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
fn main() -> Result<()> {
println!("=== Real-Time Monitoring ===\n");
let config = MinCutConfig {
enable_monitoring: true,
..Default::default()
};
let mut mincut = DynamicMinCut::new(config);
// Track cut changes
let change_count = Arc::new(AtomicUsize::new(0));
let count_clone = change_count.clone();
mincut.on_cut_change(Box::new(move |old, new| {
println!("Cut changed: {} -> {}", old, new);
count_clone.fetch_add(1, Ordering::Relaxed);
}));
// Perform 1000 random updates
println!("Performing 1000 random updates...");
use rand::Rng;
let mut rng = rand::thread_rng();
for _ in 0..1000 {
let u = rng.gen_range(0..100);
let v = rng.gen_range(0..100);
if u != v {
if rng.gen_bool(0.7) {
mincut.insert_edge(u, v).ok();
} else {
mincut.delete_edge(u, v).ok();
}
}
}
// Print metrics
let metrics = mincut.metrics();
println!("\n=== Performance Metrics ===");
println!("Current cut value: {}", metrics.current_cut_value);
println!("Total updates: {}", metrics.update_count);
println!("Graph size: {:?}", metrics.graph_size);
println!("Avg update time: {} μs", metrics.avg_update_time_ns / 1000);
println!("P95 update time: {} μs", metrics.p95_update_time_ns / 1000);
println!("P99 update time: {} μs", metrics.p99_update_time_ns / 1000);
println!("Cut changes: {}", change_count.load(Ordering::Relaxed));
Ok(())
}
3. Testing & Validation
3.1 Pre-Release Checklist
#!/bin/bash
# scripts/pre-release-check.sh
echo "=== Pre-Release Validation ==="
# 1. Build all targets
echo "Building all targets..."
cargo build --all-features
cargo build --no-default-features
# 2. Run test suite
echo "Running tests..."
cargo test --all-features
cargo test --no-default-features
# 3. Run benchmarks (sanity check)
echo "Running benchmarks..."
cargo bench --no-run
# 4. Check documentation
echo "Checking documentation..."
cargo doc --all-features --no-deps
# 5. Run clippy
echo "Running clippy..."
cargo clippy --all-features -- -D warnings
# 6. Check formatting
echo "Checking formatting..."
cargo fmt -- --check
# 7. Run property tests
echo "Running property tests..."
cargo test --release -- --ignored
# 8. Validate examples
echo "Validating examples..."
cargo run --example basic_usage
cargo run --example monitoring
echo "=== All checks passed! ==="
3.2 Performance Validation
#!/bin/bash
# scripts/validate-performance.sh
echo "=== Performance Validation ==="
# Run benchmarks and check against targets
cargo bench --bench mincut_bench -- --save-baseline main
# Check that performance meets targets
# Extract metrics and compare against thresholds
# (implementation specific to benchmark output format)
echo "Performance targets met!"
4. CI/CD Pipeline
4.1 GitHub Actions Workflow
Create .github/workflows/mincut.yml:
name: ruvector-mincut CI
on:
push:
paths:
- 'crates/ruvector-mincut/**'
- '.github/workflows/mincut.yml'
pull_request:
paths:
- 'crates/ruvector-mincut/**'
jobs:
test:
name: Test
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
rust: [stable, nightly]
steps:
- uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust }}
override: true
- name: Cache cargo
uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Build
run: cargo build --package ruvector-mincut --all-features
- name: Run tests
run: cargo test --package ruvector-mincut --all-features
- name: Run ignored tests (performance)
run: cargo test --package ruvector-mincut --release -- --ignored
if: matrix.os == 'ubuntu-latest' && matrix.rust == 'stable'
bench:
name: Benchmark
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Run benchmarks
run: cargo bench --package ruvector-mincut --no-run
coverage:
name: Code Coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Install tarpaulin
run: cargo install cargo-tarpaulin
- name: Generate coverage
run: |
cargo tarpaulin --package ruvector-mincut \
--out Lcov --all-features
- name: Upload to codecov
uses: codecov/codecov-action@v3
with:
files: ./lcov.info
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
components: clippy, rustfmt
override: true
- name: Run clippy
run: cargo clippy --package ruvector-mincut --all-features -- -D warnings
- name: Check formatting
run: cargo fmt --package ruvector-mincut -- --check
5. Release Process
5.1 Version Bump
#!/bin/bash
# scripts/release.sh
VERSION=$1
if [ -z "$VERSION" ]; then
echo "Usage: ./scripts/release.sh <version>"
exit 1
fi
# Update version in Cargo.toml
sed -i "s/^version = .*/version = \"$VERSION\"/" crates/ruvector-mincut/Cargo.toml
# Update CHANGELOG
echo "## [$VERSION] - $(date +%Y-%m-%d)" >> CHANGELOG.md
# Commit changes
git add crates/ruvector-mincut/Cargo.toml CHANGELOG.md
git commit -m "chore(mincut): Release v$VERSION"
git tag "mincut-v$VERSION"
echo "Release v$VERSION prepared"
echo "Review changes and run: git push && git push --tags"
5.2 Publishing to crates.io
#!/bin/bash
# scripts/publish-mincut.sh
# Ensure working directory is clean
if [[ -n $(git status -s) ]]; then
echo "Error: Working directory is not clean"
exit 1
fi
# Run pre-release checks
./scripts/pre-release-check.sh
# Publish to crates.io
cd crates/ruvector-mincut
cargo publish --dry-run
read -p "Proceed with publish? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
source ../../.env && \
CARGO_REGISTRY_TOKEN=$CRATES_API_KEY cargo publish --no-verify
echo "Published to crates.io!"
else
echo "Publish cancelled"
fi
6. Deployment Documentation
6.1 Installation Guide
Add to docs/installation.md:
# Installing ruvector-mincut
## From crates.io
```toml
[dependencies]
ruvector-mincut = "0.1"
```
## From source
```bash
git clone https://github.com/ruvnet/ruvector.git
cd ruvector
cargo build --package ruvector-mincut --release
```
## Feature Flags
```toml
[dependencies.ruvector-mincut]
version = "0.1"
features = ["monitoring", "parallel"]
```
Available features:
- `monitoring` - Enable performance tracking (default)
- `parallel` - Parallel update processing
- `ffi` - C ABI for foreign function interface
## Platform Support
- **Linux**: x86_64, aarch64
- **macOS**: x86_64, aarch64 (M1/M2)
- **Windows**: x86_64
## System Requirements
- Rust 1.70 or later
- ~50MB disk space for dependencies
- ~12MB RAM per 10,000 vertex graph
6.2 Migration Guide
Create docs/migration.md:
# Migration Guide
## From Static Minimum Cut Algorithms
If you're currently using static minimum cut algorithms like Stoer-Wagner:
### Before (Static)
```rust
let graph = build_graph();
let min_cut = stoer_wagner(&graph); // Recompute each time
```
### After (Dynamic)
```rust
let mut mincut = DynamicMinCut::from_graph(&graph, Default::default());
// Updates are efficient
mincut.insert_edge(u, v).unwrap();
mincut.delete_edge(x, y).unwrap();
// Query is O(1)
let cut_value = mincut.min_cut_value();
```
## Performance Considerations
- **Initialization**: O(m log n) one-time cost
- **Updates**: O(n^{o(1)}) amortized
- **Queries**: O(1) for value, O(k) for partition
When to use:
- ✅ Frequent updates (>100 per rebuild cost)
- ✅ Real-time monitoring
- ✅ Interactive applications
- ❌ Single static computation (use Stoer-Wagner instead)
7. Monitoring & Observability
7.1 Prometheus Exporter
Add monitoring integration:
// In src/monitoring/export.rs
#[cfg(feature = "monitoring")]
pub fn export_prometheus(mincut: &DynamicMinCut) -> String {
let metrics = mincut.metrics();
format!(
r#"# TYPE ruvector_mincut_value gauge
ruvector_mincut_value {{}} {}
# TYPE ruvector_mincut_updates_total counter
ruvector_mincut_updates_total {{}} {}
# TYPE ruvector_mincut_update_time_ns histogram
ruvector_mincut_update_time_ns_bucket {{le="1000"}} 0
ruvector_mincut_update_time_ns_bucket {{le="10000"}} {}
ruvector_mincut_update_time_ns_bucket {{le="100000"}} {}
ruvector_mincut_update_time_ns_bucket {{le="+Inf"}} {}
ruvector_mincut_update_time_ns_sum {}
ruvector_mincut_update_time_ns_count {}
"#,
metrics.current_cut_value,
metrics.update_count,
// ... histogram buckets
metrics.avg_update_time_ns * metrics.update_count,
metrics.update_count
)
}
8. Final Validation
8.1 Pre-Release Validation Checklist
- All tests pass on all platforms
- Benchmarks meet performance targets
- Documentation is complete and accurate
- Examples run successfully
- No clippy warnings
- Code coverage >80%
- Performance regression tests pass
- Integration with ruvector-graph works
- C ABI exports are functional
- README is comprehensive
- CHANGELOG is updated
- License files are present
8.2 Post-Release Tasks
- Publish to crates.io
- Create GitHub release with changelog
- Update main README to mention new crate
- Announce on relevant forums/channels
- Monitor for bug reports
- Prepare patch releases if needed
9. Maintenance Plan
9.1 Regular Tasks
Weekly:
- Review and respond to issues
- Merge non-breaking PRs
- Run performance benchmarks
Monthly:
- Dependency updates
- Performance optimization review
- Documentation improvements
Quarterly:
- Major feature releases
- Breaking API changes (if needed)
- Comprehensive testing
9.2 Support Channels
- GitHub Issues: Bug reports and feature requests
- Discussions: General questions and usage help
- Email: security@ruvector.io for security issues
10. Success Metrics
10.1 Technical Metrics
- Performance: Meets O(n^{o(1)}) target
- Correctness: 100% pass rate on test suite
- Coverage: >80% code coverage
- Memory: <2x graph size overhead
10.2 Adoption Metrics
- Downloads: Track crates.io downloads
- GitHub Stars: Community interest
- Issues: Response time <48 hours
- PRs: Review time <1 week
Summary
This completes the SPARC implementation plan for the subpolynomial-time dynamic minimum cut system. The five phases provide:
- Specification: Complete requirements and API design
- Pseudocode: Detailed algorithms for all operations
- Architecture: System design and module structure
- Refinement: Comprehensive TDD test plan
- Completion: Integration, deployment, and documentation
Next Steps:
- Begin Phase 4 (Refinement) with TDD implementation
- Follow the test-first development cycle
- Continuously benchmark against performance targets
- Integrate with ruvector-graph early and often
Estimated Timeline: ~20 days for V1.0 release