#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct AnchorPoint {
pub vertex_index: usize,
pub strength: f32,
pub label: String,
}
#[derive(Debug, Default)]
pub struct AnchorPointSet {
anchors: Vec<AnchorPoint>,
}
pub fn new_anchor_set() -> AnchorPointSet {
AnchorPointSet::default()
}
pub fn add_anchor(set: &mut AnchorPointSet, vertex_index: usize, label: &str) {
set.anchors.push(AnchorPoint {
vertex_index,
strength: 1.0,
label: label.to_owned(),
});
}
pub fn add_anchor_weighted(
set: &mut AnchorPointSet,
vertex_index: usize,
strength: f32,
label: &str,
) {
let clamped = strength.clamp(0.0, 1.0);
set.anchors.push(AnchorPoint {
vertex_index,
strength: clamped,
label: label.to_owned(),
});
}
pub fn anchor_count(set: &AnchorPointSet) -> usize {
set.anchors.len()
}
pub fn find_anchor(set: &AnchorPointSet, vertex_index: usize) -> Option<&AnchorPoint> {
set.anchors.iter().find(|a| a.vertex_index == vertex_index)
}
pub fn prune_weak_anchors(set: &mut AnchorPointSet, threshold: f32) {
set.anchors.retain(|a| a.strength >= threshold);
}
pub fn average_anchor_strength(set: &AnchorPointSet) -> f32 {
if set.anchors.is_empty() {
return 0.0;
}
let sum: f32 = set.anchors.iter().map(|a| a.strength).sum();
sum / set.anchors.len() as f32
}
pub fn anchor_set_to_json(set: &AnchorPointSet) -> String {
let entries: Vec<String> = set
.anchors
.iter()
.map(|a| {
format!(
r#"{{"vertex":{}, "strength":{:.4}, "label":"{}"}}"#,
a.vertex_index, a.strength, a.label
)
})
.collect();
format!("[{}]", entries.join(", "))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_set_is_empty() {
let s = new_anchor_set();
assert_eq!(anchor_count(&s), 0);
}
#[test]
fn add_anchor_increments_count() {
let mut s = new_anchor_set();
add_anchor(&mut s, 0, "root");
assert_eq!(anchor_count(&s), 1);
}
#[test]
fn add_anchor_weighted_clamps_strength() {
let mut s = new_anchor_set();
add_anchor_weighted(&mut s, 5, 1.5, "top");
assert!((s.anchors[0].strength - 1.0).abs() < 1e-6);
}
#[test]
fn find_anchor_returns_correct_vertex() {
let mut s = new_anchor_set();
add_anchor(&mut s, 3, "mid");
let a = find_anchor(&s, 3).expect("should succeed");
assert_eq!(a.vertex_index, 3);
}
#[test]
fn find_anchor_missing_returns_none() {
let s = new_anchor_set();
assert!(find_anchor(&s, 99).is_none());
}
#[test]
fn prune_removes_weak_anchors() {
let mut s = new_anchor_set();
add_anchor_weighted(&mut s, 0, 0.2, "weak");
add_anchor_weighted(&mut s, 1, 0.8, "strong");
prune_weak_anchors(&mut s, 0.5);
assert_eq!(anchor_count(&s), 1);
}
#[test]
fn average_strength_correct() {
let mut s = new_anchor_set();
add_anchor_weighted(&mut s, 0, 0.4, "a");
add_anchor_weighted(&mut s, 1, 0.6, "b");
assert!((average_anchor_strength(&s) - 0.5).abs() < 1e-5);
}
#[test]
fn average_strength_empty_set_returns_zero() {
let s = new_anchor_set();
assert_eq!(average_anchor_strength(&s), 0.0);
}
#[test]
fn json_output_contains_vertex_key() {
let mut s = new_anchor_set();
add_anchor(&mut s, 7, "pin");
let j = anchor_set_to_json(&s);
assert!(j.contains("vertex"));
}
#[test]
fn json_output_empty_is_empty_array() {
let s = new_anchor_set();
assert_eq!(anchor_set_to_json(&s), "[]");
}
}