LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
wf_link_matrix.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_API_WF_WF_LINK_MATRIX_H
6#define LINE_API_WF_WF_LINK_MATRIX_H
7
8/**
9 * @file
10 * @ingroup api_wf
11 * Shared conventions of the workflow pattern detectors.
12 *
13 * The four detectors ported from jar/src/main/java/jline/api/wf/ all read the
14 * same "link matrix": one row per directed edge, column 0 the source node id,
15 * column 1 the target node id, column 2 the routing probability of the edge.
16 * Node ids are integers carried in the numeric type, exactly as the Java
17 * Matrix does, so this header only holds the accessor that turns column 0 or 1
18 * back into an id (truncating, like the Java (int) cast) and the adjacency
19 * builders that three of the four detectors would otherwise duplicate.
20 *
21 * DIVERGENCE, deliberate: the Java detectors key their adjacency on HashMap and
22 * collect results in HashSet, so the ORDER of the detected patterns, and in
23 * findCommonJoinPoint even WHICH join point is returned, depend on Java's hash
24 * iteration order. That is not a property of the workflow. The port uses
25 * ordered containers throughout, so every result is in ascending node order and
26 * is reproducible; where the Java picks an arbitrary element of a set the port
27 * picks the smallest. Sets of size one - the only case the callers validate -
28 * are unaffected.
29 */
30
31#include <cstddef>
32#include <map>
33#include <set>
34#include <vector>
35
36#include "line/num/number.h"
37#include "line/util/error.h"
38#include "line/util/matrix.h"
39
40namespace line {
41namespace wf {
42
43namespace detail {
44
45/** Node id in column j of edge i, truncated as the Java (int) cast does. */
46template <class T>
47int wf_id(const Matrix<T>& linkMatrix, std::size_t i, std::size_t j) {
48 return static_cast<int>(num_traits<T>::to_double(linkMatrix(i, j)));
49}
50
51template <class T>
52void wf_check(const Matrix<T>& linkMatrix) {
53 if (linkMatrix.cols() < 3)
54 throw InputError("wf: the link matrix needs three columns (from, to, probability)");
55}
56
57/** node -> successors, in ascending order. */
58template <class T>
59std::map<int, std::vector<int>> wf_adjacency(const Matrix<T>& linkMatrix) {
60 wf_check(linkMatrix);
61 std::map<int, std::vector<int>> adj;
62 for (std::size_t i = 0; i < linkMatrix.rows(); ++i)
63 adj[wf_id(linkMatrix, i, 0)].push_back(wf_id(linkMatrix, i, 1));
64 return adj;
65}
66
67/** node -> (successor, probability), in edge order. */
68template <class T>
69std::map<int, std::vector<std::pair<int, T>>> wf_adjacency_prob(const Matrix<T>& linkMatrix) {
70 wf_check(linkMatrix);
71 std::map<int, std::vector<std::pair<int, T>>> adj;
72 for (std::size_t i = 0; i < linkMatrix.rows(); ++i)
73 adj[wf_id(linkMatrix, i, 0)].push_back(
74 std::make_pair(wf_id(linkMatrix, i, 1), linkMatrix(i, 2)));
75 return adj;
76}
77
78/** node -> predecessors, in edge order. */
79template <class T>
80std::map<int, std::vector<int>> wf_reverse_adjacency(const Matrix<T>& linkMatrix) {
81 wf_check(linkMatrix);
82 std::map<int, std::vector<int>> radj;
83 for (std::size_t i = 0; i < linkMatrix.rows(); ++i)
84 radj[wf_id(linkMatrix, i, 1)].push_back(wf_id(linkMatrix, i, 0));
85 return radj;
86}
87
88} // namespace detail
89
90} // namespace wf
91} // namespace line
92
93#endif // LINE_API_WF_WF_LINK_MATRIX_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Dense matrix and non-owning view.
Number-type abstraction for the templated API port.