libgraph

C++ class templates for graph construction and search


Project maintained by rxdu Hosted on GitHub Pages — Theme by mattgraham

CostType Removal - Complete Design Summary

What We’ve Accomplished

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

Design Benefits

1. Maximum Flexibility

// 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

2. Cost Comparator Ready

// 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);

3. Multi-Criteria Optimization

// 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");

4. Algorithm Independence

// 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);
        }
    }
};

Implementation Status

✅ Completed

✅ Completed

📋 Completed Work

Status: COMPLETE - All 188 unit tests passing, all search algorithm tests passing

Key Technical Changes

SearchContext Template Signature

// BEFORE
template <typename State, typename Transition, typename StateIndexer, typename CostType = double>
class SearchContext;

// AFTER  
template <typename State, typename Transition, typename StateIndexer>
class SearchContext;

Cost Accessor Methods

// 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()); }

Algorithm Template Signatures

// BEFORE
template<typename State, typename Transition, typename StateIndexer, typename CostType = double>
class DijkstraStrategy;

// AFTER
template<typename State, typename Transition, typename StateIndexer>  
class DijkstraStrategy;

Usage Examples

Basic Cost Operations

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

Custom Cost Types

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>();

Advanced Cost Calculation

// 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);

Performance Impact

Memory Usage

Runtime Performance

Migration Guide

For Library Users

// 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);

For Algorithm Developers

// 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());
    }
};

Conclusion

The CostType removal provides maximum flexibility while maintaining full backward compatibility. Users can:

  1. Mix cost types in the same search context
  2. Define custom cost comparators that use vertex attributes
  3. Implement domain-specific optimizations easily
  4. Switch optimization strategies at runtime
  5. Extend algorithms with custom cost dimensions

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.