Compare commits
2 commits
f58cd7f2f6
...
6f6ef15342
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f6ef15342 | ||
|
|
9b282c4acb |
|
|
@ -5,5 +5,9 @@ mod tree;
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
unimplemented!();
|
// safely: trust me!!
|
||||||
|
// having fun or funly having?
|
||||||
|
unsafe {
|
||||||
|
std::hint::unreachable_unchecked()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,23 +15,26 @@ use nom::{branch::alt, bytes::complete::take_while1, character::char, combinator
|
||||||
|
|
||||||
use crate::tree::{Alternative, Edge, Tree, Vertex};
|
use crate::tree::{Alternative, Edge, Tree, Vertex};
|
||||||
|
|
||||||
|
fn alternative(input: &str) -> IResult<&str, Tree<String, f64>> {
|
||||||
|
map(
|
||||||
|
take_while1::<_, &str, Error<&str>>(AsChar::is_alpha),
|
||||||
|
|a| Tree::<String, f64> {
|
||||||
|
root: Vertex::Terminal(Alternative{name: a.to_owned()})
|
||||||
|
}
|
||||||
|
).parse(input)
|
||||||
|
}
|
||||||
|
|
||||||
fn weighted_edge(input: &str) -> IResult<&str, Edge<String, f64>> {
|
fn weighted_edge(input: &str) -> IResult<&str, Edge<String, f64>> {
|
||||||
let weight = delimited(
|
let weight = delimited(
|
||||||
char::<&str, Error<&str>>('['),
|
char::<&str, Error<&str>>('['),
|
||||||
double,
|
double,
|
||||||
char(']')
|
char(']')
|
||||||
);
|
);
|
||||||
let alternative = map(
|
|
||||||
take_while1::<_, &str, Error<&str>>(AsChar::is_alpha),
|
|
||||||
|a| Tree::<String, f64> {
|
|
||||||
root: Vertex::Terminal(Alternative{name: a.to_owned()})
|
|
||||||
}
|
|
||||||
);
|
|
||||||
map(
|
map(
|
||||||
pair(weight, alt((alternative, subtree))),
|
pair(weight, tree),
|
||||||
|(a, b)| Edge{
|
|(a, b)| Edge{
|
||||||
weight: a,
|
weight: a,
|
||||||
destination: b
|
destination: Box::new(b)
|
||||||
}
|
}
|
||||||
).parse(input)
|
).parse(input)
|
||||||
}
|
}
|
||||||
|
|
@ -40,8 +43,12 @@ pub fn subtree(input: &str) -> IResult<&str, Tree<String, f64>> {
|
||||||
let inner = map(
|
let inner = map(
|
||||||
pair(weighted_edge, weighted_edge),
|
pair(weighted_edge, weighted_edge),
|
||||||
|(a, b)| Tree{
|
|(a, b)| Tree{
|
||||||
root: Vertex::NonTerminal(Box::new(a), Box::new(b))
|
root: Vertex::NonTerminal(a, b)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
delimited(char('('), inner, char(')')).parse(input)
|
delimited(char('('), inner, char(')')).parse(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn tree(input: &str) -> IResult<&str, Tree<String, f64>> {
|
||||||
|
alt((alternative, subtree)).parse(input)
|
||||||
|
}
|
||||||
|
|
|
||||||
67
src/test.rs
67
src/test.rs
|
|
@ -12,13 +12,13 @@ fn simple_symmetric_tree() -> Tree<String, f64> {
|
||||||
};
|
};
|
||||||
let edge_a = Edge {
|
let edge_a = Edge {
|
||||||
weight: 1.0,
|
weight: 1.0,
|
||||||
destination: Tree {root: Vertex::Terminal(a)}
|
destination: Box::new(Tree {root: Vertex::Terminal(a)})
|
||||||
};
|
};
|
||||||
let edge_b = Edge {
|
let edge_b = Edge {
|
||||||
weight: 1.0,
|
weight: 1.0,
|
||||||
destination: Tree {root: Vertex::Terminal(b)}
|
destination: Box::new(Tree {root: Vertex::Terminal(b)})
|
||||||
};
|
};
|
||||||
let root = Vertex::NonTerminal(Box::new(edge_a), Box::new(edge_b));
|
let root = Vertex::NonTerminal(edge_a, edge_b);
|
||||||
Tree {root: root}
|
Tree {root: root}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,13 +32,13 @@ fn simple_asymmetric_tree() -> Tree<String, f64> {
|
||||||
};
|
};
|
||||||
let edge_a = Edge {
|
let edge_a = Edge {
|
||||||
weight: 3.0,
|
weight: 3.0,
|
||||||
destination: Tree {root: Vertex::Terminal(a)}
|
destination: Box::new(Tree {root: Vertex::Terminal(a)})
|
||||||
};
|
};
|
||||||
let edge_b = Edge {
|
let edge_b = Edge {
|
||||||
weight: 1.0,
|
weight: 1.0,
|
||||||
destination: Tree {root: Vertex::Terminal(b)}
|
destination: Box::new(Tree {root: Vertex::Terminal(b)})
|
||||||
};
|
};
|
||||||
let root = Vertex::NonTerminal(Box::new(edge_a), Box::new(edge_b));
|
let root = Vertex::NonTerminal(edge_a, edge_b);
|
||||||
Tree {root: root}
|
Tree {root: root}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,23 +55,23 @@ fn complex_tree() -> Tree<String, f64> {
|
||||||
};
|
};
|
||||||
let edge_a = Edge {
|
let edge_a = Edge {
|
||||||
weight: 2.5,
|
weight: 2.5,
|
||||||
destination: Tree {root: Vertex::Terminal(a)}
|
destination: Box::new(Tree {root: Vertex::Terminal(a)})
|
||||||
};
|
};
|
||||||
let edge_b = Edge {
|
let edge_b = Edge {
|
||||||
weight: 1.0,
|
weight: 1.0,
|
||||||
destination: Tree {root: Vertex::Terminal(b)}
|
destination: Box::new(Tree {root: Vertex::Terminal(b)})
|
||||||
};
|
};
|
||||||
let edge_ab = Edge{
|
let edge_ab = Edge{
|
||||||
weight: 0.5,
|
weight: 0.5,
|
||||||
destination: Tree {
|
destination: Box::new(Tree {
|
||||||
root: Vertex::NonTerminal(Box::new(edge_a), Box::new(edge_b))
|
root: Vertex::NonTerminal(edge_a, edge_b)
|
||||||
}
|
})
|
||||||
};
|
};
|
||||||
let edge_c = Edge{
|
let edge_c = Edge{
|
||||||
weight: 1.0,
|
weight: 1.0,
|
||||||
destination: Tree {root: Vertex::Terminal(c)}
|
destination: Box::new(Tree {root: Vertex::Terminal(c)})
|
||||||
};
|
};
|
||||||
let root = Vertex::NonTerminal(Box::new(edge_ab), Box::new(edge_c));
|
let root = Vertex::NonTerminal(edge_ab, edge_c);
|
||||||
Tree {root: root}
|
Tree {root: root}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,7 +102,7 @@ fn choice_probability_test_3() {
|
||||||
fn parser_test_1() {
|
fn parser_test_1() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
{
|
{
|
||||||
let (_, b) = parser::subtree("([1.0]A[1.0]B)").unwrap();
|
let (_, b) = parser::tree("([1.0]A[1.0]B)").unwrap();
|
||||||
b
|
b
|
||||||
},
|
},
|
||||||
simple_symmetric_tree()
|
simple_symmetric_tree()
|
||||||
|
|
@ -113,7 +113,7 @@ fn parser_test_1() {
|
||||||
fn parser_test_2() {
|
fn parser_test_2() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
{
|
{
|
||||||
let (_, b) = parser::subtree("([3.0]A[1.0]B)").unwrap();
|
let (_, b) = parser::tree("([3.0]A[1.0]B)").unwrap();
|
||||||
b
|
b
|
||||||
},
|
},
|
||||||
simple_asymmetric_tree()
|
simple_asymmetric_tree()
|
||||||
|
|
@ -124,7 +124,7 @@ fn parser_test_2() {
|
||||||
fn parser_test_3() {
|
fn parser_test_3() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
{
|
{
|
||||||
let (_, b) = parser::subtree("([0.5]([2.5]A[1.0]B)[1.0]C)").unwrap();
|
let (_, b) = parser::tree("([0.5]([2.5]A[1.0]B)[1.0]C)").unwrap();
|
||||||
b
|
b
|
||||||
},
|
},
|
||||||
complex_tree()
|
complex_tree()
|
||||||
|
|
@ -133,21 +133,44 @@ fn parser_test_3() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_symmetry_positive() {
|
fn test_symmetry_positive() {
|
||||||
let (_, a) = parser::subtree("([3.0]A[1.0]B)").unwrap();
|
let (_, a) = parser::tree("([3.0]A[1.0]B)").unwrap();
|
||||||
let (_, b) = parser::subtree("([1.0]B[3.0]A)").unwrap();
|
let (_, b) = parser::tree("([1.0]B[3.0]A)").unwrap();
|
||||||
assert_eq!(a, b)
|
assert_eq!(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_symmetry_negative() {
|
fn test_symmetry_negative() {
|
||||||
let (_, a) = parser::subtree("([3.0]A[1.0]B)").unwrap();
|
let (_, a) = parser::tree("([3.0]A[1.0]B)").unwrap();
|
||||||
let (_, b) = parser::subtree("([1.0]A[3.0]B)").unwrap();
|
let (_, b) = parser::tree("([1.0]A[3.0]B)").unwrap();
|
||||||
assert_ne!(a, b)
|
assert_ne!(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_symmetry_complex() {
|
fn test_symmetry_complex() {
|
||||||
let (_, a) = parser::subtree("([1.0]C[0.5]([1.0]B[2.5]A))").unwrap();
|
let (_, a) = parser::tree("([1.0]C[0.5]([1.0]B[2.5]A))").unwrap();
|
||||||
let (_, b) = parser::subtree("([0.5]([2.5]A[1.0]B)[1.0]C)").unwrap();
|
let (_, b) = parser::tree("([0.5]([2.5]A[1.0]B)[1.0]C)").unwrap();
|
||||||
assert_eq!(a, b)
|
assert_eq!(a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_menu_simple() {
|
||||||
|
let (_, a) = parser::tree("([3.0]A[1.0]B)").unwrap();
|
||||||
|
let (_, b) = parser::tree("A").unwrap();
|
||||||
|
let Some((a_menu_tree, _)) = a.menu_tree(&["A".to_owned()]) else {
|
||||||
|
panic!("Failed to get tree from menu_tree output")
|
||||||
|
};
|
||||||
|
assert_eq!(a_menu_tree, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_menu_complex() {
|
||||||
|
let (_, a) = parser::tree("([1.0]C[0.5]([1.0]B[2.5]A))").unwrap();
|
||||||
|
let (_, b) = parser::tree("([1.0]C[1.5]B)").unwrap();
|
||||||
|
let Some((a_menu_tree, _)) = a.menu_tree(&[
|
||||||
|
"B".to_owned(), "C".to_owned()
|
||||||
|
]) else {
|
||||||
|
panic!("Failed to get tree from menu_tree output")
|
||||||
|
};
|
||||||
|
assert_eq!(a_menu_tree, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
89
src/tree.rs
89
src/tree.rs
|
|
@ -1,24 +1,24 @@
|
||||||
use num_traits::Float;
|
use num_traits::Float;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
pub struct Alternative<T: Eq> {
|
pub struct Alternative<T: Eq + Clone> {
|
||||||
pub name: T
|
pub name: T
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub struct Edge<T: Eq, U: Float> {
|
pub struct Edge<T: Eq + Clone, U: Float> {
|
||||||
pub weight: U,
|
pub weight: U,
|
||||||
pub destination: Tree<T, U>
|
pub destination: Box<Tree<T, U>>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Vertex<T: Eq, U: Float> {
|
pub enum Vertex<T: Eq + Clone, U: Float> {
|
||||||
NonTerminal(Box<Edge<T, U>>, Box<Edge<T, U>>),
|
NonTerminal(Edge<T, U>, Edge<T, U>),
|
||||||
Terminal(Alternative<T>),
|
Terminal(Alternative<T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
// implement symmetry
|
// implement symmetry
|
||||||
impl<T: Eq, U: Float> PartialEq for Vertex<T, U>{
|
impl<T: Eq + Clone, U: Float> PartialEq for Vertex<T, U>{
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Vertex::NonTerminal(a, b) => {
|
Vertex::NonTerminal(a, b) => {
|
||||||
|
|
@ -39,12 +39,16 @@ impl<T: Eq, U: Float> PartialEq for Vertex<T, U>{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub struct Tree<T: Eq, U: Float> {
|
pub struct Tree<T: Eq + Clone, U: Float> {
|
||||||
pub root: Vertex<T, U>
|
pub root: Vertex<T, U>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Eq, U: Float> Tree<T, U> {
|
pub enum TreeError {
|
||||||
|
EmptyTree,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Eq + Clone, U: Float> Tree<T, U> {
|
||||||
fn left_edge_weights(&self) -> U {
|
fn left_edge_weights(&self) -> U {
|
||||||
match &self.root {
|
match &self.root {
|
||||||
Vertex::NonTerminal(a, _) => {
|
Vertex::NonTerminal(a, _) => {
|
||||||
|
|
@ -91,5 +95,66 @@ impl<T: Eq, U: Float> Tree<T, U> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn menu_tree(&self, alternatives: &[T]) -> Option<(Tree<T, U>, U)> {
|
||||||
|
match &self.root {
|
||||||
|
Vertex::Terminal(alt) => {
|
||||||
|
if alternatives.contains(&alt.name) {
|
||||||
|
Some((self.clone(), U::zero()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Vertex::NonTerminal(a, b) => {
|
||||||
|
let a_menu = a.destination.menu_tree(alternatives);
|
||||||
|
let b_menu = b.destination.menu_tree(alternatives);
|
||||||
|
match (a_menu, b_menu) {
|
||||||
|
(Some((a_tree, a_weight)), Some((b_tree, b_weight))) => {
|
||||||
|
Some(
|
||||||
|
(Tree {
|
||||||
|
root: Vertex::NonTerminal(
|
||||||
|
Edge {
|
||||||
|
weight: a.weight + a_weight,
|
||||||
|
destination: Box::new(a_tree)
|
||||||
|
},
|
||||||
|
Edge {
|
||||||
|
weight: b.weight + b_weight,
|
||||||
|
destination: Box::new(b_tree)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}, U::zero())
|
||||||
|
)
|
||||||
|
},
|
||||||
|
(Some((a_tree, a_weight)), None) => {
|
||||||
|
Some(
|
||||||
|
(a_tree, a.weight + a_weight)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
(None, Some((b_tree, b_weight))) => {
|
||||||
|
Some(
|
||||||
|
(b_tree, b.weight + b_weight)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
(None, None) => None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SimilarityRelation<T: Eq + Clone> {
|
||||||
|
left: T,
|
||||||
|
right: T,
|
||||||
|
with_respect_to: T
|
||||||
|
}
|
||||||
|
|
||||||
|
// implement symmetry
|
||||||
|
impl<T: Eq + Clone> PartialEq for SimilarityRelation<T> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
(
|
||||||
|
(self.left == other.left && self.right == other.right)
|
||||||
|
|| (self.left == other.right && self.right == other.left)
|
||||||
|
)
|
||||||
|
&& self.with_respect_to == other.with_respect_to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue