initial cost heuristic for morphism types & accelerated graph search (wip)
This commit is contained in:
parent
32cb3cf98a
commit
267b5e009e
6 changed files with 115 additions and 7 deletions
55
src/heuristic.rs
Normal file
55
src/heuristic.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use crate::{MorphismType, TypeTerm};
|
||||
|
||||
pub fn estimated_morphism_cost(ty: &MorphismType) -> u64 {
|
||||
|
||||
if let Ok((ψ,σ)) = crate::subtype_unify(&ty.src_type, &ty.dst_type) {
|
||||
1
|
||||
} else {
|
||||
match (ty.src_type.clone().normalize(),
|
||||
ty.dst_type.clone().normalize())
|
||||
{
|
||||
(TypeTerm::Ladder(r1),
|
||||
TypeTerm::Ladder(r2)) => {
|
||||
let mut cost = 10;
|
||||
for i in 0..usize::min( r1.len(), r2.len() ) {
|
||||
cost += estimated_morphism_cost(&MorphismType {
|
||||
src_type: r1[i].clone(), dst_type: r2[i].clone() });
|
||||
}
|
||||
cost
|
||||
}
|
||||
(TypeTerm::Spec(a1),
|
||||
TypeTerm::Spec(a2)) => {
|
||||
let mut cost = 10;
|
||||
for i in 0..usize::min( a1.len(), a2.len() ) {
|
||||
cost += estimated_morphism_cost(
|
||||
&MorphismType {src_type: a1[i].clone(), dst_type: a2[i].clone() });
|
||||
}
|
||||
cost
|
||||
}
|
||||
(TypeTerm::Seq{ seq_repr: sr1, items: items1 },
|
||||
TypeTerm::Seq{ seq_repr: sr2, items: items2 }) => {
|
||||
let mut cost = 10;
|
||||
/*
|
||||
estimated_morphism_cost(
|
||||
&MorphismType { src_type: sr1, dst_type: sr2 }
|
||||
);
|
||||
*/
|
||||
for i in 0..usize::min( items1.len(), items2.len() ) {
|
||||
cost += estimated_morphism_cost(
|
||||
&MorphismType { src_type: items1[i].clone(), dst_type: items2[i].clone() }
|
||||
);
|
||||
}
|
||||
|
||||
cost
|
||||
}
|
||||
|
||||
(a, b) => {
|
||||
if a == b {
|
||||
return 0;
|
||||
} else {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,8 @@ pub mod morphism;
|
|||
pub mod morphism_base;
|
||||
pub mod morphism_path;
|
||||
|
||||
pub mod heuristic;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
|
|
|
@ -219,6 +219,17 @@ impl<M: Morphism + Clone> MorphismInstance<M> {
|
|||
self.get_type().strip_halo()
|
||||
}
|
||||
|
||||
pub fn get_weight(&self) -> u64 {
|
||||
match self {
|
||||
MorphismInstance::Id { ψ } => 0,
|
||||
MorphismInstance::Primitive { ψ, σ, morph } => 1,
|
||||
MorphismInstance::Chain { path } => path.iter().map(|m| m.get_weight()).sum(),
|
||||
MorphismInstance::MapSeq { ψ, seq_repr, item_morph } => item_morph.get_weight() + 1,
|
||||
MorphismInstance::MapStruct { ψ, src_struct_repr, dst_struct_repr, member_morph } => member_morph.iter().map(|m| m.1.get_weight()).sum(),
|
||||
MorphismInstance::MapEnum { ψ, enum_repr, variant_morph } => variant_morph.iter().map(|m| m.1.get_weight()).sum()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_type(&self) -> MorphismType {
|
||||
match self {
|
||||
MorphismInstance::Id { ψ } => {
|
||||
|
|
|
@ -5,6 +5,7 @@ use {
|
|||
morphism_base::MorphismBase,
|
||||
substitution::Substitution,
|
||||
term::*, desugared_term::*,
|
||||
heuristic::*,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -13,8 +14,9 @@ use {
|
|||
#[derive(Clone)]
|
||||
pub struct MorphismPath<M: Morphism + Clone> {
|
||||
pub weight: u64,
|
||||
pub est_remain: u64,
|
||||
pub cur_type: TypeTerm,
|
||||
pub morphisms: Vec< MorphismInstance<M> >
|
||||
pub morphisms: Vec< MorphismInstance<M> >,
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,7 +43,7 @@ impl<'a, M:Morphism+Clone> ShortestPathProblem<'a, M> {
|
|||
ShortestPathProblem {
|
||||
morphism_base,
|
||||
queue: vec![
|
||||
MorphismPath::<M> { weight: 0, cur_type: ty.src_type, morphisms: vec![] }
|
||||
MorphismPath::<M> { weight: 0, est_remain: estimated_morphism_cost(&ty), cur_type: ty.src_type, morphisms: vec![] }
|
||||
],
|
||||
goal: ty.dst_type
|
||||
}
|
||||
|
@ -49,7 +51,13 @@ impl<'a, M:Morphism+Clone> ShortestPathProblem<'a, M> {
|
|||
|
||||
pub fn advance(&mut self, prev_path: &MorphismPath<M>, morph_inst: MorphismInstance<M>) {
|
||||
let dst_type = morph_inst.get_type().dst_type;
|
||||
//eprintln!("try morph to {:?}", dst_type.clone());//.sugar(type_dict).pretty(type_dict, 0));
|
||||
/*
|
||||
eprintln!("try morph to {:?} (weight: {}) (prev: {} + est {})", dst_type.clone(),
|
||||
morph_inst.get_weight(),
|
||||
prev_path.weight,
|
||||
prev_path.est_remain,
|
||||
);//.sugar(type_dict).pretty(type_dict, 0));
|
||||
*/
|
||||
|
||||
let mut creates_loop = false;
|
||||
|
||||
|
@ -63,8 +71,9 @@ impl<'a, M:Morphism+Clone> ShortestPathProblem<'a, M> {
|
|||
}
|
||||
|
||||
if ! creates_loop {
|
||||
new_path.weight += 1;//next_morph_inst.get_weight();
|
||||
new_path.weight += morph_inst.get_weight();
|
||||
new_path.cur_type = dst_type;
|
||||
new_path.est_remain = estimated_morphism_cost(&MorphismType{ src_type: new_path.cur_type.clone(), dst_type: self.goal.clone() });
|
||||
|
||||
new_path.morphisms.push(morph_inst);
|
||||
self.queue.push(new_path);
|
||||
|
@ -73,8 +82,15 @@ impl<'a, M:Morphism+Clone> ShortestPathProblem<'a, M> {
|
|||
|
||||
pub fn solve(&mut self) -> Option< Vec<MorphismInstance<M>> > {
|
||||
while ! self.queue.is_empty() {
|
||||
/* take the shortest partial path and try to advance it by one step */
|
||||
self.queue.sort_by( |p1,p2| p2.weight.cmp(&p1.weight));
|
||||
/* take the most promising partial path and try to advance it by one step */
|
||||
self.queue.sort_by( |p1,p2| ( p2.weight + p2.est_remain ).cmp(&( p1.weight + p1.est_remain ) ));
|
||||
/*
|
||||
eprintln!("===== TOP 5 PATHS =====\nGoal: {}", self.goal.pretty(dict, 0));
|
||||
for i in 1 ..= usize::min(self.queue.len(), 5) {
|
||||
let path = &self.queue[self.queue.len() - i];
|
||||
eprintln!("[[ {} ]] (w: {}, est remain: {}) --- {}", i, path.weight, path.est_remain, path.cur_type.pretty(dict, 0));
|
||||
}
|
||||
*/
|
||||
if let Some(mut cur_path) = self.queue.pop() {
|
||||
|
||||
/* 1. Check if goal is already reached by the current path */
|
||||
|
|
24
src/test/heuristic.rs
Normal file
24
src/test/heuristic.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
use crate::{heuristic::*, dict::*, parser::*, morphism::*};
|
||||
|
||||
#[test]
|
||||
fn test_heuristic() {
|
||||
let mut dict = BimapTypeDict::new();
|
||||
|
||||
assert_eq!(
|
||||
estimated_morphism_cost(
|
||||
&MorphismType {
|
||||
src_type: dict.parse("A").expect("parse"),
|
||||
dst_type: dict.parse("A").expect("parse")
|
||||
}),
|
||||
1
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
estimated_morphism_cost(
|
||||
&MorphismType {
|
||||
src_type: dict.parse("<Digit 10> ~ Char ~ Ascii ~ native.UInt8").expect("parse"),
|
||||
dst_type: dict.parse("<Digit 16> ~ native.UInt8").expect("parse")
|
||||
}),
|
||||
41
|
||||
);
|
||||
}
|
|
@ -7,4 +7,4 @@ pub mod pnf;
|
|||
pub mod substitution;
|
||||
pub mod unification;
|
||||
pub mod morphism;
|
||||
|
||||
pub mod heuristic;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue