use crate::{
entity::{
BudgetValue, Item, Judgement, JudgementV1, RCTask, Sentence, TaskLink, TermLink,
TermLinkTemplate, Token,
},
global::{ClockTime, Float},
inference::{Budget, BudgetFunctions},
language::Term,
parameters::{Parameters, DEFAULT_PARAMETERS},
storage::{ArrayBuffer, ArrayRankTable, Bag, Buffer, IsCompatibleToAddF, RankF, RankTable},
util::{to_display_when_has_content, Iterable, ToDisplayAndBrief},
};
use nar_dev_utils::{join, RefCount};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct Concept {
token: Token,
term: Term,
task_links: Bag<TaskLink>,
term_links: Bag<TermLink>,
link_templates_to_self: Vec<TermLinkTemplate>,
questions: ArrayBuffer<RCTask>,
#[serde(deserialize_with = "beliefs::deserialize")]
beliefs: ArrayRankTable<JudgementV1>,
}
mod beliefs {
use super::*;
pub const RANK_F: RankF<JudgementV1> = BudgetValue::rank_belief;
pub const IS_COMPATIBLE_TO_ADD_F: IsCompatibleToAddF<JudgementV1> = belief_compatible_to_add;
type Table = ArrayRankTable<JudgementV1>;
pub fn new(capacity: usize) -> Table {
Table::new(
capacity,
RANK_F, IS_COMPATIBLE_TO_ADD_F,
)
}
fn belief_compatible_to_add(incoming: &impl Judgement, existed: &impl Judgement) -> bool {
!incoming.is_belief_equivalent(existed)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<ArrayRankTable<JudgementV1>, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut table = ArrayRankTable::deserialize(deserializer)?;
table.override_fn(beliefs::RANK_F, beliefs::IS_COMPATIBLE_TO_ADD_F);
Ok(table)
}
}
#[derive(Debug, Clone, Copy)]
pub struct ConceptParameters {
task_link_forgetting_cycle: usize,
term_link_forgetting_cycle: usize,
maximum_questions_length: usize,
maximum_belief_length: usize,
task_link_bag_size: usize,
term_link_bag_size: usize,
}
impl From<&Parameters> for ConceptParameters {
fn from(parameters: &Parameters) -> Self {
Self {
task_link_forgetting_cycle: parameters.task_link_forgetting_cycle,
term_link_forgetting_cycle: parameters.term_link_forgetting_cycle,
maximum_questions_length: parameters.maximum_questions_length,
maximum_belief_length: parameters.maximum_belief_length,
task_link_bag_size: parameters.task_link_bag_size,
term_link_bag_size: parameters.term_link_bag_size,
}
}
}
impl Concept {
pub fn new(
term: Term,
parameters: ConceptParameters,
initial_budget: BudgetValue,
link_templates_to_self: Vec<TermLinkTemplate>,
) -> Self {
let ConceptParameters {
maximum_questions_length,
maximum_belief_length,
task_link_bag_size,
term_link_bag_size,
task_link_forgetting_cycle,
term_link_forgetting_cycle,
} = parameters;
let token = Token::new(term.name(), initial_budget);
let questions = ArrayBuffer::new(maximum_questions_length);
let beliefs = beliefs::new(maximum_belief_length);
let task_links = Bag::new(task_link_forgetting_cycle, task_link_bag_size);
let term_links = Bag::new(term_link_forgetting_cycle, term_link_bag_size);
Self {
token,
term,
task_links,
term_links,
link_templates_to_self,
questions,
beliefs,
}
}
pub fn beliefs(&self) -> impl Iterator<Item = &JudgementV1> {
self.beliefs.iter()
}
#[must_use]
pub fn add_belief(&mut self, belief: JudgementV1) -> Option<JudgementV1> {
self.beliefs.add(belief)
}
pub fn questions(&self) -> impl Iterator<Item = &RCTask> {
self.questions.iter()
}
pub fn questions_mut(&mut self) -> impl Iterator<Item = &mut RCTask> {
self.questions.iter_mut()
}
#[must_use]
pub fn add_question(&mut self, question: RCTask) -> Option<RCTask> {
self.questions.add(question)
}
pub fn link_templates_to_self(&self) -> &[TermLinkTemplate] {
&self.link_templates_to_self
}
pub fn put_in_term_link(&mut self, link: TermLink) -> Option<TermLink> {
self.term_links.put_in(link)
}
#[must_use]
pub fn put_in_task_link(&mut self, link: TaskLink) -> Option<TaskLink> {
self.task_links.put_in(link)
}
#[must_use]
pub fn take_out_task_link(&mut self) -> Option<TaskLink> {
self.task_links.take_out()
}
#[must_use]
pub fn put_task_link_back(&mut self, link: TaskLink) -> Option<TaskLink> {
self.task_links.put_back(link)
}
#[must_use]
pub fn put_term_link_back(&mut self, link: TermLink) -> Option<TermLink> {
self.term_links.put_back(link)
}
pub fn term(&self) -> &Term {
&self.term
}
pub fn term_links_average_priority(&self) -> Float {
self.term_links.average_priority()
}
pub fn get_belief(&self, task_sentence: &impl Sentence) -> Option<&JudgementV1> {
for belief in self.beliefs.iter() {
if !task_sentence.evidential_overlap(belief) {
let selected = belief;
return Some(selected);
}
}
None
}
pub fn take_out_term_link_from_task_link(
&mut self,
task_link: &mut TaskLink,
time: ClockTime,
) -> Option<TermLink> {
for _ in 0..DEFAULT_PARAMETERS.max_matched_term_link {
let term_link = self.term_links.take_out()?;
if task_link.novel(&term_link, time) {
return Some(term_link);
}
let _ = self.term_links.put_back(term_link);
}
None
}
pub(crate) fn iter_tasks(&self) -> impl Iterator<Item = &RCTask> {
let iter_task_links = self.iter_task_links().map(TaskLink::target_rc_ref);
let iter_questions = self.iter_questions();
iter_task_links.chain(iter_questions)
}
pub(crate) fn iter_beliefs(&self) -> impl Iterator<Item = &JudgementV1> {
self.beliefs.iter()
}
pub(crate) fn iter_questions(&self) -> impl Iterator<Item = &RCTask> {
self.questions.iter()
}
pub(crate) fn iter_term_links(&self) -> impl Iterator<Item = &TermLink> {
self.term_links.iter()
}
pub(crate) fn iter_task_links(&self) -> impl Iterator<Item = &TaskLink> {
self.task_links.iter()
}
pub(crate) fn iter_tasks_mut(&mut self) -> impl Iterator<Item = &mut RCTask> {
let iter_task_links = self.task_links.iter_mut().map(TaskLink::target_rc_ref_mut);
let iter_questions = self.questions.iter_mut();
iter_task_links.chain(iter_questions)
}
}
impl Budget for Concept {
fn priority(&self) -> super::ShortFloat {
self.token.priority()
}
fn __priority_mut(&mut self) -> &mut super::ShortFloat {
self.token.__priority_mut()
}
fn durability(&self) -> super::ShortFloat {
self.token.durability()
}
fn __durability_mut(&mut self) -> &mut super::ShortFloat {
self.token.__durability_mut()
}
fn quality(&self) -> super::ShortFloat {
self.token.quality()
}
fn __quality_mut(&mut self) -> &mut super::ShortFloat {
self.token.__quality_mut()
}
}
impl Item for Concept {
fn key(&self) -> &String {
self.token.key()
}
}
const DETAILED_STRING: bool = false;
impl ToDisplayAndBrief for Concept {
fn to_display(&self) -> String {
match DETAILED_STRING {
true => join! {
=> self.token.budget().to_display_brief()
=> " "
=> self.key()
},
false => self.key().into(),
}
}
fn to_display_long(&self) -> String {
let mut base = join! {
=> self.to_display_brief()
=> to_display_when_has_content(" term_links: ", self.term_links.to_display())
=> to_display_when_has_content(" task_links: ", self.task_links.to_display())
};
if !self.questions.is_empty() {
base += "\n questions:";
for t in self.questions.iter() {
base += "\n";
base += &t.get_().to_display();
}
}
if !self.beliefs.is_empty() {
base += "\n beliefs:";
for b in self.beliefs.iter() {
base += "\n";
base += &b.to_display();
}
}
base
}
}