use crate::core::{
RobustnessSemantics, SignalIdentifier, StlOperatorAndSignalIdentifier, StlOperatorTrait,
};
use crate::ring_buffer::Step;
use std::collections::HashSet;
use std::fmt::Display;
use std::time::Duration;
#[derive(Clone)]
pub struct Not<T, Y> {
operand: Box<dyn StlOperatorAndSignalIdentifier<T, Y>>,
max_lookahead: Duration,
}
impl<T, Y> Not<T, Y> {
pub fn new(operand: Box<dyn StlOperatorAndSignalIdentifier<T, Y>>) -> Self
where
T: Clone + 'static,
Y: RobustnessSemantics + 'static,
{
let max_lookahead = operand.get_max_lookahead();
Not {
operand,
max_lookahead,
}
}
}
impl<T, Y> StlOperatorTrait<T> for Not<T, Y>
where
T: Clone + 'static,
Y: RobustnessSemantics + 'static,
{
type Output = Y;
fn get_max_lookahead(&self) -> Duration {
self.max_lookahead
}
fn update(&mut self, step: &Step<T>) -> Vec<Step<Self::Output>> {
let operand_updates = self.operand.update(step);
let output_robustness: Vec<Step<Y>> = operand_updates
.into_iter()
.map(|step| {
let negated_value = Y::not(step.value);
Step {
signal: "output",
value: negated_value,
timestamp: step.timestamp,
}
})
.collect();
output_robustness
}
}
impl<T, Y> SignalIdentifier for Not<T, Y> {
fn get_signal_identifiers(&mut self) -> HashSet<&'static str> {
self.operand.get_signal_identifiers()
}
}
impl<T, Y> Display for Not<T, Y> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "¬({})", self.operand)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::StlOperatorTrait;
use crate::operators::atomic_operators::Atomic;
use crate::step;
use pretty_assertions::assert_eq;
use std::time::Duration;
#[test]
fn not_operator_robustness() {
let atomic = Atomic::<f64>::new_greater_than("x", 10.0);
let mut not = Not::new(Box::new(atomic));
not.get_signal_identifiers();
let step = step!("x", 15.0, Duration::from_secs(5));
let robustness = not.update(&step);
assert_eq!(
robustness,
vec![step!("output", -5.0, Duration::from_secs(5))]
);
}
#[test]
fn not_signal_identifiers() {
let atomic = Atomic::<f64>::new_greater_than("x", 10.0);
let mut not: Not<f64, f64> = Not::new(Box::new(atomic));
let ids = not.get_signal_identifiers();
let expected_ids: HashSet<&'static str> = vec!["x"].into_iter().collect();
assert_eq!(ids, expected_ids);
}
#[test]
fn not_display() {
let atomic = Atomic::<f64>::new_greater_than("x", 10.0);
let not: Not<f64, f64> = Not::new(Box::new(atomic));
let display_str = format!("{}", not);
assert_eq!(display_str, "¬(x > 10)");
}
}