This commit is contained in:
Youngjoon Lee 2024-08-21 10:45:41 +02:00
parent 58fccb085e
commit 546d0a7f55
No known key found for this signature in database
GPG Key ID: 167546E2D1712F8C
3 changed files with 285 additions and 46 deletions

View File

@ -1,4 +1,4 @@
use std::{fmt::Display, path::Path};
use std::path::Path;
use queue::QueueConfig;
use rand::{rngs::StdRng, Rng, SeedableRng};
@ -6,6 +6,7 @@ use rustc_hash::FxHashMap;
use crate::{
node::{MessageId, Node},
ordercoeff::Sequence,
paramset::ParamSet,
};
@ -43,8 +44,8 @@ pub fn run_iteration(
// Results
let mut sent_times: FxHashMap<MessageId, f32> = FxHashMap::default();
let mut latencies: FxHashMap<MessageId, f32> = FxHashMap::default();
let mut sent_sequence = MessageSequence::new();
let mut received_sequence = MessageSequence::new();
let mut sent_sequence = Sequence::new();
let mut received_sequence = Sequence::new();
let mut data_msg_counts_in_queue: Vec<u32> = Vec::new();
let mut rng = StdRng::seed_from_u64(seed);
@ -139,9 +140,9 @@ fn save_latencies(
writer.flush().unwrap();
}
fn save_sequence(sequence: &MessageSequence, path: &str) {
fn save_sequence(sequence: &Sequence, path: &str) {
let mut writer = csv::Writer::from_path(path).unwrap();
sequence.messages.iter().for_each(|entry| {
sequence.iter().for_each(|entry| {
writer.write_record([entry.to_string()]).unwrap();
});
writer.flush().unwrap();
@ -166,44 +167,3 @@ fn save_data_msg_counts(
});
writer.flush().unwrap();
}
struct MessageSequence {
messages: Vec<SequenceEntry>,
}
impl MessageSequence {
fn new() -> Self {
Self {
messages: Vec::new(),
}
}
fn add_message(&mut self, msg: MessageId) {
self.messages.push(SequenceEntry::Message(msg));
}
fn add_noise(&mut self) {
if let Some(last) = self.messages.last_mut() {
if let SequenceEntry::Noise(cnt) = last {
*cnt += 1;
} else {
self.messages.push(SequenceEntry::Noise(1))
}
}
}
}
enum SequenceEntry {
Message(MessageId),
Noise(u32), // the number of consecutive noises
}
impl Display for SequenceEntry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
SequenceEntry::Message(msg) => msg.to_string(),
SequenceEntry::Noise(cnt) => format!("-{cnt}"),
};
f.write_str(s.as_str())
}
}

View File

