use crate::__impl_to_display_and_display;
use crate::{global::ClockTime, inference::Evidential};
use anyhow::Result;
use narsese::lexical::Stamp as LexicalStamp;
use serde::{Deserialize, Serialize};
use std::hash::{Hash, Hasher};
#[derive(Debug, Clone, Eq, Serialize, Deserialize)]
pub struct Stamp {
evidential_base: Box<[ClockTime]>,
creation_time: ClockTime,
}
impl Evidential for Stamp {
#[inline(always)]
fn evidential_base(&self) -> &[ClockTime] {
&self.evidential_base
}
#[inline(always)]
fn creation_time(&self) -> ClockTime {
self.creation_time
}
fn stamp_to_lexical(&self) -> LexicalStamp {
LexicalStamp::new()
}
}
__impl_to_display_and_display! {
@(stamp_to_display;;)
Stamp as Evidential
}
impl PartialEq for Stamp {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.evidential_eq(other)
}
}
impl Hash for Stamp {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
self.evidential_base().hash(state);
}
}
impl Stamp {
pub fn new(creation_time: ClockTime, evidential_base: impl Into<Vec<ClockTime>>) -> Self {
Self {
evidential_base: evidential_base.into().into_boxed_slice(),
creation_time,
}
}
pub fn with_time(current_serial: ClockTime, time: ClockTime) -> Self {
let evidential_base = vec![current_serial];
Self::new(time, evidential_base)
}
pub fn with_old(old: &impl Evidential, time: ClockTime) -> Self {
Self::new(time, old.evidential_base())
}
pub fn from_merge_unchecked(
first: &impl Evidential,
second: &impl Evidential,
time: ClockTime,
max_evidence_base_length: usize,
) -> Self {
let merged_base = Self::merged_evidential_base(
first.evidential_base(),
second.evidential_base(),
max_evidence_base_length,
);
Self::new(time, merged_base)
}
pub fn from_merge(
first: &impl Evidential,
second: &impl Evidential,
time: ClockTime,
max_evidence_base_length: usize,
) -> Option<Self> {
match first.evidential_overlap(second) {
true => None,
false => Some(Self::from_merge_unchecked(
first,
second,
time,
max_evidence_base_length,
)),
}
}
pub fn from_lexical(
_: LexicalStamp,
current_serial: ClockTime,
time: ClockTime,
) -> Result<Self> {
Ok(Self::with_time(current_serial, time))
}
}
#[macro_export]
macro_rules! stamp {
({ $creation_time:tt : $($evidence:expr $(;)? )* }) => {
Stamp::new(
$creation_time,
&[ $( $evidence ),* ]
)
};
}
#[cfg(test)]
mod tests {
use super::*;
use crate::stamp;
use crate::util::ToDisplayAndBrief;
use nar_dev_utils::macro_once;
type S = Stamp;
macro_rules! assert_s_eq {
($s1:expr, $s2:expr $(, $($arg:tt)*)?) => {
assert_eq!($s1.evidential_base(), $s2.evidential_base() $(, $($arg)*)?);
assert_eq!($s1.creation_time(), $s2.creation_time() $(, $($arg)*)?);
};
(Option $s1:expr, $s2:expr $(, $($arg:tt)*)?) => {
assert_eq!($s1.is_some(), $s2.is_some() $(, $($arg)*)?);
if let (Some(s1), Some(s2)) = ($s1, $s2) {
assert_s_eq!(s1, s2 $(, $($arg)*)?);
}
};
}
#[test]
fn with_time() {
macro_once! {
macro test($( ( $current_serial:expr, $time:expr ) => $stamp:tt )*) {
$(
assert_s_eq!(S::with_time( $current_serial, $time ), stamp!($stamp));
)*
}
(1, 0) => {0: 1}
(2, 1) => {1: 2}
(2147483647, 10000) => {10000: 2147483647}
(0xfade, 0xabcd) => {0xabcd: 0xfade}
}
}
#[test]
fn with_old() {
macro_once! {
macro test($( ( $old:tt, $time:expr ) => $stamp:tt )*) {
$(
assert_s_eq!(S::with_old( &stamp!($old), $time ), stamp!($stamp));
)*
}
({0: 1}, 1) => {1: 1}
({0: 2}, 1) => {1: 2}
({10000: 2147483647}, 0) => {0: 2147483647}
({10000: 0xabcd}, 0xfade) => {0xfade: 0xabcd}
}
}
#[test]
fn from_merge() {
macro_once! {
macro test {
(@SINGLE ( $s1:tt, $s2:tt, $time:expr, $max_base_l:expr ) => None ) => {
assert_s_eq!(Option S::from_merge(&stamp!($s1), &stamp!($s2), $time, $max_base_l), None::<S>);
}
(@SINGLE ( $s1:tt, $s2:tt, $time:expr, $max_base_l:expr ) => $stamp:tt ) => {
assert_s_eq!(Option S::from_merge(&stamp!($s1), &stamp!($s2), $time, $max_base_l), Some(stamp!($stamp)));
}
( $( $parameters:tt => $expected:tt )* ) => {
$( test!( @SINGLE $parameters => $expected ); )*
}
}
({0: 1}, {0: 1}, 1, 8) => None
({0: 1}, {0: 2}, 10, 8) => {10: 2; 1}
({0: 2}, {0: 1}, 10, 8) => {10: 1; 2}
({0: 2; 4; 6}, {0: 1; 3; 5}, 10, 8) => {10: 1; 2; 3; 4; 5; 6}
({1 : 2}, {0 : 1}, 2, 8) => {2 : 1;2} ({13 : 3}, {13 : 1;2}, 13, 8) => {13 : 1;3;2}
({34 : 4}, {14 : 1;3;2}, 35, 8) => {35 : 1;4;3;2}
({34 : 4}, {14 : 1;3;2}, 35, 4) => {35 : 1;4;3;2}
({34 : 4}, {14 : 1;3;2}, 35, 3) => {35 : 1;4;3}
({34 : 4}, {14 : 1;3;2}, 35, 2) => {35 : 1;4}
({34 : 4}, {14 : 1;3;2}, 35, 1) => {35 : 1}
({34 : 4}, {14 : 1;3;2}, 35, 0) => {35 :}
}
}
#[test]
fn evidential_base() {
macro_once! {
macro test($( $stamp:tt => [ $($time:expr $(,)? )* ] )*) {
$(
let expected: &[ClockTime] = &[ $($time),* ];
assert_eq!(stamp!($stamp).evidential_base(), expected);
)*
}
{0: } => []
{0: 1} => [1]
{0 : 1;3;4} => [1,3,4]
{0 : 0xabcd;3;0xfade} => [0xabcd,3,0xfade]
{7 : 1;6;3} => [1, 6, 3] }
}
#[test]
fn evidence_length() {
macro_once! {
macro test($( $stamp:tt => $expected:expr )*) {
$(
assert_eq!(stamp!($stamp).evidence_length(), $expected);
)*
}
{15 : 15} => 1 {29 : 15} => 1 {18 : 15;6} => 2 {7 : 1;6;3} => 3 }
}
#[test]
fn creation_time() {
macro_once! {
macro test($( $stamp:tt => $expected:expr )*) {
$(
assert_eq!(stamp!($stamp).creation_time(), $expected);
)*
}
{15 : 15} => 15 {6 : 6} => 6 {7 : 1;6;3} => 7 }
}
#[test]
fn get() {
macro_once! {
macro test($( $stamp:tt @ $index:expr => $expected:expr )*) {
$(
assert_eq!(stamp!($stamp).get($index), $expected);
)*
}
{15 : 15} @ 0 => 15
{29 : 15} @ 0 => 15 {33 : 15;6} @ 0 => 15 {16 : 1;15;3} @ 1 => 15 }
}
#[test]
fn evidential_eq() {
macro_once! {
macro test( $( ($s1:tt, $s2:tt) => $expected:tt )* ) {
$(
assert_eq!(stamp!($s1).evidential_eq(&stamp!($s2)), $expected);
assert_eq!(stamp!($s1) == stamp!($s2), $expected);
)*
}
({0: 1}, {0: 1}) => true
({0: 1}, {0: 2}) => false
({0: 2}, {0: 1}) => false
({0: 1}, {1: 1}) => true
({0: 1; 2}, {0: 1; 2}) => true
({0: 1; 2}, {0: 2; 1}) => true
({1000: 1; 2}, {0: 2; 1}) => true ({0: 1; 2; 3}, {0: 2; 1; 3}) => true
({0: 1; 2; 3}, {0: 1; 3; 2}) => true
({0: 1; 2; 3}, {0: 3; 2; 1}) => true
({0: 1; 2; 3}, {0: 2; 3; 1}) => true
({0: 1; 2; 3}, {0: 3; 1; 2}) => true
}
}
#[test]
fn to_display() {
macro_once! {
macro test($( $stamp:tt => $expected:expr )*) {
$(
assert_eq!(stamp!($stamp).to_display(), $expected);
)*
}
{15 : 15} => "{15 : 15}" {29 : 15} => "{29 : 15}" {18 : 15;6} => "{18 : 15;6}" {7 : 1;6;3} => "{7 : 1;6;3}" }
}
}