taco_threshold_automaton/lia_threshold_automaton.rs
1//! A linear arithmetic threshold automaton or [`LIAThresholdAutomaton`]
2//! is a threshold automaton containing linear arithmetic guards. The
3//! goal of the [`LIAThresholdAutomaton`] is to stay as close to the formal
4//! definition of a threshold automaton as possible.
5//!
6//! To convert a [`GeneralThresholdAutomaton`] to a [`LIAThresholdAutomaton`]
7//! all guards are translated into one of these forms:
8//! - [`SingleAtomConstraint`]: Which represents a threshold in the form
9//! `x <COMPARISON_OP> c_1 * p_1 + ... c_n * p_n + c`
10//! where `c_1, ..., c_n, c` are rational constants, `p_1, ..., p_n` are
11//! Parameters and x is a single shared variable.
12//! - [`SumAtomConstraint`]: Represents a threshold of the form
13//! `cx_1 * x_1 + ... + cx_m * x_m <COMPARISON_OP> c_1 * p_1 + ... c_n * p_n + c`
14//! where `c_1, ..., c_n, cx_1, ..., cx_m, c` are rational constants, `p_1,
15//! ..., p_n` are Parameters and x_1, ..., x_m are shared variables.
16//! Additionally, all coefficients `cx_1, ..., cx_m` must be all positive.
17//! - [`ComparisonConstraint`]: Comparison constraints are structured analog to
18//! a [`SumAtomConstraint`], but allow mixing positive and negative constants
19//! in the constants `cx_1, ..., cx_m`.
20//!
21//! Note that not all algorithms support all types of guards. Especially the
22//! [`ComparisonConstraint`] makes the verification problem undecidable (even without
23//! decrements and or resets). For more information see:
24//!
25//! > All Flavors of Threshold Automata - Jure Kukovec, Igor Konnov,
26//! > Josef Widder - <https://doi.org/10.4230/LIPIcs.CONCUR.2018.19>
27
28use std::collections::HashMap;
29use std::fmt::Debug;
30use std::hash::Hash;
31
32use crate::expressions::{Atomic, BooleanConnective, BooleanExpression, Location, Variable};
33
34use crate::general_threshold_automaton::{Action, GeneralThresholdAutomaton, Rule};
35use crate::lia_threshold_automaton::integer_thresholds::{ThresholdConstraintOver, WeightedSum};
36
37pub mod general_to_lia;
38pub mod integer_thresholds;
39pub mod no_sum_var_ta;
40pub mod properties;
41
42/// A linear arithmetic threshold automaton or [`LIAThresholdAutomaton`]
43/// is a threshold automaton containing linear arithmetic guards. The
44/// goal of the [`LIAThresholdAutomaton`] is to stay as close to the formal
45/// definition of a threshold automaton as possible.
46///
47/// To convert a [`GeneralThresholdAutomaton`] to a [`LIAThresholdAutomaton`]
48/// all guards are translated into one of these forms:
49/// - [`SingleAtomConstraint`]: Which represents a threshold in the form
50/// `x <COMPARISON_OP> c_1 * p_1 + ... c_n * p_n + c`
51/// where `c_1, ..., c_n, c` are rational constants, `p_1, ..., p_n` are
52/// Parameters and x is a single shared variable.
53/// - [`SumAtomConstraint`]: Represents a threshold of the form
54/// `cx_1 * x_1 + ... + cx_m * x_m <COMPARISON_OP> c_1 * p_1 + ... c_n * p_n + c`
55/// where `c_1, ..., c_n, cx_1, ..., cx_m, c` are rational constants, `p_1,
56/// ..., p_n` are Parameters and x_1, ..., x_m are shared variables.
57/// Additionally, all coefficients `cx_1, ..., cx_m` must be all positive.
58/// - [`ComparisonConstraint`]: Comparison constraints are structured analog to
59/// a [`SumAtomConstraint`], but allow mixing positive and negative constants in
60/// the constants `cx_1, ..., cx_m`.
61///
62/// Note that not all algorithms support all types of guards. Especially the
63/// [`ComparisonConstraint`] makes the verification problem undecidable (even without
64/// decrements and or resets). For more information see:
65///
66/// > All Flavors of Threshold Automata - Jure Kukovec, Igor Konnov,
67/// > Josef Widder - <https://doi.org/10.4230/LIPIcs.CONCUR.2018.19>
68#[derive(Debug, PartialEq, Clone)]
69pub struct LIAThresholdAutomaton {
70 /// [`GeneralThresholdAutomaton`] the canonical automaton has been constructed from
71 ta: GeneralThresholdAutomaton,
72 /// Initial conditions on variables in linear arithmetic
73 init_variable_constr: Vec<LIAVariableConstraint>,
74 /// Transition rules of the threshold automaton indexed by source location
75 rules: HashMap<Location, Vec<LIARule>>,
76 /// Additional variables that are used to replace sums
77 /// TODO: remove when a proper ordering for sums of variables is implemented
78 additional_vars_for_sums: HashMap<Variable, WeightedSum<Variable>>,
79}
80
81/// Rule type of [`LIAThresholdAutomaton`]
82///
83/// A rule guarded by a constraint representable in linear arithmetic (see
84/// [`LIAVariableConstraint`]).
85#[derive(Debug, PartialEq, Clone, Eq, Hash)]
86pub struct LIARule {
87 /// Id assigned to the rule in the specification
88 id: u32,
89 /// Source location of the rule
90 source: Location,
91 /// Target location of the rule
92 target: Location,
93 /// Guard of the rule
94 guard: LIAVariableConstraint,
95 /// Effect of the rule
96 actions: Vec<Action>,
97}
98
99/// Errors that can occur when trying to transform a threshold automaton in a
100/// linear arithmetic threshold automaton
101#[derive(Debug, Clone, PartialEq)]
102pub enum LIATransformationError {
103 /// Error occurred during transformation of a guard of a rule, see
104 /// [`ConstraintRewriteError`] for more details on the error
105 GuardError(
106 Box<Rule>,
107 Box<BooleanExpression<Variable>>,
108 Box<ConstraintRewriteError>,
109 ),
110 /// Error occurred during the transformation of an initial variable
111 /// constraint, see [`ConstraintRewriteError`] for more details on the error
112 InitialConstraintError(
113 Box<BooleanExpression<Variable>>,
114 Box<ConstraintRewriteError>,
115 ),
116}
117
118/// Abstract constraint type for linear arithmetic formulas over shared
119/// variables
120///
121/// This struct allows to represent combinations the different types of
122/// constraints over evaluations of shared variables. It allows to reference:
123///
124/// - [`SingleAtomConstraint`]: Which represents a threshold in the form
125/// `x <COMPARISON_OP> c_1 * p_1 + ... c_n * p_n + c`
126/// where `c_1, ..., c_n, c` are rational constants, `p_1, ..., p_n` are
127/// Parameters and x is a single shared variable.
128/// - [`SumAtomConstraint`]: Represents a threshold of the form
129/// `cx_1 * x_1 + ... + cx_m * x_m <COMPARISON_OP> c_1 * p_1 + ... c_n * p_n + c`
130/// where `c_1, ..., c_n, cx_1, ..., cx_m, c` are rational constants, `p_1,
131/// ..., p_n` are Parameters and x_1, ..., x_m are shared variables.
132/// Additionally, all coefficients `cx_1, ..., cx_m` must be all positive.
133/// - [`ComparisonConstraint`]: Comparison constraints are structured analog to
134/// a [`SumAtomConstraint`], but allow mixing positive and negative constants in
135/// the constants `cx_1, ..., cx_m`.
136///
137/// and boolean combinations of these guards
138#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
139pub enum LIAVariableConstraint {
140 /// Constraint over the difference between variables / comparing variables
141 ComparisonConstraint(ComparisonConstraint<Variable>),
142 /// Constraint over a single variable
143 SingleVarConstraint(SingleAtomConstraint<Variable>),
144 /// Constraint over the sum of multiple variables
145 SumVarConstraint(SumAtomConstraint<Variable>),
146 /// Boolean Combination of multiple constraints over variables
147 BinaryGuard(
148 Box<LIAVariableConstraint>,
149 BooleanConnective,
150 Box<LIAVariableConstraint>,
151 ),
152 /// True / always enabled
153 True,
154 /// False / always disabled
155 False,
156}
157
158/// Error that can occur during the transformation of a guard
159#[derive(Debug, Clone, PartialEq)]
160pub enum ConstraintRewriteError {
161 /// Constraint is not a linear arithmetic constraint (e.g. it could contain
162 /// multiplications of atoms)
163 NotLinearArithmetic,
164 /// Constraint over parameters values instead of shared memory values
165 ///
166 /// Constraints like this should be part of the resilience condition
167 ParameterConstraint(Box<BooleanExpression<Variable>>),
168}
169
170/// Threshold guard over a single atom
171///
172/// This struct represents a guard over a single atom, i.e., it represents a
173/// constraint formula of the form `v COMPOP cp_1 * p_1 + ... + cp_n * p_m + c`
174/// where `cp_1, ..., cp_m` are rational factors, `COMPOP` is a comparison
175/// operator (i.e.,`<, >, <=, >=, ==, !=`), `v` is a atom, `p_1, ..., p_m`
176/// are parameters, and `c` is a rational constant.
177#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
178pub struct SingleAtomConstraint<T: Atomic>(ThresholdConstraintOver<T>);
179
180/// Error that can occur when trying to construct a [`SingleAtomConstraint`]
181#[derive(Debug, Clone, PartialEq)]
182pub enum SingleAtomConstrExtractionError {
183 /// The constraint references multiple atoms, it could be a
184 /// [`SumAtomConstraint`] or [`ComparisonConstraint`]
185 HasMultipleAtoms,
186 /// Rewriting of the constraint failed
187 TransformationFailed(ConstraintRewriteError),
188}
189
190/// Constraint over the evaluation over a sum of multiple atoms
191///
192/// This struct represents a guard over the values of a sum of atoms, i.e., it
193/// represents a constraint formula of the form
194/// `cv_1 * v_1 + ... + cv_n * v_n <COMPOP> cp_1 * p_1 + ... + cp_n * p_m + c`
195/// where `cv_1, ..., cv_n, cp_1, ..., cp_m` are rational factors, `COMPOP` is
196/// a comparison operator (i.e.,`<, >, <=, >=, ==, !=`), `v_1, ..., v_n` are
197/// variables, `p_1, ..., p_m` are parameters, and `c` is a rational constant.
198///
199/// Additionally, all variable coefficients, i.e., `cv_1, ..., cv_n`, must be
200/// greater than zero.
201#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
202pub struct SumAtomConstraint<T: Atomic>(ThresholdConstraintOver<WeightedSum<T>>);
203
204/// Error that can occur during the creation of a [`SumAtomConstraint`]
205#[derive(Debug, Clone, PartialEq)]
206pub enum SumVarConstraintCreationError {
207 /// Guard is a [`ComparisonConstraint`] not a [`SumAtomConstraint`]
208 IsComparisonConstraint,
209 /// Guard is a [`SingleAtomConstraint`] not a [`SumAtomConstraint`]
210 IsSingleAtomConstraint,
211}
212
213/// Constraint over the difference between atoms / comparing atoms
214///
215/// This struct represents a comparison guard, i.e., it represents a guard of
216/// the form
217/// `cv_1 * v_1 + ... + cv_n * v_n <COMPOP> cp_1 * p_1 + ... + cp_n * p_m + c`
218/// where `cv_1, ..., cv_n, cp_1, ..., cp_m` are rational factors, `<COMPOP>` is
219/// a comparison operator (i.e.,`<, >, <=, >=, ==, !=`), `v_1, ..., v_n` are
220/// atoms, `p_1, ..., p_m` are parameters, and `c` is a rational constant.
221///
222/// Additionally, at least one of the atom coefficients, i.e.,
223/// `cv_1, ..., cv_n`, must be smaller than zero and at least one greater than
224/// zero. Otherwise the guard would be a [`SumAtomConstraint`].
225#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
226pub struct ComparisonConstraint<T: Atomic>(ThresholdConstraintOver<WeightedSum<T>>);
227
228/// Error that can occur during the creation of a comparison guard
229#[derive(Debug, Clone, PartialEq)]
230pub enum ComparisonConstraintCreationError {
231 /// Guard is a [`SumAtomConstraint`] not a [`ComparisonConstraint`]
232 IsSumVarConstraint,
233}