55#pragma once
66
77#include < cstdint>
8+ #include < limits>
89#include < optional>
910#include < unordered_map>
1011#include < utility>
1314
1415#include " netgraph/core/flow.hpp"
1516#include " netgraph/core/flow_graph.hpp"
16- #include " netgraph/core/shortest_paths.hpp"
17+ #include " netgraph/core/algorithms.hpp"
18+ #include " netgraph/core/options.hpp"
1719#include " netgraph/core/types.hpp"
1820
1921namespace netgraph ::core {
2022
2123enum class PathAlg : std::int32_t { SPF = 1 };
2224
25+ // Execution context bundles algorithms and graph handle for clear dependency injection
26+ struct ExecutionContext {
27+ Algorithms* algorithms;
28+ GraphHandle graph;
29+
30+ // Constructor with validation
31+ ExecutionContext (Algorithms& algs, const GraphHandle& gh) noexcept
32+ : algorithms(&algs), graph(gh) {}
33+ };
34+
35+ // Configuration for FlowPolicy behavior. Mirrors the long-form constructor
36+ // parameters in a grouped, maintainable struct.
37+ struct FlowPolicyConfig {
38+ PathAlg path_alg { PathAlg::SPF };
39+ FlowPlacement flow_placement { FlowPlacement::Proportional };
40+ EdgeSelection selection { EdgeSelection{} };
41+ int min_flow_count { 1 };
42+ std::optional<int > max_flow_count { std::nullopt };
43+ std::optional<Cost> max_path_cost { std::nullopt };
44+ std::optional<double > max_path_cost_factor { std::nullopt };
45+ bool shortest_path { false };
46+ bool reoptimize_flows_on_each_placement { false };
47+ int max_no_progress_iterations { 100 };
48+ int max_total_iterations { 10000 };
49+ bool diminishing_returns_enabled { true };
50+ int diminishing_returns_window { 8 };
51+ double diminishing_returns_epsilon_frac { 1e-3 };
52+ };
53+
2354// FlowPolicy orchestrates flow creation, placement, reopt, and removal for a
2455// single demand (src,dst,flowClass) on a shared FlowGraph.
2556class FlowPolicy {
2657public:
27- FlowPolicy (PathAlg path_alg,
58+ // New config-based constructor
59+ FlowPolicy (const ExecutionContext& ctx, const FlowPolicyConfig& cfg)
60+ : ctx_(ctx),
61+ path_alg_ (cfg.path_alg), flow_placement_(cfg.flow_placement), selection_(cfg.selection),
62+ shortest_path_(cfg.shortest_path),
63+ min_flow_count_(cfg.min_flow_count), max_flow_count_(cfg.max_flow_count), max_path_cost_(cfg.max_path_cost),
64+ max_path_cost_factor_(cfg.max_path_cost_factor), reoptimize_flows_on_each_placement_(cfg.reoptimize_flows_on_each_placement),
65+ max_no_progress_iterations_(cfg.max_no_progress_iterations), max_total_iterations_(cfg.max_total_iterations),
66+ diminishing_returns_enabled_(cfg.diminishing_returns_enabled), diminishing_returns_window_(cfg.diminishing_returns_window),
67+ diminishing_returns_epsilon_frac_(cfg.diminishing_returns_epsilon_frac) {
68+ if (flow_placement_ == FlowPlacement::EqualBalanced && !max_flow_count_.has_value ()) {
69+ throw std::invalid_argument (" max_flow_count must be set for EQUAL_BALANCED placement." );
70+ }
71+ }
72+
73+ FlowPolicy (const ExecutionContext& ctx,
74+ PathAlg path_alg,
2875 FlowPlacement flow_placement,
2976 EdgeSelection selection,
3077 int min_flow_count = 1 ,
@@ -38,7 +85,8 @@ class FlowPolicy {
3885 bool diminishing_returns_enabled = true ,
3986 int diminishing_returns_window = 8 ,
4087 double diminishing_returns_epsilon_frac = 1e-3 )
41- : path_alg_(path_alg), flow_placement_(flow_placement), selection_(selection),
88+ : ctx_(ctx),
89+ path_alg_(path_alg), flow_placement_(flow_placement), selection_(selection),
4290 shortest_path_(shortest_path),
4391 min_flow_count_(min_flow_count), max_flow_count_(max_flow_count), max_path_cost_(max_path_cost),
4492 max_path_cost_factor_(max_path_cost_factor), reoptimize_flows_on_each_placement_(reoptimize_flows_on_each_placement),
@@ -87,6 +135,7 @@ class FlowPolicy {
87135 [[nodiscard]] FlowRecord* reoptimize_flow (FlowGraph& fg, const FlowIndex& idx, double headroom);
88136
89137 // Config
138+ ExecutionContext ctx_;
90139 PathAlg path_alg_ { PathAlg::SPF };
91140 FlowPlacement flow_placement_ { FlowPlacement::Proportional };
92141 EdgeSelection selection_ { EdgeSelection{} };
@@ -104,14 +153,9 @@ class FlowPolicy {
104153
105154 // State
106155 std::unordered_map<FlowIndex, FlowRecord, FlowIndexHash> flows_;
107- Cost best_path_cost_ { 0 };
156+ Cost best_path_cost_ { std::numeric_limits<Cost>:: max () };
108157 std::int64_t next_flow_id_ { 0 };
109158
110- // When selection_.multipath == false, freeze exactly one edge per neighbor
111- // pair (u,v) across all flows: subsequent path searches may only reuse the
112- // same chosen EdgeId for that (u,v). Key is (static_cast<uint64_t>(u)<<32)|v.
113- std::unordered_map<std::uint64_t , EdgeId> locked_uv_edge_;
114-
115159 // Static paths (optional)
116160 std::vector<std::tuple<NodeId, NodeId, PredDAG, Cost>> static_paths_;
117161};
0 commit comments