biodivine_lib_param_bn/
_impl_boolean_network_to_bnet.rs1use crate::{BinaryOp, BooleanNetwork, FnUpdate, VariableId};
2use regex::Regex;
3
4impl BooleanNetwork {
5 pub fn to_bnet(&self, rename_if_necessary: bool) -> Result<String, String> {
14 let mut network = self.clone();
15 let name_re = Regex::new(r"^[a-zA-Z_][a-zA-Z0-9_]*$").unwrap();
17 for var in network.variables() {
18 let name = network.get_variable_name(var);
19 if !name_re.is_match(name) {
20 if rename_if_necessary {
21 let new_name = format!("_{}", name);
22 network.as_graph_mut().set_variable_name(var, &new_name)?;
23 } else {
24 return Err(format!(
25 "Variable {} cannot be exported to bnet. Please rename it first.",
26 name
27 ));
28 }
29 }
30 }
31 let mut model = "targets,factors\n".to_string();
32 for v in network.variables() {
33 let name = network.get_variable_name(v);
34 if let Some(function) = network.get_update_function(v) {
35 let function_string = fn_update_to_bnet_string(v, function, self)?;
36 let line = format!("{}, {}\n", name, function_string);
37 model.push_str(line.as_str());
38 } else {
39 if self.regulators(v).is_empty() {
41 continue;
42 } else {
43 return Err("Parametrised network cannot be converted to .bnet.".to_string());
44 }
45 }
46 }
47
48 Ok(model)
49 }
50}
51
52fn fn_update_to_bnet_string(
53 var: VariableId,
54 function: &FnUpdate,
55 network: &BooleanNetwork,
56) -> Result<String, String> {
57 Ok(match function {
58 FnUpdate::Var(id) => network.get_variable_name(*id).clone(),
59 FnUpdate::Param(id, args) => {
60 if args.is_empty() {
61 network.get_parameter(*id).get_name().to_string()
62 } else {
63 return Err(
64 "Networks with free functions cannot be converted to .bnet.".to_string()
65 );
66 }
67 }
68 FnUpdate::Const(value) => {
69 let name = network.get_variable_name(var);
71 if *value {
72 format!("({} | !{})", name, name)
73 } else {
74 format!("({} & !{})", name, name)
75 }
76 }
77 FnUpdate::Not(inner) => {
78 format!("!{}", fn_update_to_bnet_string(var, inner, network)?)
79 }
80 FnUpdate::Binary(op, left, right) => {
81 let left = fn_update_to_bnet_string(var, left, network)?;
82 let right = fn_update_to_bnet_string(var, right, network)?;
83 match *op {
84 BinaryOp::And => format!("({} & {})", left, right),
85 BinaryOp::Or => format!("({} | {})", left, right),
86 BinaryOp::Imp => format!("(!{} | {})", left, right),
87 BinaryOp::Iff => format!("(({} & {}) | (!{} & !{}))", left, right, left, right),
88 BinaryOp::Xor => format!("(({} & !{}) | (!{} & {}))", left, right, left, right),
89 }
90 }
91 })
92}
93
94#[cfg(test)]
95mod tests {
96 use crate::BooleanNetwork;
97 use std::convert::TryFrom;
98
99 #[test]
100 fn test_network_to_bnet() {
101 let model = std::fs::read_to_string("aeon_models/g2a_instantiated.aeon").unwrap();
102 let network = BooleanNetwork::try_from(model.as_str()).unwrap();
103 let network_after =
104 BooleanNetwork::try_from_bnet(network.to_bnet(false).unwrap().as_str()).unwrap();
105
106 assert_eq!(network.graph.num_vars(), network_after.graph.num_vars());
107 for v in network.graph.variables() {
108 assert_eq!(
109 network.graph.get_variable(v),
110 network_after.graph.get_variable(v)
111 );
112 assert_eq!(
113 network.graph.regulators(v),
114 network_after.graph.regulators(v)
115 );
116 assert_eq!(
117 network.get_update_function(v),
118 network_after.get_update_function(v)
119 );
120
121 for reg in network.graph.regulators(v) {
122 let r1 = network.graph.find_regulation(reg, v).unwrap();
124 let r2 = network_after.graph.find_regulation(reg, v).unwrap();
125 assert_eq!(r1.regulator, r2.regulator);
126 assert_eq!(r1.target, r2.target);
127 }
128 }
129 }
130
131 #[test]
132 fn test_network_to_bnet_invalid() {
133 let bn = BooleanNetwork::try_from("A -> B \n B -> A").unwrap();
134 assert!(bn.to_bnet(false).is_err());
136 let bn = BooleanNetwork::try_from("3A -> B \n B -> 3A \n $B:3A \n $3A:B").unwrap();
137 assert!(bn.to_bnet(false).is_err());
139 assert!(bn.to_bnet(true).is_ok());
140 }
141}