LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
sym_engine.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_SYM_SYM_ENGINE_H
6#define LINE_API_SYM_SYM_ENGINE_H
7
8/**
9 * @file
10 * @ingroup api_sym
11 * Computer algebra operations LINE needs, as seen by this port.
12 *
13 * Port of jline.api.sym.SymEngine. C++ has no computer algebra system any more
14 * than Java does, so every operation here is delegated to an external engine;
15 * SageRestEngine is the SageMath implementation and is resolved by
16 * sym_engines.h. Expressions cross the interface as plain ASCII infix strings,
17 * e.g. "2*x1 - 3*x2".
18 *
19 * EXPRESSION STRINGS ARE NOT COMPARABLE ACROSS CODEBASES, and not even across
20 * engine versions: the symbol numbering x1..xE follows event enumeration order
21 * and printed normal forms depend on the engine. Compare by substituting values
22 * with eval() and comparing numbers; a string diff against the JAR's output is
23 * a false failure waiting to happen.
24 *
25 * ABSENT VALUES. Java returns null for a field the request did not ask for.
26 * Here an absent scalar is the empty string and an absent list or matrix is
27 * empty, with an explicit `has*` flag where emptiness would otherwise be
28 * ambiguous.
29 */
30
31#include <map>
32#include <string>
33#include <vector>
34
35#include "line/util/error.h"
36
37namespace line {
38namespace sym {
39
40/** The symbolic backend is unreachable, or rejected the request. */
41class SymEngineError : public Error {
42public:
43 explicit SymEngineError(const std::string& what) : Error(what) {}
44};
45
46/** Symbolic stationary distribution of a CTMC. */
47/** One weighted sum of the stationary distribution, or a ratio of two. */
49 std::string name; ///< Caller supplied name
50 std::string expr; ///< The value as a rational function, or "undefined"
51 std::string num; ///< Numerator of `expr`, empty when undefined
52 std::string den; ///< Denominator of `expr`, empty when undefined
53 /**
54 * Why the value is undefined, empty otherwise.
55 *
56 * A ratio whose denominator measure is identically zero over the whole rate
57 * space has no value. The numeric arms sweep such a 0/0 to zero with an
58 * isnan pass, which is a defensible cleanup of floating point dust and an
59 * indefensible answer for an exact one.
60 */
61 std::string reason;
62
63 /** True if this measure has a value. */
64 bool isDefined() const { return reason.empty(); }
65};
66
67/** A ratio of two measures, by their index into the weight block. */
68struct RatioSpec {
69 std::string name; ///< Name of the resulting measure
70 std::size_t num = 0; ///< Index of the numerator measure
71 std::size_t den = 0; ///< Index of the denominator measure
72};
73
74/** Stationary distribution together with the measures taken from it. */
76 std::vector<std::string> pi; ///< Stationary probability of each state
77 std::vector<std::string> num; ///< Numerator of each entry over `den`
78 std::string den = "1"; ///< Common denominator of the whole vector
79 int nConnComp = 1; ///< Weakly connected components
80 std::vector<int> connComp; ///< Component index of each state, one based
81 std::vector<CtmcMeasure> measures; ///< One per weight vector, in order
82 std::vector<CtmcMeasure> ratios; ///< One per requested ratio, in order
83};
84
85/** First passage time transform and moments. */
86struct Passage {
87 std::string lst; ///< The transform L(s), empty if not requested
88 std::string lstNum; ///< Numerator of `lst`
89 std::string lstDen; ///< Denominator of `lst`
90 std::vector<std::string> lstAll; ///< Per start state transform
91 std::vector<std::string> moments; ///< Moments 1..nmax for the initial law
92 std::vector<std::vector<std::string>> momAll; ///< Per start state moments
93 std::vector<int> unreachable; ///< States that cannot reach the target
94};
95
97 std::vector<std::string> pi; ///< Stationary probability of each state, as an expression
98 std::vector<std::string> num; ///< Numerator of each entry over the common denominator
99 std::string den = "1"; ///< Common denominator of the whole vector
100 int nConnComp = 1; ///< Weakly connected components of the generator
101 std::vector<int> connComp; ///< Component index of each state, one based
102};
103
104/**
105 * Exact parametric sensitivity, following Trivedi and Bobbio (2017), Sec. 9.7.
106 *
107 * As in `@SolverCTMC/getSensitivity.m`, dr/dtheta is taken to be zero: a reward
108 * whose rates themselves depend on theta needs the second term of Eq. (9.83)
109 * and is not covered here.
110 */
112 std::vector<std::string> pi; ///< Stationary distribution
113 std::vector<std::string> dpi; ///< Derivative of the distribution with respect to theta
114 std::string Er; ///< Mean reward, empty if no reward was given
115 std::string S; ///< Unscaled sensitivity d(E[r])/dtheta, Eq. (9.79)
116 std::string SS; ///< Scaled sensitivity (theta/E[r]) d(E[r])/dtheta, Eq. (9.80)
117 bool hasReward = false; ///< Whether Er, S and SS were computed
118};
119
120/** Symbolic analysis of a fluid vector field. */
121struct FluidODEs {
122 std::vector<std::vector<std::string>> jacobian; ///< d f_i / d x_j
123 std::vector<std::string> latex; ///< LaTeX form of each right hand side
124 std::vector<std::map<std::string, std::string>> equilibria; ///< variable -> expression
125 bool hasJacobian = false;
126 bool hasLatex = false;
127 bool hasEquilibria = false;
128};
129
130/** A computer algebra backend. */
132public:
133 virtual ~SymEngine() {}
134
135 /** Name of the backing engine, e.g. "sage". */
136 virtual std::string name() const = 0;
137
138 /** True if the engine answers a health probe. */
139 virtual bool isAvailable() const = 0;
140
141 /**
142 * Symbolic stationary distribution of a CTMC, pi Q = 0 with sum(pi) = 1.
143 *
144 * @param Q generator entries as expression strings, row major and square
145 * @param symbols the symbols appearing in Q, e.g. x1..xE
146 * @return the solution, with pi also split over a common denominator
147 */
148 virtual CtmcSolution solveCTMC(const std::vector<std::vector<std::string>>& Q,
149 const std::vector<std::string>& symbols) = 0;
150
151 /**
152 * Exact parametric sensitivity of a steady-state reward.
153 *
154 * @param Q generator entries as expression strings, row major
155 * @param symbols the symbols appearing in Q
156 * @param theta the symbol to differentiate with respect to
157 * @param reward reward rate per state, empty for the distribution alone
158 * @return the sensitivity of the distribution and, if a reward is given, of its mean
159 */
160 virtual SymSensitivity ctmcSensitivity(const std::vector<std::vector<std::string>>& Q,
161 const std::vector<std::string>& symbols,
162 const std::string& theta,
163 const std::vector<std::string>& reward) = 0;
164
165 /**
166 * Rewrites expressions into a normal form.
167 *
168 * @param exprs the expressions
169 * @param form one of simplify, factor, together, cancel, expand, latex
170 * @return the rewritten expressions, in the input order
171 */
172 /**
173 * Stationary distribution and a set of weighted sums of it.
174 *
175 * Every mean SolverCTMC reports is a NUMERIC linear functional of pi, so
176 * the caller builds one weight vector per measure with no algebra at all
177 * and this one round trip returns each `w . pi` as a rational function: a
178 * throughput is `pi . depRates`, a queue length is `pi . stateSpaceAggr`, a
179 * marginal probability is `pi . indicator` and a mean reward is `pi . r`.
180 *
181 * @param Q generator entries as expression strings, row major
182 * @param symbols the symbols appearing in Q
183 * @param weights one row per measure, each of length Q.size(); entries are
184 * parsed in the same field as Q, so an expression is
185 * admissible and not only a number
186 * @param names a name per weight row, or empty for w0, w1, ...
187 * @param ratios ratios of two measures, or empty for none
188 */
189 virtual CtmcMeasures ctmcMeasures(const std::vector<std::vector<std::string>>& Q,
190 const std::vector<std::string>& symbols,
191 const std::vector<std::vector<std::string>>& weights,
192 const std::vector<std::string>& names,
193 const std::vector<RatioSpec>& ratios) = 0;
194
195 /**
196 * First passage time into a target set: the transform and the moments.
197 *
198 * With A the complement of the target, S = Q(A,A) the sub-generator,
199 * s0 = -S*1 the exit vector and alpha the initial law restricted to A,
200 * following Harrison and Knottenbelt (2002),
201 *
202 * L(s) = alpha (sI - S)^-1 s0 + atom Eqs. 1-2
203 * (-S) M(n) = n M(n-1), M(0) = 1 Eq. 3
204 *
205 * THE MOMENTS COME FROM THE RECURSION, not from differentiating L: it
206 * carries no transform symbol, stays in the same fraction field and is
207 * `nmax` right solves against one matrix. Differentiating would leave the
208 * fraction field, and the evaluation at s = 0 can hit 0/0 where a factor of
209 * s failed to cancel.
210 *
211 * @param S the sub-generator on the non-target states, row major
212 * @param s0 the exit vector -S*1
213 * @param alpha the initial law restricted to the non-target states
214 * @param atom the initial mass already inside the target set
215 * @param symbols the rate symbols appearing in S
216 * @param svar the transform symbol; adjoined to the field only when a
217 * transform is asked for, and required to differ from every
218 * rate symbol
219 * @param want any of lst, lstall, moments, momall
220 * @param nmax highest moment order, at least 1
221 */
222 virtual Passage ctmcPassage(const std::vector<std::vector<std::string>>& S,
223 const std::vector<std::string>& s0,
224 const std::vector<std::string>& alpha,
225 const std::string& atom,
226 const std::vector<std::string>& symbols,
227 const std::string& svar,
228 const std::vector<std::string>& want, int nmax) = 0;
229
230 virtual std::vector<std::string> simplify(const std::vector<std::string>& exprs,
231 const std::string& form) = 0;
232
233 /**
234 * Differentiates expressions.
235 *
236 * @param exprs the expressions
237 * @param variable the differentiation variable
238 * @param order the order of the derivative, at least 1
239 * @return the derivatives, in the input order
240 */
241 virtual std::vector<std::string> diff(const std::vector<std::string>& exprs,
242 const std::string& variable, int order) = 0;
243
244 /**
245 * Substitutes values for symbols and evaluates.
246 *
247 * @param exprs the expressions
248 * @param assignment value of each symbol
249 * @return the numeric values, NaN where a free symbol remains
250 */
251 virtual std::vector<double> eval(const std::vector<std::string>& exprs,
252 const std::map<std::string, double>& assignment) = 0;
253
254 /**
255 * Jacobian, LaTeX form and equilibria of a fluid vector field.
256 *
257 * @param rhs the right hand side of dx/dt, one expression per state variable
258 * @param vars the state variable names
259 * @param want any of jacobian, latex, equilibria
260 * @return the requested items
261 */
262 virtual FluidODEs fluidODEs(const std::vector<std::string>& rhs,
263 const std::vector<std::string>& vars,
264 const std::vector<std::string>& want) = 0;
265};
266
267} // namespace sym
268} // namespace line
269
270#endif // LINE_API_SYM_SYM_ENGINE_H
Error(const std::string &what)
Definition error.h:33
SymEngineError(const std::string &what)
Definition sym_engine.h:43
A computer algebra backend.
Definition sym_engine.h:131
virtual bool isAvailable() const =0
True if the engine answers a health probe.
virtual std::string name() const =0
Name of the backing engine, e.g.
virtual CtmcSolution solveCTMC(const std::vector< std::vector< std::string > > &Q, const std::vector< std::string > &symbols)=0
Symbolic stationary distribution of a CTMC, pi Q = 0 with sum(pi) = 1.
virtual std::vector< std::string > diff(const std::vector< std::string > &exprs, const std::string &variable, int order)=0
Differentiates expressions.
virtual SymSensitivity ctmcSensitivity(const std::vector< std::vector< std::string > > &Q, const std::vector< std::string > &symbols, const std::string &theta, const std::vector< std::string > &reward)=0
Exact parametric sensitivity of a steady-state reward.
virtual std::vector< std::string > simplify(const std::vector< std::string > &exprs, const std::string &form)=0
virtual std::vector< double > eval(const std::vector< std::string > &exprs, const std::map< std::string, double > &assignment)=0
Substitutes values for symbols and evaluates.
virtual FluidODEs fluidODEs(const std::vector< std::string > &rhs, const std::vector< std::string > &vars, const std::vector< std::string > &want)=0
Jacobian, LaTeX form and equilibria of a fluid vector field.
virtual CtmcMeasures ctmcMeasures(const std::vector< std::vector< std::string > > &Q, const std::vector< std::string > &symbols, const std::vector< std::vector< std::string > > &weights, const std::vector< std::string > &names, const std::vector< RatioSpec > &ratios)=0
Rewrites expressions into a normal form.
virtual Passage ctmcPassage(const std::vector< std::vector< std::string > > &S, const std::vector< std::string > &s0, const std::vector< std::string > &alpha, const std::string &atom, const std::vector< std::string > &symbols, const std::string &svar, const std::vector< std::string > &want, int nmax)=0
First passage time into a target set: the transform and the moments.
The exception types the port throws.
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
Symbolic stationary distribution of a CTMC.
Definition sym_engine.h:48
std::string name
Caller supplied name.
Definition sym_engine.h:49
std::string num
Numerator of expr, empty when undefined.
Definition sym_engine.h:51
std::string reason
Why the value is undefined, empty otherwise.
Definition sym_engine.h:61
std::string expr
The value as a rational function, or "undefined".
Definition sym_engine.h:50
std::string den
Denominator of expr, empty when undefined.
Definition sym_engine.h:52
bool isDefined() const
True if this measure has a value.
Definition sym_engine.h:64
Stationary distribution together with the measures taken from it.
Definition sym_engine.h:75
std::vector< CtmcMeasure > ratios
One per requested ratio, in order.
Definition sym_engine.h:82
std::string den
Common denominator of the whole vector.
Definition sym_engine.h:78
std::vector< CtmcMeasure > measures
One per weight vector, in order.
Definition sym_engine.h:81
int nConnComp
Weakly connected components.
Definition sym_engine.h:79
std::vector< std::string > num
Numerator of each entry over den.
Definition sym_engine.h:77
std::vector< int > connComp
Component index of each state, one based.
Definition sym_engine.h:80
std::vector< std::string > pi
Stationary probability of each state.
Definition sym_engine.h:76
std::vector< std::string > pi
Stationary probability of each state, as an expression.
Definition sym_engine.h:97
std::vector< int > connComp
Component index of each state, one based.
Definition sym_engine.h:101
std::vector< std::string > num
Numerator of each entry over the common denominator.
Definition sym_engine.h:98
int nConnComp
Weakly connected components of the generator.
Definition sym_engine.h:100
std::string den
Common denominator of the whole vector.
Definition sym_engine.h:99
Symbolic analysis of a fluid vector field.
Definition sym_engine.h:121
std::vector< std::string > latex
LaTeX form of each right hand side.
Definition sym_engine.h:123
std::vector< std::map< std::string, std::string > > equilibria
variable -> expression
Definition sym_engine.h:124
std::vector< std::vector< std::string > > jacobian
d f_i / d x_j
Definition sym_engine.h:122
First passage time transform and moments.
Definition sym_engine.h:86
std::vector< std::vector< std::string > > momAll
Per start state moments.
Definition sym_engine.h:92
std::vector< std::string > lstAll
Per start state transform.
Definition sym_engine.h:90
std::string lstNum
Numerator of lst.
Definition sym_engine.h:88
std::string lst
The transform L(s), empty if not requested.
Definition sym_engine.h:87
std::vector< std::string > moments
Moments 1..nmax for the initial law.
Definition sym_engine.h:91
std::vector< int > unreachable
States that cannot reach the target.
Definition sym_engine.h:93
std::string lstDen
Denominator of lst.
Definition sym_engine.h:89
A ratio of two measures, by their index into the weight block.
Definition sym_engine.h:68
std::size_t num
Index of the numerator measure.
Definition sym_engine.h:70
std::string name
Name of the resulting measure.
Definition sym_engine.h:69
std::size_t den
Index of the denominator measure.
Definition sym_engine.h:71
Exact parametric sensitivity, following Trivedi and Bobbio (2017), Sec.
Definition sym_engine.h:111
bool hasReward
Whether Er, S and SS were computed.
Definition sym_engine.h:117
std::vector< std::string > dpi
Derivative of the distribution with respect to theta.
Definition sym_engine.h:113
std::vector< std::string > pi
Stationary distribution.
Definition sym_engine.h:112
std::string SS
Scaled sensitivity (theta/E[r]) d(E[r])/dtheta, Eq. (9.80).
Definition sym_engine.h:116
std::string Er
Mean reward, empty if no reward was given.
Definition sym_engine.h:114
std::string S
Unscaled sensitivity d(E[r])/dtheta, Eq. (9.79).
Definition sym_engine.h:115