initial cost heuristic for morphism types & accelerated graph search (wip)
This commit is contained in:
parent
314f2141d8
commit
8212174cc4
6 changed files with 124 additions and 7 deletions
src
60
src/heuristic.rs
Normal file
60
src/heuristic.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
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 {
|
||||
bounds: Vec::new(),
|
||||
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 {
|
||||
bounds: Vec::new(),
|
||||
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 {
|
||||
bounds: Vec::new(),
|
||||
src_type: items1[i].clone(), dst_type: items2[i].clone() }
|
||||
);
|
||||
}
|
||||
|
||||
cost
|
||||
}
|
||||
|
||||
(a, b) => {
|
||||
if a == b {
|
||||
return 0;
|
||||
} else {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ pub mod context;
|
|||
pub mod constraint_system;
|
||||
pub mod morphism_graph;
|
||||
|
||||
pub mod heuristic;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
|
|
|
@ -230,6 +230,7 @@ pub trait Morphism : Sized {
|
|||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum MorphismInstance<M: Morphism + Clone> {
|
||||
//Id{ ψ: TypeTerm }
|
||||
Primitive{
|
||||
ψ: TypeTerm,
|
||||
σ: HashMapSubst,
|
||||
|
@ -262,6 +263,17 @@ impl<M: Morphism + Clone> MorphismInstance<M> {
|
|||
self.get_type().strip_common_rungs()
|
||||
}
|
||||
|
||||
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::Primitive { ψ, σ, morph } => {
|
||||
|
|
|
@ -2,7 +2,8 @@ use {
|
|||
crate::{
|
||||
morphism_graph::{Morphism, MorphismInstance, MorphismType, MorphismBase},
|
||||
term::*,
|
||||
HashMapSubst
|
||||
HashMapSubst,
|
||||
heuristic::*,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,8 +12,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> >,
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,7 +41,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
|
||||
}
|
||||
|
@ -47,7 +49,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;
|
||||
|
||||
|
@ -61,8 +69,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{ bounds: Vec::new(), src_type: new_path.cur_type.clone(), dst_type: self.goal.clone() });
|
||||
|
||||
new_path.morphisms.push(morph_inst);
|
||||
self.queue.push(new_path);
|
||||
|
@ -71,8 +80,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 */
|
||||
|
|
26
src/test/heuristic.rs
Normal file
26
src/test/heuristic.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use crate::{heuristic::*, dict::*, parser::*, morphism_graph::*};
|
||||
|
||||
#[test]
|
||||
fn test_heuristic() {
|
||||
let mut dict = BimapTypeDict::new();
|
||||
|
||||
assert_eq!(
|
||||
estimated_morphism_cost(
|
||||
&MorphismType {
|
||||
bounds: Vec::new(),
|
||||
src_type: dict.parse("A").expect("parse"),
|
||||
dst_type: dict.parse("A").expect("parse")
|
||||
}),
|
||||
1
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
estimated_morphism_cost(
|
||||
&MorphismType {
|
||||
bounds: Vec::new(),
|
||||
src_type: dict.parse("<Digit 10> ~ Char ~ Ascii ~ native.UInt8").expect("parse"),
|
||||
dst_type: dict.parse("<Digit 16> ~ native.UInt8").expect("parse")
|
||||
}),
|
||||
41
|
||||
);
|
||||
}
|
|
@ -6,3 +6,4 @@ pub mod pnf;
|
|||
pub mod context;
|
||||
pub mod constraint_system;
|
||||
pub mod morphism_graph;
|
||||
pub mod heuristic;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue