2025-09-10 19:22:29 -04:00
|
|
|
use num_traits::Float;
|
|
|
|
|
|
2025-09-23 14:51:26 -04:00
|
|
|
mod parser;
|
|
|
|
|
|
2025-09-10 19:22:29 -04:00
|
|
|
/*
|
|
|
|
|
* NOTES
|
|
|
|
|
* - each alternative should appear only once in a tree. need to figure out a
|
|
|
|
|
* way to enforce this.
|
|
|
|
|
* - looks like this is like quite difficult to do through the type system
|
|
|
|
|
*/
|
|
|
|
|
|
2025-09-23 14:51:26 -04:00
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
|
|
|
pub struct Alternative<T: Eq> {
|
2025-09-10 19:22:29 -04:00
|
|
|
name: T
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-23 14:51:26 -04:00
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
|
|
|
pub struct Edge<T: Eq, U: Float> {
|
2025-09-10 19:22:29 -04:00
|
|
|
weight: U,
|
|
|
|
|
destination: Tree<T, U>
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-23 14:51:26 -04:00
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
|
|
|
pub enum Vertex<T: Eq, U: Float> {
|
2025-09-10 19:22:29 -04:00
|
|
|
NonTerminal(Box<Edge<T, U>>, Box<Edge<T, U>>),
|
|
|
|
|
Terminal(Alternative<T>),
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-23 14:51:26 -04:00
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
|
|
|
pub struct Tree<T: Eq, U: Float> {
|
2025-09-10 19:22:29 -04:00
|
|
|
root: Vertex<T, U>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: Eq, U: Float> Tree<T, U> {
|
|
|
|
|
fn left_edge_weights(&self) -> U {
|
|
|
|
|
match &self.root {
|
|
|
|
|
Vertex::NonTerminal(a, _) => {
|
|
|
|
|
let left = &*a;
|
|
|
|
|
left.weight
|
|
|
|
|
+ left.destination.left_edge_weights()
|
|
|
|
|
+ left.destination.right_edge_weights()
|
|
|
|
|
},
|
|
|
|
|
Vertex::Terminal(_) => U::zero()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn right_edge_weights(&self) -> U {
|
|
|
|
|
match &self.root {
|
|
|
|
|
Vertex::NonTerminal(_, b) => {
|
|
|
|
|
let right = &*b;
|
|
|
|
|
right.weight
|
|
|
|
|
+ right.destination.left_edge_weights()
|
|
|
|
|
+ right.destination.right_edge_weights()
|
|
|
|
|
},
|
|
|
|
|
Vertex::Terminal(_) => U::zero()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn choice_probability(&self, alternative: &T) -> U {
|
|
|
|
|
match &self.root {
|
|
|
|
|
Vertex::Terminal(alt) => {
|
|
|
|
|
if alt.name == *alternative { U::one() } else { U::zero() }
|
|
|
|
|
},
|
|
|
|
|
Vertex::NonTerminal(a, b) => {
|
|
|
|
|
let left = &*a;
|
|
|
|
|
let right = &*b;
|
|
|
|
|
let left_edge_weights = self.left_edge_weights();
|
|
|
|
|
let right_edge_weights = self.right_edge_weights();
|
|
|
|
|
let left_choice_probability =
|
|
|
|
|
left.destination.choice_probability(alternative);
|
|
|
|
|
let right_choice_probability =
|
|
|
|
|
right.destination.choice_probability(alternative);
|
|
|
|
|
(
|
|
|
|
|
left_edge_weights * left_choice_probability
|
|
|
|
|
+ right_edge_weights * right_choice_probability
|
|
|
|
|
)
|
|
|
|
|
/(left_edge_weights + right_edge_weights)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
unimplemented!();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
use assert_approx_eq::assert_approx_eq;
|
|
|
|
|
|
2025-09-23 14:51:26 -04:00
|
|
|
fn simple_symmetric_tree() -> Tree<String, f64> {
|
|
|
|
|
let a = Alternative {
|
|
|
|
|
name: "A".to_owned()
|
|
|
|
|
};
|
|
|
|
|
let b = Alternative {
|
|
|
|
|
name: "B".to_owned()
|
|
|
|
|
};
|
2025-09-10 19:22:29 -04:00
|
|
|
let edge_a = Edge {
|
|
|
|
|
weight: 1.0,
|
|
|
|
|
destination: Tree {root: Vertex::Terminal(a)}
|
|
|
|
|
};
|
|
|
|
|
let edge_b = Edge {
|
|
|
|
|
weight: 1.0,
|
|
|
|
|
destination: Tree {root: Vertex::Terminal(b)}
|
|
|
|
|
};
|
|
|
|
|
let root = Vertex::NonTerminal(Box::new(edge_a), Box::new(edge_b));
|
2025-09-23 14:51:26 -04:00
|
|
|
Tree {root: root}
|
2025-09-10 19:22:29 -04:00
|
|
|
}
|
|
|
|
|
|
2025-09-23 14:51:26 -04:00
|
|
|
fn simple_asymmetric_tree() -> Tree<String, f64> {
|
|
|
|
|
let a = Alternative {
|
|
|
|
|
name: "A".to_owned()
|
|
|
|
|
};
|
|
|
|
|
let b = Alternative {
|
|
|
|
|
name: "B".to_owned()
|
|
|
|
|
};
|
|
|
|
|
let edge_a = Edge {
|
|
|
|
|
weight: 3.0,
|
|
|
|
|
destination: Tree {root: Vertex::Terminal(a)}
|
|
|
|
|
};
|
|
|
|
|
let edge_b = Edge {
|
|
|
|
|
weight: 1.0,
|
|
|
|
|
destination: Tree {root: Vertex::Terminal(b)}
|
|
|
|
|
};
|
2025-09-10 19:22:29 -04:00
|
|
|
let root = Vertex::NonTerminal(Box::new(edge_a), Box::new(edge_b));
|
2025-09-23 14:51:26 -04:00
|
|
|
Tree {root: root}
|
2025-09-10 19:22:29 -04:00
|
|
|
}
|
|
|
|
|
|
2025-09-23 14:51:26 -04:00
|
|
|
fn complex_tree() -> Tree<String, f64> {
|
|
|
|
|
let a = Alternative {
|
|
|
|
|
name: "A".to_owned()
|
|
|
|
|
};
|
|
|
|
|
let b = Alternative {
|
|
|
|
|
name: "B".to_owned()
|
|
|
|
|
};
|
|
|
|
|
let c = Alternative {
|
|
|
|
|
name: "C".to_owned()
|
|
|
|
|
};
|
2025-09-10 19:22:29 -04:00
|
|
|
let edge_a = Edge {
|
|
|
|
|
weight: 2.5,
|
|
|
|
|
destination: Tree {root: Vertex::Terminal(a)}
|
|
|
|
|
};
|
|
|
|
|
let edge_b = Edge {
|
|
|
|
|
weight: 1.0,
|
|
|
|
|
destination: Tree {root: Vertex::Terminal(b)}
|
|
|
|
|
};
|
|
|
|
|
let edge_ab = Edge{
|
|
|
|
|
weight: 0.5,
|
|
|
|
|
destination: Tree {
|
|
|
|
|
root: Vertex::NonTerminal(Box::new(edge_a), Box::new(edge_b))
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
let edge_c = Edge{
|
|
|
|
|
weight: 1.0,
|
|
|
|
|
destination: Tree {root: Vertex::Terminal(c)}
|
|
|
|
|
};
|
|
|
|
|
let root = Vertex::NonTerminal(Box::new(edge_ab), Box::new(edge_c));
|
2025-09-23 14:51:26 -04:00
|
|
|
Tree {root: root}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// A test for the simplest symmetric case
|
|
|
|
|
#[test]
|
|
|
|
|
fn choice_probability_test_1() {
|
|
|
|
|
assert_eq!(simple_symmetric_tree().choice_probability(&("A".to_owned())), 0.5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A test for the simplest asymmetric case
|
|
|
|
|
#[test]
|
|
|
|
|
fn choice_probability_test_2() {
|
|
|
|
|
assert_eq!(simple_asymmetric_tree().choice_probability(&("A".to_owned())), 0.75);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A test for depth higher than 1
|
|
|
|
|
#[test]
|
|
|
|
|
fn choice_probability_test_3() {
|
2025-09-10 19:22:29 -04:00
|
|
|
assert_approx_eq!(
|
2025-09-23 14:51:26 -04:00
|
|
|
complex_tree().choice_probability(&("A".to_owned())),
|
2025-09-10 19:22:29 -04:00
|
|
|
(2.5/(2.5+1.0))*((2.5+1.0+0.5)/(2.5+1.0+0.5+1.0))
|
|
|
|
|
);
|
|
|
|
|
}
|
2025-09-23 14:51:26 -04:00
|
|
|
|
|
|
|
|
// A test for parsing the simplest symmetric case
|
|
|
|
|
#[test]
|
|
|
|
|
fn parser_test_1() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
{
|
|
|
|
|
let (_, b) = parser::subtree("([1.0]A[1.0]B)").unwrap();
|
|
|
|
|
b
|
|
|
|
|
},
|
|
|
|
|
simple_symmetric_tree()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn parser_test_2() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
{
|
|
|
|
|
let (_, b) = parser::subtree("([3.0]A[1.0]B)").unwrap();
|
|
|
|
|
b
|
|
|
|
|
},
|
|
|
|
|
simple_asymmetric_tree()
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn parser_test_3() {
|
|
|
|
|
assert_eq!(
|
|
|
|
|
{
|
|
|
|
|
let (_, b) = parser::subtree("([0.5]([2.5]A[1.0]B)[1.0]C)").unwrap();
|
|
|
|
|
b
|
|
|
|
|
},
|
|
|
|
|
complex_tree()
|
|
|
|
|
)
|
|
|
|
|
}
|
2025-09-10 19:22:29 -04:00
|
|
|
}
|