/// model/objects.rs, BAYES STAR, (c) coppola.ai 2024 use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::collections::hash_map::DefaultHasher; use std::fmt; use std::hash::{Hash, Hasher}; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] pub enum ArgumentType { Constant, Variable, } #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Domain { Jack, Jill, } impl Domain { pub fn from_str(s: &str) -> Option { match s { "Jack" => Some(Domain::Jack), "Jill" => Some(Domain::Jill), _ => None, } } } impl fmt::Display for Domain { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let domain_str = match self { Domain::Jack => "Jack", Domain::Jill => "Jill", }; write!(f, "{}", domain_str) } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] pub enum Argument { Constant(ConstantArgument), Variable(VariableArgument), } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] pub struct ConstantArgument { pub domain: Domain, pub entity_id: String, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] pub struct VariableArgument { pub domain: Domain, } impl ConstantArgument { pub fn new(domain: Domain, entity_id: String) -> Self { ConstantArgument { domain, entity_id } } pub fn hash_string(&self) -> String { self.entity_id.clone() } } impl VariableArgument { pub fn new(domain: Domain) -> Self { VariableArgument { domain } } pub fn hash_string(&self) -> String { format!("?{}", self.domain) } } impl Argument { pub fn hash_string(&self) -> String { match self { Argument::Constant(arg) => arg.hash_string(), Argument::Variable(arg) => arg.hash_string(), } } pub fn convert_to_quantified(&self) -> Argument { match self { Argument::Constant(arg) => { Argument::Variable(VariableArgument::new(arg.domain.clone())) } Argument::Variable(arg) => Argument::Variable(arg.clone()), } } pub fn is_constant(&self) -> bool { match self { Argument::Constant(_) => true, Argument::Variable(_) => false, } } pub fn is_variable(&self) -> bool { !self.is_constant() } } impl fmt::Display for ConstantArgument { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Customize the formatting as needed write!(f, "{:?}", self) // For example, you can use Debug formatting here } } impl fmt::Display for VariableArgument { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Customize the formatting as needed write!(f, "{:?}", self) // For example, you can use Debug formatting here } } impl fmt::Display for Argument { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Argument::Constant(arg) => write!(f, "Constant({})", arg), // Update as needed Argument::Variable(arg) => write!(f, "Variable({})", arg), // Update as needed // Add cases for other variants if they exist } } } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] pub struct LabeledArgument { pub role_name: String, pub argument: Argument, } impl LabeledArgument { pub fn new(role_name: String, argument: Argument) -> Self { LabeledArgument { role_name, argument, } } pub fn hash_string(&self) -> String { format!("{}={}", self.role_name, self.argument.hash_string()) } pub fn convert_to_quantified(&self) -> LabeledArgument { LabeledArgument::new( self.role_name.clone(), self.argument.convert_to_quantified(), ) } pub fn do_substitution(&self, value: Argument) -> LabeledArgument { LabeledArgument::new(self.role_name.clone(), value) } } pub const EXISTENCE_FUNCTION: &str = "exist"; #[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] pub struct Predicate { pub function: String, roles: Vec, } impl fmt::Debug for Predicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.debug_string()) } } impl Predicate { pub fn new(function: String, roles: Vec) -> Self { let mut buffer = roles.clone(); buffer.sort_by(|a, b| a.role_name.cmp(&b.role_name)); Predicate { function, roles: buffer } } pub fn debug_string(&self) -> String { self.hash_string() } pub fn hash_string(&self) -> String { let role_strings: Vec = self .roles .iter() .map(|role| role.hash_string()) .collect(); format!("{}[{}]", &self.function, role_strings.join(",")) } pub fn role_names(&self) -> Vec { self.roles .iter() .map(|role| role.role_name.clone()) .collect() } pub fn is_fact(&self) -> bool { self.roles.iter().all(|role| role.argument.is_constant()) } pub fn roles(&self) -> Vec { self.roles.clone() } } #[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] pub struct Proposition { pub predicate: Predicate, } impl fmt::Debug for Proposition { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.debug_string()) } } fn hash_proposition(proposition: &Proposition) -> u64 { let mut hasher = DefaultHasher::new(); proposition.hash(&mut hasher); hasher.finish() } impl Proposition { pub fn from(predicate: Predicate) -> Self { if !predicate.is_fact() { panic!( "This predicate is not a fact {:?}.", predicate.hash_string() ); } Proposition { predicate } } pub fn hash_string(&self) -> String { self.predicate.hash_string() } pub fn debug_string(&self) -> String { self.predicate.hash_string() } } #[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] pub struct PredicateGroup { pub terms: Vec, } impl fmt::Debug for PredicateGroup { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.debug_string()) } } impl PredicateGroup { pub fn new(terms: Vec) -> Self { PredicateGroup { terms } } pub fn hash_string(&self) -> String { let mut hash_strings: Vec = self .terms .iter() .map(|term| term.hash_string()) // Map each term to its search string .collect(); hash_strings.sort(); // Sort the search strings in ascending order hash_strings.join(";") // Join the sorted strings, separated by a comma and a space } pub fn debug_string(&self) -> String { self.hash_string() } } #[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] pub struct PropositionGroup { pub terms: Vec, } impl fmt::Debug for PropositionGroup { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.debug_string()) } } impl PropositionGroup { pub fn new(terms: Vec) -> Self { let mut buffer = terms.clone(); buffer.sort_by(|a, b| a.predicate.function.cmp(&b.predicate.function)); PropositionGroup { terms } } pub fn hash_string(&self) -> String { let hash_strings: Vec = self .terms .iter() .map(|term| term.predicate.hash_string()) // Map each term to its search string .collect(); let join = hash_strings.join("&"); // Join the sorted strings, separated by a comma and a space format!("{{{}}}", &join) } pub fn debug_string(&self) -> String { self.hash_string() } } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct PredicateFactor { pub premise: PredicateGroup, pub role_maps: GroupRoleMap, pub conclusion: Predicate, } impl PredicateFactor { // Generate a unique key for the implication pub fn unique_key(&self) -> String { format!( "{}->{}{}", self.premise.hash_string(), self.conclusion.hash_string(), self.mapping_string() ) } // Generate a feature string based on the premise and the role map pub fn feature_string(&self) -> String { format!("{}{}", self.premise.hash_string(), self.mapping_string()) } // Convert the role map to a string fn mapping_string(&self) -> String { self.role_maps.to_string() // Assuming RoleMap has a ToString implementation } } #[derive(Debug, Clone)] pub struct Entity { pub domain: Domain, pub name: String, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct RoleMap { pub role_map: Vec<(String, String)>, } impl RoleMap { pub fn new(role_map: HashMap) -> Self { let mut sorted_vec: Vec<(String, String)> = role_map.into_iter().collect(); sorted_vec.sort_by(|a, b| a.0.cmp(&b.0)); RoleMap { role_map: sorted_vec } } pub fn get(&self, role_name: &str) -> Option<&String> { for (from, to) in &self.role_map { if role_name == from { return Some(to); } } None } } impl fmt::Display for RoleMap { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut entries: Vec<_> = self.role_map.iter().collect(); // Sort the entries by key entries.sort_by(|(a_key, _), (b_key, _)| a_key.cmp(b_key)); let entries_str: Vec = entries .into_iter() .map(|(key, value)| format!("{}: {}", key, value)) .collect(); write!(f, "{{{}}}", entries_str.join(", ")) } } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct GroupRoleMap { pub role_maps: Vec, } impl GroupRoleMap { pub fn new(role_maps: Vec) -> Self { GroupRoleMap { role_maps } } } impl fmt::Display for GroupRoleMap { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let role_maps_str = self .role_maps .iter() .map(|role_map| role_map.to_string()) // Convert each RoleMap to a String using its Display implementation .collect::>() .join(", "); // Concatenate all the string representations with a comma separator write!(f, "[{}]", role_maps_str) } }