|
| 1 | +# Elegant Disjoint Interval Set API |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This is a completely redesigned implementation of the Disjoint Interval Set (DIS) library, following the principles of simplicity, composability, and mathematical elegance. The new API lives in the `dis` namespace and provides a clean, intuitive interface for working with intervals and interval sets. |
| 6 | + |
| 7 | +## Key Design Principles |
| 8 | + |
| 9 | +1. **Simplicity**: Every component does one thing exceptionally well |
| 10 | +2. **Composability**: Operations naturally compose together |
| 11 | +3. **Mathematical Rigor**: Models true mathematical concepts accurately |
| 12 | +4. **Zero-Cost Abstractions**: Template-based design with compile-time optimization |
| 13 | +5. **Multiple Expression Styles**: Support both mathematical notation and programming idioms |
| 14 | + |
| 15 | +## Architecture |
| 16 | + |
| 17 | +``` |
| 18 | +include/dis/ |
| 19 | +├── core/ # Essential functionality |
| 20 | +│ ├── interval.hpp # Single interval implementation |
| 21 | +│ └── disjoint_interval_set.hpp # Set of disjoint intervals |
| 22 | +├── io/ # Input/Output utilities |
| 23 | +│ ├── parser.hpp # String DSL parser |
| 24 | +│ └── format.hpp # Formatting and visualization |
| 25 | +└── dis.hpp # Main header file |
| 26 | +``` |
| 27 | + |
| 28 | +## Core Features |
| 29 | + |
| 30 | +### Intervals |
| 31 | + |
| 32 | +```cpp |
| 33 | +using namespace dis; |
| 34 | + |
| 35 | +// Multiple factory methods for clarity |
| 36 | +auto closed = real_interval::closed(0, 10); // [0, 10] |
| 37 | +auto open = real_interval::open(0, 10); // (0, 10) |
| 38 | +auto point = real_interval::point(5); // {5} |
| 39 | +auto unbounded = real_interval::unbounded(); // (-∞, ∞) |
| 40 | +auto positive = real_interval::greater_than(0); // (0, ∞) |
| 41 | + |
| 42 | +// Rich queries |
| 43 | +bool contains = closed.contains(5); |
| 44 | +bool overlaps = closed.overlaps(open); |
| 45 | +double length = closed.length(); |
| 46 | +double midpoint = closed.midpoint(); |
| 47 | + |
| 48 | +// Set operations |
| 49 | +auto intersection = closed & open; // or closed.intersect(open) |
| 50 | +auto hull = closed.hull(open); // Convex hull if possible |
| 51 | +``` |
| 52 | + |
| 53 | +### Disjoint Interval Sets |
| 54 | + |
| 55 | +```cpp |
| 56 | +// Fluent construction |
| 57 | +auto set = real_set{} |
| 58 | + .add(0, 10) |
| 59 | + .add(20, 30) |
| 60 | + .add(25, 35); // Automatically merged with [20,30] |
| 61 | + |
| 62 | +// From string notation |
| 63 | +auto parsed = real_set::from_string("[0,10] U [20,30] U {50}"); |
| 64 | + |
| 65 | +// Set operations with multiple notations |
| 66 | +auto union_set = set1 | set2; // Union |
| 67 | +auto intersection = set1 & set2; // Intersection |
| 68 | +auto difference = set1 - set2; // Difference |
| 69 | +auto symmetric = set1 ^ set2; // Symmetric difference |
| 70 | +auto complement = ~set1; // Complement |
| 71 | +``` |
| 72 | + |
| 73 | +### DIS-Specific Queries |
| 74 | + |
| 75 | +```cpp |
| 76 | +// Component analysis |
| 77 | +auto span = set.span(); // Convex hull of all intervals |
| 78 | +auto gaps = set.gaps(); // Intervals between components |
| 79 | +size_t count = set.component_count(); |
| 80 | + |
| 81 | +// Measure operations |
| 82 | +double measure = set.measure(); // Total length |
| 83 | +double gap_measure = set.gap_measure(); // Total gap length |
| 84 | +double density = set.density(); // measure / span.length |
| 85 | +``` |
| 86 | + |
| 87 | +### Functional Operations |
| 88 | + |
| 89 | +```cpp |
| 90 | +// Filter intervals by predicate |
| 91 | +auto large = set.filter([](const auto& i) { |
| 92 | + return i.length() > 10; |
| 93 | +}); |
| 94 | + |
| 95 | +// Transform intervals |
| 96 | +auto scaled = set.map([](const auto& i) { |
| 97 | + return real_interval::closed( |
| 98 | + *i.lower_bound() * 2, |
| 99 | + *i.upper_bound() * 2 |
| 100 | + ); |
| 101 | +}); |
| 102 | + |
| 103 | +// Iterate with action |
| 104 | +set.for_each([](const auto& interval) { |
| 105 | + std::cout << interval << '\n'; |
| 106 | +}); |
| 107 | +``` |
| 108 | + |
| 109 | +### String DSL |
| 110 | + |
| 111 | +The parser supports mathematical notation: |
| 112 | + |
| 113 | +```cpp |
| 114 | +// Standard notation |
| 115 | +"[0,10]" // Closed interval |
| 116 | +"(0,10)" // Open interval |
| 117 | +"[0,10)" // Half-open interval |
| 118 | +"{5}" // Singleton |
| 119 | +"{}" // Empty set |
| 120 | + |
| 121 | +// Set operations (both ASCII and Unicode) |
| 122 | +"[0,10] U [20,30]" // Union |
| 123 | +"[0,10] & [20,30]" // Intersection |
| 124 | +"[0,10] \\ [5,15]" // Difference |
| 125 | +"[0,10] ^ [5,15]" // Symmetric difference |
| 126 | +``` |
| 127 | + |
| 128 | +### Visualization |
| 129 | + |
| 130 | +```cpp |
| 131 | +// Different output formats |
| 132 | +auto str = interval_formatter<double>::format(set, |
| 133 | + interval_formatter<double>::Style::Mathematical); // [0,10] U [20,30] |
| 134 | + |
| 135 | +// ASCII visualization |
| 136 | +std::cout << interval_formatter<double>::visualize(set, 0, 100, 60); |
| 137 | +// Output: .....[=====]......[=====]........................ |
| 138 | +``` |
| 139 | + |
| 140 | +## Comparison with Original Implementation |
| 141 | + |
| 142 | +### Improvements |
| 143 | + |
| 144 | +1. **Cleaner API**: Named constructors, fluent interface, consistent naming |
| 145 | +2. **Better Composability**: All operations return values, enabling chaining |
| 146 | +3. **Richer Queries**: gaps(), span(), density(), measure() operations |
| 147 | +4. **String DSL**: Parse mathematical notation directly |
| 148 | +5. **Functional Style**: filter(), map(), for_each() operations |
| 149 | +6. **Multiple Notations**: Support both mathematical (∪, ∩) and programming (&, |) operators |
| 150 | +7. **Better Organization**: Clean separation of concerns with core/io/extensions |
| 151 | + |
| 152 | +### Simplifications |
| 153 | + |
| 154 | +1. **Single Responsibility**: Each class does one thing well |
| 155 | +2. **Value Semantics**: Immutable operations by default |
| 156 | +3. **Template Simplicity**: Straightforward template parameters |
| 157 | +4. **Clear Invariants**: Automatic normalization maintains disjoint property |
| 158 | + |
| 159 | +## Usage Examples |
| 160 | + |
| 161 | +### Resource Scheduling |
| 162 | + |
| 163 | +```cpp |
| 164 | +auto room_available = real_set{} |
| 165 | + .add(8, 9) // 8 AM - 9 AM |
| 166 | + .add(10, 12) // 10 AM - 12 PM |
| 167 | + .add(14, 17); // 2 PM - 5 PM |
| 168 | + |
| 169 | +auto meeting = real_interval::closed(10, 11); |
| 170 | +if (room_available.contains(meeting)) { |
| 171 | + std::cout << "Meeting can be scheduled\n"; |
| 172 | +} |
| 173 | + |
| 174 | +auto utilization = room_available.measure() / room_available.span().length(); |
| 175 | +``` |
| 176 | + |
| 177 | +### Data Range Analysis |
| 178 | + |
| 179 | +```cpp |
| 180 | +auto valid_ranges = real_set::from_string("[0,100] U [200,300]"); |
| 181 | +auto query_range = real_interval::closed(50, 250); |
| 182 | +auto valid_portion = valid_ranges & real_set{query_range}; |
| 183 | + |
| 184 | +std::cout << "Valid data in range: " << valid_portion.measure() << " units\n"; |
| 185 | +``` |
| 186 | +
|
| 187 | +## Building and Testing |
| 188 | +
|
| 189 | +```bash |
| 190 | +# Compile tests |
| 191 | +g++ -std=c++20 -O2 -I./include -o test tests/test_elegant_api.cpp |
| 192 | +./test |
| 193 | +
|
| 194 | +# Compile examples |
| 195 | +g++ -std=c++20 -O2 -I./include -o demo examples/elegant_api_demo.cpp |
| 196 | +./demo |
| 197 | +``` |
| 198 | + |
| 199 | +## Future Enhancements |
| 200 | + |
| 201 | +While the core API is complete and elegant, potential extensions include: |
| 202 | + |
| 203 | +1. **Compile-time intervals**: Static intervals for compile-time validation |
| 204 | +2. **Multi-dimensional support**: Hyperrectangles and boxes |
| 205 | +3. **Custom boundary types**: Support for discrete types, dates, etc. |
| 206 | +4. **Lazy evaluation**: For complex operation chains |
| 207 | +5. **Parallel algorithms**: For large-scale interval processing |
| 208 | + |
| 209 | +## Conclusion |
| 210 | + |
| 211 | +This implementation demonstrates how a focused, well-designed API can make complex mathematical concepts accessible and enjoyable to work with. The library follows the Unix philosophy of doing one thing well, while providing multiple ways to express operations for different use cases and preferences. |
| 212 | + |
| 213 | +The result is a library that is: |
| 214 | +- **Simple** to understand and use |
| 215 | +- **Powerful** enough for complex applications |
| 216 | +- **Elegant** in its design and implementation |
| 217 | +- **Composable** for building larger systems |
| 218 | +- **Efficient** with zero-cost abstractions |
| 219 | + |
| 220 | +This is the kind of API that would be worthy of inclusion in Boost or the C++ standard library. |
0 commit comments