/// 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<Domain> {
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<LabeledArgument>,
}
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<LabeledArgument>) -> 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<String> = self
.roles
.iter()
.map(|role| role.hash_string())
.collect();
format!("{}[{}]", &self.function, role_strings.join(","))
}
pub fn role_names(&self) -> Vec<String> {
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<LabeledArgument> {
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<Predicate>,
}
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<Predicate>) -> Self {
PredicateGroup { terms }
}
pub fn hash_string(&self) -> String {
let mut hash_strings: Vec<String> = 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<Proposition>,
}
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<Proposition>) -> 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<String> = 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<String, String>) -> 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<String> = 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<RoleMap>,
}
impl GroupRoleMap {
pub fn new(role_maps: Vec<RoleMap>) -> 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::<Vec<String>>()
.join(", "); // Concatenate all the string representations with a comma separator
write!(f, "[{}]", role_maps_str)
}
}