Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,42 @@ jobs:
- uses: codecov/codecov-action@v5
if: github.ref == 'refs/heads/main'
with:
fail_ci_if_error: true
fail_ci_if_error: true
files: ./build/coverage.info
exclude: tests, src/demo
flags: unittests # optional
token: ${{ secrets.CODECOV_TOKEN }} # required
verbose: true # optional (default = false)
verbose: true # optional (default = false)

# AddressSanitizer + UndefinedBehaviorSanitizer
sanitize-asan:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Update submodules
run: git submodule update --init --recursive
- name: Configure with ASAN + UBSAN
run: mkdir build && cd build && cmake -DBUILD_TESTING=ON -DENABLE_ASAN=ON -DENABLE_UBSAN=ON -DCMAKE_BUILD_TYPE=Debug ..
- name: Build
run: cmake --build build
- name: Run tests with ASAN + UBSAN
env:
ASAN_OPTIONS: detect_leaks=1:abort_on_error=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: cd build && ./bin/utests

# ThreadSanitizer (separate job - incompatible with ASAN)
sanitize-tsan:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Update submodules
run: git submodule update --init --recursive
- name: Configure with TSAN
run: mkdir build && cd build && cmake -DBUILD_TESTING=ON -DENABLE_TSAN=ON -DCMAKE_BUILD_TYPE=Debug ..
- name: Build
run: cmake --build build
- name: Run tests with TSAN
env:
TSAN_OPTIONS: halt_on_error=1:second_deadlock_stack=1
run: cd build && ./bin/utests
48 changes: 48 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- **PathResult struct**: Rich search results with `total_cost`, `nodes_expanded`, and `found` flag
- **SearchLimits struct**: Early termination via `max_expansions` or `timeout_ms`
- **Multi-goal search**: `Dijkstra::SearchMultiGoal()` and `AStar::SearchMultiGoal()` find path to nearest goal
- **Nodes expanded counter**: `context.GetNodesExpanded()` for search diagnostics
- **Debug cost assertions**: Validate non-negative, finite costs in debug builds (`debug_checks.hpp`)
- **Production readiness documentation**: `docs/PRODUCTION_READINESS.md`
- **14 new unit tests** for production features (317 total tests)

### Changed
- **Deterministic tie-breaking**: Priority queue comparators now break ties by `vertex_id` for reproducible results

### Fixed
- **Iterator invalidation**: `Edge` and `Vertex::vertices_from` now use stable `Vertex*` pointers instead of iterators that could invalidate on `unordered_map` rehash

## [3.0.1] - 2025-08-19

### Fixed
- Codecov configuration updates

## [3.0.0] - 2025-08-19

### Added
- Unified search framework with CRTP strategy pattern
- Thread-safe concurrent searches via external `SearchContext`
- Generic cost type support with `CostTraits`
- `DynamicPriorityQueue` for efficient priority updates
- Comprehensive exception handling with custom exception types
- Structure validation for graphs and trees
- Extensive documentation and tutorials

### Changed
- Major API redesign for thread safety and generic costs
- Search algorithms now accept `SearchContext&` for thread-safe operation
- Improved memory management with RAII patterns

## [2.x] - Previous Releases

See git history for earlier changes.
27 changes: 27 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ option(BUILD_TESTING "Build tests" OFF)
option(BUILD_SAMPLES "Build samples" ON)
option(STATIC_CHECK "Perform static check" OFF)
option(COVERAGE_CHECK "Perform coverage check" OFF)
option(ENABLE_ASAN "Enable AddressSanitizer" OFF)
option(ENABLE_UBSAN "Enable UndefinedBehaviorSanitizer" OFF)
option(ENABLE_TSAN "Enable ThreadSanitizer" OFF)

# sanity check of the options
if (COVERAGE_CHECK)
Expand All @@ -32,6 +35,30 @@ if (COVERAGE_CHECK)
endif ()
endif ()

