rewrite morphism search

This commit is contained in:
Michael Sippel 2025-05-29 17:38:21 +02:00
parent 4ab07df9f2
commit b6add2b1a2
Signed by: senvas
GPG key ID: F96CF119C34B64A6
10 changed files with 1140 additions and 519 deletions

View file

@ -7,5 +7,8 @@ version = "0.1.0"
[dependencies]
tiny-ansi = { version = "0.1.0", optional = true }
[dev-dependencies]
pretty_assertions = "*"
[features]
pretty = ["dep:tiny-ansi"]

View file

@ -19,6 +19,8 @@ pub type HashMapSubst = std::collections::HashMap<u64, TypeTerm>;
pub trait SubstitutionMut {
fn append(&mut self, other: &Self);
fn filter(self, f: impl FnMut(&(u64, TypeTerm)) -> bool) -> Self;
fn filter_morphtype(self, ty: &crate::MorphismType) -> Self;
}
impl SubstitutionMut for HashMapSubst {
@ -27,6 +29,17 @@ impl SubstitutionMut for HashMapSubst {
self.insert(*v,t.clone());
}
}
fn filter(self, f: impl FnMut(&(u64, TypeTerm)) -> bool) -> Self {
self.into_iter().filter(f).collect()
}
fn filter_morphtype(self, ty: &crate::MorphismType) -> Self {
self.filter(|(v,t)| {
ty.src_type.contains_var(*v) ||
ty.dst_type.contains_var(*v)
})
}
}
impl Substitution for HashMapSubst {

View file

@ -1,10 +1,11 @@
use crate::{MorphismType, TypeTerm};
use crate::{morphism_graph::MorphismType, TypeTerm};
impl MorphismType {
pub fn estimated_cost(&self) -> u64 {
if let Ok((ψ,σ)) = crate::subtype_unify(&self.src_type, &self.dst_type) {
1
0
} else {
match (self.src_type.clone().normalize(),
self.dst_type.clone().normalize())
@ -28,7 +29,7 @@ impl MorphismType {
(TypeTerm::Seq{ seq_repr: sr1, items: items1 },
TypeTerm::Seq{ seq_repr: sr2, items: items2 }) => {
let mut cost = 10;
/*
/* // todo : add cost seq-repr conversion?
estimated_morphism_cost(
&MorphismType { src_type: sr1, dst_type: sr2 }
);
@ -40,6 +41,11 @@ impl MorphismType {
cost
}
(TypeTerm::Var(_), x)
| (x, TypeTerm::Var(_))
=> {
return 1;
}
(a, b) => {
if a == b {
return 0;

View file

@ -1,8 +1,8 @@
pub mod morphism_base;
pub mod morphism_path;
pub mod morphism_graph;
pub use morphism_base::*;
pub use morphism_path::*;
pub use morphism_graph::*;
use {
crate::{
@ -230,28 +230,27 @@ pub trait Morphism : Sized {
#[derive(Clone, PartialEq, Debug)]
pub enum MorphismInstance<M: Morphism + Clone> {
Id { ψ: TypeTerm },
Primitive{
Id { τ: TypeTerm },
Primitive{ m: M },
Sub {
ψ: TypeTerm,
m: Box<MorphismInstance<M>>
},
Specialize{
σ: HashMapSubst,
morph: M,
},
Chain{
path: Vec<MorphismInstance<M>>
m: Box<MorphismInstance<M>>
},
Chain{ path: Vec<MorphismInstance<M>> },
MapSeq{
ψ: TypeTerm,
seq_repr: Option<Box<TypeTerm>>,
item_morph: Box<MorphismInstance<M>>,
},
MapStruct{
ψ: TypeTerm,
src_struct_repr: Option<Box<TypeTerm>>,
dst_struct_repr: Option<Box<TypeTerm>>,
member_morph: Vec< (String, MorphismInstance<M>) >
},
MapEnum{
ψ: TypeTerm,
enum_repr: Option<Box<TypeTerm>>,
variant_morph: Vec< (String, MorphismInstance<M>) >
}
@ -263,43 +262,58 @@ impl<M: Morphism + Clone> MorphismInstance<M> {
self.get_type().strip_common_rungs()
}
pub fn from_chain(τ: TypeTerm, path: &Vec<MorphismInstance<M>>) -> Self {
if path.len() == 0 {
MorphismInstance::Id { τ }
} else if path.len() == 1 {
path[0].clone()
} else {
MorphismInstance::Chain { path: path.clone() }
}
}
pub fn get_weight(&self) -> u64 {
match self {
MorphismInstance::Id { ψ } => 0,
MorphismInstance::Primitive { ψ, σ, morph } => 1,
MorphismInstance::Id { τ } => 0,
MorphismInstance::Sub { ψ, m } => m.get_weight(),
MorphismInstance::Specialize { σ, m } => m.get_weight(),
MorphismInstance::Primitive { m } => 10,
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()
MorphismInstance::MapSeq { seq_repr, item_morph } => item_morph.get_weight() + 15,
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 { ψ } => {
MorphismInstance::Id { τ } => {
MorphismType {
bounds: Vec::new(),
src_type: ψ.clone(),
dst_type: ψ.clone()
src_type: τ.clone(),
dst_type: τ.clone()
}
}
MorphismInstance::Primitive { ψ, σ, morph } => {
MorphismInstance::Primitive { m } => { m.get_type() },
MorphismInstance::Sub { ψ, m } =>
MorphismType {
bounds: morph.get_type().bounds,
bounds: m.get_type().bounds,
src_type:
TypeTerm::Ladder(vec![
ψ.clone(),
morph.get_type().src_type
.apply_subst(σ).clone()
]).strip(),
m.get_type().src_type
]),
dst_type: TypeTerm::Ladder(vec![
ψ.clone(),
morph.get_type().dst_type
.apply_subst(σ).clone()
]).strip(),
}
}
m.get_type().dst_type
]),
},
MorphismInstance::Specialize { σ, m } =>
MorphismType {
bounds: Vec::new(),
src_type: m.get_type().src_type.apply_subst(σ).clone(),
dst_type: m.get_type().dst_type.apply_subst(σ).clone(),
},
MorphismInstance::Chain { path } => {
if path.len() > 0 {
//let s = self.get_subst();
@ -309,8 +323,7 @@ impl<M: Morphism + Clone> MorphismInstance<M> {
bounds: Vec::new(), // <-- fixme: but first implement variable scopes
src_type: path.first().unwrap().get_type().src_type.clone(),
dst_type: path.last().unwrap().get_type().dst_type.clone()
}
//.apply_subst(&s)
}//.apply_subst(&s)
} else {
MorphismType {
bounds: Vec::new(),
@ -319,63 +332,50 @@ impl<M: Morphism + Clone> MorphismInstance<M> {
}
}
}
MorphismInstance::MapSeq { ψ, seq_repr, item_morph } => {
MorphismInstance::MapSeq { seq_repr, item_morph } => {
MorphismType {
bounds: item_morph.get_type().bounds,
src_type: TypeTerm::Ladder(vec![
ψ.clone(),
TypeTerm::Seq{ seq_repr: seq_repr.clone(),
items: vec![ item_morph.get_type().src_type ]}
]),
dst_type: TypeTerm::Ladder(vec![
ψ.clone(),
TypeTerm::Seq{ seq_repr: seq_repr.clone(),
items: vec![ item_morph.get_type().dst_type ]}
])
src_type: TypeTerm::Seq{ seq_repr: seq_repr.clone(),
items: vec![ item_morph.get_type().src_type ]},
dst_type: TypeTerm::Seq{ seq_repr: seq_repr.clone(),
items: vec![ item_morph.get_type().dst_type ]},
}
}
MorphismInstance::MapStruct { ψ, src_struct_repr, dst_struct_repr, member_morph } => {
MorphismInstance::MapStruct { src_struct_repr, dst_struct_repr, member_morph } => {
MorphismType {
bounds: Vec::new(), // <-- fixme: same as with chain
src_type: TypeTerm::Ladder(vec![ ψ.clone(),
TypeTerm::Struct{
src_type: TypeTerm::Struct{
struct_repr: src_struct_repr.clone(),
members:
member_morph.iter().map(|(symbol, morph)| {
StructMember{ symbol:symbol.clone(), ty: morph.get_type().src_type }
}).collect()
}
]),
dst_type: TypeTerm::Ladder(vec![ ψ.clone(),
TypeTerm::Struct{
},
dst_type: TypeTerm::Struct {
struct_repr: dst_struct_repr.clone(),
members: member_morph.iter().map(|(symbol, morph)| {
StructMember { symbol: symbol.clone(), ty: morph.get_type().dst_type}
}).collect()
}
])
}
}
MorphismInstance::MapEnum { ψ, enum_repr, variant_morph } => {
MorphismInstance::MapEnum { enum_repr, variant_morph } => {
MorphismType {
bounds: Vec::new(), // <-- fixme: same as with chain
src_type: TypeTerm::Ladder(vec![ ψ.clone(),
TypeTerm::Struct{
src_type: TypeTerm::Struct{
struct_repr: enum_repr.clone(),
members:
variant_morph.iter().map(|(symbol, morph)| {
StructMember{ symbol:symbol.clone(), ty: morph.get_type().src_type }
}).collect()
}
]),
dst_type: TypeTerm::Ladder(vec![ ψ.clone(),
TypeTerm::Struct{
},
dst_type: TypeTerm::Struct{
struct_repr: enum_repr.clone(),
members: variant_morph.iter().map(|(symbol, morph)| {
StructMember { symbol: symbol.clone(), ty: morph.get_type().dst_type}
}).collect()
}
])
}
}
}.normalize()
@ -383,10 +383,14 @@ impl<M: Morphism + Clone> MorphismInstance<M> {
pub fn get_subst(&self) -> HashMapSubst {
match self {
MorphismInstance::Id { ψ } => {
std::collections::HashMap::new()
MorphismInstance::Id { τ } => HashMap::new(),
MorphismInstance::Primitive { m } => HashMap::new(),
MorphismInstance::Sub { ψ, m } => m.get_subst(),
MorphismInstance::Specialize { σ, m } => {
let mut σ0 = m.get_subst();
σ0.append(σ);
σ0
}
MorphismInstance::Primitive { ψ, σ, morph } => σ.clone(),
MorphismInstance::Chain { path } => {
path.iter().fold(
std::collections::HashMap::new(),
@ -396,17 +400,17 @@ impl<M: Morphism + Clone> MorphismInstance<M> {
}
)
},
MorphismInstance::MapSeq { ψ, seq_repr, item_morph } => {
MorphismInstance::MapSeq { seq_repr, item_morph } => {
item_morph.get_subst()
},
MorphismInstance::MapStruct { ψ, src_struct_repr, dst_struct_repr, member_morph } => {
MorphismInstance::MapStruct { src_struct_repr, dst_struct_repr, member_morph } => {
let mut σ = HashMap::new();
for (symbol, m) in member_morph.iter() {
σ.append(&mut m.get_subst());
}
σ
},
MorphismInstance::MapEnum { ψ, enum_repr, variant_morph } => {
MorphismInstance::MapEnum { enum_repr, variant_morph } => {
todo!();
HashMap::new()
},
@ -416,19 +420,24 @@ impl<M: Morphism + Clone> MorphismInstance<M> {
pub fn apply_subst(&mut self, γ: &HashMapSubst) {
let ty = self.get_type();
match self {
MorphismInstance::Id { ψ } => {
ψ.apply_subst( γ );
MorphismInstance::Id { τ } => {
τ.apply_subst( γ );
}
MorphismInstance::Primitive { ψ, σ, morph } => {
MorphismInstance::Primitive { m } => { },
MorphismInstance::Sub { ψ, m } => {
ψ.apply_subst(γ);
for (_,t) in σ.iter_mut() {
m.apply_subst(γ);
}
MorphismInstance::Specialize { σ, m } => {
for (n,t) in σ.iter_mut() {
t.apply_subst(γ);
}
for (v,t) in γ.iter() {
if morph.get_type().src_type.apply_subst(σ).contains_var(*v)
|| morph.get_type().dst_type.apply_subst(σ).contains_var(*v) {
σ.insert(*v, t.clone());
}
for (i,t) in γ.iter() {
if m.get_type().src_type.apply_subst(σ).contains_var(*i)
|| m.get_type().dst_type.apply_subst(σ).contains_var(*i) {
σ.insert(*i, t.clone());
}
}
},
MorphismInstance::Chain { path } => {
@ -436,16 +445,15 @@ impl<M: Morphism + Clone> MorphismInstance<M> {
n.apply_subst(γ);
}
}
MorphismInstance::MapSeq { ψ, seq_repr, item_morph } => {
ψ.apply_subst(γ);
MorphismInstance::MapSeq { seq_repr, item_morph } => {
item_morph.apply_subst(γ);
}
MorphismInstance::MapStruct { ψ, src_struct_repr, dst_struct_repr, member_morph } => {
MorphismInstance::MapStruct { src_struct_repr, dst_struct_repr, member_morph } => {
for (_,ty) in member_morph {
ty.apply_subst(γ);
}
},
MorphismInstance::MapEnum { ψ, enum_repr, variant_morph } => {
MorphismInstance::MapEnum { enum_repr, variant_morph } => {
for (_,ty) in variant_morph {
ty.apply_subst(γ);
}

View file

@ -1,11 +1,29 @@
use {
crate::{
morphism_path::{ShortestPathProblem},
morphism_graph::{MorphismInstance, Morphism, MorphismType},
TypeTerm, StructMember, TypeDict
}, std::io::{Write}
morphism_graph::{Morphism, MorphismInstance, MorphismType}, HashMapSubst, StructMember, TypeDict, TypeTerm
}, std::io::Write
};
pub trait MorphBase<
Morph: Morphism + Clone,
Weight: Eq + Ord + Default
> {
fn get_morphisms(&self, halo_key: &TypeTerm) -> Vec<MorphismInstance<Morph>> {
vec![]
}
fn heuristic(&self, t: &MorphismType) -> Weight {
Weight::default()
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum DecomposedMorphismType {
SeqMap { item: MorphismType },
StructMap { members: Vec<(String, MorphismType)> },
EnumMap { variants: Vec<(String, MorphismType)> }
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
#[derive(Clone)]
@ -26,21 +44,14 @@ impl<M: Morphism + Clone> MorphismBase<M> {
self.morphisms.push( m );
}
pub fn get_morphism_instance(&self, ty: &MorphismType) -> Option<MorphismInstance<M>> {
if let Some(path) = ShortestPathProblem::new(self, ty.clone()).solve() {
if path.len() == 0 {
Some(MorphismInstance::Id{ ψ: ty.src_type.clone() })
} else if path.len() == 1 {
Some(path[0].clone())
} else {
Some(MorphismInstance::Chain { path })
}
} else {
None
}
}
pub fn complex_morphism_decomposition(&self, src_type: &TypeTerm, dst_type: &TypeTerm) -> Option< MorphismInstance<M> > {
/*
given a morphism type (src/dst types),
try to match their outer structure (Struct/Seq/Map)
and spawn a GraphSearch for each component
*/
pub fn morphism_decomposition(&self, src_type: &TypeTerm, dst_type: &TypeTerm) ->
Option< (TypeTerm, DecomposedMorphismType) >
{
let (src_ψ, src_floor) = src_type.get_floor_type();
let (dst_ψ, dst_floor) = dst_type.get_floor_type();
@ -56,7 +67,7 @@ impl<M: Morphism + Clone> MorphismBase<M> {
=> {
// todo: optimization: check if struct repr match
let mut member_morph = Vec::new();
let mut member_morph_types = Vec::new();
let mut failed = false;
let mut necessary = false;
@ -65,18 +76,11 @@ impl<M: Morphism + Clone> MorphismBase<M> {
for StructMember{ symbol: symbol_lhs, ty: ty_lhs } in members_lhs.iter() {
if symbol_rhs == symbol_lhs {
found_src_member = true;
if let Some(mm) = self.get_morphism_instance(&MorphismType {
member_morph_types.push((symbol_rhs.clone(), MorphismType {
bounds: Vec::new(),
src_type: ty_lhs.clone(),
dst_type: ty_rhs.clone()
}) {
if ty_lhs != ty_rhs {
necessary = true;
}
member_morph.push((symbol_lhs.clone(), mm))
} else {
failed = true;
src_type: ty_lhs.clone(), dst_type: ty_rhs.clone() }));
if ty_lhs != ty_rhs {
necessary = true;
}
break;
}
@ -90,12 +94,9 @@ impl<M: Morphism + Clone> MorphismBase<M> {
}
if ! failed && necessary {
Some(MorphismInstance::MapStruct {
ψ: src_ψ,
src_struct_repr: struct_repr_lhs.clone(),
dst_struct_repr: struct_repr_rhs.clone(),
member_morph
})
Some((src_ψ, DecomposedMorphismType::StructMap {
members: member_morph_types
}))
} else {
None
}
@ -105,96 +106,60 @@ impl<M: Morphism + Clone> MorphismBase<M> {
(TypeTerm::Seq{ seq_repr: seq_repr_lhs, items: items_lhs },
TypeTerm::Seq{ seq_repr: _seq_rerpr_rhs, items: items_rhs })
=> {
//let mut item_morphs = Vec::new();
for (ty_lhs, ty_rhs) in items_lhs.iter().zip(items_rhs.iter()) {
if let Some(item_morph) = self.get_morphism_instance(&MorphismType{
bounds: Vec::new(),
src_type: ty_lhs.clone(),
dst_type: ty_rhs.clone()
}) {
return Some(MorphismInstance::MapSeq { ψ: src_ψ, seq_repr: seq_repr_lhs.clone(), item_morph: Box::new(item_morph) });
}
break;
return Some((src_ψ, DecomposedMorphismType::SeqMap {
item: MorphismType{
bounds: Vec::new(),
src_type: ty_lhs.clone(), dst_type: ty_rhs.clone() }
}));
}
None
}
(TypeTerm::Enum { enum_repr: enum_repr_lhs, variants: variants_lhs },
TypeTerm::Enum { enum_repr: enum_repr_rhs, variants: variants_rhs }
) => {
todo!()
}
_ => {
None
}
}
}
pub fn enum_morphisms_from(&self, src_type: &TypeTerm) -> Vec< MorphismInstance<M> > {
pub fn enum_morphisms_from(&self, src_type: &TypeTerm) -> Vec< (TypeTerm, HashMapSubst, M) > {
let mut morphs = Vec::new();
//eprintln!("enum morphisms from {:?}", src_type);
for m in self.morphisms.iter() {
let m_src_type = m.get_type().src_type;
let m_dst_type = m.get_type().dst_type;
let m_src_type = m.get_type().src_type.normalize();
let m_dst_type = m.get_type().dst_type.normalize();
/* 1. primitive morphisms */
// check if the given start type is compatible with the
// check if the given source type is compatible with the
// morphisms source type,
// i.e. check if `src_type` is a subtype of `m_src_type`
if let Ok((ψ, σ)) = crate::constraint_system::subtype_unify(src_type, &m_src_type) {
let morph_inst = MorphismInstance::Primitive { ψ, σ, morph: m.clone() };
//eprintln!("..found direct morph to {:?}", morph_inst.get_type().dst_type);
morphs.push(morph_inst);
}
/* 2. check complex types */
else if let Some(complex_morph) = self.complex_morphism_decomposition(src_type, &m_src_type) {
//eprintln!("found complex morph to {:?}", complex_morph.get_type().dst_type);
morphs.push(complex_morph);
morphs.push((ψ, σ, m.clone()));
}
}
morphs
}
pub fn enum_complex_morphisms(&self, src_type: &TypeTerm) -> Vec<(TypeTerm, DecomposedMorphismType)> {
let mut morphs = Vec::new();
for m in self.morphisms.iter() {
let m_src_type = m.get_type().src_type.normalize();
pub fn to_dot(&self, dict: &mut impl TypeDict) -> String {
let mut dot_source = String::new();
dot_source.push_str("digraph MorphismGraph {");
pub fn ty_to_dot_label(dict: &mut impl TypeDict, ty: &TypeTerm) -> String {
let pretty_str = ty.pretty(dict, 0);
let mut child = std::process::Command::new("aha").arg("--no-header")
.stdin( std::process::Stdio::piped() )
.stdout(std::process::Stdio::piped())
.spawn().expect("spawn child");
let mut stdin = child.stdin.take().expect("cant get stdin");
std::thread::spawn(move ||{ stdin.write_all(pretty_str.as_bytes()).expect("failed to write")});
let out = child.wait_with_output().expect("");
let html_str = String::from_utf8_lossy(&out.stdout).replace("\n", "<BR/>").replace("span", "B");
html_str
/* 2. check complex types */
if let Some(decomposition) = self.morphism_decomposition(src_type, &m_src_type) {
morphs.push(decomposition);
}
}
// add vertices
for (i,m) in self.morphisms.iter().enumerate() {
dot_source.push_str(&format!("
SRC{} [label=<{}>]
DST{} [label=<{}>]
SRC{} -> DST{} [label=\"{}\"]
", i, ty_to_dot_label(dict, &m.get_type().src_type),
i, ty_to_dot_label(dict, &m.get_type().dst_type),
i,i,i
));
}
// add edges
dot_source.push_str("}");
dot_source
morphs
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\

View file

@ -0,0 +1,541 @@
use {
crate::{
morphism_graph::DecomposedMorphismType, HashMapSubst, Morphism, MorphismBase, MorphismInstance, MorphismType, SubstitutionMut, TypeDict, TypeTerm
},
std::{collections::HashMap, sync::{Arc,RwLock}}
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
pub struct MorphismGraph<M: Morphism+Clone> {
solved_paths: HashMap< MorphismType, MorphismInstance<M> >,
base: MorphismBase<M>
}
pub struct GraphSearch<M: Morphism+Clone> {
goal: MorphismType,
solution: Option< MorphismInstance<M> >,
explore_queue: Vec< Arc<RwLock<SearchNode<M>>> >,
skip_preview: bool
}
#[derive(Clone, Debug, PartialEq)]
pub enum GraphSearchState<M: Morphism+Clone> {
Solved( MorphismInstance<M> ),
Continue,
Err( GraphSearchError )
}
#[derive(Clone, Debug, PartialEq)]
pub enum GraphSearchError {
NoMorphismFound
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
/// represents a partial path during search in the morphism graph
pub struct SearchNode<M: Morphism+Clone> {
/// predecessor node
pred: Option< Arc<RwLock< SearchNode<M> >> >,
/// (measured) weight of the preceding path
weight: u64,
ty: MorphismType,
/// the advancement over pred
step: Step<M>,
ψ: TypeTerm,
}
pub enum Step<M: Morphism+Clone> {
Id { τ: TypeTerm },
Inst{ m: MorphismInstance<M> },
//Sub{ ψ: TypeTerm },
Specialize { σ: HashMapSubst },
MapSeq { item: GraphSearch<M> },
MapStruct { members: Vec< (String, GraphSearch<M>) > },
MapEnum { variants: Vec< (String, GraphSearch<M>) > }
}
pub enum SolvedStep<M: Morphism+Clone> {
Id { τ: TypeTerm },
Inst{ m: MorphismInstance<M> },
Specialize { σ: HashMapSubst },
MapSeq { item: MorphismInstance<M> },
MapStruct { members: Vec< (String, MorphismInstance<M>) > },
MapEnum { variants: Vec< (String, MorphismInstance<M>) > }
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
pub trait SearchNodeExt<M: Morphism+Clone> {
fn specialize(&self, σ: HashMapSubst) -> Arc<RwLock<SearchNode<M>>>;
fn chain(&self, ψ: TypeTerm, σ: HashMapSubst, m: M) -> Arc<RwLock<SearchNode<M>>>;
fn set_sub(&self, ψ: TypeTerm) -> Arc<RwLock<SearchNode<M>>>;
fn map_seq(&self, goal: MorphismType) -> Arc<RwLock<SearchNode<M>>>;
fn map_struct(&self, goals: Vec<(String, MorphismType)>) -> Arc<RwLock<SearchNode<M>>>;
fn map_enum(&self, goals: Vec<(String, MorphismType)>) -> Arc<RwLock<SearchNode<M>>>;
fn advance(&self, base: &MorphismBase<M>, dict: &mut impl TypeDict) -> Result<bool, GraphSearchError>;
fn to_morphism_instance(&self) -> Option< MorphismInstance<M> >;
fn is_ready(&self) -> bool;
fn get_weight(&self) -> u64;
fn get_type(&self) -> MorphismType;
fn creates_loop(&self) -> bool;
}
impl<M: Morphism+Clone> SearchNodeExt<M> for Arc<RwLock<SearchNode<M>>> {
fn get_weight(&self) -> u64 {
self.read().unwrap().weight
+ match &self.read().unwrap().step {
Step::Id { τ } => 0,
Step::Inst { m } => m.get_weight(),
Step::Specialize { σ } => 0,
Step::MapSeq { item } => item.best_path_weight(),
Step::MapStruct { members } => todo!(),
Step::MapEnum { variants } => todo!(),
}
}
fn get_type(&self) -> MorphismType {
let s = self.read().unwrap();
MorphismType {
bounds: Vec::new(),
src_type: TypeTerm::Ladder(vec![ s.ψ.clone(), s.ty.src_type.clone() ]).normalize(),
dst_type: TypeTerm::Ladder(vec![ s.ψ.clone(), s.ty.dst_type.clone() ]).normalize(),
}
}
// tell if this sub-search already has a solution
fn is_ready(&self) -> bool {
let n = self.read().unwrap();
match &n.step {
Step::Id { τ } => true,
//Step::Sub { ψ } => n.pred.as_ref().unwrap().is_ready(),
Step::Specialize { σ } => true,
Step::MapSeq { item } => {
item.get_solution().is_some()
}
Step::MapStruct { members } => {
//members.
todo!()
}
Step::MapEnum { variants } => {
todo!()
}
Step::Inst { m } => true
}
}
fn creates_loop(&self) -> bool {
/*
let mut cur_node = self.read().unwrap().pred.clone();
while let Some(n) = cur_node {
if n.get_type().dst_type == self.get_type().dst_type {
return true;
}
cur_node = n.read().unwrap().pred.clone();
}
*/
false
}
fn advance(&self, base: &MorphismBase<M>, dict: &mut impl TypeDict) -> Result<bool, GraphSearchError> {
let mut n = self.write().unwrap();
match &mut n.step {
Step::MapSeq { item } => {
eprintln!("advance seq-map");
match item.advance(base, dict) {
GraphSearchState::Solved(item_morph) => {
eprintln!("Sequence-Map Sub Graph Solved!!");
n.ty = MorphismType {
bounds: Vec::new(),
src_type: TypeTerm::Seq { seq_repr: None, items: vec![ item_morph.get_type().src_type ] },
dst_type: TypeTerm::Seq { seq_repr: None, items: vec![ item_morph.get_type().dst_type ] },
};
Ok(false)
}
GraphSearchState::Continue => Ok(true),
GraphSearchState::Err(err) => Err(err)
}
}
Step::MapStruct { members } => {
todo!()
}
Step::MapEnum { variants } => {
todo!()
}
_ => Ok(false)
}
}
fn specialize(&self, σ: HashMapSubst) -> Arc<RwLock<SearchNode<M>>> {
let src_type= self.get_type().src_type;
let dst_type= self.get_type().dst_type;
let σ = σ.filter(|(v,t)| src_type.contains_var(*v) || dst_type.contains_var(*v));
if σ.is_empty() {
self.clone()
} else {
Arc::new(RwLock::new(SearchNode {
pred: Some(self.clone()),
weight: self.get_weight(),
ty: MorphismType {
bounds: Vec::new(),
src_type: self.get_type().src_type.apply_subst(&σ).clone().normalize(),
dst_type: self.get_type().dst_type.apply_subst(&σ).clone().normalize()
},
step: Step::Specialize { σ },
ψ: self.read().unwrap().ψ.clone()
}))
}
}
fn chain(&self, ψ: TypeTerm, σ: HashMapSubst, m: M) -> Arc<RwLock<SearchNode<M>>> {
let m = MorphismInstance::Primitive { m: m.clone() };
let mut parent = self.clone();
{
let mut σ = σ.clone().filter(|(v,t)|
self.get_type().dst_type.contains_var(*v)
);
parent = parent.specialize(σ);
}
let mut σ_src = σ.clone().filter(|(v,t)|
m.get_type().src_type.contains_var(*v) &&
!self.get_type().dst_type.contains_var(*v)
);
let mut σ_dst = σ.clone().filter(|(v,t)|
m.get_type().dst_type.contains_var(*v)
);
let mut n = Arc::new(RwLock::new(SearchNode {
pred: Some(parent),
weight: self.get_weight(),
ty: MorphismType {
bounds: Vec::new(),
src_type: self.get_type().src_type,
dst_type: m.get_type().dst_type
}.apply_subst(&σ_src),
step: Step::Inst{
m: if σ_src.is_empty() {
m
} else {
MorphismInstance::Specialize { σ: σ_src, m: Box::new(m) }
}
},
ψ: TypeTerm::unit(),
}));
n.set_sub(ψ);
n = n.specialize(σ_dst);
n
}
fn set_sub(&self, ψ: TypeTerm) -> Arc<RwLock<SearchNode<M>>> {
let oldψ = &mut self.write().unwrap().ψ;
*oldψ = TypeTerm::Ladder(vec![ ψ, oldψ.clone() ]).normalize();
self.clone()
}
fn map_seq(&self, goal: MorphismType) -> Arc<RwLock<SearchNode<M>>> {
Arc::new(RwLock::new(SearchNode {
pred: Some(self.clone()),
weight: self.get_weight(),
ty: MorphismType {
bounds: Vec::new(),
src_type: TypeTerm::Seq{ seq_repr: None, items: vec![goal.src_type.clone()] },
dst_type: TypeTerm::Seq{ seq_repr: None, items: vec![goal.src_type.clone()] }
},
step: Step::MapSeq { item: GraphSearch::new(goal) },
ψ: self.read().unwrap().ψ.clone()
}))
}
fn map_struct(&self, goals: Vec<(String, MorphismType)>) -> Arc<RwLock<SearchNode<M>>> {
Arc::new(RwLock::new(SearchNode {
pred: Some(self.clone()),
weight: self.get_weight(),
ty: todo!(),
step: Step::MapStruct { members: goals.into_iter().map(|(name,goal)| (name, GraphSearch::new(goal))).collect() },
ψ: self.read().unwrap().ψ.clone()
}))
}
fn map_enum(&self, goals: Vec<(String, MorphismType)>) -> Arc<RwLock<SearchNode<M>>> {
Arc::new(RwLock::new(SearchNode {
pred: Some(self.clone()),
weight: self.get_weight(),
ty: todo!(),
step: Step::MapEnum { variants: goals.into_iter().map(|(name,goal)| (name, GraphSearch::new(goal))).collect() },
ψ: self.read().unwrap().ψ.clone()
}))
}
fn to_morphism_instance(&self) -> Option< MorphismInstance<M> > {
let mut steps = Vec::new();
let mut cur_node = Some(self.clone());
while let Some(n) = cur_node {
let n = n.read().unwrap();
steps.push((n.ψ.clone(),
match &n.step {
Step::Id { τ } => SolvedStep::Id { τ: τ.clone() },
Step::Inst { m } => SolvedStep::Inst { m: m.clone() },
Step::Specialize { σ } => SolvedStep::Specialize { σ: σ.clone() },
Step::MapSeq { item } => SolvedStep::MapSeq { item: item.get_solution().unwrap() },
Step::MapStruct { members } => SolvedStep::MapStruct { members: members.iter().map(|(n,m)| (n.clone(), m.get_solution().unwrap())).collect() },
Step::MapEnum { variants } => SolvedStep::MapEnum { variants: variants.iter().map(|(n,m)| (n.clone(), m.get_solution().unwrap())).collect() },
}));
cur_node = n.pred.clone();
}
steps.reverse();
let mut begin = TypeTerm::unit();
let mut path = Vec::new();
eprintln!("to_morph_instance:\n==");
for (ψ, s) in steps {
match s {
SolvedStep::Id { τ } => {
eprintln!("to_morph_instance: ID {:?}", τ);
begin = τ.clone(); },
SolvedStep::Inst{ m } => {
eprintln!("to_morph_instance: Inst {:?} -- {:?}", ψ, m.get_type());
let mut m = m.clone();
if ! ψ.is_empty() {
m = MorphismInstance::Sub { ψ, m: Box::new(m) };
}
path.push(m.clone());
},
SolvedStep::Specialize { σ } => {
eprintln!("to_morph_instance: Specialize {:?}", σ);
if path.len() > 0 && !σ.is_empty() {
let m = MorphismInstance::from_chain(begin.clone(), &path);
path = vec![
MorphismInstance::Specialize { σ: σ.clone(), m: Box::new(m) }
];
}
}
SolvedStep::MapSeq { item } => {
let mut m = MorphismInstance::MapSeq {
seq_repr: None,
item_morph: Box::new(item)
};
if ! ψ.is_empty() {
m = MorphismInstance::Sub { ψ, m: Box::new(m) };
}
path.push(m);
}
SolvedStep::MapStruct { members } => {
todo!();
//path.push(MorphismInstance::MapStruct { src_struct_repr: (), dst_struct_repr: (), member_morph: () })
}
SolvedStep::MapEnum { variants } => {
todo!();
}
}
}
Some(MorphismInstance::from_chain(begin, &path))
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
impl<M: Morphism+Clone> MorphismGraph<M> {
pub fn new(base: MorphismBase<M>) -> Self {
MorphismGraph {
solved_paths: HashMap::new(),
base
}
}
pub fn search(&self, goal: MorphismType, dict: &mut impl TypeDict) -> Result<
MorphismInstance<M>,
GraphSearchError
> {
let mut search = GraphSearch::<M>::new(goal);
loop {
match search.advance(&self.base, dict) {
GraphSearchState::Solved(m) => { return Ok(m); }
GraphSearchState::Continue => { continue; }
GraphSearchState::Err(err) => { return Err(err); }
}
}
}
}
impl<M: Morphism+Clone> GraphSearch<M> {
pub fn new(goal: MorphismType) -> Self {
GraphSearch {
goal: goal.clone(),
solution: None,
explore_queue: vec![
Arc::new(RwLock::new(SearchNode {
pred: None,
weight: 0,
ty: MorphismType {
bounds: Vec::new(),
src_type: goal.src_type.clone(),
dst_type: goal.src_type.clone()
},
step: Step::Id { τ: goal.src_type.clone() },
ψ: TypeTerm::unit()
}))
],
skip_preview: false
}
}
pub fn get_solution(&self) -> Option< MorphismInstance<M> > {
self.solution.clone()
}
pub fn best_path_weight(&self) -> u64 {
if let Some(best) = self.explore_queue.last() {
best.get_weight()
} else {
0
}
}
pub fn est_remain(goal: &MorphismType, search_node: &Arc<RwLock<SearchNode<M>>>) -> u64 {
MorphismType {
bounds: Vec::new(),
src_type: goal.src_type.clone(),
dst_type: search_node.get_type().src_type.clone()
}.estimated_cost()
+
MorphismType {
bounds: Vec::new(),
src_type: search_node.get_type().dst_type.clone(),
dst_type: goal.dst_type.clone()
}.estimated_cost()
}
pub fn choose_next_node(&mut self, dict: &mut impl TypeDict) -> Option<Arc<RwLock<SearchNode<M>>>> {
let goal= self.goal.clone();
self.explore_queue.sort_by(
|a,b| {
(Self::est_remain(&goal, b) + b.get_weight() )
.cmp(
&(Self::est_remain(&goal, a) + a.get_weight())
)
}
);
if !self.skip_preview {
eprintln!("===== TOP 5 PATHS =====\nGoal:\n {} -> {}",
goal.src_type.pretty(dict, 0),
goal.dst_type.pretty(dict, 0)
);
for i in 1 ..= usize::min(self.explore_queue.len(), 5) {
let n = &self.explore_queue[self.explore_queue.len() - i];
eprintln!("[[ {} ]] (weight: {} + est remain: {}) --- {} --> {}", i,
n.get_weight(),
Self::est_remain(&goal, &n),
n.get_type().src_type.pretty(dict, 0),
n.get_type().dst_type.pretty(dict, 0));
}
} else {
self.skip_preview = false;
}
self.explore_queue.pop()
}
pub fn advance(&mut self, base: &MorphismBase<M>, dict: &mut impl TypeDict) -> GraphSearchState<M> {
if let Some(node) = self.choose_next_node(dict) {
match node.advance(base, dict) {
Ok(_) => {
if ! node.is_ready() {
if ! node.creates_loop() {
self.skip_preview = true;
self.explore_queue.push(node);
}
return GraphSearchState::Continue;
} else {
let w = node.to_morphism_instance().unwrap().get_weight();
eprintln!("set Weight of complex morph to {}", w);
node.write().unwrap().weight = w;
}
}
Err(err) => {
return GraphSearchState::Err(err);
}
}
if node.creates_loop() {
eprintln!("Creates loop.");
return GraphSearchState::Continue;
}
/* 1. Check if goal is already reached by the current path */
if let Ok((, σ)) = crate::constraint_system::subtype_unify( &node.get_type().dst_type, &self.goal.dst_type ) {
/* found path */
self.solution = Some(
if σ.is_empty() {
node.to_morphism_instance().unwrap()
} else {
node
.specialize( σ.filter_morphtype(&node.get_type()) )
.to_morphism_instance()
.unwrap()
}
);
return GraphSearchState::Solved(self.get_solution().unwrap());
}
let mut decompositions = base.enum_complex_morphisms(&node.get_type().dst_type);
if let Some(d) = base.morphism_decomposition(&node.get_type().dst_type, &self.goal.dst_type) {
decompositions.push(d);
}
eprintln!("{} decompositions", decompositions.len());
let mut done = Vec::new();
for (ψ,decomposition) in decompositions {
if ! done.contains(&(ψ.clone(),decomposition.clone())) {
self.explore_queue.push(
match &decomposition {
DecomposedMorphismType::SeqMap { item } => { node.map_seq( item.clone() ) },
DecomposedMorphismType::StructMap { members } => { node.map_struct(members.clone()) },
DecomposedMorphismType::EnumMap { variants } => { node.map_enum(variants.clone()) },
}.set_sub(ψ.clone())
);
done.push((ψ, decomposition));
}else {
//eprintln!("avoid duplicate decomposition");
}
}
/* 2. Try to advance current path */
for (ψ,σ,m) in base.enum_morphisms_from(&node.get_type().dst_type) {
eprintln!("add direct path");
self.explore_queue.push( node.chain(ψ,σ,m) );
}
GraphSearchState::Continue
} else {
GraphSearchState::Err(GraphSearchError::NoMorphismFound)
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\

View file

@ -1,120 +0,0 @@
use {
crate::{
morphism_graph::{Morphism, MorphismInstance, MorphismType, MorphismBase},
term::*,
HashMapSubst,
heuristic::*,
}
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
#[derive(Clone)]
pub struct MorphismPath<M: Morphism + Clone> {
pub weight: u64,
pub est_remain: u64,
pub cur_type: TypeTerm,
pub morphisms: Vec< MorphismInstance<M> >,
}
impl<M: Morphism+Clone> MorphismPath<M> {
fn apply_subst(&mut self, σ: &HashMapSubst) {
for m in self.morphisms.iter_mut() {
m.apply_subst(σ);
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
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, est_remain: ty.estimated_cost(), cur_type: ty.src_type, morphisms: vec![] }
],
goal: ty.dst_type
}
}
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 {:?} (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;
let mut new_path = prev_path.clone();
new_path.apply_subst(&morph_inst.get_subst());
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 += morph_inst.get_weight();
new_path.cur_type = dst_type;
new_path.est_remain = MorphismType{ bounds: Vec::new(), src_type: new_path.cur_type.clone(), dst_type: self.goal.clone() }.estimated_cost();
new_path.morphisms.push(morph_inst);
self.queue.push(new_path);
}
}
pub fn solve(&mut self) -> Option< Vec<MorphismInstance<M>> > {
while ! self.queue.is_empty() {
/* 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 */
if let Ok((, σ)) = crate::constraint_system::subtype_unify( &cur_path.cur_type, &self.goal ) {
/* found path,
* now apply substitution and trim to variables in terms of each step
*/
cur_path.apply_subst(&σ);
return Some(cur_path.morphisms);
}
/* 2. Try to advance current path */
else if let Some(complex_morph) =
self.morphism_base.complex_morphism_decomposition( &cur_path.cur_type, &self.goal )
{
self.advance(&cur_path, complex_morph);
}
for next_morph_inst in self.morphism_base.enum_morphisms_from(&cur_path.cur_type) {
self.advance(&cur_path, next_morph_inst);
}
}
}
None
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\

View file

@ -5,17 +5,19 @@ use crate::{term::TypeTerm, constraint_system, EnumVariant, StructMember};
pub fn splice_ladders( mut upper: Vec< TypeTerm >, mut lower: Vec< TypeTerm > ) -> Vec< TypeTerm > {
eprintln!("splice ladders {:?} <<<====>>> {:?} ", upper, lower);
// check for overlap
for i in 0 .. upper.len() {
if upper[i] == lower[0] {
let mut result_ladder = Vec::<TypeTerm>::new();
result_ladder.append(&mut upper[0..i].iter().cloned().collect());
result_ladder.append(&mut lower);
return result_ladder;
if lower.len() > 0 {
for i in 0 .. upper.len() {
if upper[i] == lower[0] {
let mut result_ladder = Vec::<TypeTerm>::new();
result_ladder.append(&mut upper[0..i].iter().cloned().collect());
result_ladder.append(&mut lower);
return result_ladder;
}
}
}
// no overlap found, just concatenate ladders
upper.append(&mut lower);
// no overlap found, just concatenate ladders
upper.append(&mut lower);
}
upper
}

View file

@ -10,7 +10,7 @@ fn test_heuristic() {
src_type: dict.parse("A").expect("parse"),
dst_type: dict.parse("A").expect("parse")
}.estimated_cost(),
1
0
);
assert_eq!(
@ -19,6 +19,6 @@ fn test_heuristic() {
src_type: dict.parse("<Digit 10> ~ Char ~ Ascii ~ native.UInt8").expect("parse"),
dst_type: dict.parse("<Digit 16> ~ native.UInt8").expect("parse")
}.estimated_cost(),
41
40
);
}

View file

@ -1,40 +1,12 @@
use {
crate::{dict::*, morphism_graph::{Morphism, MorphismInstance, MorphismType}, morphism_base::MorphismBase, morphism_path::ShortestPathProblem, parser::*, HashMapSubst, TypeTerm
crate::{dict::*, morphism_graph::*, parser::*,
HashMapSubst, TypeTerm
},
std::collections::HashMap
};
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
fn print_subst(m: &HashMapSubst, dict: &mut impl TypeDict) {
eprintln!("{{");
for (k,v) in m.iter() {
eprintln!(" {} --> {}",
dict.get_typename(*k).unwrap(),
v.pretty(dict, 0)
);
}
eprintln!("}}");
}
fn print_path(dict: &mut impl TypeDict, path: &Vec<MorphismInstance<DummyMorphism>>) {
for n in path.iter() {
eprintln!("
morph {}
--> {}
with
",
n.get_type().src_type.pretty(dict, 0),
n.get_type().dst_type.pretty(dict, 0),
);
print_subst(&n.get_subst(), dict)
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\
#[derive(Clone, Debug, PartialEq, Eq)]
struct DummyMorphism(MorphismType);
impl Morphism for DummyMorphism {
@ -54,227 +26,457 @@ fn morphism_test_setup() -> ( BimapTypeDict, MorphismBase<DummyMorphism> ) {
base.add_morphism(
DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
src_type: dict.parse("<Digit Radix> ~ Char").unwrap(),
dst_type: dict.parse("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap()
})
);
base.add_morphism(
DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse_desugared("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict)
})
);
base.add_morphism(
DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse_desugared(" ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix>~_2^64~machine.UInt64>").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared(" ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix>~_2^64~machine.UInt64>").unwrap().sugar(&mut dict)
})
);
base.add_morphism(
DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse_desugared(" ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix>~_2^64~machine.UInt64>").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared(" ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix>~_2^64~machine.UInt64>").unwrap().sugar(&mut dict)
})
);
base.add_morphism(
DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse_desugared(" ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix>~_2^64~machine.UInt64>").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared(" ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix>~_2^64~machine.UInt64>").unwrap().sugar(&mut dict)
src_type: dict.parse("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap(),
dst_type: dict.parse("<Digit Radix> ~ Char").unwrap()
})
);
base.add_morphism(
DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse(" ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix>~_2^64~machine.UInt64>").unwrap(),
dst_type: dict.parse(" ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix>~_2^64~machine.UInt64>").unwrap()
})
);
base.add_morphism(
DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse(" ~ <PosInt Radix LittleEndian> ~ <Seq <Digit Radix>~_2^64~machine.UInt64>").unwrap(),
dst_type: dict.parse(" ~ <PosInt Radix BigEndian> ~ <Seq <Digit Radix>~_2^64~machine.UInt64>").unwrap()
})
);
base.add_morphism(
DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse(" ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix>~_2^64~machine.UInt64>").unwrap(),
dst_type: dict.parse(" ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix>~_2^64~machine.UInt64>").unwrap()
})
);
base.add_morphism(
DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse("_2^64 ~ ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix>~_2^64~machine.UInt64>").unwrap(),
dst_type: dict.parse("_2^64 ~ machine.UInt64").unwrap()
})
);
base.add_morphism(
DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse("_2^64 ~ machine.UInt64").unwrap(),
dst_type: dict.parse("_2^64 ~ ~ <PosInt 0 LittleEndian> ~ <Seq <Digit 0>~_2^64~machine.UInt64>").unwrap()
})
);
(dict, base)
}
#[test]
fn test_morphgraph_id() {
let (mut dict, mut base) = morphism_test_setup();
let morph_graph = MorphismGraph::new(base);
assert_eq!(
morph_graph.search(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("_2^64 ~ machine.UInt64").expect("parse"),
dst_type: dict.parse("_2^64 ~ machine.UInt64").expect("parse"),
}, &mut dict),
Ok(MorphismInstance::Id {
τ: dict.parse("_2^64 ~ machine.UInt64").expect("parse")
})
);
}
#[test]
fn test_morphgraph_prim() {
let (mut dict, base) = morphism_test_setup();
let morph_graph = MorphismGraph::new(base);
assert_eq!(
morph_graph.search(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("<Digit 10> ~ Char").expect("parse"),
dst_type: dict.parse("<Digit 10> ~ _2^64 ~ machine.UInt64").expect("parse"),
}, &mut dict),
Ok(
MorphismInstance::Specialize { σ: vec![
(0, TypeTerm::Num(10))
].into_iter().collect(), m: Box::new(
MorphismInstance::Primitive {
m: DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse("<Digit Radix> ~ Char").expect("parse"),
dst_type: dict.parse("<Digit Radix> ~ _2^64 ~ machine.UInt64").expect("parse"),
})
})
}
)
);
}
#[test]
fn test_morphgraph_chain() {
let (mut dict, base) = morphism_test_setup();
let morph_graph = MorphismGraph::new(base);
assert_eq!(
morph_graph.search(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("<Digit 10> ~ Char").expect("parse"),
dst_type: dict.parse("<Digit 10> ~ _2^64 ~ ~ <PosInt 0 LittleEndian> ~ <Seq <Digit 0>~_2^64~machine.UInt64>").expect("parse"),
}, &mut dict),
Ok(
MorphismInstance::Chain {
path: vec![
MorphismInstance::Specialize {
σ: vec![
(0, TypeTerm::Num(10)),
].into_iter().collect(),
m: Box::new(
MorphismInstance::Primitive {
m: DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse("<Digit Radix> ~ Char").expect("parse"),
dst_type: dict.parse("<Digit Radix> ~ _2^64 ~ machine.UInt64").expect("parse"),
})
})
},
MorphismInstance::Sub {
ψ: dict.parse("<Digit 10>").expect("parse"),
m: Box::new(
MorphismInstance::Primitive { m: DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse("_2^64 ~ machine.UInt64").unwrap(),
dst_type: dict.parse("_2^64 ~ ~ <PosInt 0 LittleEndian> ~ <Seq <Digit 0>~_2^64~machine.UInt64>").unwrap()
}) }
)
}
]
}
)
);
}
#[test]
fn test_morphgraph_spec() {
let mut dict = BimapTypeDict::new();
let mut base = MorphismBase::<DummyMorphism>::new();
dict.add_varname("X".into());
dict.add_varname("Y".into());
base.add_morphism(DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse("T ~ A").expect(""),
dst_type: dict.parse("T ~ <B X> ~ U").expect("")
}));
base.add_morphism(DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse("T ~ <B Y> ~ U").expect(""),
dst_type: dict.parse("T ~ <B Y> ~ V").expect("")
}));
let morph_graph = MorphismGraph::new(base);
assert_eq!(
morph_graph.search(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("T ~ A").unwrap(),
dst_type: dict.parse("T ~ <B test> ~ U").unwrap(),
}, &mut dict),
Ok(
MorphismInstance::Specialize {
σ: vec![
(0, dict.parse("test").expect("parse") )
].into_iter().collect(),
m: Box::new(MorphismInstance::Primitive { m: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("T ~ A").expect("parse"),
dst_type: dict.parse("T ~ <B X> ~ U").expect("parse")
}) })
}
)
);
assert_eq!(
morph_graph.search(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("T ~ A").unwrap(),
dst_type: dict.parse("T ~ <B test> ~ V").unwrap(),
}, &mut dict),
Ok(
MorphismInstance::Specialize {
σ: vec![
( 1, dict.parse("test").expect("parse") )
].into_iter().collect(),
m: Box::new(
MorphismInstance::Chain {
path: vec![
MorphismInstance::Specialize {
σ: vec![
( 0, dict.parse("Y").expect("parse") )
].into_iter().collect(),
m: Box::new(MorphismInstance::Primitive { m: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("T ~ A").expect("parse"),
dst_type: dict.parse("T ~ <B X> ~ U").expect("parse")
}) }) },
MorphismInstance::Primitive { m: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("T ~ <B Y> ~ U").expect("parse"),
dst_type: dict.parse("T ~ <B Y> ~ V").expect("parse")
}) }
]
}
)
}
)
);
}
#[test]
fn test_morphgraph_map_seq() {
let mut dict = BimapTypeDict::new();
let mut base = MorphismBase::<DummyMorphism>::new();
base.add_morphism(DummyMorphism(MorphismType{
bounds: Vec::new(),
src_type: dict.parse("A ~ F").expect(""),
dst_type: dict.parse("A ~ E").expect("")
}));
let morph_graph = MorphismGraph::new(base);
assert_eq!(
morph_graph.search(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("<Seq A ~ F>").unwrap(),
dst_type: dict.parse("<Seq A ~ E>").unwrap(),
}, &mut dict),
Ok(
MorphismInstance::MapSeq { seq_repr: None, item_morph: Box::new(
MorphismInstance::Primitive {
m: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("A ~ F").unwrap(),
dst_type: dict.parse("A ~ E").unwrap()
})
}
) }
)
);
}
#[test]
fn test_morphism_path1() {
let (mut dict, base) = morphism_test_setup();
let path = ShortestPathProblem::new(&base, MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared("<Digit 10> ~ Char").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared("<Digit 10> ~ _2^64 ~ machine.UInt64").unwrap().sugar(&mut dict),
}).solve();
let morph_graph = MorphismGraph::new(base);
assert_eq!(
path,
Some(
vec![
MorphismInstance::Primitive {
σ: vec![
(0, TypeTerm::Num(10)),
].into_iter().collect(),
ψ: TypeTerm::unit(),
morph: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
}),
}
]
));
morph_graph.search(MorphismType {
bounds: Vec::new(),
src_type: dict.parse(" ~ <PosInt 10 LittleEndian> ~ <Seq <Digit 10> ~ Char>").unwrap(),
dst_type: dict.parse(" ~ <PosInt 10 LittleEndian> ~ <Seq <Digit 10> ~ _2^64 ~ machine.UInt64>").unwrap(),
}, &mut dict),
Ok(
MorphismInstance::Sub {
ψ: dict.parse(" ~ <PosInt 10 LittleEndian>").expect(""),
m: Box::new(
MorphismInstance::MapSeq {
seq_repr: None,
item_morph: Box::new(
MorphismInstance::Specialize {
σ: vec![
(0, TypeTerm::Num(10)),
].into_iter().collect(),
m: Box::new(MorphismInstance::Primitive {
m: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("<Digit Radix> ~ Char").unwrap(),
dst_type: dict.parse("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap()
}),
})
}
)
}
)
}));
}
#[test]
fn test_morphism_path2() {
let (mut dict, base) = morphism_test_setup();
let path = ShortestPathProblem::new(&base, MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared(" ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ Char>").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared(" ~ <PosInt 10 BigEndian> ~ <Seq <Digit 10> ~ _2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
}).solve();
let morph_graph = MorphismGraph::new(base);
assert_eq!(
path,
Some(
vec![
MorphismInstance::MapSeq {
ψ: dict.parse_desugared(" ~ <PosInt 10 BigEndian>").expect("").sugar(&mut dict),
seq_repr: None,
item_morph: Box::new(MorphismInstance::Primitive {
σ: vec![
(0, TypeTerm::Num(10)),
].into_iter().collect(),
ψ: TypeTerm::unit(),
morph: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
}),
})
}
]
));
morph_graph.search(MorphismType {
bounds: Vec::new(),
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(),
}, &mut dict),
Ok(
MorphismInstance::Specialize {
σ: vec![
(2, TypeTerm::Num(16)),
].into_iter().collect(),
m: Box::new(
MorphismInstance::Chain {
path: vec![
MorphismInstance::Sub {
ψ: dict.parse(" ~ <PosInt 10 LittleEndian>").expect(""),
m: Box::new(
MorphismInstance::MapSeq {
seq_repr: None,
item_morph: Box::new(
MorphismInstance::Specialize {
σ: vec![
(0, TypeTerm::Num(10)),
].into_iter().collect(),
m: Box::new(MorphismInstance::Primitive {
m: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("<Digit Radix> ~ Char").unwrap(),
dst_type: dict.parse("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap()
}),
})
}
)
}
)
},
MorphismInstance::Specialize {
σ: vec![
(1, TypeTerm::Num(10))
].into_iter().collect(),
m: Box::new(
MorphismInstance::Primitive{
m: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared(" ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix> ~ _2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared(" ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix> ~ _2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
}),
}
)
}
]
})
}
));
}
#[test]
fn test_morphism_path3() {
let (mut dict, base) = morphism_test_setup();
let (mut dict, mut base) = morphism_test_setup();
let path = ShortestPathProblem::new(&base, MorphismType {
let mut morph_graph = MorphismGraph::new(base);
let result = morph_graph.search(MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared(" ~ <PosInt 10 LittleEndian> ~ <Seq <Digit 10> ~ Char>").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared(" ~ <PosInt 16 LittleEndian> ~ <Seq <Digit 16> ~ _2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
}).solve();
src_type: dict.parse(" ~ <PosInt 10 LittleEndian> ~ <Seq <Digit 10> ~ Char>").unwrap(),
dst_type: dict.parse(" ~ <PosInt 16 LittleEndian> ~ <Seq <Digit 16> ~ Char>").unwrap()
}, &mut dict);
if let Some(path) = path.as_ref() {
print_path(&mut dict, path);
}
eprintln!("{:#?}", result);
return;
assert_eq!(
path,
Some(
vec![
MorphismInstance::MapSeq {
ψ: dict.parse_desugared(" ~ <PosInt 10 LittleEndian>").expect("").sugar(&mut dict),
seq_repr: None,
item_morph: Box::new(MorphismInstance::Primitive {
σ: vec![
(0, TypeTerm::Num(10)),
].into_iter().collect(),
ψ: TypeTerm::unit(),
morph: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
}),
})
},
result,
MorphismInstance::Primitive {
Ok(
MorphismInstance::Specialize {
σ: vec![
(2, TypeTerm::Num(16)),
].into_iter().collect(),
m: Box::new(
MorphismInstance::Chain {
path: vec![
MorphismInstance::Sub {
ψ: dict.parse(" ~ <PosInt 10 LittleEndian>").expect(""),
m: Box::new(
MorphismInstance::MapSeq {
seq_repr: None,
item_morph: Box::new(
MorphismInstance::Specialize {
σ: vec![
(0, TypeTerm::Num(10)),
].into_iter().collect(),
m: Box::new(MorphismInstance::Primitive {
m: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("<Digit Radix> ~ Char").unwrap(),
dst_type: dict.parse("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap()
}),
})
}
)
}
)
},
MorphismInstance::Specialize {
σ: vec![
(1, TypeTerm::Num(10)),
(2, TypeTerm::Num(16)),
// (dict.get_typeid(&"DstRadix".into()).unwrap(), TypeTerm::Num(16)),
].into_iter().collect(),
ψ: TypeTerm::unit(),
morph: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared(" ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix> ~ _2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared(" ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix> ~ _2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
}),
}
]
m: Box::new(
MorphismInstance::Primitive{
m: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared(" ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix> ~ _2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared(" ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix> ~ _2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
}),
}
)
},
MorphismInstance::Sub {
ψ: dict.parse(" ~ <PosInt DstRadix LittleEndian>").expect(""),
m: Box::new(
MorphismInstance::MapSeq {
seq_repr: None,
item_morph: Box::new(
MorphismInstance::Specialize {
σ: vec![
(0, dict.parse("DstRadix").expect("")),
].into_iter().collect(),
m: Box::new(MorphismInstance::Primitive {
m: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap(),
dst_type: dict.parse("<Digit Radix> ~ Char").unwrap()
}),
})
})
})
}
]
})
}
));
}
#[test]
fn test_morphism_path4() {
let (mut dict, base) = morphism_test_setup();
let path = ShortestPathProblem::new(&base, MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared(" ~ <PosInt 10 LittleEndian> ~ <Seq <Digit 10> ~ Char>").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared(" ~ <PosInt 16 LittleEndian> ~ <Seq <Digit 16> ~ Char>").unwrap().sugar(&mut dict)
}).solve();
if let Some(path) = path.as_ref() {
print_path(&mut dict, path);
}
assert_eq!(
path,
Some(
vec![
MorphismInstance::MapSeq {
ψ: dict.parse_desugared(" ~ <PosInt 10 LittleEndian>").expect("").sugar(&mut dict),
seq_repr: None,
item_morph: Box::new(MorphismInstance::Primitive {
σ: vec![
(0, TypeTerm::Num(10)),
].into_iter().collect(),
ψ: TypeTerm::unit(),
morph: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap().sugar(&mut dict)
}),
})
},
MorphismInstance::Primitive {
σ: vec![
(1, TypeTerm::Num(10)),
(2, TypeTerm::Num(16)),
].into_iter().collect(),
ψ: TypeTerm::unit(),
morph: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared(" ~ <PosInt SrcRadix LittleEndian> ~ <Seq <Digit SrcRadix> ~ _2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared(" ~ <PosInt DstRadix LittleEndian> ~ <Seq <Digit DstRadix> ~ _2^64 ~ machine.UInt64>").unwrap().sugar(&mut dict)
}),
},
MorphismInstance::MapSeq {
ψ: dict.parse_desugared(" ~ <PosInt 16 LittleEndian>").expect("").sugar(&mut dict),
seq_repr: None,
item_morph: Box::new(MorphismInstance::Primitive {
σ: vec![
(2, TypeTerm::Num(16)),
(0, TypeTerm::Num(16)),
].into_iter().collect(),
ψ: TypeTerm::unit(),
morph: DummyMorphism(MorphismType {
bounds: Vec::new(),
src_type: dict.parse_desugared("<Digit Radix> ~ _2^64 ~ machine.UInt64").unwrap().sugar(&mut dict),
dst_type: dict.parse_desugared("<Digit Radix> ~ Char").unwrap().sugar(&mut dict)
}),
})
},
]
));
}
/*
#[test]
fn test_morphism_path_posint() {
@ -538,3 +740,4 @@ fn test_morphism_path_listedit()
);
}
*/
*/