Files
wifi-densepose/crates/ruvector-mincut/docs/guide/04-integration-guide.md
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

2117 lines
53 KiB
Markdown

# Integration Guide
This guide covers all methods for integrating `ruvector-mincut` into your applications across different platforms and languages.
## Table of Contents
- [Rust Crate Integration](#rust-crate-integration)
- [WebAssembly (WASM)](#webassembly-wasm)
- [Node.js Integration](#nodejs-integration)
- [Python Integration](#python-integration)
- [REST API Service](#rest-api-service)
- [GraphQL Integration](#graphql-integration)
- [Architecture Patterns](#architecture-patterns)
---
## Rust Crate Integration
### Basic Setup
Add `ruvector-mincut` to your `Cargo.toml`:
```toml
[dependencies]
ruvector-mincut = "0.1.0"
ruvector-graph = "0.1.0" # For graph database features
# Optional: Enable specific features
[dependencies.ruvector-mincut]
version = "0.1.0"
features = ["parallel", "advanced", "visualization"]
```
### Feature Flags
The crate supports several feature combinations:
```toml
[features]
default = []
# Core features
parallel = ["rayon"] # Parallel execution with rayon
advanced = ["petgraph"] # Advanced algorithms (Nagamochi-Ibaraki, etc.)
visualization = ["plotters"] # Graph visualization support
# Performance features
simd = [] # SIMD optimizations
native = [] # Native CPU optimizations
# Serialization
serde = ["dep:serde"]
bincode = ["dep:bincode"]
# All features
full = ["parallel", "advanced", "visualization", "simd", "serde"]
```
### Workspace Setup
For multi-crate workspaces:
```toml
# workspace/Cargo.toml
[workspace]
members = [
"app",
"algorithms",
]
[workspace.dependencies]
ruvector-mincut = { version = "0.1.0", features = ["parallel", "advanced"] }
# app/Cargo.toml
[dependencies]
ruvector-mincut = { workspace = true }
# algorithms/Cargo.toml
[dependencies]
ruvector-mincut = { workspace = true, features = ["visualization"] }
```
### Basic Usage Example
```rust
use ruvector_mincut::{MinCutWrapper, MinCutAlgorithm};
use ruvector_mincut::graph::GraphBuilder;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Build a graph
let mut builder = GraphBuilder::new();
builder.add_edge(0, 1, 1.0);
builder.add_edge(1, 2, 1.0);
builder.add_edge(2, 3, 1.0);
builder.add_edge(3, 0, 1.0);
builder.add_edge(0, 2, 0.5);
let graph = builder.build()?;
// Create wrapper and find minimum cut
let mut wrapper = MinCutWrapper::new(graph);
let result = wrapper.compute_min_cut(MinCutAlgorithm::StoerWagner)?;
println!("Minimum cut value: {}", result.cut_value);
println!("Partition 1: {:?}", result.partition1);
println!("Partition 2: {:?}", result.partition2);
Ok(())
}
```
### Advanced Usage with Features
```rust
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use ruvector_mincut::{
MinCutWrapper,
MinCutAlgorithm,
algorithms::PaperAlgorithm,
};
fn parallel_analysis(graphs: Vec<Graph>) -> Vec<MinCutResult> {
#[cfg(feature = "parallel")]
{
graphs.par_iter()
.map(|g| {
let mut wrapper = MinCutWrapper::new(g.clone());
wrapper.compute_min_cut(MinCutAlgorithm::FlowBased).unwrap()
})
.collect()
}
#[cfg(not(feature = "parallel"))]
{
graphs.iter()
.map(|g| {
let mut wrapper = MinCutWrapper::new(g.clone());
wrapper.compute_min_cut(MinCutAlgorithm::FlowBased).unwrap()
})
.collect()
}
}
#[cfg(feature = "advanced")]
fn use_paper_algorithms(graph: &Graph) -> Result<f64, MinCutError> {
use ruvector_mincut::PaperAlgorithm;
let mut wrapper = MinCutWrapper::new(graph.clone());
// Use state-of-the-art algorithm from SODA 2025
let result = wrapper.compute_paper_algorithm(
PaperAlgorithm::RandomizedMinCutVerification
)?;
Ok(result.cut_value)
}
```
---
## WebAssembly (WASM)
### Building for WASM Target
#### Prerequisites
```bash
# Install wasm-pack
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
# Add wasm32 target
rustup target add wasm32-unknown-unknown
```
#### Build Commands
```bash
# Development build
wasm-pack build --target web --dev crates/ruvector-mincut-wasm
# Production build with optimizations
wasm-pack build --target web --release crates/ruvector-mincut-wasm
# Build for Node.js
wasm-pack build --target nodejs crates/ruvector-mincut-wasm
# Build for bundlers (webpack, rollup)
wasm-pack build --target bundler crates/ruvector-mincut-wasm
```
#### Optimization Tips
```toml
# Cargo.toml for WASM builds
[profile.release]
opt-level = "z" # Optimize for size
lto = true # Link-time optimization
codegen-units = 1 # Better optimization
panic = "abort" # Smaller binary
strip = true # Strip symbols
[profile.release.package."*"]
opt-level = "z"
```
### Browser Integration
#### HTML Setup
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>RuVector MinCut Demo</title>
</head>
<body>
<h1>Minimum Cut Calculator</h1>
<div>
<label>Number of nodes:</label>
<input type="number" id="nodeCount" value="10" min="2" max="1000">
</div>
<div>
<label>Edge density:</label>
<input type="range" id="density" min="0.1" max="1.0" step="0.1" value="0.3">
<span id="densityValue">0.3</span>
</div>
<button id="computeBtn">Compute Min Cut</button>
<div id="results"></div>
<canvas id="graphCanvas" width="800" height="600"></canvas>
<script type="module">
import init, {
MinCutWrapper,
GraphBuilder,
MinCutAlgorithm
} from './pkg/ruvector_mincut_wasm.js';
async function run() {
// Initialize WASM module
await init();
document.getElementById('computeBtn').addEventListener('click', computeMinCut);
document.getElementById('density').addEventListener('input', (e) => {
document.getElementById('densityValue').textContent = e.target.value;
});
}
async function computeMinCut() {
const nodeCount = parseInt(document.getElementById('nodeCount').value);
const density = parseFloat(document.getElementById('density').value);
// Build random graph
const builder = new GraphBuilder();
for (let i = 0; i < nodeCount; i++) {
for (let j = i + 1; j < nodeCount; j++) {
if (Math.random() < density) {
const weight = Math.random() * 10;
builder.add_edge(i, j, weight);
}
}
}
const graph = builder.build();
// Compute minimum cut
const wrapper = new MinCutWrapper(graph);
const startTime = performance.now();
const result = wrapper.compute_min_cut(MinCutAlgorithm.StoerWagner);
const elapsed = performance.now() - startTime;
// Display results
document.getElementById('results').innerHTML = `
<h2>Results</h2>
<p><strong>Minimum Cut Value:</strong> ${result.cut_value.toFixed(4)}</p>
<p><strong>Partition 1 Size:</strong> ${result.partition1.length}</p>
<p><strong>Partition 2 Size:</strong> ${result.partition2.length}</p>
<p><strong>Computation Time:</strong> ${elapsed.toFixed(2)} ms</p>
<p><strong>Edges in Cut:</strong> ${result.cut_edges.length}</p>
`;
// Visualize (optional - requires additional canvas code)
visualizeGraph(graph, result);
}
function visualizeGraph(graph, result) {
const canvas = document.getElementById('graphCanvas');
const ctx = canvas.getContext('2d');
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Simple force-directed layout visualization
// (Simplified version - production would use D3.js or similar)
const nodes = result.partition1.concat(result.partition2);
const positions = layoutNodes(nodes, canvas.width, canvas.height);
// Draw edges
ctx.strokeStyle = '#ccc';
ctx.lineWidth = 1;
// ... edge drawing code
// Draw nodes
result.partition1.forEach(nodeId => {
drawNode(ctx, positions[nodeId], '#3498db');
});
result.partition2.forEach(nodeId => {
drawNode(ctx, positions[nodeId], '#e74c3c');
});
}
function drawNode(ctx, pos, color) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(pos.x, pos.y, 8, 0, 2 * Math.PI);
ctx.fill();
}
function layoutNodes(nodes, width, height) {
// Simple circular layout
const positions = {};
const radius = Math.min(width, height) * 0.4;
const centerX = width / 2;
const centerY = height / 2;
nodes.forEach((nodeId, i) => {
const angle = (2 * Math.PI * i) / nodes.length;
positions[nodeId] = {
x: centerX + radius * Math.cos(angle),
y: centerY + radius * Math.sin(angle)
};
});
return positions;
}
run();
</script>
</body>
</html>
```
#### TypeScript Integration
```typescript
// mincut-worker.ts
import init, {
MinCutWrapper,
GraphBuilder,
MinCutAlgorithm,
type MinCutResult
} from 'ruvector-mincut-wasm';
interface GraphData {
nodes: number;
edges: Array<[number, number, number]>;
}
interface ComputeRequest {
type: 'compute';
graph: GraphData;
algorithm: string;
}
let initialized = false;
self.onmessage = async (e: MessageEvent<ComputeRequest>) => {
if (!initialized) {
await init();
initialized = true;
}
const { graph, algorithm } = e.data;
try {
// Build graph
const builder = new GraphBuilder();
graph.edges.forEach(([from, to, weight]) => {
builder.add_edge(from, to, weight);
});
const g = builder.build();
// Compute minimum cut
const wrapper = new MinCutWrapper(g);
const algo = MinCutAlgorithm[algorithm as keyof typeof MinCutAlgorithm];
const result = wrapper.compute_min_cut(algo);
self.postMessage({
success: true,
result: {
cutValue: result.cut_value,
partition1: Array.from(result.partition1),
partition2: Array.from(result.partition2),
cutEdges: Array.from(result.cut_edges)
}
});
} catch (error) {
self.postMessage({
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
});
}
};
```
#### Main Application
```typescript
// app.ts
import type { MinCutResult } from './types';
class MinCutService {
private worker: Worker;
private requestId = 0;
private pending = new Map<number, {
resolve: (result: MinCutResult) => void;
reject: (error: Error) => void;
}>();
constructor() {
this.worker = new Worker(
new URL('./mincut-worker.ts', import.meta.url),
{ type: 'module' }
);
this.worker.onmessage = (e) => {
const { id, success, result, error } = e.data;
const pending = this.pending.get(id);
if (pending) {
if (success) {
pending.resolve(result);
} else {
pending.reject(new Error(error));
}
this.pending.delete(id);
}
};
}
async computeMinCut(
graph: GraphData,
algorithm: string = 'StoerWagner'
): Promise<MinCutResult> {
return new Promise((resolve, reject) => {
const id = this.requestId++;
this.pending.set(id, { resolve, reject });
this.worker.postMessage({
type: 'compute',
id,
graph,
algorithm
});
});
}
terminate() {
this.worker.terminate();
}
}
// Usage
const service = new MinCutService();
const graph = {
nodes: 6,
edges: [
[0, 1, 2.0],
[1, 2, 3.0],
[2, 3, 1.0],
[3, 4, 2.0],
[4, 5, 1.0],
[5, 0, 2.0],
[0, 3, 0.5]
]
};
const result = await service.computeMinCut(graph);
console.log('Min cut value:', result.cutValue);
```
---
## Node.js Integration
### Installation
```bash
# Using npm
npm install ruvector-mincut-node
# Using yarn
yarn add ruvector-mincut-node
# Using pnpm
pnpm add ruvector-mincut-node
```
### TypeScript Setup
```typescript
// types/mincut.d.ts
declare module 'ruvector-mincut-node' {
export interface Edge {
from: number;
to: number;
weight: number;
}
export interface MinCutResult {
cutValue: number;
partition1: number[];
partition2: number[];
cutEdges: Array<[number, number]>;
}
export interface ConnectivityCurve {
numClusters: number;
cutValue: number;
}
export enum MinCutAlgorithm {
StoerWagner = 'StoerWagner',
FlowBased = 'FlowBased',
KargerStein = 'KargerStein',
NagamochiIbaraki = 'NagamochiIbaraki',
Hierarchical = 'Hierarchical'
}
export class GraphBuilder {
constructor();
addEdge(from: number, to: number, weight: number): void;
build(): Graph;
}
export class Graph {
nodeCount(): number;
edgeCount(): number;
}
export class MinCutWrapper {
constructor(graph: Graph);
computeMinCut(algorithm: MinCutAlgorithm): Promise<MinCutResult>;
computeConnectivityCurve(maxClusters?: number): Promise<ConnectivityCurve[]>;
computeLocalKCut(k: number, sourceNode: number): Promise<MinCutResult>;
}
export class PaperAlgorithm {
static RandomizedMinCutVerification: string;
static BoundedMinCutEnumeration: string;
static ApproximateGlobalMinCut: string;
}
}
```
### Basic Usage
```typescript
// src/mincut.ts
import {
GraphBuilder,
MinCutWrapper,
MinCutAlgorithm,
type MinCutResult
} from 'ruvector-mincut-node';
async function computeMinimumCut(
edges: Array<[number, number, number]>
): Promise<MinCutResult> {
// Build graph
const builder = new GraphBuilder();
for (const [from, to, weight] of edges) {
builder.addEdge(from, to, weight);
}
const graph = builder.build();
// Compute minimum cut
const wrapper = new MinCutWrapper(graph);
const result = await wrapper.computeMinCut(MinCutAlgorithm.StoerWagner);
return result;
}
// Example usage
const edges: Array<[number, number, number]> = [
[0, 1, 1.0],
[1, 2, 1.0],
[2, 3, 1.0],
[3, 0, 1.0],
[0, 2, 0.5]
];
computeMinimumCut(edges).then(result => {
console.log('Minimum cut value:', result.cutValue);
console.log('Partition 1:', result.partition1);
console.log('Partition 2:', result.partition2);
});
```
### Express.js Service
```typescript
// src/server.ts
import express, { Request, Response } from 'express';
import {
GraphBuilder,
MinCutWrapper,
MinCutAlgorithm
} from 'ruvector-mincut-node';
const app = express();
app.use(express.json());
interface MinCutRequest {
edges: Array<[number, number, number]>;
algorithm?: string;
}
app.post('/api/mincut', async (req: Request<{}, {}, MinCutRequest>, res: Response) => {
try {
const { edges, algorithm = 'StoerWagner' } = req.body;
if (!edges || !Array.isArray(edges)) {
return res.status(400).json({
error: 'Invalid request: edges array required'
});
}
// Validate edges
for (const edge of edges) {
if (!Array.isArray(edge) || edge.length !== 3) {
return res.status(400).json({
error: 'Invalid edge format: expected [from, to, weight]'
});
}
}
// Build graph
const builder = new GraphBuilder();
edges.forEach(([from, to, weight]) => {
builder.addEdge(from, to, weight);
});
const graph = builder.build();
// Compute minimum cut
const wrapper = new MinCutWrapper(graph);
const algo = MinCutAlgorithm[algorithm as keyof typeof MinCutAlgorithm]
|| MinCutAlgorithm.StoerWagner;
const result = await wrapper.computeMinCut(algo);
res.json({
success: true,
data: {
cutValue: result.cutValue,
partition1: result.partition1,
partition2: result.partition2,
cutEdges: result.cutEdges,
algorithm: algorithm
}
});
} catch (error) {
console.error('Error computing min cut:', error);
res.status(500).json({
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
});
}
});
app.post('/api/connectivity-curve', async (req: Request, res: Response) => {
try {
const { edges, maxClusters = 10 } = req.body;
const builder = new GraphBuilder();
edges.forEach(([from, to, weight]: [number, number, number]) => {
builder.addEdge(from, to, weight);
});
const graph = builder.build();
const wrapper = new MinCutWrapper(graph);
const curve = await wrapper.computeConnectivityCurve(maxClusters);
res.json({
success: true,
data: curve
});
} catch (error) {
console.error('Error computing connectivity curve:', error);
res.status(500).json({
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
});
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`MinCut service running on port ${PORT}`);
});
```
### Async Patterns with Worker Threads
```typescript
// src/worker-pool.ts
import { Worker } from 'worker_threads';
import { cpus } from 'os';
interface WorkerTask {
id: number;
edges: Array<[number, number, number]>;
algorithm: string;
}
interface WorkerResult {
id: number;
result: any;
error?: string;
}
export class MinCutWorkerPool {
private workers: Worker[] = [];
private queue: Array<{
task: WorkerTask;
resolve: (result: any) => void;
reject: (error: Error) => void;
}> = [];
private activeWorkers = 0;
private taskId = 0;
constructor(private poolSize: number = cpus().length) {
this.initializeWorkers();
}
private initializeWorkers() {
for (let i = 0; i < this.poolSize; i++) {
const worker = new Worker('./mincut-worker.js');
worker.on('message', (result: WorkerResult) => {
this.activeWorkers--;
const pending = this.queue.shift();
if (pending) {
if (result.error) {
pending.reject(new Error(result.error));
} else {
pending.resolve(result.result);
}
}
this.processQueue();
});
worker.on('error', (error) => {
console.error('Worker error:', error);
this.activeWorkers--;
this.processQueue();
});
this.workers.push(worker);
}
}
async computeMinCut(
edges: Array<[number, number, number]>,
algorithm: string = 'StoerWagner'
): Promise<any> {
return new Promise((resolve, reject) => {
const task: WorkerTask = {
id: this.taskId++,
edges,
algorithm
};
this.queue.push({ task, resolve, reject });
this.processQueue();
});
}
private processQueue() {
while (this.activeWorkers < this.poolSize && this.queue.length > 0) {
const { task } = this.queue[0];
const worker = this.workers[this.activeWorkers];
this.activeWorkers++;
worker.postMessage(task);
}
}
terminate() {
this.workers.forEach(worker => worker.terminate());
this.workers = [];
}
}
// Usage
const pool = new MinCutWorkerPool();
const tasks = [
pool.computeMinCut([[0, 1, 1], [1, 2, 1]], 'StoerWagner'),
pool.computeMinCut([[0, 1, 2], [1, 2, 3]], 'FlowBased'),
pool.computeMinCut([[0, 1, 1], [1, 2, 1], [2, 0, 1]], 'KargerStein')
];
const results = await Promise.all(tasks);
console.log('All results:', results);
```
---
## Python Integration
### PyO3 Bindings Concept
```python
# ruvector_mincut/__init__.py
"""
Python bindings for ruvector-mincut library.
This module provides Python access to high-performance minimum cut algorithms
implemented in Rust.
"""
from typing import List, Tuple, Optional, Dict, Any
from enum import Enum
class MinCutAlgorithm(Enum):
"""Available minimum cut algorithms."""
STOER_WAGNER = "StoerWagner"
FLOW_BASED = "FlowBased"
KARGER_STEIN = "KargerStein"
NAGAMOCHI_IBARAKI = "NagamochiIbaraki"
HIERARCHICAL = "Hierarchical"
class MinCutResult:
"""Result of a minimum cut computation."""
def __init__(
self,
cut_value: float,
partition1: List[int],
partition2: List[int],
cut_edges: List[Tuple[int, int]]
):
self.cut_value = cut_value
self.partition1 = partition1
self.partition2 = partition2
self.cut_edges = cut_edges
def __repr__(self) -> str:
return (
f"MinCutResult(cut_value={self.cut_value}, "
f"partition1={self.partition1}, "
f"partition2={self.partition2})"
)
def to_dict(self) -> Dict[str, Any]:
"""Convert result to dictionary."""
return {
'cut_value': self.cut_value,
'partition1': self.partition1,
'partition2': self.partition2,
'cut_edges': self.cut_edges
}
class GraphBuilder:
"""Builder for constructing graphs."""
def __init__(self):
"""Initialize a new graph builder."""
self._edges: List[Tuple[int, int, float]] = []
def add_edge(self, from_node: int, to_node: int, weight: float = 1.0) -> 'GraphBuilder':
"""
Add an edge to the graph.
Args:
from_node: Source node ID
to_node: Target node ID
weight: Edge weight (default: 1.0)
Returns:
Self for method chaining
"""
self._edges.append((from_node, to_node, weight))
return self
def build(self) -> 'Graph':
"""
Build the graph.
Returns:
Constructed Graph object
"""
# This would call the Rust implementation
from . import _native
return Graph(_native.build_graph(self._edges))
class Graph:
"""Graph data structure."""
def __init__(self, handle):
"""Initialize with native handle (internal use)."""
self._handle = handle
def node_count(self) -> int:
"""Get the number of nodes in the graph."""
from . import _native
return _native.graph_node_count(self._handle)
def edge_count(self) -> int:
"""Get the number of edges in the graph."""
from . import _native
return _native.graph_edge_count(self._handle)
class MinCutWrapper:
"""Wrapper for minimum cut computations."""
def __init__(self, graph: Graph):
"""
Initialize wrapper with a graph.
Args:
graph: Graph to analyze
"""
self.graph = graph
from . import _native
self._handle = _native.create_mincut_wrapper(graph._handle)
def compute_min_cut(
self,
algorithm: MinCutAlgorithm = MinCutAlgorithm.STOER_WAGNER
) -> MinCutResult:
"""
Compute the minimum cut.
Args:
algorithm: Algorithm to use
Returns:
MinCutResult containing the cut value and partitions
Raises:
ValueError: If computation fails
"""
from . import _native
result = _native.compute_min_cut(self._handle, algorithm.value)
return MinCutResult(
cut_value=result['cut_value'],
partition1=result['partition1'],
partition2=result['partition2'],
cut_edges=result['cut_edges']
)
def compute_connectivity_curve(
self,
max_clusters: Optional[int] = None
) -> List[Dict[str, Any]]:
"""
Compute connectivity curve showing cut values at different cluster counts.
Args:
max_clusters: Maximum number of clusters (default: node_count)
Returns:
List of dictionaries with 'num_clusters' and 'cut_value'
"""
from . import _native
return _native.compute_connectivity_curve(self._handle, max_clusters)
def compute_local_k_cut(
self,
k: int,
source_node: int
) -> MinCutResult:
"""
Compute local k-cut around a source node.
Args:
k: Target cluster count
source_node: Source node for local cut
Returns:
MinCutResult for the local cut
"""
from . import _native
result = _native.compute_local_k_cut(self._handle, k, source_node)
return MinCutResult(
cut_value=result['cut_value'],
partition1=result['partition1'],
partition2=result['partition2'],
cut_edges=result['cut_edges']
)
# Convenience functions
def compute_min_cut(
edges: List[Tuple[int, int, float]],
algorithm: MinCutAlgorithm = MinCutAlgorithm.STOER_WAGNER
) -> MinCutResult:
"""
Convenience function to compute minimum cut from edge list.
Args:
edges: List of (from, to, weight) tuples
algorithm: Algorithm to use
Returns:
MinCutResult
Example:
>>> edges = [(0, 1, 1.0), (1, 2, 1.0), (2, 0, 1.0)]
>>> result = compute_min_cut(edges)
>>> print(f"Cut value: {result.cut_value}")
"""
builder = GraphBuilder()
for from_node, to_node, weight in edges:
builder.add_edge(from_node, to_node, weight)
graph = builder.build()
wrapper = MinCutWrapper(graph)
return wrapper.compute_min_cut(algorithm)
```
### Python Usage Example
```python
# examples/python_example.py
from ruvector_mincut import (
GraphBuilder,
MinCutWrapper,
MinCutAlgorithm,
compute_min_cut
)
import matplotlib.pyplot as plt
import networkx as nx
def basic_example():
"""Basic usage example."""
# Build a simple graph
builder = GraphBuilder()
builder.add_edge(0, 1, 1.0)
builder.add_edge(1, 2, 1.0)
builder.add_edge(2, 3, 1.0)
builder.add_edge(3, 0, 1.0)
builder.add_edge(0, 2, 0.5)
graph = builder.build()
# Compute minimum cut
wrapper = MinCutWrapper(graph)
result = wrapper.compute_min_cut(MinCutAlgorithm.STOER_WAGNER)
print(f"Minimum cut value: {result.cut_value}")
print(f"Partition 1: {result.partition1}")
print(f"Partition 2: {result.partition2}")
print(f"Cut edges: {result.cut_edges}")
def connectivity_analysis():
"""Analyze connectivity curve."""
# Create a larger graph
edges = []
for i in range(10):
edges.append((i, (i + 1) % 10, 1.0))
if i % 2 == 0:
edges.append((i, (i + 5) % 10, 0.5))
builder = GraphBuilder()
for from_node, to_node, weight in edges:
builder.add_edge(from_node, to_node, weight)
graph = builder.build()
wrapper = MinCutWrapper(graph)
# Get connectivity curve
curve = wrapper.compute_connectivity_curve(max_clusters=5)
# Plot
clusters = [c['num_clusters'] for c in curve]
cut_values = [c['cut_value'] for c in curve]
plt.figure(figsize=(10, 6))
plt.plot(clusters, cut_values, marker='o')
plt.xlabel('Number of Clusters')
plt.ylabel('Minimum Cut Value')
plt.title('Connectivity Curve')
plt.grid(True)
plt.savefig('connectivity_curve.png')
print("Saved connectivity curve to connectivity_curve.png")
def visualize_cut():
"""Visualize the minimum cut."""
# Build graph
edges = [
(0, 1, 1.0), (1, 2, 1.0), (2, 3, 1.0),
(3, 4, 1.0), (4, 5, 1.0), (5, 0, 1.0),
(0, 3, 0.5), (1, 4, 0.5), (2, 5, 0.5)
]
# Compute minimum cut
result = compute_min_cut(edges)
# Create NetworkX graph for visualization
G = nx.Graph()
for from_node, to_node, weight in edges:
G.add_edge(from_node, to_node, weight=weight)
# Color nodes by partition
colors = []
for node in G.nodes():
if node in result.partition1:
colors.append('lightblue')
else:
colors.append('lightcoral')
# Highlight cut edges
edge_colors = []
for edge in G.edges():
if edge in result.cut_edges or (edge[1], edge[0]) in result.cut_edges:
edge_colors.append('red')
else:
edge_colors.append('gray')
# Draw
plt.figure(figsize=(10, 8))
pos = nx.spring_layout(G)
nx.draw(G, pos, node_color=colors, edge_color=edge_colors,
node_size=500, with_labels=True, width=2)
plt.title(f'Minimum Cut (value: {result.cut_value})')
plt.savefig('mincut_visualization.png')
print("Saved visualization to mincut_visualization.png")
if __name__ == '__main__':
print("Running basic example...")
basic_example()
print("\nAnalyzing connectivity...")
connectivity_analysis()
print("\nVisualizing cut...")
visualize_cut()
```
---
## REST API Service
### Actix-Web Service
```rust
// src/api/mod.rs
use actix_web::{web, App, HttpResponse, HttpServer, middleware};
use serde::{Deserialize, Serialize};
use ruvector_mincut::{MinCutWrapper, MinCutAlgorithm, MinCutError};
use ruvector_mincut::graph::GraphBuilder;
#[derive(Debug, Deserialize)]
struct Edge {
from: usize,
to: usize,
weight: f64,
}
#[derive(Debug, Deserialize)]
struct MinCutRequest {
edges: Vec<Edge>,
algorithm: Option<String>,
}
#[derive(Debug, Serialize)]
struct MinCutResponse {
cut_value: f64,
partition1: Vec<usize>,
partition2: Vec<usize>,
cut_edges: Vec<(usize, usize)>,
algorithm: String,
computation_time_ms: f64,
}
#[derive(Debug, Serialize)]
struct ErrorResponse {
error: String,
details: Option<String>,
}
#[derive(Debug, Deserialize)]
struct ConnectivityRequest {
edges: Vec<Edge>,
max_clusters: Option<usize>,
}
#[derive(Debug, Serialize)]
struct ConnectivityPoint {
num_clusters: usize,
cut_value: f64,
}
#[derive(Debug, Serialize)]
struct ConnectivityResponse {
curve: Vec<ConnectivityPoint>,
computation_time_ms: f64,
}
// Health check endpoint
async fn health() -> HttpResponse {
HttpResponse::Ok().json(serde_json::json!({
"status": "healthy",
"version": env!("CARGO_PKG_VERSION")
}))
}
// Compute minimum cut endpoint
async fn compute_min_cut(req: web::Json<MinCutRequest>) -> HttpResponse {
let start = std::time::Instant::now();
// Build graph
let mut builder = GraphBuilder::new();
for edge in &req.edges {
builder.add_edge(edge.from, edge.to, edge.weight);
}
let graph = match builder.build() {
Ok(g) => g,
Err(e) => {
return HttpResponse::BadRequest().json(ErrorResponse {
error: "Failed to build graph".to_string(),
details: Some(e.to_string()),
});
}
};
// Parse algorithm
let algorithm = match req.algorithm.as_deref() {
Some("StoerWagner") | None => MinCutAlgorithm::StoerWagner,
Some("FlowBased") => MinCutAlgorithm::FlowBased,
Some("KargerStein") => MinCutAlgorithm::KargerStein,
Some("NagamochiIbaraki") => MinCutAlgorithm::NagamochiIbaraki,
Some("Hierarchical") => MinCutAlgorithm::Hierarchical,
Some(algo) => {
return HttpResponse::BadRequest().json(ErrorResponse {
error: "Invalid algorithm".to_string(),
details: Some(format!("Unknown algorithm: {}", algo)),
});
}
};
// Compute minimum cut
let mut wrapper = MinCutWrapper::new(graph);
let result = match wrapper.compute_min_cut(algorithm) {
Ok(r) => r,
Err(e) => {
return HttpResponse::InternalServerError().json(ErrorResponse {
error: "Computation failed".to_string(),
details: Some(e.to_string()),
});
}
};
let elapsed = start.elapsed();
HttpResponse::Ok().json(MinCutResponse {
cut_value: result.cut_value,
partition1: result.partition1,
partition2: result.partition2,
cut_edges: result.cut_edges,
algorithm: format!("{:?}", algorithm),
computation_time_ms: elapsed.as_secs_f64() * 1000.0,
})
}
// Connectivity curve endpoint
async fn connectivity_curve(req: web::Json<ConnectivityRequest>) -> HttpResponse {
let start = std::time::Instant::now();
// Build graph
let mut builder = GraphBuilder::new();
for edge in &req.edges {
builder.add_edge(edge.from, edge.to, edge.weight);
}
let graph = match builder.build() {
Ok(g) => g,
Err(e) => {
return HttpResponse::BadRequest().json(ErrorResponse {
error: "Failed to build graph".to_string(),
details: Some(e.to_string()),
});
}
};
// Compute connectivity curve
let mut wrapper = MinCutWrapper::new(graph);
let curve = match wrapper.compute_connectivity_curve(req.max_clusters) {
Ok(c) => c,
Err(e) => {
return HttpResponse::InternalServerError().json(ErrorResponse {
error: "Computation failed".to_string(),
details: Some(e.to_string()),
});
}
};
let elapsed = start.elapsed();
let response_curve: Vec<ConnectivityPoint> = curve
.into_iter()
.map(|point| ConnectivityPoint {
num_clusters: point.num_clusters,
cut_value: point.cut_value,
})
.collect();
HttpResponse::Ok().json(ConnectivityResponse {
curve: response_curve,
computation_time_ms: elapsed.as_secs_f64() * 1000.0,
})
}
// List available algorithms
async fn list_algorithms() -> HttpResponse {
HttpResponse::Ok().json(serde_json::json!({
"algorithms": [
{
"name": "StoerWagner",
"description": "Exact algorithm with O(V³) time complexity",
"exact": true
},
{
"name": "FlowBased",
"description": "Maximum flow based algorithm",
"exact": true
},
{
"name": "KargerStein",
"description": "Randomized algorithm with high probability guarantees",
"exact": false
},
{
"name": "NagamochiIbaraki",
"description": "O(VE + V²log V) deterministic algorithm",
"exact": true
},
{
"name": "Hierarchical",
"description": "Hierarchical clustering based approach",
"exact": false
}
]
}))
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let port = std::env::var("PORT")
.unwrap_or_else(|_| "8080".to_string())
.parse::<u16>()
.expect("Invalid PORT");
log::info!("Starting MinCut API server on port {}", port);
HttpServer::new(|| {
App::new()
.wrap(middleware::Logger::default())
.wrap(middleware::Compress::default())
.route("/health", web::get().to(health))
.route("/api/mincut", web::post().to(compute_min_cut))
.route("/api/connectivity", web::post().to(connectivity_curve))
.route("/api/algorithms", web::get().to(list_algorithms))
})
.bind(("0.0.0.0", port))?
.run()
.await
}
```
### API Client Example
```typescript
// client/mincut-api-client.ts
export interface Edge {
from: number;
to: number;
weight: number;
}
export interface MinCutResult {
cutValue: number;
partition1: number[];
partition2: number[];
cutEdges: Array<[number, number]>;
algorithm: string;
computationTimeMs: number;
}
export interface ConnectivityPoint {
numClusters: number;
cutValue: number;
}
export class MinCutAPIClient {
constructor(private baseUrl: string = 'http://localhost:8080') {}
async computeMinCut(
edges: Edge[],
algorithm?: string
): Promise<MinCutResult> {
const response = await fetch(`${this.baseUrl}/api/mincut`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ edges, algorithm })
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'API request failed');
}
return response.json();
}
async computeConnectivityCurve(
edges: Edge[],
maxClusters?: number
): Promise<{ curve: ConnectivityPoint[]; computationTimeMs: number }> {
const response = await fetch(`${this.baseUrl}/api/connectivity`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ edges, max_clusters: maxClusters })
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'API request failed');
}
return response.json();
}
async listAlgorithms(): Promise<any> {
const response = await fetch(`${this.baseUrl}/api/algorithms`);
return response.json();
}
}
// Usage
const client = new MinCutAPIClient();
const edges = [
{ from: 0, to: 1, weight: 1.0 },
{ from: 1, to: 2, weight: 1.0 },
{ from: 2, to: 0, weight: 1.0 }
];
const result = await client.computeMinCut(edges, 'StoerWagner');
console.log(result);
```
---
## GraphQL Integration
### Schema Definition
```graphql
# schema.graphql
type Query {
"""Get available algorithms"""
algorithms: [Algorithm!]!
"""Check service health"""
health: HealthStatus!
}
type Mutation {
"""Compute minimum cut for a graph"""
computeMinCut(input: MinCutInput!): MinCutResult!
"""Compute connectivity curve"""
computeConnectivityCurve(input: ConnectivityInput!): ConnectivityCurve!
"""Compute local k-cut around a source node"""
computeLocalKCut(input: LocalKCutInput!): MinCutResult!
}
input EdgeInput {
from: Int!
to: Int!
weight: Float!
}
input MinCutInput {
edges: [EdgeInput!]!
algorithm: AlgorithmType = STOER_WAGNER
}
input ConnectivityInput {
edges: [EdgeInput!]!
maxClusters: Int
}
input LocalKCutInput {
edges: [EdgeInput!]!
k: Int!
sourceNode: Int!
}
enum AlgorithmType {
STOER_WAGNER
FLOW_BASED
KARGER_STEIN
NAGAMOCHI_IBARAKI
HIERARCHICAL
}
type Algorithm {
name: String!
description: String!
exact: Boolean!
timeComplexity: String!
}
type MinCutResult {
cutValue: Float!
partition1: [Int!]!
partition2: [Int!]!
cutEdges: [[Int!]!]!
algorithm: String!
computationTimeMs: Float!
}
type ConnectivityPoint {
numClusters: Int!
cutValue: Float!
}
type ConnectivityCurve {
curve: [ConnectivityPoint!]!
computationTimeMs: Float!
}
type HealthStatus {
status: String!
version: String!
}
```
### Resolver Implementation
```rust
// src/graphql/mod.rs
use async_graphql::{
Context, Object, Schema, EmptySubscription, SimpleObject, Enum, InputObject
};
use ruvector_mincut::{MinCutWrapper, MinCutAlgorithm};
use ruvector_mincut::graph::GraphBuilder;
#[derive(InputObject)]
struct EdgeInput {
from: usize,
to: usize,
weight: f64,
}
#[derive(InputObject)]
struct MinCutInput {
edges: Vec<EdgeInput>,
#[graphql(default)]
algorithm: AlgorithmType,
}
#[derive(InputObject)]
struct ConnectivityInput {
edges: Vec<EdgeInput>,
max_clusters: Option<usize>,
}
#[derive(InputObject)]
struct LocalKCutInput {
edges: Vec<EdgeInput>,
k: usize,
source_node: usize,
}
#[derive(Enum, Copy, Clone, Eq, PartialEq)]
enum AlgorithmType {
StoerWagner,
FlowBased,
KargerStein,
NagamochiIbaraki,
Hierarchical,
}
impl From<AlgorithmType> for MinCutAlgorithm {
fn from(algo: AlgorithmType) -> Self {
match algo {
AlgorithmType::StoerWagner => MinCutAlgorithm::StoerWagner,
AlgorithmType::FlowBased => MinCutAlgorithm::FlowBased,
AlgorithmType::KargerStein => MinCutAlgorithm::KargerStein,
AlgorithmType::NagamochiIbaraki => MinCutAlgorithm::NagamochiIbaraki,
AlgorithmType::Hierarchical => MinCutAlgorithm::Hierarchical,
}
}
}
#[derive(SimpleObject)]
struct Algorithm {
name: String,
description: String,
exact: bool,
time_complexity: String,
}
#[derive(SimpleObject)]
struct MinCutResultGQL {
cut_value: f64,
partition1: Vec<usize>,
partition2: Vec<usize>,
cut_edges: Vec<Vec<usize>>,
algorithm: String,
computation_time_ms: f64,
}
#[derive(SimpleObject)]
struct ConnectivityPointGQL {
num_clusters: usize,
cut_value: f64,
}
#[derive(SimpleObject)]
struct ConnectivityCurveGQL {
curve: Vec<ConnectivityPointGQL>,
computation_time_ms: f64,
}
#[derive(SimpleObject)]
struct HealthStatus {
status: String,
version: String,
}
pub struct QueryRoot;
#[Object]
impl QueryRoot {
async fn algorithms(&self) -> Vec<Algorithm> {
vec![
Algorithm {
name: "StoerWagner".to_string(),
description: "Exact algorithm with O(V³) time complexity".to_string(),
exact: true,
time_complexity: "O(V³)".to_string(),
},
Algorithm {
name: "FlowBased".to_string(),
description: "Maximum flow based algorithm".to_string(),
exact: true,
time_complexity: "O(V²E)".to_string(),
},
Algorithm {
name: "KargerStein".to_string(),
description: "Randomized algorithm with high probability".to_string(),
exact: false,
time_complexity: "O(V²log³V)".to_string(),
},
Algorithm {
name: "NagamochiIbaraki".to_string(),
description: "Deterministic near-linear algorithm".to_string(),
exact: true,
time_complexity: "O(VE + V²log V)".to_string(),
},
Algorithm {
name: "Hierarchical".to_string(),
description: "Hierarchical clustering approach".to_string(),
exact: false,
time_complexity: "O(V²log V)".to_string(),
},
]
}
async fn health(&self) -> HealthStatus {
HealthStatus {
status: "healthy".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
}
}
}
pub struct MutationRoot;
#[Object]
impl MutationRoot {
async fn compute_min_cut(&self, input: MinCutInput) -> async_graphql::Result<MinCutResultGQL> {
let start = std::time::Instant::now();
// Build graph
let mut builder = GraphBuilder::new();
for edge in input.edges {
builder.add_edge(edge.from, edge.to, edge.weight);
}
let graph = builder.build()?;
// Compute minimum cut
let mut wrapper = MinCutWrapper::new(graph);
let result = wrapper.compute_min_cut(input.algorithm.into())?;
let elapsed = start.elapsed();
Ok(MinCutResultGQL {
cut_value: result.cut_value,
partition1: result.partition1,
partition2: result.partition2,
cut_edges: result.cut_edges.into_iter()
.map(|(a, b)| vec![a, b])
.collect(),
algorithm: format!("{:?}", input.algorithm),
computation_time_ms: elapsed.as_secs_f64() * 1000.0,
})
}
async fn compute_connectivity_curve(
&self,
input: ConnectivityInput
) -> async_graphql::Result<ConnectivityCurveGQL> {
let start = std::time::Instant::now();
// Build graph
let mut builder = GraphBuilder::new();
for edge in input.edges {
builder.add_edge(edge.from, edge.to, edge.weight);
}
let graph = builder.build()?;
// Compute connectivity curve
let mut wrapper = MinCutWrapper::new(graph);
let curve = wrapper.compute_connectivity_curve(input.max_clusters)?;
let elapsed = start.elapsed();
Ok(ConnectivityCurveGQL {
curve: curve.into_iter()
.map(|p| ConnectivityPointGQL {
num_clusters: p.num_clusters,
cut_value: p.cut_value,
})
.collect(),
computation_time_ms: elapsed.as_secs_f64() * 1000.0,
})
}
async fn compute_local_k_cut(
&self,
input: LocalKCutInput
) -> async_graphql::Result<MinCutResultGQL> {
let start = std::time::Instant::now();
// Build graph
let mut builder = GraphBuilder::new();
for edge in input.edges {
builder.add_edge(edge.from, edge.to, edge.weight);
}
let graph = builder.build()?;
// Compute local k-cut
let mut wrapper = MinCutWrapper::new(graph);
let result = wrapper.compute_local_k_cut(input.k, input.source_node)?;
let elapsed = start.elapsed();
Ok(MinCutResultGQL {
cut_value: result.cut_value,
partition1: result.partition1,
partition2: result.partition2,
cut_edges: result.cut_edges.into_iter()
.map(|(a, b)| vec![a, b])
.collect(),
algorithm: "LocalKCut".to_string(),
computation_time_ms: elapsed.as_secs_f64() * 1000.0,
})
}
}
pub type MinCutSchema = Schema<QueryRoot, MutationRoot, EmptySubscription>;
pub fn create_schema() -> MinCutSchema {
Schema::build(QueryRoot, MutationRoot, EmptySubscription).finish()
}
```
### GraphQL Server
```rust
// src/graphql_server.rs
use actix_web::{web, App, HttpServer, guard, middleware};
use async_graphql::http::{playground_source, GraphQLPlaygroundConfig};
use async_graphql_actix_web::{GraphQLRequest, GraphQLResponse};
mod graphql;
use graphql::create_schema;
async fn graphql_playground() -> actix_web::HttpResponse {
actix_web::HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(playground_source(
GraphQLPlaygroundConfig::new("/graphql")
))
}
async fn graphql_handler(
schema: web::Data<graphql::MinCutSchema>,
req: GraphQLRequest,
) -> GraphQLResponse {
schema.execute(req.into_inner()).await.into()
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
let schema = create_schema();
log::info!("GraphQL Playground: http://localhost:8080/playground");
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(schema.clone()))
.wrap(middleware::Logger::default())
.service(
web::resource("/graphql")
.guard(guard::Post())
.to(graphql_handler)
)
.service(
web::resource("/playground")
.guard(guard::Get())
.to(graphql_playground)
)
})
.bind(("0.0.0.0", 8080))?
.run()
.await
}
```
---
## Architecture Patterns
### WASM Browser Deployment
```mermaid
graph TB
subgraph "Browser Environment"
UI[Web UI<br/>React/Vue/Svelte]
Worker[Web Worker<br/>WASM Runtime]
Canvas[Canvas<br/>Visualization]
end
subgraph "WASM Module"
WasmBind[wasm-bindgen<br/>JS Bindings]
MinCut[MinCut Algorithms<br/>Rust Core]
Graph[Graph Structures]
end
UI -->|Post Message| Worker
Worker -->|Load & Initialize| WasmBind
WasmBind -->|Call| MinCut
MinCut -->|Use| Graph
Worker -->|Results| UI
UI -->|Render| Canvas
style UI fill:#3498db
style Worker fill:#2ecc71
style WasmBind fill:#e74c3c
style MinCut fill:#f39c12
```
### Node.js Server Architecture
```mermaid
graph TB
subgraph "Client Layer"
Web[Web Clients]
Mobile[Mobile Apps]
CLI[CLI Tools]
end
subgraph "API Layer"
REST[REST API<br/>Express/Fastify]
GraphQL[GraphQL API<br/>Apollo Server]
WS[WebSocket<br/>Real-time]
end
subgraph "Service Layer"
Pool[Worker Pool<br/>Thread Pool]
Cache[Redis Cache<br/>Results]
Queue[Task Queue<br/>Bull/BullMQ]
end
subgraph "Core Layer"
Native[Native Module<br/>ruvector-mincut-node]
Rust[Rust Core<br/>MinCut Algorithms]
end
Web --> REST
Mobile --> GraphQL
CLI --> REST
REST --> Pool
GraphQL --> Pool
WS --> Queue
Pool --> Cache
Pool --> Native
Queue --> Native
Native --> Rust
style Web fill:#3498db
style REST fill:#2ecc71
style Pool fill:#e74c3c
style Native fill:#f39c12
```
### Microservice Integration
```mermaid
graph TB
subgraph "API Gateway"
Gateway[Kong/Traefik<br/>API Gateway]
end
subgraph "MinCut Service"
API[MinCut API<br/>Actix-Web]
Compute[Compute Workers<br/>Rayon Thread Pool]
Cache[Local Cache<br/>LRU]
end
subgraph "Supporting Services"
Graph[Graph Service<br/>ruvector-graph]
Metrics[Metrics<br/>Prometheus]
Trace[Tracing<br/>Jaeger]
end
subgraph "Storage Layer"
DB[(Graph Database<br/>Neo4j/AgentDB)]
Object[(Object Storage<br/>S3/MinIO)]
end
Gateway --> API
API --> Compute
API --> Cache
API --> Graph
API --> Metrics
API --> Trace
Graph --> DB
Compute --> Object
style Gateway fill:#3498db
style API fill:#2ecc71
style Compute fill:#e74c3c
style Graph fill:#f39c12
style DB fill:#9b59b6
```
### Distributed Processing
```mermaid
graph TB
subgraph "Load Balancer"
LB[HAProxy/Nginx]
end
subgraph "Service Instances"
S1[MinCut Service 1]
S2[MinCut Service 2]
S3[MinCut Service 3]
end
subgraph "Message Queue"
Queue[RabbitMQ/Kafka<br/>Task Distribution]
end
subgraph "Worker Nodes"
W1[Worker 1<br/>GPU Acceleration]
W2[Worker 2<br/>CPU Intensive]
W3[Worker 3<br/>Memory Optimized]
end
subgraph "Coordination"
Coord[Coordinator<br/>Task Scheduling]
Monitor[Monitor<br/>Health Checks]
end
LB --> S1
LB --> S2
LB --> S3
S1 --> Queue
S2 --> Queue
S3 --> Queue
Queue --> Coord
Coord --> W1
Coord --> W2
Coord --> W3
Monitor --> S1
Monitor --> S2
Monitor --> S3
Monitor --> W1
Monitor --> W2
Monitor --> W3
style LB fill:#3498db
style Queue fill:#2ecc71
style Coord fill:#e74c3c
style W1 fill:#f39c12
```
---
## Integration with ruvector-graph
For graph database features and persistent storage, integrate with `ruvector-graph`:
```rust
use ruvector_mincut::MinCutWrapper;
use ruvector_graph::{GraphDB, Query};
// Load graph from database
let db = GraphDB::connect("localhost:7687")?;
let graph = db.query("MATCH (n)-[r]-(m) RETURN n, r, m")?;
// Compute minimum cut
let mut wrapper = MinCutWrapper::new(graph);
let result = wrapper.compute_min_cut(MinCutAlgorithm::StoerWagner)?;
// Store results back to database
db.execute(
"CREATE (r:MinCutResult {value: $value})",
&[("value", result.cut_value)]
)?;
```
---
## Best Practices
### Performance Optimization
1. **Use Web Workers for WASM** - Keep UI responsive
2. **Worker Pools for Node.js** - Utilize all CPU cores
3. **Caching** - Cache results for identical graphs
4. **Batch Processing** - Process multiple graphs in parallel
5. **Algorithm Selection** - Choose appropriate algorithm for graph size
### Error Handling
```typescript
try {
const result = await computeMinCut(edges);
} catch (error) {
if (error.message.includes('memory')) {
// Graph too large, try different algorithm
} else if (error.message.includes('timeout')) {
// Computation timeout, use approximate algorithm
} else {
// Other errors
}
}
```
### Security Considerations
1. **Input Validation** - Validate graph size limits
2. **Rate Limiting** - Prevent abuse of compute resources
3. **Timeout Protection** - Set computation timeouts
4. **Resource Limits** - Limit memory usage per request
---
## Next Steps
- [Performance Optimization Guide](./05-performance-optimization.md)
- [API Reference](../api/README.md)
- [Examples](../../examples/README.md)