# Sanitizer configuration
# Note: ASAN and TSAN are mutually exclusive
if (ENABLE_ASAN AND ENABLE_TSAN)
message(FATAL_ERROR "ASAN and TSAN cannot be enabled simultaneously")
endif ()

if (ENABLE_ASAN)
message(STATUS "AddressSanitizer enabled")
add_compile_options(-fsanitize=address -fno-omit-frame-pointer -g)
add_link_options(-fsanitize=address)
endif ()

if (ENABLE_UBSAN)
message(STATUS "UndefinedBehaviorSanitizer enabled")
add_compile_options(-fsanitize=undefined -fno-omit-frame-pointer -g)
add_link_options(-fsanitize=undefined)
endif ()

if (ENABLE_TSAN)
message(STATUS "ThreadSanitizer enabled")
add_compile_options(-fsanitize=thread -fno-omit-frame-pointer -g)
add_link_options(-fsanitize=thread)
endif ()

## Additional cmake module path
set(USER_CMAKE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
list(APPEND CMAKE_MODULE_PATH "${USER_CMAKE_PATH}/modules")
Expand Down
36 changes: 33 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,43 @@ Optimal space complexity O(m+n) using adjacency lists:
**Concurrent read-only searches** are fully supported:
```cpp
// Each thread gets independent search context
void worker_thread(const Graph<Location>& map) {
void worker_thread(const Graph<Location>* graph) {
SearchContext<Location> context; // Thread-local state
auto path = Dijkstra::Search(map, context, start, goal); // Thread-safe
auto path = Dijkstra::Search(graph, context, start, goal); // Thread-safe
}
```

**Thread-Safety Model:**
- **Graph**: Read-only access only during concurrent searches (const pointer accepted)
- **SearchContext**: Each concurrent search requires its own instance
- **Strategy objects**: Stateless, can be safely shared across threads
- **Legacy API**: Overloads without SearchContext parameter are NOT thread-safe

**Graph modifications** require external synchronization (by design for performance).

### Production Features (v3.1.0)

**Rich search results** with cost and diagnostics:
```cpp
auto result = SearchAlgorithm<...>::SearchWithResult(graph, context, start, goal, strategy);
if (result.found) {
std::cout << "Cost: " << result.total_cost << ", Expanded: " << result.nodes_expanded;
}
```

**Bounded search** for real-time systems:
```cpp
auto limits = SearchLimits::MaxExpansions(1000); // or SearchLimits::Timeout(50)
auto result = SearchAlgorithm<...>::SearchWithLimits(graph, context, start, goal, strategy, limits);
```

**Multi-goal search** (find nearest goal):
```cpp
std::vector<Location> goals = {charging_station1, charging_station2, charging_station3};
auto result = Dijkstra::SearchMultiGoal(graph, context, robot_position, goals);
// result.goal_index tells which goal was reached
```

---

## Build & Integration
Expand Down Expand Up @@ -138,7 +167,7 @@ cmake --build .
./bin/simple_graph_demo
./bin/thread_safe_search_demo

# Run comprehensive tests (199 tests, 100% pass rate)
# Run comprehensive tests (317 tests, 100% pass rate)
./bin/utests
```

Expand Down Expand Up @@ -180,6 +209,7 @@ auto path = Dijkstra::Search(map, {0, "Home"}, {1, "Work"});
- **[Architecture Overview](docs/architecture.md)** - System design and template patterns
- **[Advanced Features](docs/advanced_features.md)** - Custom costs, validation, thread safety
- **[Search Algorithms Guide](docs/search_algorithms.md)** - Deep dive into A*, Dijkstra, BFS, DFS
- **[Production Readiness](docs/PRODUCTION_READINESS.md)** - Robotics deployment guide

### **For Contributors**
- **[Performance Testing](docs/performance_testing.md)** - Benchmarking and optimization
Expand Down
Loading