diff --git a/src/lib.rs b/src/lib.rs index 47e67aa..7a0add5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ pub mod pnf; pub mod subtype; pub mod unification; pub mod morphism; +pub mod morphism_path; pub mod steiner_tree; #[cfg(test)] diff --git a/src/morphism.rs b/src/morphism.rs index 9f29ba8..8c7a3f0 100644 --- a/src/morphism.rs +++ b/src/morphism.rs @@ -75,15 +75,6 @@ impl<M: Morphism + Clone> MorphismInstance<M> { //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ -#[derive(Clone)] -pub struct MorphismPath<M: Morphism + Clone> { - pub weight: u64, - pub cur_type: TypeTerm, - pub morphisms: Vec< MorphismInstance<M> > -} - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ - #[derive(Clone)] pub struct MorphismBase<M: Morphism + Clone> { morphisms: Vec< M >, @@ -171,117 +162,6 @@ impl<M: Morphism + Clone> MorphismBase<M> { dst_types } - /* try to find shortest morphism-path for a given type - */ - pub fn find_morphism_path(&self, ty: MorphismType -// , type_dict: &mut impl TypeDict - ) - -> Option< Vec<MorphismInstance<M>> > - { - let ty = ty.normalize(); - let mut queue = vec![ - MorphismPath::<M> { weight: 0, cur_type: ty.src_type.clone(), morphisms: vec![] } - ]; - - while ! queue.is_empty() { - queue.sort_by( |p1,p2| p2.weight.cmp(&p1.weight)); - - if let Some(mut cur_path) = queue.pop() { - if let Ok((halo, σ)) = crate::unification::subtype_unify( &cur_path.cur_type, &ty.dst_type ) { - /* found path, - * now apply substitution and trim to variables in terms of each step - */ - for n in cur_path.morphisms.iter_mut() { - let src_type = n.m.get_type().src_type; - let dst_type = n.m.get_type().dst_type; - - let mut new_σ = HashMap::new(); - for (k,v) in σ.iter() { - if let TypeID::Var(varid) = k { - if src_type.contains_var(*varid) - || dst_type.contains_var(*varid) { - new_σ.insert( - k.clone(), - v.clone().apply_substitution(&|k| σ.get(k).cloned()).clone().strip() - ); - } - } - } - for (k,v) in n.σ.iter() { - if let TypeID::Var(varid) = k { - if src_type.contains_var(*varid) - || dst_type.contains_var(*varid) { - new_σ.insert( - k.clone(), - v.clone().apply_substitution(&|k| σ.get(k).cloned()).clone().strip() - ); - } - } - } - - n.halo = n.halo.clone().apply_substitution( - &|k| σ.get(k).cloned() - ).clone().strip().param_normalize(); - - n.σ = new_σ; - } - - return Some(cur_path.morphisms); - } - - //eprintln!("cur path (w ={}) : @ {:?}", cur_path.weight, cur_path.cur_type);//.clone().sugar(type_dict).pretty(type_dict, 0) ); - for mut next_morph_inst in self.enum_morphisms(&cur_path.cur_type) { - let dst_type = next_morph_inst.get_type().dst_type; -// eprintln!("try morph to {}", dst_type.clone().sugar(type_dict).pretty(type_dict, 0)); - - let mut creates_loop = false; - - let mut new_path = cur_path.clone(); - for n in new_path.morphisms.iter_mut() { - let mut new_σ = HashMap::new(); - - for (k,v) in next_morph_inst.σ.iter() { - new_σ.insert( - k.clone(), - v.clone().apply_substitution(&|k| next_morph_inst.σ.get(k).cloned()).clone() - ); - } - - for (k,v) in n.σ.iter() { - new_σ.insert( - k.clone(), - v.clone().apply_substitution(&|k| next_morph_inst.σ.get(k).cloned()).clone() - ); - } - - n.halo = n.halo.clone().apply_substitution( - &|k| next_morph_inst.σ.get(k).cloned() - ).clone().strip().param_normalize(); - - n.σ = new_σ; - } - - for m in new_path.morphisms.iter() { - if m.get_type().src_type == dst_type { - creates_loop = true; - break; - } - } - - if ! creates_loop { - new_path.weight += next_morph_inst.m.weight(); - new_path.cur_type = dst_type; - - new_path.morphisms.push(next_morph_inst); - queue.push(new_path); - } - } - } - } - None - } - - pub fn find_direct_morphism(&self, ty: &MorphismType, dict: &mut impl TypeDict diff --git a/src/morphism_path.rs b/src/morphism_path.rs new file mode 100644 index 0000000..2927e6d --- /dev/null +++ b/src/morphism_path.rs @@ -0,0 +1,139 @@ +use { + crate::{ + morphism::{MorphismType, Morphism, MorphismInstance, MorphismBase}, + dict::*, + term::* + } +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +#[derive(Clone)] +pub struct MorphismPath<M: Morphism + Clone> { + pub weight: u64, + pub cur_type: TypeTerm, + pub morphisms: Vec< MorphismInstance<M> > +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +pub struct ShortestPathProblem<'a, M: Morphism + Clone> { + pub morphism_base: &'a MorphismBase<M>, + pub goal: TypeTerm, + queue: Vec< MorphismPath<M> > +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +impl<'a, M:Morphism+Clone> ShortestPathProblem<'a, M> { + pub fn new(morphism_base: &'a MorphismBase<M>, ty: MorphismType) -> Self { + ShortestPathProblem { + morphism_base, + queue: vec![ + MorphismPath::<M> { weight: 0, cur_type: ty.src_type, morphisms: vec![] } + ], + goal: ty.dst_type + } + } + + pub fn solve(&mut self) -> Option< Vec<MorphismInstance<M>> > { + while ! self.queue.is_empty() { + self.queue.sort_by( |p1,p2| p2.weight.cmp(&p1.weight)); + + if let Some(mut cur_path) = self.queue.pop() { + if let Ok((halo, σ)) = crate::unification::subtype_unify( &cur_path.cur_type, &self.goal ) { + /* found path, + * now apply substitution and trim to variables in terms of each step + */ + for n in cur_path.morphisms.iter_mut() { + let src_type = n.m.get_type().src_type; + let dst_type = n.m.get_type().dst_type; + + let mut new_σ = std::collections::HashMap::new(); + for (k,v) in σ.iter() { + if let TypeID::Var(varid) = k { + if src_type.contains_var(*varid) + || dst_type.contains_var(*varid) { + new_σ.insert( + k.clone(), + v.clone().apply_substitution(&|k| σ.get(k).cloned()).clone().strip() + ); + } + } + } + for (k,v) in n.σ.iter() { + if let TypeID::Var(varid) = k { + if src_type.contains_var(*varid) + || dst_type.contains_var(*varid) { + new_σ.insert( + k.clone(), + v.clone().apply_substitution(&|k| σ.get(k).cloned()).clone().strip() + ); + } + } + } + + n.halo = n.halo.clone().apply_substitution( + &|k| σ.get(k).cloned() + ).clone().strip().param_normalize(); + + n.σ = new_σ; + } + + return Some(cur_path.morphisms); + } + + //eprintln!("cur path (w ={}) : @ {:?}", cur_path.weight, cur_path.cur_type);//.clone().sugar(type_dict).pretty(type_dict, 0) ); + for mut next_morph_inst in self.morphism_base.enum_morphisms(&cur_path.cur_type) { + let dst_type = next_morph_inst.get_type().dst_type; +// eprintln!("try morph to {}", dst_type.clone().sugar(type_dict).pretty(type_dict, 0)); + + let mut creates_loop = false; + + let mut new_path = cur_path.clone(); + for n in new_path.morphisms.iter_mut() { + let mut new_σ = std::collections::HashMap::new(); + + for (k,v) in next_morph_inst.σ.iter() { + new_σ.insert( + k.clone(), + v.clone().apply_substitution(&|k| next_morph_inst.σ.get(k).cloned()).clone() + ); + } + + for (k,v) in n.σ.iter() { + new_σ.insert( + k.clone(), + v.clone().apply_substitution(&|k| next_morph_inst.σ.get(k).cloned()).clone() + ); + } + + n.halo = n.halo.clone().apply_substitution( + &|k| next_morph_inst.σ.get(k).cloned() + ).clone().strip().param_normalize(); + + n.σ = new_σ; + } + + for m in new_path.morphisms.iter() { + if m.get_type().src_type == dst_type { + creates_loop = true; + break; + } + } + + if ! creates_loop { + new_path.weight += next_morph_inst.m.weight(); + new_path.cur_type = dst_type; + + new_path.morphisms.push(next_morph_inst); + self.queue.push(new_path); + } + } + } + } + None + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/steiner_tree.rs b/src/steiner_tree.rs index f3fa931..65bbe32 100644 --- a/src/steiner_tree.rs +++ b/src/steiner_tree.rs @@ -92,12 +92,13 @@ impl PathApproxSteinerTreeSolver { for goal in self.leaves { eprintln!("solve steiner tree: find path to goal {:?}", goal); // try to find shortest path from root to current leaf - if let Some(new_path) = morphisms.find_morphism_path( + if let Some(new_path) = crate::morphism_path::ShortestPathProblem::new( + morphisms, MorphismType { src_type: self.root.clone(), dst_type: goal.clone() } - ) { + ).solve() { eprintln!("path to {:?} has len {}", goal.clone(), new_path.len()); for morph_inst in new_path { let t = morph_inst.get_type(); diff --git a/src/test/morphism.rs b/src/test/morphism.rs index e6db4a3..9a35969 100644 --- a/src/test/morphism.rs +++ b/src/test/morphism.rs @@ -1,5 +1,5 @@ use { - crate::{dict::*, parser::*, unparser::*, morphism::*, TypeTerm} + crate::{dict::*, parser::*, unparser::*, morphism::*, TypeTerm, morphism_path::*} }; //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ @@ -104,10 +104,10 @@ fn morphism_test_setup() -> ( BimapTypeDict, MorphismBase<DummyMorphism> ) { fn test_morphism_path1() { let (mut dict, mut base) = morphism_test_setup(); - let path = base.find_morphism_path(MorphismType { + let path = ShortestPathProblem::new(&base, MorphismType { src_type: dict.parse("<Digit 10> ~ Char").unwrap(), dst_type: dict.parse("<Digit 10> ~ ℤ_2^64 ~ machine.UInt64").unwrap(), - }); + }).solve(); assert_eq!( path, @@ -132,10 +132,10 @@ fn test_morphism_path1() { fn test_morphism_path2() { let (mut dict, mut base) = morphism_test_setup(); - let path = base.find_morphism_path(MorphismType { + let path = ShortestPathProblem::new(&base, MorphismType { src_type: dict.parse("ℕ ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ Char>").unwrap(), dst_type: dict.parse("ℕ ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ ℤ_2^64 ~ machine.UInt64>").unwrap(), - }); + }).solve(); assert_eq!( path, @@ -160,10 +160,10 @@ fn test_morphism_path2() { fn test_morphism_path3() { let (mut dict, mut base) = morphism_test_setup(); - let path = base.find_morphism_path(MorphismType { + let path = ShortestPathProblem::new(&base, MorphismType { src_type: dict.parse("ℕ ~ <PosInt 10 LittleEndian> ~ <Seq <Digit 10> ~ Char>").unwrap(), dst_type: dict.parse("ℕ ~ <PosInt 16 LittleEndian> ~ <Seq <Digit 16> ~ ℤ_2^64 ~ machine.UInt64>").unwrap(), - }); + }).solve(); if let Some(path) = path.as_ref() { print_path(&mut dict, path); @@ -205,10 +205,10 @@ fn test_morphism_path3() { fn test_morphism_path4() { let (mut dict, mut base) = morphism_test_setup(); - let path = base.find_morphism_path(MorphismType { + let path = ShortestPathProblem::new(&base, MorphismType { src_type: dict.parse("ℕ ~ <PosInt 10 LittleEndian> ~ <Seq <Digit 10> ~ Char>").unwrap(), dst_type: dict.parse("ℕ ~ <PosInt 16 LittleEndian> ~ <Seq <Digit 16> ~ Char>").unwrap() - }); + }).solve(); if let Some(path) = path.as_ref() { print_path(&mut dict, path); @@ -263,10 +263,10 @@ fn test_morphism_path4() { fn test_morphism_path_posint() { let (mut dict, mut base) = morphism_test_setup(); - let path = base.find_morphism_path(MorphismType { + let path = ShortestPathProblem::new(&base, MorphismType { src_type: dict.parse("ℕ ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ Char>").unwrap(), dst_type: dict.parse("ℕ ~ <PosInt 16 BigEndian> ~ <Seq <Digit 16> ~ Char>").unwrap(), - }); + }).solve(); if let Some(path) = path.as_ref() { print_path(&mut dict, path); @@ -412,10 +412,10 @@ fn test_morphism_path_listedit() ); - let path = base.find_morphism_path(MorphismType { + let path = ShortestPathProblem::new(&base, MorphismType { src_type: dict.parse("<Seq~List~Vec <Digit 10>~Char>").unwrap(), dst_type: dict.parse("<Seq~List <Digit 10>~Char> ~ EditTree").unwrap(), - }); + }).solve(); if let Some(path) = path.as_ref() { print_path(&mut dict, path); diff --git a/src/unification.rs b/src/unification.rs index 767bbde..5072ea4 100644 --- a/src/unification.rs +++ b/src/unification.rs @@ -224,7 +224,7 @@ impl UnificationProblem { // error UnificationError > { - eprintln!("eval_subtype {:?} <=? {:?}", unification_pair.lhs, unification_pair.rhs); + // eprintln!("eval_subtype {:?} <=? {:?}", unification_pair.lhs, unification_pair.rhs); match (unification_pair.lhs.clone(), unification_pair.rhs.clone()) { /*