s2gpp 1.0.2

Algorithm for Highly Efficient Detection of Correlation Anomalies in Multivariate Time Series
Documentation
use crate::data_store::edge::{EdgeRef, MaterializedEdge};
use crate::data_store::materialize::Materialize;
use crate::data_store::node::NodeRef;
use crate::messages::PoisonPill;
use crate::training::scoring::messages::{ScoringHelperInstruction, ScoringHelperResponse};
use actix::prelude::*;
use std::collections::HashMap;
use std::ops::Range;

pub(crate) struct ScoringHelper {
    pub edges: Vec<EdgeRef>,
    pub edges_in_time: Vec<usize>,
    pub edge_weight: HashMap<MaterializedEdge, usize>,
    pub node_degrees: HashMap<NodeRef, usize>,
    pub query_length: usize,
    pub receiver: Recipient<ScoringHelperResponse>,
}

impl ScoringHelper {
    fn score_p_degree(&mut self, edge_range: Range<usize>) -> (f32, usize) {
        let p_edge = self.edges[edge_range].iter();
        let len_score = p_edge.len();
        let alpha = 0.00000001 + (len_score as f32);
        let score: f32 = p_edge
            .map(|edge| {
                (self.edge_weight.get(&edge.materialize()).unwrap()
                    * (self
                        .node_degrees
                        .get(&edge.get_from_node())
                        .expect("Edge with unknown Node found!")
                        - 1)) as f32
            })
            .sum();
        (score / alpha, len_score)
    }
}

impl Actor for ScoringHelper {
    type Context = SyncContext<Self>;
}

impl Handler<ScoringHelperInstruction> for ScoringHelper {
    type Result = ();

    fn handle(&mut self, msg: ScoringHelperInstruction, _ctx: &mut Self::Context) -> Self::Result {
        let mut single_scores: Vec<f32> = vec![];
        let mut first_empty = false;

        for i in msg.start..msg.start + msg.length {
            let from_edge_idx = self.edges_in_time[i];
            let to_edge_idx = self.edges_in_time[i + self.query_length - 1] + 1;

            let (score, len_score) =
                self.score_p_degree(from_edge_idx..to_edge_idx.min(self.edges.len()));

            single_scores.push(if len_score == 0 {
                match single_scores.last() {
                    Some(last) => *last,
                    None => {
                        first_empty = true;
                        0.0
                    }
                }
            } else {
                -score
            });
        }
        self.receiver
            .do_send(ScoringHelperResponse {
                start: msg.start,
                scores: single_scores,
                first_empty,
            })
            .unwrap();
    }
}

impl Handler<PoisonPill> for ScoringHelper {
    type Result = ();

    fn handle(&mut self, _msg: PoisonPill, ctx: &mut Self::Context) -> Self::Result {
        ctx.stop();
    }
}