1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
use crate::algorithms::fo_logic::eval_algorithm::eval_node;
use crate::algorithms::fo_logic::fol_tree::FolTreeNode;
use crate::algorithms::fo_logic::parser::parse_and_minimize_fol_formula;
use crate::algorithms::fo_logic::utils::*;
use biodivine_hctl_model_checker::postprocessing::sanitizing::sanitize_colored_vertices;
use biodivine_lib_param_bn::symbolic_async_graph::{GraphColoredVertices, SymbolicAsyncGraph};
/// Evaluate each of a list of FOL formulas given by their syntax trees on a given transition `graph`.
///
/// The `graph` MUST support enough sets of symbolic variables to represent all occurring FO vars.
/// Return the list of resulting sets of colored vertices (in the same order as input formulas).
///
/// This version does not sanitize the resulting BDDs ([eval_multiple_trees] does).
pub fn eval_multiple_trees_dirty(
formula_trees: Vec<FolTreeNode>,
graph: &SymbolicAsyncGraph,
) -> Result<Vec<GraphColoredVertices>, String> {
// evaluate the formulas and collect results
let mut results: Vec<GraphColoredVertices> = Vec::new();
for parse_tree in formula_trees {
results.push(eval_node(parse_tree, graph));
}
Ok(results)
}
/// Evaluate formula given by its syntactic tree, but do not sanitize the results.
/// The `graph` MUST support enough sets of symbolic variables to represent all occurring FO vars.
pub fn eval_tree_dirty(
formula_tree: FolTreeNode,
graph: &SymbolicAsyncGraph,
) -> Result<GraphColoredVertices, String> {
let result = eval_multiple_trees_dirty(vec![formula_tree], graph)?;
Ok(result[0].clone())
}
/// Evaluate each of a list of FOL formulas given by their syntax trees on a given transition `graph`.
/// The `graph` MUST support enough sets of symbolic variables to represent all occurring FO vars.
/// Return the list of resulting sets of colored vertices (in the same order as input formulas).
pub fn eval_multiple_trees(
formula_trees: Vec<FolTreeNode>,
graph: &SymbolicAsyncGraph,
) -> Result<Vec<GraphColoredVertices>, String> {
// evaluate the formulas and collect results
let results = eval_multiple_trees_dirty(formula_trees, graph)?;
// sanitize the results' bdds - get rid of additional bdd vars used for HCTL vars
let sanitized_results: Vec<GraphColoredVertices> = results
.iter()
.map(|x| sanitize_colored_vertices(graph, x))
.collect();
Ok(sanitized_results)
}
/// Evaluate formula given by its syntactic tree.
/// The `graph` MUST support enough sets of symbolic variables to represent all occurring FO vars.
/// Return the resulting set of colored vertices.
pub fn eval_tree(
formula_tree: FolTreeNode,
graph: &SymbolicAsyncGraph,
) -> Result<GraphColoredVertices, String> {
let result = eval_multiple_trees(vec![formula_tree], graph)?;
Ok(result[0].clone())
}
/// Parse given FOL formulas list into syntactic trees and perform compatibility check with
/// the provided `graph` (i.e., check if `graph` object supports all needed symbolic variables).
///
/// Argument `base_var_name` is for the BN var which was used as a base for extra variables.
fn parse_and_validate(
formulas: Vec<&str>,
graph: &SymbolicAsyncGraph,
base_var_name: &str,
) -> Result<Vec<FolTreeNode>, String> {
// parse all the formulas and check that graph supports enough FOL vars and contains correct functions
let mut parsed_trees = Vec::new();
for formula in formulas {
let tree = parse_and_minimize_fol_formula(formula, base_var_name)?;
// check if all variables valid
let fol_vars = collect_unique_fol_vars(&tree);
for fol_var in fol_vars {
if !check_fol_var_support(graph, &fol_var) {
return Err(format!(
"Variable `{fol_var}` not found in symbolic context."
));
}
}
// check if all functions valid
let function_symbols = collect_unique_fn_symbols(&tree)?;
for (fn_name, arity) in function_symbols.iter() {
if let Ok(var) = get_var_from_implicit(fn_name) {
// if this is update fn symbol, we must check the corresponding variable exists
if !check_update_fn_support(graph.as_network().unwrap(), &var, *arity) {
return Err(format!(
"Variable for update function `{fn_name}` does not exist, or its arity is different."
));
}
} else {
// if this is uninterpreted fn symbol, we must check the corresponding parameter exists
if !check_fn_symbol_support(graph.symbolic_context(), fn_name, *arity) {
return Err(format!(
"Function `{fn_name}` with arity {arity} not found in symbolic context."
));
}
}
}
parsed_trees.push(tree);
}
Ok(parsed_trees)
}
/// Evaluate each of a list of FOL formulas on a given transition `graph`.
/// Return the resulting sets of colored vertices (in the same order as input formulas).
/// The `graph` MUST support enough sets of symbolic variables to represent all occurring FO vars.
///
/// Argument `base_var_name` is for the BN var which was used as a base for extra variables.
pub fn eval_multiple_formulas(
formulas: Vec<&str>,
graph: &SymbolicAsyncGraph,
base_var_name: &str,
) -> Result<Vec<GraphColoredVertices>, String> {
// get the abstract syntactic trees
let parsed_trees = parse_and_validate(formulas, graph, base_var_name)?;
// run the main model-checking procedure on formulas trees
eval_multiple_trees(parsed_trees, graph)
}
/// Evaluate each of a list of FOL formulas, but do not sanitize the results.
/// The `graph` MUST support enough sets of symbolic variables to represent all occurring FO vars.
///
/// Argument `base_var_name` is for the BN var which was used as a base for extra variables.
pub fn eval_multiple_formulas_dirty(
formulas: Vec<&str>,
graph: &SymbolicAsyncGraph,
base_var_name: &str,
) -> Result<Vec<GraphColoredVertices>, String> {
// get the abstract syntactic trees
let parsed_trees = parse_and_validate(formulas, graph, base_var_name)?;
// run the main model-checking procedure on formulas trees
eval_multiple_trees_dirty(parsed_trees, graph)
}
/// Evaluate given formula a given transition `graph`.
/// The `graph` MUST support enough sets of symbolic variables to represent all occurring FO vars.
/// Return the resulting set of colored vertices.
///
/// Argument `base_var_name` is for the BN var which was used as a base for extra variables.
pub fn eval_formula(
formula: &str,
graph: &SymbolicAsyncGraph,
base_var_name: &str,
) -> Result<GraphColoredVertices, String> {
let result = eval_multiple_formulas(vec![formula], graph, base_var_name)?;
Ok(result[0].clone())
}
/// Evaluate given formula, but do not sanitize the result.
/// The `graph` MUST support enough sets of symbolic variables to represent all occurring FO vars.
///
/// Argument `base_var_name` is for the BN var which was used as a base for extra variables.
pub fn eval_formula_dirty(
formula: &str,
graph: &SymbolicAsyncGraph,
base_var_name: &str,
) -> Result<GraphColoredVertices, String> {
let result = eval_multiple_formulas_dirty(vec![formula], graph, base_var_name)?;
Ok(result[0].clone())
}