@ -1,5 +1,6 @@
mod iteration;
mod node;
mod ordercoeff;
mod paramset;
use std::{

View File

@ -0,0 +1,278 @@
use std::fmt::Display;
use crate::node::MessageId;
pub struct Sequence(Vec<Entry>);
#[derive(Debug, PartialEq, Eq)]
pub enum Entry {
Message(MessageId),
Noise(u32), // the number of consecutive noises
}
impl Display for Entry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Entry::Message(msg) => msg.to_string(),
Entry::Noise(cnt) => format!("-{cnt}"),
};
f.write_str(s.as_str())
}
}
impl Sequence {
pub fn new() -> Self {
Self(Vec::new())
}
pub fn add_message(&mut self, msg: MessageId) {
self.0.push(Entry::Message(msg));
}
pub fn add_noise(&mut self) {
if let Some(last) = self.0.last_mut() {
if let Entry::Noise(cnt) = last {
*cnt += 1;
} else {
self.0.push(Entry::Noise(1))
}
}
}
pub fn iter(&self) -> impl Iterator<Item = &Entry> {
self.0.iter()
}
}
impl Sequence {
pub fn calculate_strong_ordering_coefficient(&self, other: &Sequence) -> u64 {
let mut coeff = 0;
let mut i = 0;
while i < self.0.len() {
if let Entry::Message(_) = &self.0[i] {
let (c, next_i) = self.calculate_strong_ordering_coefficient_from(i, other);
coeff += c;
if next_i != i {
i = next_i;
} else {
i += 1;
}
} else {
i += 1;
}
}
coeff
}
fn calculate_strong_ordering_coefficient_from(
&self,
start_idx: usize,
other: &Sequence,
) -> (u64, usize) {
let msg1 = match self.0[start_idx] {
Entry::Message(msg) => msg,
_ => panic!("Entry at {start_idx} must be Message"),
};
for (j, entry) in other.iter().enumerate() {
if let Entry::Message(msg2) = entry {
if msg1 == *msg2 {
// Found the 1st matching msg. Start finding the next adjacent matching msg.
return self.scan_adjacent_common_msgs(start_idx, other, j);
}
}
}
(0, start_idx)
}
fn scan_adjacent_common_msgs(
&self,
start_idx: usize,
other: &Sequence,
other_start_idx: usize,
) -> (u64, usize) {
let mut coeff = 0;
let mut i = start_idx + 1;
let mut j = other_start_idx + 1;
while i < self.0.len() && j < other.0.len() {
match (&self.0[i], &other.0[j]) {
(Entry::Noise(cnt1), Entry::Noise(cnt2)) => {
if cnt1 == cnt2 {
i += 1;
j += 1;
} else {
break;
}
}
(Entry::Message(msg1), Entry::Message(msg2)) => {
if msg1 == msg2 {
coeff += 1;
i += 1;
j += 1;
} else {
break;
}
}
_ => break,
}
}
(coeff, i)
}
// pub fn calculate_weak_ordering_coefficient(&self, other: &Sequence) -> u64 {
// let mut i = 0;
// let mut j = 0;
// let mut coeff = 0;
// while i < self.0.len() && j < other.0.len() {
// // Skip noise to find the first message in both sequences
// i = self.skip_noise(i);
// j = other.skip_noise(j);
// // Check if both indices point to valid messages and match
// if i < self.0.len() && j < other.0.len() && self.0[i] == other.0[j] {
// let next_i = self.skip_noise(i + 1);
// let next_j = other.skip_noise(j + 1);
// // Check if the next pair of messages match
// if next_i < self.0.len()
// && next_j < other.0.len()
// && self.0[next_i] == other.0[next_j]
// {
// coeff += 1;
// }
// // Move to the next message pair
// i = next_i;
// j = next_j;
// } else {
// // Move to the next elements in the sequences
// i += 1;
// // j += 1;
// }
// }
// coeff
// }
// fn skip_noise(&self, mut index: usize) -> usize {
// while index < self.0.len() {
// if let Entry::Message(_) = self.0[index] {
// break;
// }
// index += 1;
// }
// index
// }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strong_ordering_coefficient() {
// Case 0: Empty sequences
let seq = Sequence(vec![]);
assert_eq!(seq.calculate_strong_ordering_coefficient(&seq), 0);
// Case 1: Exact one matched pair with no noise
let seq = Sequence(vec![Entry::Message(1), Entry::Message(2)]);
assert_eq!(seq.calculate_strong_ordering_coefficient(&seq), 1);
// Case 2: Exact one matched pair with noise
let seq = Sequence(vec![Entry::Message(1), Entry::Noise(10), Entry::Message(2)]);
assert_eq!(seq.calculate_strong_ordering_coefficient(&seq), 1);
// Case 3: One matched pair with no noise
let seq1 = Sequence(vec![
Entry::Message(1),
Entry::Message(2),
Entry::Message(3),
]);
let seq2 = Sequence(vec![
Entry::Message(1),
Entry::Message(2),
Entry::Message(4),
]);
assert_eq!(seq1.calculate_strong_ordering_coefficient(&seq2), 1);
assert_eq!(seq2.calculate_strong_ordering_coefficient(&seq1), 1);
// Case 4: One matched pair with noise
let seq1 = Sequence(vec![
Entry::Message(1),
Entry::Noise(10),
Entry::Message(2),
Entry::Message(3),
]);
let seq2 = Sequence(vec![Entry::Message(1), Entry::Noise(10), Entry::Message(2)]);
assert_eq!(seq1.calculate_strong_ordering_coefficient(&seq2), 1);
assert_eq!(seq2.calculate_strong_ordering_coefficient(&seq1), 1);
// Case 5: Two matched pairs with noise
let seq1 = Sequence(vec![
Entry::Message(1),
Entry::Noise(10),
Entry::Message(2),
Entry::Message(3),
]);
let seq2 = Sequence(vec![
Entry::Message(1),
Entry::Noise(10),
Entry::Message(2),
Entry::Message(3),
Entry::Message(4),
]);
assert_eq!(seq1.calculate_strong_ordering_coefficient(&seq2), 2);
assert_eq!(seq2.calculate_strong_ordering_coefficient(&seq1), 2);
// Case 6: Only partial match with no noise
let seq1 = Sequence(vec![Entry::Message(1), Entry::Message(2)]);
let seq2 = Sequence(vec![Entry::Message(2), Entry::Message(3)]);
assert_eq!(seq1.calculate_strong_ordering_coefficient(&seq2), 0);
assert_eq!(seq2.calculate_strong_ordering_coefficient(&seq1), 0);
// Case 7: Only partial match with noise
let seq1 = Sequence(vec![Entry::Message(1), Entry::Message(2), Entry::Noise(10)]);
let seq2 = Sequence(vec![Entry::Message(2), Entry::Noise(10), Entry::Message(3)]);
assert_eq!(seq1.calculate_strong_ordering_coefficient(&seq2), 0);
assert_eq!(seq2.calculate_strong_ordering_coefficient(&seq1), 0);
// Case 8: No match at all
let seq1 = Sequence(vec![Entry::Message(1), Entry::Message(2), Entry::Noise(10)]);
let seq2 = Sequence(vec![Entry::Message(3), Entry::Noise(10), Entry::Message(4)]);
assert_eq!(seq1.calculate_strong_ordering_coefficient(&seq2), 0);
assert_eq!(seq2.calculate_strong_ordering_coefficient(&seq1), 0);
// Case 9: No match because of different count of noises
let seq1 = Sequence(vec![Entry::Message(1), Entry::Noise(10), Entry::Message(2)]);
let seq2 = Sequence(vec![Entry::Message(1), Entry::Noise(5), Entry::Message(2)]);
assert_eq!(seq1.calculate_strong_ordering_coefficient(&seq2), 0);
assert_eq!(seq2.calculate_strong_ordering_coefficient(&seq1), 0);
// Case 9: Matches with noise but mixed orders
let seq1 = Sequence(vec![
Entry::Message(1),
Entry::Message(2),
Entry::Noise(10),
Entry::Message(3),
Entry::Message(4),
Entry::Message(5),
Entry::Message(6),
]);
let seq2 = Sequence(vec![
Entry::Message(4),
Entry::Message(5),
Entry::Message(1),
Entry::Message(2),
Entry::Noise(10),
Entry::Message(3),
Entry::Message(6),
]);
assert_eq!(seq1.calculate_strong_ordering_coefficient(&seq2), 3);
assert_eq!(seq2.calculate_strong_ordering_coefficient(&seq1), 3);
}
}