Type-Level Maximum Flow in TypeScript
This challenge involves implementing a maximum flow algorithm at the TypeScript type level. You will represent a directed graph with capacities as a type, and your solution will be a type that computes the maximum flow from a specified source to a sink. This exercise explores the expressive power of TypeScript's type system for solving algorithmic problems.
Problem Description
The goal is to create a TypeScript type, MaxFlow<Graph, Source, Sink>, that statically computes the maximum flow value from a Source node to a Sink node within a given Graph. The graph and its capacities will be defined using TypeScript's type system.
Key Requirements:
-
Graph Representation: The graph will be represented as a tuple of edge objects. Each edge object will define:
from: The starting node of the edge.to: The ending node of the edge.capacity: The maximum flow that can pass through this edge.- Nodes will be represented by string literals.
-
Maximum Flow Computation: The
MaxFlowtype should implement a maximum flow algorithm (e.g., Ford-Fulkerson or Edmonds-Karp, but adapted for type-level computation) to find the maximum flow. -
Output: The
MaxFlowtype should resolve to a union of numbers, where each number represents a possible flow value. The largest number in this union will be the maximum flow. -
Iterative Refinement: The type-level computation will likely involve an iterative process of finding augmenting paths and updating residual capacities. This can be achieved using recursive conditional types.
Expected Behavior:
Given a graph definition, a source node, and a sink node, the MaxFlow type should, at compile time, determine the maximum possible flow from the source to the sink.
Edge Cases:
- Graphs with no path from source to sink.
- Graphs with zero capacity edges.
- Graphs with cycles.
- Source and sink being the same node.
Examples
Example 1: A simple path
type SimpleGraph = [
{ from: 'A'; to: 'B'; capacity: 10 },
{ from: 'B'; to: 'C'; capacity: 5 }
];
// Expected: MaxFlow<SimpleGraph, 'A', 'C'> should resolve to 5
Example 2: Multiple paths
type MultiPathGraph = [
{ from: 'S'; to: 'A'; capacity: 10 },
{ from: 'S'; to: 'B'; capacity: 5 },
{ from: 'A'; to: 'T'; capacity: 10 },
{ from: 'B'; to: 'T'; capacity: 5 }
];
// Expected: MaxFlow<MultiPathGraph, 'S', 'T'> should resolve to 15
Example 3: Bottleneck capacity
type BottleneckGraph = [
{ from: 'S'; to: 'A'; capacity: 10 },
{ from: 'S'; to: 'B'; capacity: 10 },
{ from: 'A'; to: 'C'; capacity: 5 },
{ from: 'B'; to: 'C'; capacity: 10 },
{ from: 'C'; to: 'T'; capacity: 10 }
];
// Expected: MaxFlow<BottleneckGraph, 'S', 'T'> should resolve to 15
Example 4: No path
type NoPathGraph = [
{ from: 'A'; to: 'B'; capacity: 10 }
];
// Expected: MaxFlow<NoPathGraph, 'A', 'C'> should resolve to 0
Constraints
- The number of nodes and edges will be relatively small (e.g., up to 10 nodes and 20 edges) to remain within TypeScript's type computation limits.
- Capacities will be positive integers up to 100.
- Node names will be short string literals.
- The
MaxFlowtype should ideally terminate within a reasonable number of type instantiations.
Notes
- This challenge requires a deep understanding of conditional types, tuple manipulation, and recursive type definitions in TypeScript.
- Consider how to represent and update residual graphs at the type level.
- Think about how to find augmenting paths using type-level pattern matching and filtering.
- The problem is designed to be challenging and may require significant experimentation with TypeScript's type system.
- Success looks like having a
MaxFlowtype that correctly computes the maximum flow for the provided examples and satisfies the constraints.