5#ifndef LINE_API_WF_WORKFLOW_MANAGER_H
6#define LINE_API_WF_WORKFLOW_MANAGER_H
136inline double wf_factorial(std::size_t n) {
138 for (std::size_t k = 2; k <= n; ++k) f *= static_cast<double>(k);
146 if (sequences.empty())
return 1.0;
147 std::size_t total = 0;
148 for (std::size_t i = 0; i < sequences.size(); ++i) total += sequences[i].size();
149 const double avg =
static_cast<double>(total) /
static_cast<double>(sequences.size());
150 return std::min(1.0, avg / 5.0);
155 if (parallels.empty())
return 1.0;
156 std::size_t total = 0;
157 for (std::size_t i = 0; i < parallels.size(); ++i) total += parallels[i].size();
158 const double avg =
static_cast<double>(total) /
static_cast<double>(parallels.size());
159 return std::max(0.1, 1.0 - (avg - 2.0) / 10.0);
170 if (loops.empty())
return 1.0;
177 if (branches.empty())
return 1.0;
179 for (std::size_t i = 0; i < branches.size(); ++i)
181 return sum /
static_cast<double>(branches.size());
188 double score =
static_cast<double>(nodes) +
static_cast<double>(links) * 0.5;
189 for (std::size_t i = 0; i < p.
sequences.size(); ++i) {
190 const double n =
static_cast<double>(p.
sequences[i].size());
191 score += n * n * 0.1;
193 for (std::size_t i = 0; i < p.
parallels.size(); ++i)
194 score += detail::wf_factorial(p.
parallels[i].size()) * 0.2;
195 score +=
static_cast<double>(p.
loops.size()) * 10.0;
196 for (std::size_t i = 0; i < p.
branches.size(); ++i)
197 score +=
static_cast<double>(p.
branches[i].branchNodes.size()) * 2.0;
249 for (std::size_t i = 0; i < p.
sequences.size(); ++i) {
250 const double n =
static_cast<double>(p.
sequences[i].size());
255 for (std::size_t i = 0; i < p.
parallels.size(); ++i) {
262 for (std::size_t i = 0; i < p.
branches.size(); ++i) {
285 const std::vector<WfSolver>&
solvers,
287 std::vector<std::pair<WfSolver, BenchmarkRow>> out;
288 for (std::size_t i = 0; i <
solvers.size(); ++i) {
290 const std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
293 const std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
296 std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(t1 - t0)
298 const std::size_t n = QN.rows() * QN.cols();
299 row.hasResults = (n > 0);
301 for (std::size_t rr = 0; rr < QN.rows(); ++rr)
302 for (std::size_t cc = 0; cc < QN.cols(); ++cc)
304 row.totalQueueLength =
sum;
305 row.avgQueueLength = (n > 0) ?
sum /
static_cast<double>(n) : 0.0;
306 }
catch (
const std::exception& e) {
308 const char* what = e.what();
309 row.error = (what !=
nullptr && what[0] !=
'\0') ? what :
"Unknown error";
311 out.push_back(std::make_pair(
solvers[i], row));
318 std::vector<WfSolver> v;
332 if (
sn.nodes.empty()) v.
issues.push_back(
"Network has no nodes");
334 v.
issues.push_back(
"Workflow analysis validation failed");
336 v.
issues.push_back(
"Workflow-enhanced solver selection validation failed");
344inline std::string fixed2(
double x) {
345 std::ostringstream s;
346 s.setf(std::ios::fixed);
353inline std::string plain(
double x) {
354 std::ostringstream s;
373 std::ostringstream o;
376 o <<
" \"solver_recommendation\": \"" << rec <<
"\",\n";
378 o <<
" \"patterns\": {\n";
379 o <<
" \"sequences\": " << p.
sequences.size() <<
",\n";
380 o <<
" \"parallels\": " << p.
parallels.size() <<
",\n";
381 o <<
" \"loops\": " << p.
loops.size() <<
",\n";
382 o <<
" \"branches\": " << p.
branches.size() <<
"\n";
386 o <<
"Metric,Value\n";
387 o <<
"Recommended Solver," << rec <<
"\n";
389 o <<
"Sequences," << p.
sequences.size() <<
"\n";
390 o <<
"Parallels," << p.
parallels.size() <<
"\n";
391 o <<
"Loops," << p.
loops.size() <<
"\n";
392 o <<
"Branches," << p.
branches.size() <<
"\n";
394 o <<
"=== Workflow Analysis Summary ===\n\n";
395 o <<
"Recommended Solver: " << rec <<
"\n";
397 o <<
"Detected Patterns:\n";
398 o <<
"- Sequences: " << p.
sequences.size() <<
"\n";
399 o <<
"- Parallels: " << p.
parallels.size() <<
"\n";
400 o <<
"- Loops: " << p.
loops.size() <<
"\n";
401 o <<
"- Branches: " << p.
branches.size() <<
"\n\n";
A network plus its refreshed NetworkStruct.
The exception types the port throws.
Dense matrix and non-owning view.
WorkflowAnalysis< T > analyze_workflow(const WorkflowRepresentation< T > &w)
Detect, collapse, and report.
ExtendedSolverRecommendation< T > recommend_solver_with_workflow_analysis(const qn::NetworkStruct< T > &sn)
The entry point: analyse the workflow, then let it amend the base choice.
bool validate_workflow_enhancement(const qn::NetworkStruct< T > &sn)
The reference's self-check: a usable recommendation over a valid analysis.
WorkflowAnalysisResult< T > analyze_workflow_full(const qn::NetworkStruct< T > &sn)
The facade's headline call: analysis, recommendation, insights, metrics.
std::string wf_solver_name(WfSolver s)
The reference's own spelling of each choice.
bool validate_analysis(const WorkflowAnalysis< T > &a)
The collapsed workflow is consistent and every detected pattern validates.
std::vector< std::string > get_optimization_recommendations(const WorkflowAnalysis< T > &a)
The reference's recommendation strings, in its order.
double calculate_complexity_score(std::size_t nodes, std::size_t links, const DetectedPatterns< T > &p)
The weighted size-plus-pattern score behind the complexity level.
WfSolver
The solvers the reference chooses among.
double calculate_sequence_efficiency(const std::vector< std::vector< int > > &sequences)
avg sequence length capped at 5, the reference's saturation point.
std::string quick_analysis(const qn::NetworkStruct< T > &sn)
The reference's one-call summary.
WfExportFormat
The export formats the facade offers.
double calculate_parallel_efficiency(const std::vector< std::vector< int > > ¶llels)
Efficiency falls linearly past two-way parallelism, floored at 0.1.
std::vector< std::pair< WfSolver, BenchmarkRow > > benchmark_solvers(const std::vector< WfSolver > &solvers, const std::function< Matrix< T >(WfSolver)> &runner)
Time each solver and aggregate its queue lengths.
WfSolver create_optimal_solver(const qn::NetworkStruct< T > &sn)
The chosen solver alone, i.e.
std::vector< WfSolver > default_benchmark_solvers()
The reference's default benchmark set.
DetectedPatterns< T > get_pattern_analysis(const qn::NetworkStruct< T > &sn)
The patterns alone.
ComplexityReport< T > generate_complexity_report(const qn::NetworkStruct< T > &sn)
The complexity report, with the reference's four bands on the score.
BranchDiversity< T > calculate_branch_diversity(const BranchPattern< T > &pattern)
Shannon entropy of the branch probabilities, the same entropy normalized by log(n),...
WorkflowValidation validate_workflow(const qn::NetworkStruct< T > &sn)
The model is well formed and both analyses validate.
OptimizationInsights get_optimization_insights(const qn::NetworkStruct< T > &sn)
All three advisory blocks for one model.
double calculate_branch_efficiency(const std::vector< BranchPattern< T > > &branches)
The mean NORMALIZED entropy over the branches, i.e.
std::string export_analysis(const WorkflowAnalysisResult< T > &a, WfExportFormat format=WfExportFormat::Summary)
Render the analysis.
double calculate_loop_efficiency(const std::vector< int > &loops)
The reference's placeholder: any loop at all costs half the efficiency.
WfSolver get_optimal_solver(const qn::NetworkStruct< T > &sn)
The chosen solver without the rest of the report.
WorkflowRepresentation< T > wf_from_struct(const qn::NetworkStruct< T > &sn)
Build a workflow representation from a NetworkStruct.
std::vector< std::string > get_workflow_recommendations(const qn::NetworkStruct< T > &sn)
The recommendation strings alone.
WorkflowPerformanceMetrics calculate_performance_metrics(const WorkflowAnalysis< T > &a, const ExtendedSolverRecommendation< T > &r)
The six metrics of the analysis result.
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
One row of the benchmark table.
Mirrors the Java BranchPattern.
The complexity report, one band per pattern family plus the overall score.
std::string complexityLevel
LOW, MEDIUM, HIGH or VERY_HIGH.
PatternComplexityEntry branches
PatternComplexityEntry parallels
PatternComplexityEntry sequences
PatternComplexityEntry loops
double overallComplexityScore
WorkflowComplexity< T > originalMetrics
WorkflowComplexity< T > optimizedMetrics
Everything the four detectors found.
std::vector< std::vector< int > > sequences
std::vector< BranchPattern< T > > branches
std::vector< std::vector< int > > parallels
What the recommendation returns: the choice and why.
The advisory text the reference's getOptimizationInsights assembles.
Per-pattern-family complexity, one entry of the report's patternComplexity.
std::size_t totalNodes
totalBranches for the branch family
Everything analyze_workflow_full returns, i.e.
OptimizationInsights optimizationInsights
WorkflowPerformanceMetrics performanceMetrics
ExtendedSolverRecommendation< T > solverRecommendation
WorkflowAnalysis< T > patternAnalysis
What analyze_workflow returns.
WorkflowStatistics< T > statistics
DetectedPatterns< T > detectedPatterns
The reference's complexity map, for either the original or the collapsed graph.
What validate_workflow reports.
std::vector< std::string > issues
The workflow analyzer: detect every pattern, collapse them, report the two complexities and the recom...
Workflow-aware solver recommendation: the port of jar/src/main/java/jline/api/wf/Wf_auto_integration....