C++ class templates for graph construction and search
✅ SearchContext Modernized: Removed CostType
template parameter and made it fully attribute-based
✅ Flexible Cost Storage: Any cost type can now be stored using attributes
✅ Backward Compatibility: Legacy property access still works through property wrappers
// BEFORE: Limited to single cost type
SearchContext<State, Transition, StateIndexer, double> context; // Locked to double
// AFTER: Any cost types in same context
SearchContext<State, Transition, StateIndexer> context;
auto& info = context.GetSearchInfo(vertex_id);
info.SetGCost(10.5); // double
info.SetAttribute("hop_count", 3); // int
info.SetAttribute("fuel_cost", FuelData{12.1, "diesel"}); // custom type
info.SetAttribute("risk_level", RiskLevel::HIGH); // enum
// Cost calculation using vertex attributes + search context
double CalculateNavigationCost(vertex_iterator vertex, const SearchContext& context) {
const auto& state = vertex->state;
// Base cost from search
double base_time = context.GetSearchInfo(vertex->vertex_id).GetGCost<double>();
// Vertex-specific penalties
double traffic_penalty = state.traffic_level * 3.0;
double terrain_penalty = (state.terrain == "mountain") ? 15.0 : 0.0;
// Context-specific data
double fuel_consumed = context.GetSearchInfo(vertex->vertex_id)
.GetAttributeOr<double>("fuel_consumed", 0.0);
return base_time + traffic_penalty + terrain_penalty + fuel_consumed * 0.1;
}
// Use with any search algorithm
SearchContext<NavigationState, RoadSegment, DefaultIndexer<NavigationState>> context;
context.SetCostCalculator(CalculateNavigationCost);
// Same search context handles multiple cost dimensions
auto& info = context.GetSearchInfo(vertex_id);
// Different cost types in same algorithm
info.SetAttribute("time_cost", 45.5); // double (minutes)
info.SetAttribute("energy_cost", 12); // int (kWh)
info.SetAttribute("comfort_score", 8.5f); // float (1-10 scale)
info.SetAttribute("route_type", RouteType::SCENIC); // enum
// Flexible cost combination
double weighted_cost = time_weight * info.GetAttribute<double>("time_cost") +
energy_weight * info.GetAttribute<int>("energy_cost") +
comfort_weight * info.GetAttribute<float>("comfort_score");
// Search algorithms work with ANY cost representation
template<typename State, typename Transition, typename StateIndexer>
class ModernDijkstraStrategy {
double GetPriority(const SearchInfo& info) const {
// Can access any cost attribute
return info.GetGCost<double>(); // or GetAttribute<CustomCost>("g_cost")
}
void RelaxVertex(SearchInfo& current, SearchInfo& successor, double edge_cost) {
double new_cost = current.GetGCost<double>() + edge_cost;
if (new_cost < successor.GetGCost<double>()) {
successor.SetGCost(new_cost);
// Can also set algorithm-specific attributes
successor.SetAttribute("relaxation_count",
successor.GetAttributeOr<int>("relaxation_count", 0) + 1);
}
}
};
GetGCost<T>()
, SetGCost<T>()
MakeXStrategy
helper functionsStatus: COMPLETE - All 188 unit tests passing, all search algorithm tests passing
// BEFORE
template <typename State, typename Transition, typename StateIndexer, typename CostType = double>
class SearchContext;
// AFTER
template <typename State, typename Transition, typename StateIndexer>
class SearchContext;
// BEFORE: Fixed CostType
CostType GetGCost() const { return attributes.GetAttribute<CostType>("g_cost"); }
// AFTER: Flexible types
template<typename T = double>
T GetGCost() const { return GetAttributeOr<T>("g_cost", std::numeric_limits<T>::max()); }
// BEFORE
template<typename State, typename Transition, typename StateIndexer, typename CostType = double>
class DijkstraStrategy;
// AFTER
template<typename State, typename Transition, typename StateIndexer>
class DijkstraStrategy;
SearchContext<MyState, double, DefaultIndexer<MyState>> context;
auto& info = context.GetSearchInfo(1);
// Type-flexible cost setting
info.SetGCost(10.5); // double (default)
info.SetGCost<float>(10.5f); // explicit float
info.SetGCost<int>(10); // explicit int
// Type-flexible cost getting
double d_cost = info.GetGCost<double>(); // explicit double
auto default_cost = info.GetGCost(); // defaults to double
int i_cost = info.GetGCost<int>(); // explicit int
struct MultiCriteriaCost {
double time, fuel, comfort;
MultiCriteriaCost(double t, double f, double c) : time(t), fuel(f), comfort(c) {}
// Required operators for search algorithms
bool operator<(const MultiCriteriaCost& other) const {
return (time + fuel + comfort) < (other.time + other.fuel + other.comfort);
}
};
// Use custom cost type
auto& info = context.GetSearchInfo(1);
info.SetGCost(MultiCriteriaCost{45.0, 12.5, 7.0});
auto cost = info.GetGCost<MultiCriteriaCost>();
// Cost calculator that uses vertex attributes + search context
auto cost_calculator = [](auto vertex, const auto& context) {
auto& info = context.GetSearchInfo(vertex->vertex_id);
// Combine multiple cost sources
double base_cost = info.GetGCost<double>();
double vertex_penalty = vertex->state.CalculatePenalty();
double context_modifier = info.GetAttributeOr<double>("difficulty_modifier", 1.0);
return base_cost * context_modifier + vertex_penalty;
};
// Apply to search
SearchContext<RichState, Transition, DefaultIndexer<RichState>> context;
context.SetCostCalculator(cost_calculator);
// OLD CODE (still works due to backward compatibility)
auto& info = context.GetSearchInfo(vertex_id);
info.g_cost = 10.5;
double cost = info.g_cost;
// NEW RECOMMENDED CODE
auto& info = context.GetSearchInfo(vertex_id);
info.SetGCost(10.5);
double cost = info.GetGCost<double>();
// OR even more flexible
info.SetAttribute("time_cost", 10.5);
info.SetAttribute("fuel_cost", 3.2f);
info.SetAttribute("comfort_penalty", 8);
// OLD: Algorithm tied to specific cost type
template<typename State, typename Transition, typename StateIndexer, typename CostType>
class MySearchAlgorithm;
// NEW: Algorithm works with any cost type via attributes
template<typename State, typename Transition, typename StateIndexer>
class MySearchAlgorithm {
void ProcessVertex(SearchInfo& info) {
// Use attributes for any cost type
auto current_cost = info.GetAttribute<double>("my_algorithm_cost");
info.SetAttribute("processing_time", getCurrentTime());
}
};
The CostType removal provides maximum flexibility while maintaining full backward compatibility. Users can:
This design makes the library future-proof and ready for complex real-world applications like multi-criteria pathfinding, uncertainty-aware planning, and dynamic cost optimization.