Dainarx is a prototypical tool for the derivative-agnostic inference of nonlinear hybrid automata with high-order NARX-modeled dynamics from input-output discrete-time traces of hybrid systems.
The extended version for noisy data: Dainarx-Noisy.
- Python 3.9
Install the dependencies:
pip install numpy scikit-learn networkx matplotlib
"scikit-learn" is used for SVM learning, while "networkx" is only used to compute test metrics. "matplotlib" is used for plotting images.
Run:
python main.py
You can change the path in main.py to test different automata.
If you want to test all the automata, run the following command:
python test_all.py
The system will generate evaluation_log.csv in the root directory, recording all the test results.
- The "data" folder stores the traces generated by the code.
- The "automata" folder stores automaton data.
- The json format of the automaton data is as follows.
{
"automaton": { // Automaton.
"var": "x1, x2", // List of output variables, separated by ','.
"input": "u", // List of input variables, separated by ','.
"mode": [ // A list of automata modes.
{
"id": 1, // The id of the mode.
"eq": "x1[1] = 1, x2[2] = -3 * x2[1] - 25 * x2[0] + u"
// Eq represents the ode of each variable in this mode, separated by ','.
// Variables that are not defined in "var" and "input" cannot appear.
// x[k] represents the KTH derivative of x. The input variable u directly represents the value of u.
// The left side of the equal sign is the highest-order differential, and the right side is the expression. Implicit functions are not supported.
// ode must be provided for each variable.
},
{
"id": 2,
"eq": "x1[1] = -1, x2[2] = -3 * x2[1] - 25 * x2[0]"
}
],
"edge": [
{
"direction": "1 -> 2", // The edge from mode u to mode v, represented as "u -> v".
"condition": "x1 >= 5", // Transition conditions. Variables that are not defined in "var" and "input" cannot appear.
"reset": { // Reset function.
"x1": ["x1[0] - 1"]
// The representation structure is the same as "init_state", and the meaning of the expression is the same as "eq".
// An empty string ("") indicates that the item has not been reset (not modified). Variables/items that do not appear will be padded with an empty string.
}
},
{
"direction": "2 -> 1",
"condition": "x1 <= 0"
}
]
},
"init_state": [ // The initial state list, with several initial states generating several trajectory data.
{
"mode": 1, // Initial mode.
"x1": [0], // The initial state of x1, where "[a, b, c, ...]" represents the initial states of x1[0], x1[1], x1[2], and so on.
"x2": [0], // If no initial state is provided, or if the number of initial states provided is insufficient for the order of the equation, zeros are automatically added backward.
"u": "2 + 1.5 * sin(t)" // The expression of each input, a function related to t.
},
{
"mode": 1,
"x1": [2],
"x2": [3],
"u": "1 + sin(t)"
}
],
"config": { // Parameter List.
"dt": 0.01, // Discrete time step, default is 0.01.
"total_time": 10.0, // Total sampling time, default is 10.
"order": 3, // Order of the difference equation, default is 3.
"window_size": 10, // Size of the sliding window, default is 10.
"clustering_method": "fit", // Clustering method, default is "fit", options are "fit" and "dis".
"minus": false, // Whether to minimize the order, default is false.
"need_bias": true, // Whether a constant term is needed, default is true.
"kernel": "linear", // SVM kernel function, default is "linear".
"other_items": "", // Other nonlinear or cross terms in the difference equation, default is empty.
"svm_c": 1e6, // SVM parameter C, default is 1e6.
"self_loop": false, // Whether self-loops are allowed, default is false.
"need_reset": false, // Whether to learn reset, default is false; recommended to enable if order > 1.
"class_weight": 1.0 // Weight of negative samples in SVM (positive sample = 1.0), default is 1.0.
// Explanation of other_items:
// Example: "x0, x2, x3: x[1] * x_[?]; x[?] * x1[2]"
// Expressions are separated by semicolons (;).
// The part before the colon (:) defines the scope of the expression; "xi" means it applies to the i-th variable (starting from 0). If no scope is provided, it applies to all variables.
// "x" refers to the variable itself, "x_" refers to any other variable except itself, "xi" refers to the i-th variable.
// "x[1]" means x[t - 1], "x[a]" means x[t - a], representing past values in the difference equation. Terms with lag greater than order or zero are not allowed.
// "x[?]" represents any lag term in the range [1, order].
// Example:
// order = 2, other_items = "x0, x2: x[1] * x_[?]"
// For x0, the following additional terms will be fitted:
// x0[1] * x1[1], x0[1] * x1[2], x0[1] * x2[1], x0[1] * x2[2].
// For x1, no additional terms will be fitted.
// For x2, the following additional terms will be fitted:
// x2[1] * x0[1], x2[1] * x0[2], x2[1] * x1[1], x2[1] * x1[2].
}
}