use crate::sketchbook::ids::{StatPropertyId, UninterpretedFnId, VarId};
use crate::sketchbook::model::{Essentiality, Monotonicity};
use crate::sketchbook::properties::static_props;
use crate::sketchbook::JsonSerde;
use serde::{Deserialize, Serialize};
use static_props::{StatProperty, StatPropertyType};
fn input_id_to_index(input_id: &Option<String>) -> Result<Option<usize>, String> {
match input_id {
Some(s) if s.starts_with("var") && s[3..].chars().all(char::is_numeric) => s[3..]
.parse::<usize>()
.map(Some)
.map_err(|e| format!("{:?}", e)),
None => Ok(None),
_ => Err("Input ID has invalid format, must be `varN`".to_string()),
}
}
fn input_index_to_id(input_index: usize) -> String {
format!("var{}", input_index)
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct GenericStatPropData {
pub formula: String,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RegulationEssentialData {
pub input: Option<String>,
pub target: Option<String>,
pub value: Essentiality,
pub context: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct FnInputEssentialData {
pub input: Option<String>,
pub target: Option<String>,
pub value: Essentiality,
pub context: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct RegulationMonotonicData {
pub input: Option<String>,
pub target: Option<String>,
pub value: Monotonicity,
pub context: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct FnInputMonotonicData {
pub input: Option<String>,
pub target: Option<String>,
pub value: Monotonicity,
pub context: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "variant")]
pub enum StatPropertyTypeData {
GenericStatProp(GenericStatPropData),
RegulationEssential(RegulationEssentialData),
RegulationEssentialContext(RegulationEssentialData),
FnInputEssential(FnInputEssentialData),
FnInputEssentialContext(FnInputEssentialData),
RegulationMonotonic(RegulationMonotonicData),
RegulationMonotonicContext(RegulationMonotonicData),
FnInputMonotonic(FnInputMonotonicData),
FnInputMonotonicContext(FnInputMonotonicData),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StatPropertyData {
pub id: String,
pub name: String,
pub annotation: String,
#[serde(flatten)]
pub variant: StatPropertyTypeData,
}
impl<'de> JsonSerde<'de> for StatPropertyData {}
impl StatPropertyData {
pub fn new_generic(id: &str, name: &str, formula: &str, annot: &str) -> StatPropertyData {
let variant = StatPropertyTypeData::GenericStatProp(GenericStatPropData {
formula: formula.to_string(),
});
Self::new_raw(id, name, variant, annot)
}
pub fn from_property(id: &StatPropertyId, property: &StatProperty) -> StatPropertyData {
let name = property.get_name();
let annot = property.get_annotation();
let variant = match property.get_prop_data() {
StatPropertyType::GenericStatProp(p) => {
StatPropertyTypeData::GenericStatProp(GenericStatPropData {
formula: p.raw_formula.clone(),
})
}
StatPropertyType::RegulationEssential(p) => {
StatPropertyTypeData::RegulationEssential(RegulationEssentialData {
input: p.input.as_ref().map(|i| i.to_string()),
target: p.target.as_ref().map(|i| i.to_string()),
value: p.value,
context: None,
})
}
StatPropertyType::RegulationEssentialContext(p) => {
StatPropertyTypeData::RegulationEssentialContext(RegulationEssentialData {
input: p.input.as_ref().map(|i| i.to_string()),
target: p.target.as_ref().map(|i| i.to_string()),
value: p.value,
context: p.context.clone(),
})
}
StatPropertyType::RegulationMonotonic(p) => {
StatPropertyTypeData::RegulationMonotonic(RegulationMonotonicData {
input: p.input.as_ref().map(|i| i.to_string()),
target: p.target.as_ref().map(|i| i.to_string()),
value: p.value,
context: None,
})
}
StatPropertyType::RegulationMonotonicContext(p) => {
StatPropertyTypeData::RegulationMonotonicContext(RegulationMonotonicData {
input: p.input.as_ref().map(|i| i.to_string()),
target: p.target.as_ref().map(|i| i.to_string()),
value: p.value,
context: p.context.clone(),
})
}
StatPropertyType::FnInputEssential(p) => {
StatPropertyTypeData::FnInputEssential(FnInputEssentialData {
input: p.input_index.map(input_index_to_id),
target: p.target.as_ref().map(|i| i.to_string()),
value: p.value,
context: None,
})
}
StatPropertyType::FnInputEssentialContext(p) => {
StatPropertyTypeData::FnInputEssentialContext(FnInputEssentialData {
input: p.input_index.map(input_index_to_id),
target: p.target.as_ref().map(|i| i.to_string()),
value: p.value,
context: p.context.clone(),
})
}
StatPropertyType::FnInputMonotonic(p) => {
StatPropertyTypeData::FnInputMonotonic(FnInputMonotonicData {
input: p.input_index.map(input_index_to_id),
target: p.target.as_ref().map(|i| i.to_string()),
value: p.value,
context: None,
})
}
StatPropertyType::FnInputMonotonicContext(p) => {
StatPropertyTypeData::FnInputMonotonicContext(FnInputMonotonicData {
input: p.input_index.map(input_index_to_id),
target: p.target.as_ref().map(|i| i.to_string()),
value: p.value,
context: p.context.clone(),
})
}
};
Self::new_raw(id.as_str(), name, variant, annot)
}
pub fn to_property(&self) -> Result<StatProperty, String> {
let name = self.name.as_str();
let annot = self.annotation.as_str();
let property = match &self.variant {
StatPropertyTypeData::GenericStatProp(p) => {
StatProperty::try_mk_generic(name, &p.formula, annot)?
}
StatPropertyTypeData::FnInputMonotonic(p) => StatProperty::mk_fn_input_monotonic(
name,
input_id_to_index(&p.input)?,
p.target
.as_ref()
.and_then(|t| UninterpretedFnId::new(t).ok()),
p.value,
annot,
),
StatPropertyTypeData::FnInputMonotonicContext(p) => {
StatProperty::mk_fn_input_monotonic_context(
name,
input_id_to_index(&p.input)?,
p.target
.as_ref()
.and_then(|t| UninterpretedFnId::new(t).ok()),
p.value,
p.context.clone().ok_or("Context missing.")?,
annot,
)
}
StatPropertyTypeData::FnInputEssential(p) => StatProperty::mk_fn_input_essential(
name,
input_id_to_index(&p.input)?,
p.target
.as_ref()
.and_then(|t| UninterpretedFnId::new(t).ok()),
p.value,
annot,
),
StatPropertyTypeData::FnInputEssentialContext(p) => {
StatProperty::mk_fn_input_essential_context(
name,
input_id_to_index(&p.input)?,
p.target
.as_ref()
.and_then(|t| UninterpretedFnId::new(t).ok()),
p.value,
p.context.clone().ok_or("Context missing.")?,
annot,
)
}
StatPropertyTypeData::RegulationMonotonic(p) => StatProperty::mk_regulation_monotonic(
name,
p.input.as_ref().and_then(|i| VarId::new(i).ok()),
p.target.as_ref().and_then(|t| VarId::new(t).ok()),
p.value,
annot,
),
StatPropertyTypeData::RegulationMonotonicContext(p) => {
StatProperty::mk_regulation_monotonic_context(
name,
p.input.as_ref().and_then(|i| VarId::new(i).ok()),
p.target.as_ref().and_then(|t| VarId::new(t).ok()),
p.value,
p.context.clone().ok_or("Context missing.")?,
annot,
)
}
StatPropertyTypeData::RegulationEssential(p) => StatProperty::mk_regulation_essential(
name,
p.input.as_ref().and_then(|i| VarId::new(i).ok()),
p.target.as_ref().and_then(|t| VarId::new(t).ok()),
p.value,
annot,
),
StatPropertyTypeData::RegulationEssentialContext(p) => {
StatProperty::mk_regulation_essential_context(
name,
p.input.as_ref().and_then(|i| VarId::new(i).ok()),
p.target.as_ref().and_then(|t| VarId::new(t).ok()),
p.value,
p.context.clone().ok_or("Context missing.")?,
annot,
)
}
};
Ok(property)
}
fn new_raw(
id: &str,
name: &str,
variant: StatPropertyTypeData,
annot: &str,
) -> StatPropertyData {
StatPropertyData {
id: id.to_string(),
name: name.to_string(),
variant,
annotation: annot.to_string(),
}
}
}