algomate 0.1.0
algomate: ^0.1.0 copied to clipboard
Professional algorithm selection companion with intelligent strategy selection, built-in benchmarking, and performance optimization. Features Clean Architecture, comprehensive error handling, and prod [...]
AlgoMate ๐คโก #
Algorithm selection companion for Dart and Flutter
AlgoMate helps you choose the right algorithm and complexity for your data operations with performance-focused architecture and intelligent selection policies. Built with DDD (Domain-Driven Design) + Clean Architecture principles.
Features โจ #
- ๐ฏ Intelligent Selection: Automatically choose the best algorithm based on data characteristics and hints
- โก Performance Focused: Zero-allocation hot paths, optimized for speed and predictability
- ๐ง Easy to Use: Simple facade API with sensible defaults and builder pattern
- ๐ Multiple Complexities: Built-in support for O(1), O(log n), O(n), O(n log n), O(nยฒ), and more
- ๐๏ธ Extensible: Register custom strategies and policies without touching domain logic
- ๐งช Production Ready: Comprehensive error handling, logging, and testing support
- ๐ฑ Flutter Friendly: Isolate support for heavy operations to avoid UI blocking
- ๐ Built-in Benchmarking: Performance measurement and comparison tools with statistical analysis
- ๐ Concurrent Execution: CPU-intensive operations in isolates with timeout and resource management
Quick Start ๐ #
Installation #
Add to your pubspec.yaml
:
dependencies:
algomate: ^0.1.0
Basic Usage #
import 'package:algomate/algomate.dart';
void main() {
// Create selector with development defaults
final selector = AlgoSelectorFacade.development();
// Sort a list - automatically chooses best algorithm
final result = selector.sort(
input: [64, 34, 25, 12, 22, 11, 90],
hint: SelectorHint(n: 7),
);
result.fold(
(success) {
print('Sorted: ${success.output}');
print('Used: ${success.selectedStrategy.name}');
print('Complexity: ${success.selectedStrategy.timeComplexity}');
},
(failure) => print('Failed: $failure'),
);
}
Advanced Usage ๐ฌ #
Custom Strategy Registration #
// Define your own algorithm strategy
class CustomQuickSort extends Strategy<List<int>, List<int>> {
@override
AlgoMetadata get metadata => AlgoMetadata(
name: 'custom_quick_sort',
timeComplexity: TimeComplexity.nLogN,
spaceComplexity: TimeComplexity.logN,
requiresSorted: false,
memoryOverhead: 0,
);
@override
List<int> call(List<int> input) {
return quickSort(input); // Your implementation
}
}
// Register and use
final selector = AlgoSelectorFacade.development();
selector.registerStrategy(CustomQuickSort());
Production Configuration #
final productionSelector = AlgoMate.createSelector()
.withLogging(LogLevel.error) // Minimal logging
.withMemoryConstraint(MemoryConstraint.low)
.withStabilityPreference(StabilityPreference.preferred)
.withIsolateExecution(enabled: true) // Enable isolate execution
.withBenchmarking(enabled: false) // Disable benchmarking
.build();
Comprehensive Example #
import 'package:algomate/algomate.dart';
void main() async {
final selector = AlgoSelectorFacade.development();
// Different dataset sizes demonstrate intelligent selection
final testSizes = [10, 100, 1000, 10000];
for (final size in testSizes) {
final data = List.generate(size, (i) => size - i);
final result = selector.sort(
input: data,
hint: SelectorHint(n: size),
);
result.fold(
(success) {
print('Size $size: Used ${success.selectedStrategy.name}');
print(' Time: ${success.executionStats?.executionTimeMicros}ฮผs');
print(' Complexity: ${success.selectedStrategy.metadata.timeComplexity}');
},
(error) => print('Error: $error'),
);
}
}
API Reference ๐ #
Core Classes #
AlgoSelectorFacade
Main interface for algorithm selection and execution.
class AlgoSelectorFacade {
// Factory constructors
static AlgoSelectorFacade development()
static AlgoSelectorFacade production()
// Sort operations
Result<ExecuteResult<List<T>>, Failure> sort<T extends Comparable<T>>(
{required List<T> input, SelectorHint? hint}
)
// Search operations
Result<ExecuteResult<int>, Failure> search<T>(
{required List<T> input, required T target, SelectorHint? hint}
)
// Generic execution
Result<ExecuteResult<O>, Failure> execute<I, O>(
ExecuteCommand<I, O> command
)
// Strategy management
Result<void, Failure> registerStrategy<I, O>(Strategy<I, O> strategy)
Result<List<AlgoMetadata>, Failure> listStrategies({String? operationType})
}
SelectorHint
Provides context hints for intelligent algorithm selection.
class SelectorHint {
final int? n; // Dataset size
final bool? isSorted; // Pre-sorted data hint
final MemoryConstraint? memoryBudget; // Memory limitations
final StabilityPreference? stability; // Stable sort preference
final PerformanceProfile? profile; // Speed vs memory preference
const SelectorHint({
this.n,
this.isSorted,
this.memoryBudget,
this.stability,
this.profile,
});
}
ExecuteResult<T>
Contains execution results with performance metadata.
class ExecuteResult<T> {
final T output; // Algorithm output
final AlgoMetadata selectedStrategy; // Chosen algorithm
final ExecutionStats? executionStats; // Performance metrics
const ExecuteResult({
required this.output,
required this.selectedStrategy,
this.executionStats,
});
}
AlgoMetadata
Algorithm characteristics and complexity information.
class AlgoMetadata {
final String name; // Strategy identifier
final TimeComplexity timeComplexity; // Big-O time complexity
final TimeComplexity spaceComplexity; // Big-O space complexity
final bool requiresSorted; // Requires sorted input
final int memoryOverhead; // Additional memory bytes
final bool isStable; // Preserves equal element order
final bool isInPlace; // Modifies input in-place
const AlgoMetadata({...});
}
Enums and Value Objects #
TimeComplexity
enum TimeComplexity {
constant, // O(1)
logarithmic, // O(log n)
linear, // O(n)
nLogN, // O(n log n)
quadratic, // O(nยฒ)
cubic, // O(nยณ)
exponential, // O(2^n)
}
MemoryConstraint
enum MemoryConstraint {
unlimited(double.infinity),
high(1073741824), // 1GB
medium(268435456), // 256MB
low(67108864), // 64MB
veryLow(16777216), // 16MB
}
Result<T, F>
Functional error handling pattern.
sealed class Result<T, F> {
const Result();
R fold<R>(R Function(T success) onSuccess, R Function(F failure) onFailure);
bool get isSuccess;
bool get isFailure;
}
class Success<T, F> extends Result<T, F> {
final T value;
const Success(this.value);
}
class Failure<T, F> extends Result<T, F> {
final F error;
const Failure(this.error);
}
Architecture ๐๏ธ #
AlgoMate is built using Domain-Driven Design (DDD) + Clean Architecture:
lib/src/
โโโ domain/ # Core business logic
โ โโโ entities/ # Strategy, ConfigurableStrategy
โ โโโ services/ # ComplexityRanker, SelectorPolicy
โ โโโ value_objects/ # TimeComplexity, AlgoMetadata
โโโ application/ # Use cases and ports
โ โโโ use_cases/ # ExecuteStrategyUseCase
โ โโโ dtos/ # ExecuteCommand, ExecuteResult
โ โโโ ports/ # Logger, BenchmarkRunner, IsolateExecutor
โโโ infrastructure/ # External adapters and implementations
โ โโโ strategies/ # Built-in algorithm implementations
โ โโโ adapters/ # Logging, benchmarking, isolate execution
โโโ interface/ # Public API
โโโ facade/ # AlgoSelectorFacade
โโโ builders/ # SelectorBuilder
Contributing ๐ค #
We welcome contributions! Please follow these guidelines:
Development Setup #
-
Fork and clone
git clone https://github.com/your-username/algomate.git cd algomate
-
Install dependencies
dart pub get
-
Run tests
dart test
-
Check code quality
dart analyze dart format lib test
Adding New Algorithms #
-
Create strategy class
class YourAlgorithm extends Strategy<InputType, OutputType> { @override AlgoMetadata get metadata => AlgoMetadata( name: 'your_algorithm', timeComplexity: TimeComplexity.nLogN, spaceComplexity: TimeComplexity.linear, // ... other metadata ); @override OutputType call(InputType input) { // Your implementation } }
-
Add tests
group('YourAlgorithm', () { test('should handle basic cases', () { final strategy = YourAlgorithm(); final result = strategy.call(testInput); expect(result, equals(expectedOutput)); }); test('should handle edge cases', () { final strategy = YourAlgorithm(); expect(() => strategy.call(emptyInput), returnsNormally); }); });
-
Update documentation
- Add algorithm to README.md
- Document complexity characteristics
- Provide usage examples
Code Style Guidelines #
- Follow Effective Dart
- Use functional programming patterns where appropriate
- Maintain immutability in domain objects
- Handle errors using
Result<T, Failure>
pattern - Document public APIs with comprehensive examples
Pull Request Process #
- Create feature branch:
git checkout -b feature/amazing-feature
- Make your changes following the architecture patterns
- Add/update tests to maintain coverage
- Update documentation and examples
- Run all quality checks:
dart analyze && dart test && dart format --set-exit-if-changed lib test
- Submit PR with clear description of changes
Architecture Guidelines #
Follow the established DDD + Clean Architecture:
- Domain Layer: Pure business logic, no external dependencies
- Application Layer: Use cases orchestrating domain objects
- Infrastructure Layer: External adapters and implementations
- Interface Layer: Public API facade and builders
Performance Considerations #
- Prefer zero-allocation hot paths
- Use traditional loops over functional approaches for performance-critical code
- Benchmark new algorithms using the built-in benchmarking framework
- Document performance characteristics in algorithm metadata
Changelog ๐ #
v0.1.0 - Initial Release (September 1, 2024) #
๐ New Features
-
Complete DDD + Clean Architecture implementation
- Domain-driven design with clear separation of concerns
- Clean architecture with dependency inversion
- Functional error handling with
Result<T, Failure>
pattern
-
Intelligent Algorithm Selection System
- Context-aware strategy selection based on dataset characteristics
- 6 sorting algorithms: Insertion, In-place Insertion, Binary Insertion, Merge, Iterative Merge, Hybrid Merge
- 2 search algorithms: Linear Search, Binary Search
- Smart selection based on size hints, memory constraints, and stability preferences
-
Performance-Focused Infrastructure
- Zero-allocation hot paths for maximum performance
- Built-in benchmarking suite with statistical analysis
- Isolate execution engine for CPU-intensive operations
- Comprehensive performance measurement and comparison tools
-
Production-Ready Features
- Comprehensive error handling with specific failure types
- Resource management for isolate execution with automatic cleanup
- Multiple logging adapters (Console, Silent, Buffered)
- Memory constraint handling and validation
-
Developer Experience
- Fluent builder API for easy configuration
- Simple facade pattern for common operations
- Extensive documentation with practical examples
- Complete test coverage with edge case handling
๐ Built-in Algorithm Library
Sorting Algorithms:
InsertionSort
- O(nยฒ) time, O(1) space - Optimal for small datasetsInPlaceInsertionSort
- O(nยฒ) time, O(1) space - Memory-efficient variantBinaryInsertionSort
- O(nยฒ) time, O(1) space - Optimized insertions with binary searchMergeSort
- O(n log n) time, O(n) space - Stable, predictable performanceIterativeMergeSort
- O(n log n) time, O(n) space - Stack-safe implementationHybridMergeSort
- O(n log n) time, O(n) space - Switches to insertion sort for small subarrays
Search Algorithms:
LinearSearch
- O(n) time, O(1) space - Works on unsorted dataBinarySearch
- O(log n) time, O(1) space - Requires sorted input data
๐๏ธ Infrastructure Components
- Logging System: Console, Silent, and Buffered loggers with configurable levels
- Benchmarking Framework: Harness-based and simple benchmark runners with statistical analysis
- Isolate Execution Engine: Dart isolate executor with timeout and resource management
- Strategy Registry: In-memory storage with efficient lookup and type-safe operations
๐งช Testing & Quality Assurance
- 100% test coverage for core functionality
- Comprehensive integration tests for algorithm selection
- Edge case testing (empty inputs, error scenarios, large datasets)
- Performance regression testing with benchmarking
- Static analysis with zero critical issues
๐ Documentation
- Complete API reference with examples
- Architecture documentation with diagrams
- Performance optimization guidelines
- Migration guide from manual algorithm selection
- Troubleshooting guide for common issues
โก Performance Characteristics
- Zero-allocation hot paths in selection algorithms
- Efficient complexity ranking with pre-computed scores
- Memory-optimized strategy storage and retrieval
- Minimal overhead in algorithm execution pipeline
- Smart caching of strategy metadata for repeated operations
Migration Notes: This is the initial release. Future versions will maintain backward compatibility while adding new algorithms and optimization features.
Known Limitations:
- Currently focused on sorting and searching algorithms
- Isolate execution requires Dart 2.19+ for optimal performance
- Benchmarking framework works best with consistent hardware environments
License ๐ #
MIT License - see LICENSE file for details.
Made with โค๏ธ for the Dart and Flutter community
Platform Support ๐ฏ #
- โ Dart VM: Full support with isolate execution
- โ Flutter Mobile: iOS and Android with isolate support
- โ Flutter Web: Core algorithms (isolates not supported)
- โ Flutter Desktop: Windows, macOS, Linux with full features
- โ Dart CLI: Command-line applications and servers
Requirements ๐ #
- Dart SDK: >= 3.0.0 < 4.0.0
- Flutter: >= 3.10.0 (for Flutter projects)
- Platform: Any platform supporting Dart
Benchmarks ๐โโ๏ธ #
Performance comparison on MacBook Pro M2 (sorting 10,000 integers):
Algorithm | Time (ฮผs) | Memory | Stable | In-Place |
---|---|---|---|---|
Insertion Sort | 45,230 | O(1) | โ | โ |
Binary Insertion | 38,120 | O(1) | โ | โ |
Merge Sort | 1,250 | O(n) | โ | โ |
Hybrid Merge | 1,180 | O(n) | โ | โ |
Dart Built-in | 890 | O(log n) | โ | โ |
Benchmarks may vary based on hardware and dataset characteristics
Community & Support ๐ฌ #
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: Full API Reference
- Examples: GitHub Examples
Acknowledgments ๐ #
- Inspired by algorithm selection research and adaptive algorithms
- Built with clean architecture principles from Uncle Bob Martin
- Domain-driven design patterns from Eric Evans
- Performance optimization techniques from the Dart team
Star โญ this repository if AlgoMate helps your project!
Built-in Algorithm Library ๐ #
AlgoMate comes with optimized implementations:
Sorting Algorithms:
InsertionSort
- O(nยฒ) - Best for small datasetsInPlaceInsertionSort
- O(nยฒ) - Memory efficientBinaryInsertionSort
- O(nยฒ) - Optimized insertionsMergeSort
- O(n log n) - Stable, predictable performanceIterativeMergeSort
- O(n log n) - Stack-safe merge sortHybridMergeSort
- O(n log n) - Switches to insertion sort for small arrays
Search Algorithms:
LinearSearch
- O(n) - Works on unsorted dataBinarySearch
- O(log n) - Requires sorted data
Performance Measurement ๐ #
Use built-in benchmarking tools for performance analysis:
import 'package:algomate/algomate.dart';
void main() async {
final benchmarkRunner = HarnessBenchmarkRunner();
// Compare different sorting approaches
final comparison = benchmarkRunner.compare(
functions: {
'insertion_sort': () => insertionSort(data),
'merge_sort': () => mergeSort(data),
'dart_builtin': () => data.toList()..sort(),
},
iterations: 1000,
warmupIterations: 100,
);
print(comparison); // Statistical analysis with confidence intervals
}
Concurrent Execution โก #
Execute CPU-intensive operations in isolates:
void main() async {
final isolateExecutor = DartIsolateExecutor();
// Sort large dataset in isolate (won't block UI)
final largeData = List.generate(100000, (i) => 100000 - i);
final sortedResult = await isolateExecutor.execute<List<int>, List<int>>(
function: (data) => mergeSort(data),
input: largeData,
timeout: Duration(seconds: 30),
);
print('Sorted ${sortedResult.length} elements');
isolateExecutor.dispose(); // Clean up resources
}
Error Handling ๐ก๏ธ #
AlgoMate uses functional error handling with the Result<T, Failure>
pattern:
// Handle results functionally
final result = selector.sort(input: data, hint: hint);
result.fold(
(success) {
// Success case - use success.output
print('Algorithm: ${success.selectedStrategy.name}');
print('Time taken: ${success.executionStats?.executionTimeMicros}ฮผs');
return success.output;
},
(failure) {
// Error case - handle specific failures
switch (failure.runtimeType) {
case ValidationFailure:
print('Invalid input: ${failure.message}');
break;
case ExecutionFailure:
print('Execution failed: ${failure.message}');
break;
case ConfigurationFailure:
print('Configuration error: ${failure.message}');
break;
default:
print('Unknown error: ${failure.message}');
}
return <int>[];
},
);
Performance Optimization Guide ๐ #
Algorithm Selection Logic #
AlgoMate automatically selects algorithms based on:
-
Dataset Size
- Small (n < 50): Insertion Sort variants
- Medium (50 โค n < 1000): Binary Insertion Sort
- Large (n โฅ 1000): Merge Sort variants
-
Memory Constraints
- Very Low: In-place algorithms only
- Low: Prefer space-efficient variants
- Unlimited: Best time complexity
-
Data Characteristics
- Pre-sorted: Algorithms with O(n) best case
- Stability required: Stable sort algorithms
- Duplicates: Algorithms handling duplicates well
Custom Performance Tuning #
// Fine-tune for your specific use case
final selector = AlgoMate.createSelector()
.withCustomPolicy((candidates, hint) {
// Your custom selection logic
return candidates.where((strategy) {
return strategy.metadata.timeComplexity.index <= TimeComplexity.nLogN.index;
}).toList();
})
.build();
// Override built-in strategies
selector.registerStrategy(YourOptimizedMergeSort());
Testing Support ๐งช #
AlgoMate provides comprehensive testing utilities:
import 'package:algomate/testing.dart';
void main() {
group('Custom Algorithm Tests', () {
late AlgoSelectorFacade selector;
late MockBenchmarkRunner mockBenchmark;
setUp(() {
mockBenchmark = MockBenchmarkRunner();
selector = AlgoMate.createSelector()
.withBenchmarkRunner(mockBenchmark)
.build();
});
test('should select optimal algorithm for size', () {
final result = selector.sort(
input: List.generate(100, (i) => i),
hint: SelectorHint(n: 100),
);
expect(result.isSuccess, isTrue);
expect(
result.fold((s) => s.selectedStrategy.name, (_) => ''),
equals('binary_insertion_sort'),
);
});
test('should handle edge cases gracefully', () {
final result = selector.sort(input: [], hint: SelectorHint(n: 0));
expect(result.isSuccess, isTrue);
expect(result.fold((s) => s.output, (_) => null), equals([]));
});
});
}
Migration Guide ๐ #
From Manual Algorithm Selection #
Before:
// Manual algorithm selection
List<int> sortData(List<int> data) {
if (data.length < 50) {
return insertionSort(data);
} else {
return mergeSort(data);
}
}
After:
// AlgoMate automatic selection
List<int> sortData(List<int> data) {
final selector = AlgoSelectorFacade.development();
return selector.sort(
input: data,
hint: SelectorHint(n: data.length),
).fold(
(success) => success.output,
(failure) => throw Exception(failure.message),
);
}
From Other Algorithm Libraries #
Before:
// Using dart:core sort
final sorted = list.toList()..sort();
// Using external library
final sorted = QuickSort().sort(list);
After:
// AlgoMate with intelligent selection
final selector = AlgoSelectorFacade.production();
final result = selector.sort(
input: list,
hint: SelectorHint(
n: list.length,
isSorted: false,
memoryBudget: MemoryConstraint.medium,
stability: StabilityPreference.preferred,
),
);
final sorted = result.fold(
(success) => success.output,
(failure) => list, // Fallback to original
);
Troubleshooting ๐ง #
Common Issues #
Q: Algorithm selection seems wrong for my dataset
// A: Provide better hints
final result = selector.sort(
input: data,
hint: SelectorHint(
n: data.length,
isSorted: data.isSorted, // Important hint
memoryBudget: MemoryConstraint.low, // Memory constraint
),
);
Q: Performance is not as expected
// A: Enable detailed benchmarking
final selector = AlgoMate.createSelector()
.withBenchmarking(enabled: true, warmupIterations: 100)
.withDetailedLogging(true)
.build();
// Check execution stats
result.fold(
(success) {
print('Execution time: ${success.executionStats?.executionTimeMicros}ฮผs');
print('Memory used: ${success.executionStats?.memoryUsage}B');
},
(error) => print('Error: $error'),
);
Q: Need custom algorithm selection logic
// A: Implement custom selector policy
class CustomSelectorPolicy extends SelectorPolicy {
@override
List<Strategy<I, O>> rank<I, O>(
List<Strategy<I, O>> candidates,
SelectorHint hint,
) {
// Your custom ranking logic
return candidates..sort((a, b) => myCustomComparison(a, b, hint));
}
}
final selector = AlgoMate.createSelector()
.withCustomPolicy(CustomSelectorPolicy())
.build();