use crate::sketchbook::data_structs::ModelData;
use crate::sketchbook::ids::{LayoutId, UninterpretedFnId, VarId};
use crate::sketchbook::layout::Layout;
use crate::sketchbook::model::{
Essentiality, FnArgument, ModelState, Monotonicity, Regulation, UninterpretedFn, UpdateFn,
Variable,
};
use crate::sketchbook::utils::assert_ids_unique;
use crate::sketchbook::Manager;
use std::cmp::max;
use std::collections::{HashMap, HashSet};
impl ModelState {
pub fn new_empty() -> ModelState {
let default_layout_id = ModelState::get_default_layout_id();
let default_layout = Layout::new_empty(ModelState::get_default_layout_name()).unwrap();
ModelState {
variables: HashMap::new(),
regulations: HashSet::new(),
update_fns: HashMap::new(),
uninterpreted_fns: HashMap::new(),
layouts: HashMap::from([(default_layout_id, default_layout)]),
placeholder_variables: HashSet::new(),
}
}
pub fn new_from_model_data(model_data: &ModelData) -> Result<ModelState, String> {
let mut model = ModelState::new_empty();
model_data
.variables
.iter()
.try_for_each(|v| model.add_var_by_str(&v.id, &v.name, &v.annotation))?;
model_data.uninterpreted_fns.iter().try_for_each(|f| {
model.add_empty_uninterpreted_fn_by_str(&f.id, &f.name, f.arguments.len())?;
model.set_fn_annot_by_str(&f.id, &f.annotation)
})?;
model_data.regulations.iter().try_for_each(|r| {
model.add_regulation(
VarId::new(&r.regulator)?,
VarId::new(&r.target)?,
r.essential,
r.sign,
)
})?;
for layout_data in &model_data.layouts {
let layout = layout_data.to_layout()?;
model.add_or_update_layout_raw(LayoutId::new(&layout_data.id)?, layout)?;
}
let update_fns = model_data
.variables
.iter()
.map(|v| (v.id.as_str(), v.update_fn.as_str()))
.collect();
model.set_multiple_update_fns(update_fns)?;
for f in &model_data.uninterpreted_fns {
model.set_uninterpreted_fn_expression_by_str(&f.id, &f.expression)?;
model.set_fn_annot_by_str(&f.id, &f.annotation)?;
let arguments = f
.arguments
.iter()
.map(|(m, e)| FnArgument::new(*e, *m))
.collect();
model.set_uninterpreted_fn_all_args_by_str(&f.id, arguments)?;
}
Ok(model)
}
pub fn new_from_vars(variables: Vec<(&str, &str)>) -> Result<ModelState, String> {
let mut model = ModelState::new_empty();
let var_ids = variables.iter().map(|pair| pair.0).collect();
assert_ids_unique(&var_ids)?;
for (id, var_name) in variables {
let var_id = VarId::new(id)?;
model
.variables
.insert(var_id.clone(), Variable::new(var_name)?);
model.add_default_update_fn(var_id.clone())?;
model.insert_to_default_layout(var_id)?;
}
Ok(model)
}
pub fn add_var(&mut self, var_id: VarId, name: &str, annot: &str) -> Result<(), String> {
self.assert_no_variable(&var_id)?;
let variable = Variable::new_annotated(name, annot)?;
self.variables.insert(var_id.clone(), variable);
self.add_default_update_fn(var_id.clone())?;
self.insert_to_all_layouts(var_id)?;
Ok(())
}
pub fn add_var_by_str(&mut self, id: &str, name: &str, annot: &str) -> Result<(), String> {
let var_id = VarId::new(id)?;
self.add_var(var_id, name, annot)
}
pub fn add_multiple_variables(
&mut self,
id_name_pairs: Vec<(&str, &str)>,
) -> Result<(), String> {
let var_ids: Vec<&str> = id_name_pairs.iter().map(|pair| pair.0).collect();
self.assert_ids_unique_and_new(&var_ids, &(Self::assert_no_variable))?;
for id in var_ids {
let var_id = VarId::new(id)?;
self.assert_no_variable(&var_id)?;
}
for (id, name) in id_name_pairs {
self.add_var_by_str(id, name, "")?;
}
Ok(())
}
pub fn add_uninterpreted_fn(
&mut self,
fn_id: UninterpretedFnId,
name: &str,
arguments: Vec<FnArgument>,
expression: &str,
annot: &str,
) -> Result<(), String> {
self.assert_no_uninterpreted_fn(&fn_id)?;
let arity = arguments.len();
let f = UninterpretedFn::new(name, annot, expression, arguments, self, &fn_id)?;
self.uninterpreted_fns.insert(fn_id, f);
self.add_placeholder_vars_if_needed(arity);
Ok(())
}
pub fn add_empty_uninterpreted_fn(
&mut self,
fn_id: UninterpretedFnId,
name: &str,
arity: usize,
) -> Result<(), String> {
self.assert_no_uninterpreted_fn(&fn_id)?;
self.uninterpreted_fns.insert(
fn_id,
UninterpretedFn::new_without_constraints(name, arity)?,
);
self.add_placeholder_vars_if_needed(arity);
Ok(())
}
pub fn add_empty_uninterpreted_fn_by_str(
&mut self,
id: &str,
name: &str,
arity: usize,
) -> Result<(), String> {
let fn_id = UninterpretedFnId::new(id)?;
self.add_empty_uninterpreted_fn(fn_id, name, arity)
}
pub fn add_multiple_uninterpreted_fns(
&mut self,
id_name_arity_tuples: Vec<(&str, &str, usize)>,
) -> Result<(), String> {
let fn_ids = id_name_arity_tuples
.iter()
.map(|triplet| triplet.0)
.collect();
self.assert_ids_unique_and_new(&fn_ids, &(Self::assert_no_uninterpreted_fn))?;
for (id, name, arity) in id_name_arity_tuples {
self.add_empty_uninterpreted_fn_by_str(id, name, arity)?;
}
Ok(())
}
pub fn add_regulation(
&mut self,
regulator: VarId,
target: VarId,
essential: Essentiality,
regulation_sign: Monotonicity,
) -> Result<(), String> {
self.assert_valid_variable(®ulator)?;
self.assert_valid_variable(&target)?;
self.assert_no_regulation(®ulator, &target)?;
self.regulations.insert(Regulation::new(
regulator,
target,
essential,
regulation_sign,
));
Ok(())
}
pub fn add_regulation_by_str(&mut self, regulation_str: &str) -> Result<(), String> {
let (reg, regulation_sign, essential, tar) =
Regulation::try_components_from_string(regulation_str)?;
let regulator = VarId::new(reg.as_str())?;
let target = VarId::new(tar.as_str())?;
self.add_regulation(regulator, target, essential, regulation_sign)
}
pub fn add_multiple_regulations(&mut self, regulations: Vec<&str>) -> Result<(), String> {
for regulation_str in regulations.iter() {
let (reg, _, _, tar) = Regulation::try_components_from_string(regulation_str)?;
let regulator = VarId::new(reg.as_str())?;
let target = VarId::new(tar.as_str())?;
self.assert_no_regulation(®ulator, &target)?
}
for regulation_str in regulations {
self.add_regulation_by_str(regulation_str)?;
}
Ok(())
}
pub fn set_raw_var(&mut self, var_id: &VarId, var_data: Variable) -> Result<(), String> {
self.assert_valid_variable(var_id)?;
self.variables.insert(var_id.clone(), var_data);
Ok(())
}
pub fn set_raw_function(
&mut self,
fn_id: &UninterpretedFnId,
fn_data: UninterpretedFn,
) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(fn_id)?;
self.uninterpreted_fns.insert(fn_id.clone(), fn_data);
Ok(())
}
pub fn set_var_name(&mut self, var_id: &VarId, name: &str) -> Result<(), String> {
self.assert_valid_variable(var_id)?;
let variable = self.variables.get_mut(var_id).unwrap();
variable.set_name(name)?;
Ok(())
}
pub fn set_var_name_by_str(&mut self, id: &str, name: &str) -> Result<(), String> {
let var_id = VarId::new(id)?;
self.set_var_name(&var_id, name)
}
pub fn set_var_annot(&mut self, var_id: &VarId, annot: &str) -> Result<(), String> {
self.assert_valid_variable(var_id)?;
let variable = self.variables.get_mut(var_id).unwrap();
variable.set_annotation(annot);
Ok(())
}
pub fn set_var_annot_by_str(&mut self, id: &str, annot: &str) -> Result<(), String> {
let var_id = VarId::new(id)?;
self.set_var_annot(&var_id, annot)
}
pub fn set_var_id(&mut self, original_id: &VarId, new_id: VarId) -> Result<(), String> {
self.assert_valid_variable(original_id)?;
self.assert_no_variable(&new_id)?;
if let Some(variable) = self.variables.remove(original_id) {
self.variables.insert(new_id.clone(), variable);
}
let regs_to_update: Vec<Regulation> = self
.regulations
.iter()
.filter(|reg| reg.get_regulator() == original_id || reg.get_target() == original_id)
.cloned()
.collect();
for reg in regs_to_update {
self.regulations.remove(®);
let mut updated_reg = reg.clone();
if reg.get_regulator() == original_id {
updated_reg.swap_regulator(new_id.clone());
}
if reg.get_target() == original_id {
updated_reg.swap_target(new_id.clone());
}
self.regulations.insert(updated_reg);
}
for layout in self.layouts.values_mut() {
layout.change_node_id(original_id, new_id.clone())?;
}
if let Some(update_fn) = self.update_fns.remove(original_id) {
self.update_fns.insert(new_id.clone(), update_fn);
}
for var_id in self.variables.keys() {
let update_fn = self.update_fns.remove(var_id).unwrap();
let new_update_fn =
UpdateFn::with_substituted_var(update_fn, original_id, &new_id, self);
self.update_fns.insert(var_id.clone(), new_update_fn);
}
Ok(())
}
pub fn set_var_id_by_str(&mut self, original_id: &str, new_id: &str) -> Result<(), String> {
let original_id = VarId::new(original_id)?;
let new_id = VarId::new(new_id)?;
self.set_var_id(&original_id, new_id)
}
pub fn remove_var(&mut self, var_id: &VarId) -> Result<(), String> {
self.assert_valid_variable(var_id)?;
if self.is_var_contained_in_updates(var_id) {
return Err(format!(
"Cannot remove variable `{var_id}`, it is still contained in an update function."
));
}
self.remove_all_regulations_var(var_id)?;
self.remove_from_all_layouts(var_id)?;
if self.update_fns.remove(var_id).is_none() {
panic!("Error when removing update fn for variable {var_id}.")
}
if self.variables.remove(var_id).is_none() {
panic!("Error when removing variable {var_id} from the variable map.")
}
Ok(())
}
pub fn remove_var_by_str(&mut self, id: &str) -> Result<(), String> {
let var_id = VarId::new(id)?;
self.remove_var(&var_id)
}
pub fn set_uninterpreted_fn_name(
&mut self,
fn_id: &UninterpretedFnId,
name: &str,
) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(fn_id)?;
let uninterpreted_fn = self.uninterpreted_fns.get_mut(fn_id).unwrap();
uninterpreted_fn.set_name(name)?;
Ok(())
}
pub fn set_uninterpreted_fn_name_by_str(&mut self, id: &str, name: &str) -> Result<(), String> {
let fn_id = UninterpretedFnId::new(id)?;
self.set_uninterpreted_fn_name(&fn_id, name)
}
pub fn set_fn_annot(&mut self, fn_id: &UninterpretedFnId, annot: &str) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(fn_id)?;
let uninterpreted_fn = self.uninterpreted_fns.get_mut(fn_id).unwrap();
uninterpreted_fn.set_annotation(annot);
Ok(())
}
pub fn set_fn_annot_by_str(&mut self, id: &str, annot: &str) -> Result<(), String> {
let fn_id = UninterpretedFnId::new(id)?;
self.set_fn_annot(&fn_id, annot)
}
pub fn set_uninterpreted_fn_arity(
&mut self,
fn_id: &UninterpretedFnId,
arity: usize,
) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(fn_id)?;
self.assert_fn_not_used_in_expressions(fn_id)?;
let uninterpreted_fn = self.uninterpreted_fns.get_mut(fn_id).unwrap();
uninterpreted_fn.set_arity(arity)?;
self.add_placeholder_vars_if_needed(arity);
self.remove_placeholder_vars_if_needed();
Ok(())
}
pub fn set_uninterpreted_fn_arity_by_str(
&mut self,
id: &str,
arity: usize,
) -> Result<(), String> {
let fn_id = UninterpretedFnId::new(id)?;
self.set_uninterpreted_fn_arity(&fn_id, arity)
}
pub fn increment_fn_arity(&mut self, fn_id: &UninterpretedFnId) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(fn_id)?;
let uninterpreted_fn = self.uninterpreted_fns.get(fn_id).unwrap();
self.set_uninterpreted_fn_arity(fn_id, uninterpreted_fn.get_arity() + 1)
}
pub fn decrement_fn_arity(&mut self, fn_id: &UninterpretedFnId) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(fn_id)?;
let uninterpreted_fn = self.uninterpreted_fns.get(fn_id).unwrap();
self.set_uninterpreted_fn_arity(fn_id, uninterpreted_fn.get_arity() - 1)
}
pub fn set_uninterpreted_fn_expression(
&mut self,
fn_id: &UninterpretedFnId,
expression: &str,
) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(fn_id)?;
let original_fn = self.uninterpreted_fns.get(fn_id).unwrap().clone();
let updated_fn =
UninterpretedFn::with_new_expression(original_fn, expression, self, fn_id)?;
self.uninterpreted_fns.insert(fn_id.clone(), updated_fn);
Ok(())
}
pub fn set_uninterpreted_fn_expression_by_str(
&mut self,
id: &str,
expression: &str,
) -> Result<(), String> {
let fn_id = UninterpretedFnId::new(id)?;
self.set_uninterpreted_fn_expression(&fn_id, expression)
}
pub fn set_uninterpreted_fn_essentiality(
&mut self,
fn_id: &UninterpretedFnId,
essentiality: Essentiality,
index: usize,
) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(fn_id)?;
let uninterpreted_fn = self.uninterpreted_fns.get_mut(fn_id).unwrap();
uninterpreted_fn.set_essential(index, essentiality)?;
Ok(())
}
pub fn set_uninterpreted_fn_essentiality_by_str(
&mut self,
id: &str,
essentiality: Essentiality,
index: usize,
) -> Result<(), String> {
let fn_id = UninterpretedFnId::new(id)?;
self.set_uninterpreted_fn_essentiality(&fn_id, essentiality, index)
}
pub fn set_uninterpreted_fn_monotonicity(
&mut self,
fn_id: &UninterpretedFnId,
monotonicity: Monotonicity,
index: usize,
) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(fn_id)?;
let uninterpreted_fn = self.uninterpreted_fns.get_mut(fn_id).unwrap();
uninterpreted_fn.set_monotonic(index, monotonicity)?;
Ok(())
}
pub fn set_uninterpreted_fn_monotonicity_by_str(
&mut self,
id: &str,
monotonicity: Monotonicity,
index: usize,
) -> Result<(), String> {
let fn_id = UninterpretedFnId::new(id)?;
self.set_uninterpreted_fn_monotonicity(&fn_id, monotonicity, index)
}
pub fn set_uninterpreted_fn_all_args(
&mut self,
fn_id: &UninterpretedFnId,
fn_arguments: Vec<FnArgument>,
) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(fn_id)?;
let uninterpreted_fn = self.uninterpreted_fns.get_mut(fn_id).unwrap();
uninterpreted_fn.set_all_arguments(fn_arguments)?;
Ok(())
}
pub fn set_uninterpreted_fn_all_args_by_str(
&mut self,
id: &str,
fn_arguments: Vec<FnArgument>,
) -> Result<(), String> {
let fn_id = UninterpretedFnId::new(id)?;
self.set_uninterpreted_fn_all_args(&fn_id, fn_arguments)
}
pub fn set_uninterpreted_fn_id(
&mut self,
original_id: &UninterpretedFnId,
new_id: UninterpretedFnId,
) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(original_id)?;
self.assert_no_uninterpreted_fn(&new_id)?;
if let Some(uninterpreted_fn) = self.uninterpreted_fns.remove(original_id) {
self.uninterpreted_fns
.insert(new_id.clone(), uninterpreted_fn);
}
for fn_id in self.uninterpreted_fns.clone().keys() {
let uninterpreted_fn = self.uninterpreted_fns.remove(fn_id).unwrap();
let new_uninterpreted_fn = UninterpretedFn::with_substituted_fn_symbol(
uninterpreted_fn,
original_id,
&new_id,
self,
);
self.uninterpreted_fns
.insert(fn_id.clone(), new_uninterpreted_fn);
}
for var_id in self.variables.keys() {
let update_fn = self.update_fns.remove(var_id).unwrap();
let new_update_fn =
UpdateFn::with_substituted_fn_symbol(update_fn, original_id, &new_id, self);
self.update_fns.insert(var_id.clone(), new_update_fn);
}
Ok(())
}
pub fn set_uninterpreted_fn_id_by_str(
&mut self,
original_id: &str,
new_id: &str,
) -> Result<(), String> {
let original_id = UninterpretedFnId::new(original_id)?;
let new_id = UninterpretedFnId::new(new_id)?;
self.set_uninterpreted_fn_id(&original_id, new_id)
}
pub fn remove_uninterpreted_fn(&mut self, fn_id: &UninterpretedFnId) -> Result<(), String> {
self.assert_valid_uninterpreted_fn(fn_id)?;
self.assert_fn_not_used_in_expressions(fn_id)?;
if self.uninterpreted_fns.remove(fn_id).is_none() {
panic!("Error when removing uninterpreted fn {fn_id} from the uninterpreted_fn map.")
}
self.remove_placeholder_vars_if_needed();
Ok(())
}
pub fn remove_uninterpreted_fn_by_str(&mut self, id: &str) -> Result<(), String> {
let fn_id = UninterpretedFnId::new(id)?;
self.remove_uninterpreted_fn(&fn_id)
}
pub fn remove_regulation(&mut self, regulator: &VarId, target: &VarId) -> Result<(), String> {
let regulation = self.get_regulation(regulator, target)?.clone();
if !self.regulations.remove(®ulation) {
panic!("Error when removing regulation between {regulator} - {target}.")
}
Ok(())
}
pub fn remove_regulation_by_str(&mut self, regulation_str: &str) -> Result<(), String> {
let regulation = Regulation::try_from_string(regulation_str)?;
self.remove_regulation(regulation.get_regulator(), regulation.get_target())
}
pub fn change_regulation_sign(
&mut self,
regulator: &VarId,
target: &VarId,
new_sign: &Monotonicity,
) -> Result<(), String> {
let regulation = self.get_regulation(regulator, target)?.clone();
self.remove_regulation(regulation.get_regulator(), regulation.get_target())?;
self.add_regulation(
regulator.clone(),
target.clone(),
*regulation.get_essentiality(),
*new_sign,
)?;
Ok(())
}
pub fn change_regulation_essentiality(
&mut self,
regulator: &VarId,
target: &VarId,
new_essentiality: &Essentiality,
) -> Result<(), String> {
let regulation = self.get_regulation(regulator, target)?.clone();
self.remove_regulation(regulation.get_regulator(), regulation.get_target())?;
self.add_regulation(
regulator.clone(),
target.clone(),
*new_essentiality,
*regulation.get_sign(),
)?;
Ok(())
}
pub fn set_update_fn(&mut self, var_id: &VarId, expression: &str) -> Result<(), String> {
self.assert_valid_variable(var_id)?;
let new_update_fn = UpdateFn::try_from_str(expression, self)?;
self.update_fns.insert(var_id.clone(), new_update_fn);
Ok(())
}
pub fn set_multiple_update_fns(
&mut self,
update_functions: Vec<(&str, &str)>,
) -> Result<(), String> {
let var_ids = update_functions.iter().map(|pair| pair.0).collect();
self.assert_ids_unique_and_used(&var_ids, &(Self::assert_valid_variable))?;
let parsed_fns = update_functions
.iter()
.map(|(_, expression)| UpdateFn::try_from_str(expression, self))
.collect::<Result<Vec<UpdateFn>, String>>()?;
for (i, parsed_fn) in parsed_fns.into_iter().enumerate() {
self.update_fns.insert(VarId::new(var_ids[i])?, parsed_fn);
}
Ok(())
}
fn add_placeholder_vars_if_needed(&mut self, arity: usize) {
while arity > self.num_placeholder_vars() {
let placeholder_id = format!("var{}", self.num_placeholder_vars());
let placeholder = VarId::new(placeholder_id.as_str()).unwrap();
self.placeholder_variables.insert(placeholder);
}
}
fn remove_placeholder_vars_if_needed(&mut self) {
let highest_arity = self
.uninterpreted_fns
.values()
.fold(0, |acc, f| max(acc, f.get_arity()));
while self.num_placeholder_vars() > highest_arity {
let placeholder_id = format!("var{}", self.num_placeholder_vars() - 1);
let placeholder = VarId::new(placeholder_id.as_str()).unwrap();
self.placeholder_variables.remove(&placeholder);
}
}
fn add_default_update_fn(&mut self, var_id: VarId) -> Result<(), String> {
self.assert_valid_variable(&var_id)?;
self.update_fns.insert(var_id, UpdateFn::default());
Ok(())
}
fn remove_all_regulations_var(&mut self, variable: &VarId) -> Result<(), String> {
self.assert_valid_variable(variable)?;
self.regulations
.retain(|r| r.get_regulator() != variable && r.get_target() != variable);
Ok(())
}
}
impl ModelState {
pub fn add_layout_simple(&mut self, layout_id: LayoutId, name: &str) -> Result<(), String> {
self.assert_no_layout(&layout_id)?;
let variable_ids = self.variables.clone().into_keys().collect();
let layout = Layout::new_from_vars_default(name, variable_ids)?;
self.layouts.insert(layout_id, layout);
Ok(())
}
pub fn add_or_update_layout_raw(&mut self, id: LayoutId, layout: Layout) -> Result<(), String> {
let model_vars: HashSet<_> = self.variables.keys().collect();
let layout_vars: HashSet<_> = layout.layout_nodes().map(|(v, _)| v).collect();
if model_vars != layout_vars {
return Err("Model variables and layout variables are different.".to_string());
}
self.layouts.insert(id, layout);
Ok(())
}
pub fn add_layout_copy(
&mut self,
layout_id: LayoutId,
name: &str,
template_layout_id: &LayoutId,
) -> Result<(), String> {
self.assert_no_layout(&layout_id)?;
self.assert_valid_layout(template_layout_id)?;
let template_layout = self.get_layout(template_layout_id)?;
let layout = Layout::new_from_another_copy(name, template_layout);
self.layouts.insert(layout_id, layout);
Ok(())
}
pub fn remove_layout(&mut self, layout_id: &LayoutId) -> Result<(), String> {
self.assert_valid_layout(layout_id)?;
if *layout_id == ModelState::get_default_layout_id() {
return Err("Default layout can not be deleted.".to_string());
}
if self.layouts.remove(layout_id).is_none() {
panic!("Error when removing layout {layout_id} from the layout map.")
}
Ok(())
}
pub fn remove_layout_by_str(&mut self, id: &str) -> Result<(), String> {
let layout_id = LayoutId::new(id)?;
self.remove_layout(&layout_id)
}
pub fn update_position(
&mut self,
layout_id: &LayoutId,
var_id: &VarId,
px: f32,
py: f32,
) -> Result<(), String> {
self.assert_valid_layout(layout_id)?;
self.assert_valid_variable(var_id)?;
self.layouts
.get_mut(layout_id)
.ok_or(format!("Error accessing layout {layout_id} in layout map"))?
.update_node_position(var_id, px, py)
}
fn insert_to_layout(&mut self, var_id: VarId, layout_id: &LayoutId) -> Result<(), String> {
self.assert_valid_variable(&var_id)?;
self.assert_valid_layout(layout_id)?;
let layout = self.layouts.get_mut(layout_id).unwrap();
layout.add_default_node(var_id)?;
Ok(())
}
fn insert_to_default_layout(&mut self, var_id: VarId) -> Result<(), String> {
let default_layout_id = ModelState::get_default_layout_id();
self.insert_to_layout(var_id, &default_layout_id)
}
fn insert_to_all_layouts(&mut self, var_id: VarId) -> Result<(), String> {
for layout in self.layouts.values_mut() {
layout.add_default_node(var_id.clone())?;
}
Ok(())
}
fn remove_from_all_layouts(&mut self, var_id: &VarId) -> Result<(), String> {
for layout in self.layouts.values_mut() {
layout.remove_node(var_id)?
}
Ok(())
}
}
impl ModelState {
fn assert_no_regulation(&self, regulator: &VarId, target: &VarId) -> Result<(), String> {
if self.get_regulation(regulator, target).is_err() {
Ok(())
} else {
Err(format!(
"Invalid regulation: {regulator} already regulates {target}."
))
}
}
fn assert_no_variable(&self, var_id: &VarId) -> Result<(), String> {
if self.is_valid_var_id(var_id) {
Err(format!(
"Variable with id {var_id} already exists in this model."
))
} else {
Ok(())
}
}
fn assert_valid_variable(&self, var_id: &VarId) -> Result<(), String> {
if self.is_valid_var_id(var_id) {
Ok(())
} else {
Err(format!(
"Variable with id {var_id} does not exist in this model."
))
}
}
fn assert_no_uninterpreted_fn(&self, fn_id: &UninterpretedFnId) -> Result<(), String> {
if self.is_valid_uninterpreted_fn_id(fn_id) {
Err(format!("UninterpretedFn with id {fn_id} already exists."))
} else {
Ok(())
}
}
fn assert_valid_uninterpreted_fn(&self, fn_id: &UninterpretedFnId) -> Result<(), String> {
if self.is_valid_uninterpreted_fn_id(fn_id) {
Ok(())
} else {
Err(format!("UninterpretedFn with id {fn_id} does not exist."))
}
}
fn assert_no_layout(&self, layout_id: &LayoutId) -> Result<(), String> {
if self.is_valid_layout_id(layout_id) {
Err(format!("Layout with id {layout_id} already exists."))
} else {
Ok(())
}
}
fn assert_valid_layout(&self, layout_id: &LayoutId) -> Result<(), String> {
if self.is_valid_layout_id(layout_id) {
Ok(())
} else {
Err(format!("Layout with id {layout_id} does not exist."))
}
}
fn assert_fn_not_used_in_expressions(&self, fn_id: &UninterpretedFnId) -> Result<(), String> {
let mut fn_symbols = HashSet::new();
for update_fn in self.update_fns.values() {
let tmp_fn_symbols = update_fn.collect_fn_symbols();
fn_symbols.extend(tmp_fn_symbols);
}
for uninterpreted_fn in self.uninterpreted_fns.values() {
let tmp_fn_symbols = uninterpreted_fn.collect_fn_symbols();
fn_symbols.extend(tmp_fn_symbols);
}
if fn_symbols.contains(fn_id) {
Err(format!("Cannot remove fn symbol `{fn_id}`, it is still contained in an update/uninterpreted function."))
} else {
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use crate::sketchbook::layout::NodePosition;
use crate::sketchbook::model::{Essentiality, ModelState, Monotonicity};
#[test]
fn test_new_default() {
let model = ModelState::new_empty();
assert_eq!(model.num_vars(), 0);
assert_eq!(model.num_uninterpreted_fns(), 0);
assert_eq!(model.num_placeholder_vars(), 0);
assert_eq!(model.num_regulations(), 0);
assert_eq!(model.num_layouts(), 1);
let default_layout_id = ModelState::get_default_layout_id();
assert_eq!(
model.get_layout_name(&default_layout_id).unwrap().as_str(),
ModelState::get_default_layout_name(),
)
}
#[test]
fn test_new_from_vars() {
let var_id_name_pairs = vec![("a_id", "a_name"), ("a_id", "b_name")];
assert!(ModelState::new_from_vars(var_id_name_pairs).is_err());
let var_id_name_pairs = vec![("a_id", "a_name"), ("b_id", "b_name")];
let model = ModelState::new_from_vars(var_id_name_pairs).unwrap();
assert_eq!(model.num_vars(), 2);
assert!(model.is_valid_var_id_str("a_id"));
assert!(model.is_valid_var_id_str("b_id"));
assert!(!model.is_valid_var_id_str("c_id"));
}
#[test]
fn test_adding_variables() {
let mut model = ModelState::new_empty();
model.add_var_by_str("a", "a_name", "").unwrap();
model.add_var_by_str("b", "b_name", "").unwrap();
model.add_var_by_str("c", "c_name", "").unwrap();
assert_eq!(model.num_vars(), 3);
assert!(model.is_valid_var_id_str("c"));
let variables = vec![("aaa", "aaa_name"), ("bbb", "bbb_name")];
model.add_multiple_variables(variables).unwrap();
assert_eq!(model.num_vars(), 5);
assert!(model.is_valid_var_id_str("bbb"));
}
#[test]
fn test_adding_uninterpreted_fns() {
let mut model = ModelState::new_empty();
model
.add_empty_uninterpreted_fn_by_str("f", "f", 1)
.unwrap();
model
.add_empty_uninterpreted_fn_by_str("g", "g", 0)
.unwrap();
let f_id = model.get_uninterpreted_fn_id("f").unwrap();
let f = model.get_uninterpreted_fn(&f_id).unwrap();
assert_eq!(model.num_uninterpreted_fns(), 2);
assert_eq!(model.num_placeholder_vars(), 1);
assert!(model.is_valid_uninterpreted_fn_id_str("f"));
assert!(model.is_valid_uninterpreted_fn_id_str("g"));
assert_eq!(f.get_arity(), 1);
let uninterpreted_fns = vec![("ff", "ff", 4), ("gg", "gg", 3)];
model
.add_multiple_uninterpreted_fns(uninterpreted_fns)
.unwrap();
assert_eq!(model.num_placeholder_vars(), 4);
assert!(model.is_valid_uninterpreted_fn_id_str("ff"));
assert!(model.is_valid_uninterpreted_fn_id_str("gg"));
}
#[test]
fn test_adding_regulations() {
let var_id_name_pairs = vec![("a", "a"), ("b", "b"), ("c", "c")];
let mut model1 = ModelState::new_from_vars(var_id_name_pairs).unwrap();
let mut model2 = model1.clone();
model1.add_regulation_by_str("a -> a").unwrap();
model1.add_regulation_by_str("a -> b").unwrap();
model1.add_regulation_by_str("b -> c").unwrap();
model1.add_regulation_by_str("c -> a").unwrap();
assert_eq!(model1.num_regulations(), 4);
let regulations = vec!["a -> a", "a -> b", "b -> c", "c -> a"];
model2.add_multiple_regulations(regulations).unwrap();
assert_eq!(model1, model2);
}
#[test]
fn test_manually_editing_regulation_graph() {
let mut model = ModelState::new_empty();
let variables = vec![("a", "a_name"), ("b", "b_name"), ("c", "c_name")];
model.add_multiple_variables(variables).unwrap();
assert_eq!(model.num_vars(), 3);
assert!(model.is_valid_var_id_str("c"));
let regulations = vec!["a -> a", "a -> b", "b -> c", "c -> a"];
model.add_multiple_regulations(regulations).unwrap();
assert_eq!(model.num_regulations(), 4);
let var_a = model.get_var_id("a").unwrap();
model.remove_var(&var_a).unwrap();
assert!(model.get_var_name(&var_a).is_err());
let var_b = model.get_var_id("b").unwrap();
assert!(model.get_regulation(&var_a, &var_b).is_err());
assert_eq!(model.num_regulations(), 1);
assert!(model.add_var(var_a, "name_a", "").is_ok());
model.remove_regulation_by_str("b -> c").unwrap();
let var_c = model.get_var_id("c").unwrap();
assert!(model.get_regulation(&var_b, &var_c).is_err());
assert!(model.add_regulation_by_str("b -> c").is_ok());
assert_eq!(model.num_regulations(), 1);
}
#[test]
fn test_manually_editing_uninterpreted_fns() {
let mut model = ModelState::new_empty();
let uninterpreted_fns = vec![("f", "f", 4), ("g", "g", 1)];
model
.add_multiple_uninterpreted_fns(uninterpreted_fns)
.unwrap();
let f_id = model.get_uninterpreted_fn_id("f").unwrap();
let f = model.get_uninterpreted_fn(&f_id).unwrap();
assert_eq!(model.num_uninterpreted_fns(), 2);
assert_eq!(f.get_fn_expression(), "");
assert_eq!(f.get_essential(0), &Essentiality::Unknown);
assert_eq!(f.get_monotonic(2), &Monotonicity::Unknown);
assert_eq!(model.num_placeholder_vars(), 4);
model.set_uninterpreted_fn_name(&f_id, "ff").unwrap();
model.set_uninterpreted_fn_arity(&f_id, 3).unwrap();
model
.set_uninterpreted_fn_essentiality(&f_id, Essentiality::True, 0)
.unwrap();
model
.set_uninterpreted_fn_monotonicity(&f_id, Monotonicity::Activation, 2)
.unwrap();
model
.set_uninterpreted_fn_expression(&f_id, "g(var0) | var2")
.unwrap();
let f = model.get_uninterpreted_fn(&f_id).unwrap();
assert_eq!(f.get_name(), "ff");
assert_eq!(f.get_fn_expression(), "g(var0) | var2");
assert_eq!(f.get_essential(0), &Essentiality::True);
assert_eq!(f.get_monotonic(2), &Monotonicity::Activation);
assert_eq!(model.num_placeholder_vars(), 3);
let remove_error = model.remove_uninterpreted_fn_by_str("g");
assert!(remove_error.is_err());
let modify_arity_error = model.set_uninterpreted_fn_arity_by_str("g", 2);
assert!(modify_arity_error.is_err());
model.set_uninterpreted_fn_id_by_str("g", "h").unwrap();
let f = model.get_uninterpreted_fn(&f_id).unwrap();
assert_eq!(f.get_fn_expression(), "h(var0) | var2");
model.set_uninterpreted_fn_expression(&f_id, "").unwrap();
let f = model.get_uninterpreted_fn(&f_id).unwrap();
assert_eq!(f.get_fn_expression(), "");
model.set_uninterpreted_fn_arity_by_str("h", 5).unwrap();
assert_eq!(model.num_placeholder_vars(), 5);
model.remove_uninterpreted_fn(&f_id).unwrap();
assert_eq!(model.num_uninterpreted_fns(), 1);
assert_eq!(model.num_placeholder_vars(), 5);
model.remove_uninterpreted_fn_by_str("h").unwrap();
assert_eq!(model.num_uninterpreted_fns(), 0);
assert_eq!(model.num_placeholder_vars(), 0);
}
#[test]
fn test_update_fns() {
let var_id_name_pairs = vec![("a", "a"), ("b", "b"), ("c", "c")];
let mut model = ModelState::new_from_vars(var_id_name_pairs).unwrap();
let var_a = model.get_var_id("a").unwrap();
let initial_expression = model.get_update_fn_string(&var_a).unwrap();
assert_eq!(initial_expression, "");
let expression = "(a & b) => c";
model.set_update_fn(&var_a, "(a & b) => c").unwrap();
let modified_expression = model.get_update_fn_string(&var_a).unwrap();
assert_eq!(modified_expression, expression);
}
#[test]
fn test_add_invalid_vars() {
let mut model = ModelState::new_empty();
let variables = vec![("a", "a_name"), ("b", "b_name")];
model.add_multiple_variables(variables).unwrap();
assert_eq!(model.num_vars(), 2);
assert!(model.add_var_by_str("a", "whatever", "").is_err());
assert!(model.add_var_by_str("a ", "whatever2", "").is_err());
assert!(model.add_var_by_str("(", "whatever3", "").is_err());
assert!(model.add_var_by_str("aa+a", "whatever4", "").is_err());
assert_eq!(model.num_vars(), 2);
}
#[test]
fn test_add_invalid_regs() {
let mut model = ModelState::new_empty();
let variables = vec![("a", "a_name"), ("b", "b_name")];
model.add_multiple_variables(variables).unwrap();
let var_a = model.get_var_id("a").unwrap();
let var_b = model.get_var_id("b").unwrap();
model.add_regulation_by_str("a -> b").unwrap();
assert!(model.add_regulation_by_str("a -> b").is_err());
assert!(model.add_regulation_by_str("a -| b").is_err());
assert!(model
.add_regulation(var_a, var_b, Essentiality::Unknown, Monotonicity::Dual)
.is_err());
assert!(model.add_regulation_by_str("a -> a b").is_err());
assert!(model.add_regulation_by_str("X -> a").is_err());
assert!(model.add_regulation_by_str("a -@ a").is_err());
assert_eq!(model.num_regulations(), 1);
}
#[test]
fn test_var_name_change() {
let mut model = ModelState::new_empty();
let variables = vec![("a", "a_name"), ("b", "b_name")];
model.add_multiple_variables(variables).unwrap();
let var_a = model.get_var_id("a").unwrap();
model.set_var_name(&var_a, "new_name").unwrap();
assert_eq!(model.get_var_name(&var_a).unwrap(), "new_name");
model.set_var_name(&var_a, "b_name").unwrap();
assert_eq!(model.get_var_name(&var_a).unwrap(), "b_name");
}
#[test]
fn test_var_id_change() {
let mut model = ModelState::new_empty();
let var_a = model.generate_var_id("a", None);
model.add_var(var_a.clone(), "a_name", "").unwrap();
let var_b = model.generate_var_id("b", None);
model.add_var(var_b.clone(), "b_name", "").unwrap();
let regulations = vec!["a -> a", "a -> b", "b -> a", "b -> b"];
model.add_multiple_regulations(regulations).unwrap();
let default_layout_id = ModelState::get_default_layout_id();
let new_layout_id = model.generate_layout_id("layout2", None);
model
.add_layout_copy(new_layout_id.clone(), "layout2", &default_layout_id)
.unwrap();
model.set_update_fn(&var_a, "a | b").unwrap();
model.set_update_fn(&var_b, "a => a").unwrap();
let new_var = model.generate_var_id("c", None);
model.set_var_id(&var_a, new_var.clone()).unwrap();
assert!(!model.is_valid_var_id(&var_a));
assert!(model.is_valid_var_id(&new_var));
assert_eq!(model.num_regulations(), 4);
assert!(model.get_regulation(&new_var, &new_var).is_ok());
assert!(model.get_regulation(&new_var, &var_b).is_ok());
assert!(model.get_regulation(&var_b, &new_var).is_ok());
assert!(model.get_regulation(&var_b, &var_b).is_ok());
let layout1 = model.get_layout(&default_layout_id).unwrap();
let layout2 = model.get_layout(&new_layout_id).unwrap();
assert!(layout1.get_node_position(&var_a).is_err());
assert!(layout2.get_node_position(&var_a).is_err());
assert!(layout1.get_node_position(&new_var).is_ok());
assert!(layout2.get_node_position(&new_var).is_ok());
assert!(model.get_update_fn_string(&var_a).is_err());
assert_eq!(model.get_update_fn_string(&new_var).unwrap(), "c | b");
assert_eq!(model.get_update_fn_string(&var_b).unwrap(), "c => c");
}
#[test]
fn test_layout_manipulation() {
let var_id_name_pairs = vec![("a_id", "a_name"), ("b_id", "b_name")];
let mut model = ModelState::new_from_vars(var_id_name_pairs).unwrap();
assert_eq!(model.num_layouts(), 1);
let default_layout_id = ModelState::get_default_layout_id();
let default_layout_name = ModelState::get_default_layout_name();
let default_layout = model.get_layout(&default_layout_id).unwrap();
assert!(model.is_valid_layout_id(&default_layout_id));
assert_eq!(default_layout.get_num_nodes(), 2);
assert_eq!(default_layout.get_layout_name(), default_layout_name);
let var_id = model.get_var_id("a_id").unwrap();
model
.update_position(&default_layout_id, &var_id, 2., 2.)
.unwrap();
let position = model
.get_node_position(&default_layout_id, &var_id)
.unwrap();
assert_eq!(position, &NodePosition(2., 2.));
let new_id_1 = model.generate_layout_id("new_layout", None);
model
.add_layout_simple(new_id_1.clone(), "new_layout")
.unwrap();
let position = model.get_node_position(&new_id_1, &var_id).unwrap();
assert_eq!(position, &NodePosition(0., 0.));
let new_id_2 = model.generate_layout_id("another_layout", None);
model
.add_layout_copy(new_id_2.clone(), "new_layout", &default_layout_id)
.unwrap();
let position = model.get_node_position(&new_id_2, &var_id).unwrap();
assert_eq!(position, &NodePosition(2., 2.));
}
}