use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, BTreeSet};
use std::mem;
use eqlog_runtime::Unification;
use crate::algebra::signature::{FuncId, PredId, Signature, TypeId};
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ElId(pub(super) usize);
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct StructureId(pub usize);
pub type ElMap = BTreeMap<ElId, ElId>;
impl From<u32> for ElId {
fn from(x: u32) -> Self {
ElId(x as usize)
}
}
impl From<ElId> for u32 {
fn from(el: ElId) -> Self {
debug_assert!(el.0 <= u32::MAX as usize);
el.0 as u32
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct ConcreteType {
pub typ: TypeId,
pub parents: Vec<ElId>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct PredApp {
pub pred: PredId,
pub parents: Vec<ElId>,
pub args: Vec<ElId>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct FuncApp {
pub func: FuncId,
pub parents: Vec<ElId>,
pub args: Vec<ElId>,
}
#[derive(Clone, Debug)]
pub struct Structure {
pub els: BTreeMap<ElId, BTreeSet<ConcreteType>>,
pub pred_apps: BTreeSet<PredApp>,
pub func_apps: BTreeMap<FuncApp, ElId>,
pub var_els: BTreeMap<String, ElId>,
pub ambient_model_els: BTreeMap<TypeId, ElId>,
pub unification: Unification<ElId>,
pub(super) pending_equalities: Vec<(ElId, ElId)>,
pub(super) pending_type_impositions: Vec<(ElId, ConcreteType)>,
}
impl Default for Structure {
fn default() -> Self {
Self {
els: BTreeMap::new(),
pred_apps: BTreeSet::new(),
func_apps: BTreeMap::new(),
var_els: BTreeMap::new(),
ambient_model_els: BTreeMap::new(),
unification: Unification::new(),
pending_equalities: Vec::new(),
pending_type_impositions: Vec::new(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TypeConflict {
pub el: ElId,
pub a: ConcreteType,
pub b: ConcreteType,
}
impl Structure {
pub fn push_el(&mut self) -> ElId {
let id = ElId(self.unification.len());
self.unification.increase_size_to(id.0 + 1);
self.els.insert(id, BTreeSet::new());
id
}
pub fn impose_type(&mut self, el: ElId, mut ct: ConcreteType) -> bool {
let el = self.unification.root_const(el);
for p in ct.parents.iter_mut() {
*p = self.unification.root_const(*p);
}
if self
.pending_type_impositions
.iter()
.any(|(e, c)| *e == el && c == &ct)
{
return false;
}
self.pending_type_impositions.push((el, ct));
true
}
pub fn equate(&mut self, a: ElId, b: ElId) -> bool {
let ra = self.unification.root(a);
let rb = self.unification.root(b);
self.pending_equalities.push((a, b));
ra != rb
}
pub fn ambient_parents(&self, parent_types: &[TypeId]) -> Vec<ElId> {
parent_types
.iter()
.map(|tid| {
*self
.ambient_model_els
.get(tid)
.expect("ambient model el missing for type")
})
.collect()
}
pub fn close(&mut self, signature: &Signature) -> bool {
let mut changed = false;
loop {
let drained = self.drain_equalities();
let func_changed = self.functionality();
let type_changed = self.typing(signature);
let mor_app_changed = self.morphism_app_constraints(signature);
if !drained && !func_changed && !type_changed && !mor_app_changed {
break;
}
changed = true;
}
changed |= self.apply_pending_type_impositions();
self.canonicalise_refs();
changed
}
fn apply_pending_type_impositions(&mut self) -> bool {
let impositions = self.pending_type_impositions.clone();
let mut changed = false;
for (el, ct) in impositions {
if self.impose_concrete_type(el, ct) {
changed = true;
}
}
changed
}
fn drain_equalities(&mut self) -> bool {
let mut changed = false;
while let Some((a, b)) = self.pending_equalities.pop() {
let a = self.root(a);
let b = self.root(b);
if a == b {
continue;
}
changed = true;
let (keep, drop) = if a.0 <= b.0 { (a, b) } else { (b, a) };
self.unification.union_roots_into(drop, keep);
let mut merged = self.els.remove(&keep).unwrap_or_default();
if let Some(drop_cts) = self.els.remove(&drop) {
merged.extend(drop_cts);
}
self.els.insert(keep, merged);
}
changed
}
fn functionality(&mut self) -> bool {
let old = mem::take(&mut self.func_apps);
let mut new: BTreeMap<FuncApp, ElId> = BTreeMap::new();
let mut changed = false;
for (app, result) in old {
let canon_app = FuncApp {
func: app.func,
parents: app.parents.into_iter().map(|e| self.root(e)).collect(),
args: app.args.into_iter().map(|e| self.root(e)).collect(),
};
let canon_result = self.root(result);
match new.entry(canon_app) {
Entry::Vacant(v) => {
v.insert(canon_result);
}
Entry::Occupied(o) => {
let existing = *o.get();
if existing != canon_result {
self.pending_equalities.push((existing, canon_result));
changed = true;
}
}
}
}
self.func_apps = new;
changed
}
fn typing(&mut self, signature: &Signature) -> bool {
let mut changed = false;
let apps: Vec<(FuncApp, ElId)> = self
.func_apps
.iter()
.map(|(a, r)| (a.clone(), *r))
.collect();
for (app, _result) in &apps {
for (i, &arg) in app.args.iter().enumerate() {
if let Some(ct) = func_domain_type_at(signature, app, i) {
if self.impose_concrete_type(arg, ct) {
changed = true;
}
}
}
}
let pred_apps: Vec<PredApp> = self.pred_apps.iter().cloned().collect();
for app in &pred_apps {
let pred_data = signature.pred(app.pred);
for (i, &arg) in app.args.iter().enumerate() {
let Some(&arity_tid) = pred_data.arity.get(i) else {
break;
};
if let Some(ct) = concrete_type_at(signature, arity_tid, &app.parents) {
if self.impose_concrete_type(arg, ct) {
changed = true;
}
}
}
}
for (app, result) in apps {
if let Some(ct) = func_codomain_type_at(signature, &app) {
if self.impose_concrete_type(result, ct) {
changed = true;
}
}
}
changed
}
fn morphism_app_constraints(&mut self, signature: &Signature) -> bool {
let apps: Vec<(FuncApp, ElId)> = self
.func_apps
.iter()
.map(|(a, r)| (a.clone(), *r))
.collect();
let mut changed = false;
for (app, result) in apps {
let Some(member_tid) = signature.type_for_mor_app_func(app.func) else {
continue;
};
let Some(&parent_model_tid) = signature.type_(member_tid).parents.last() else {
continue;
};
let Some(model_ids) = signature.ids_for_model_type(parent_model_tid) else {
continue;
};
if app.args.len() != 2 {
continue;
}
let mor_el = self.root(app.args[0]);
let arg_el = self.root(app.args[1]);
let result = self.root(result);
let outer_parents: Vec<ElId> = app.parents.iter().map(|p| self.root(*p)).collect();
let dom_app = FuncApp {
func: model_ids.dom,
parents: outer_parents.clone(),
args: vec![mor_el],
};
let cod_app = FuncApp {
func: model_ids.cod,
parents: outer_parents.clone(),
args: vec![mor_el],
};
for domain_el in self.member_parents_from_type(arg_el, member_tid) {
changed |= self.insert_func_app_or_equate(dom_app.clone(), domain_el);
}
for codomain_el in self.member_parents_from_type(result, member_tid) {
changed |= self.insert_func_app_or_equate(cod_app.clone(), codomain_el);
}
if let Some(&domain_el) = self.func_apps.get(&dom_app) {
let mut parents = outer_parents.clone();
parents.push(self.root(domain_el));
if self.impose_concrete_type(
arg_el,
ConcreteType {
typ: member_tid,
parents,
},
) {
changed = true;
}
}
if let Some(&codomain_el) = self.func_apps.get(&cod_app) {
let mut parents = outer_parents.clone();
parents.push(self.root(codomain_el));
if self.impose_concrete_type(
result,
ConcreteType {
typ: member_tid,
parents,
},
) {
changed = true;
}
}
}
changed
}
fn member_parents_from_type(&self, el: ElId, member_tid: TypeId) -> Vec<ElId> {
self.concrete_types_of(el)
.into_iter()
.filter(|ct| ct.typ == member_tid)
.filter_map(|ct| ct.parents.last().copied())
.map(|parent| self.root(parent))
.collect::<BTreeSet<_>>()
.into_iter()
.collect()
}
pub(super) fn concrete_types_of(&self, el: ElId) -> Vec<ConcreteType> {
let root = self.root(el);
self.els
.get(&root)
.into_iter()
.flat_map(|cts| cts.iter().cloned())
.map(|ct| self.canonical_type(ct))
.collect::<BTreeSet<_>>()
.into_iter()
.collect()
}
fn insert_func_app_or_equate(&mut self, app: FuncApp, result: ElId) -> bool {
let canon_app = FuncApp {
func: app.func,
parents: app.parents.into_iter().map(|e| self.root(e)).collect(),
args: app.args.into_iter().map(|e| self.root(e)).collect(),
};
let result = self.root(result);
match self.func_apps.get(&canon_app).copied() {
Some(existing) => existing != result && self.equate(existing, result),
None => {
self.func_apps.insert(canon_app, result);
true
}
}
}
fn impose_concrete_type(&mut self, el: ElId, ct: ConcreteType) -> bool {
let root = self.root(el);
let ct = self.canonical_type(ct);
self.els.entry(root).or_default().insert(ct)
}
pub(super) fn insert_concrete_type_fact(&mut self, el: ElId, ct: ConcreteType) -> bool {
self.impose_concrete_type(el, ct)
}
fn canonicalise_refs(&mut self) {
let old_pred_apps = mem::take(&mut self.pred_apps);
for app in old_pred_apps {
self.pred_apps.insert(PredApp {
pred: app.pred,
parents: app.parents.into_iter().map(|e| self.root(e)).collect(),
args: app.args.into_iter().map(|e| self.root(e)).collect(),
});
}
for v in self.var_els.values_mut() {
*v = self.unification.root_const(*v);
}
let old_els = mem::take(&mut self.els);
for (id, cts) in old_els {
let root = self.root(id);
if root != id {
continue;
}
let cts = cts.into_iter().map(|ct| self.canonical_type(ct)).collect();
self.els.insert(id, cts);
}
for (el, ct) in self.pending_type_impositions.iter_mut() {
*el = self.unification.root_const(*el);
for p in ct.parents.iter_mut() {
*p = self.unification.root_const(*p);
}
}
}
fn canonical_type(&self, mut ct: ConcreteType) -> ConcreteType {
for p in ct.parents.iter_mut() {
*p = self.root(*p);
}
ct
}
pub(super) fn type_conflicts(&self) -> Vec<TypeConflict> {
let mut conflicts = Vec::new();
for (&el, cts) in &self.els {
if cts.len() < 2 {
continue;
}
let ordered = self.concrete_types_of(el);
let Some(first) = ordered.first() else {
continue;
};
for ct in ordered.iter().skip(1) {
if first.typ != ct.typ
|| !parents_match(&self.unification, &first.parents, &ct.parents)
{
conflicts.push(TypeConflict {
el,
a: first.clone(),
b: ct.clone(),
});
break;
}
}
}
conflicts
}
fn root(&self, id: ElId) -> ElId {
self.unification.root_const(id)
}
}
#[derive(Clone, Debug, Default)]
pub struct StructureCat {
pub structures: Vec<Structure>,
pub morphisms: BTreeMap<(StructureId, StructureId), ElMap>,
pub under_prods: Vec<UnderProd>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnderProd {
pub top: StructureId,
pub meet: StructureId,
pub ends: Vec<StructureId>,
}
impl StructureCat {
pub fn push(&mut self, structure: Structure) -> StructureId {
let id = StructureId(self.structures.len());
self.structures.push(structure);
id
}
pub fn add_morphism(&mut self, src: StructureId, tgt: StructureId, map: ElMap) {
assert!(
src.0 < tgt.0,
"morphisms must point forward: {src:?} -> {tgt:?}"
);
let prev = self.morphisms.insert((src, tgt), map);
assert!(prev.is_none(), "duplicate morphism {src:?} -> {tgt:?}");
}
pub fn add_under_prod(&mut self, top: StructureId, meet: StructureId, ends: Vec<StructureId>) {
self.under_prods.push(UnderProd { top, meet, ends });
}
pub fn close(&mut self, signature: &Signature) -> (bool, Vec<(StructureId, TypeConflict)>) {
let mut changed = false;
let n = self.structures.len();
loop {
let mut cycle = false;
for i in 0..n {
let id = StructureId(i);
cycle |= self.structures[i].close(signature);
cycle |= self.push_forward(id);
}
for i in (0..n).rev() {
let id = StructureId(i);
cycle |= self.pull_types_backward(id);
cycle |= self.structures[i].close(signature);
}
cycle |= self.saturate_under_prods();
changed |= cycle;
if !cycle {
break;
}
}
self.canonicalise_morphisms();
let conflicts = self.type_conflicts();
(changed, conflicts)
}
fn type_conflicts(&self) -> Vec<(StructureId, TypeConflict)> {
self.structures
.iter()
.enumerate()
.flat_map(|(i, structure)| {
structure
.type_conflicts()
.into_iter()
.map(move |conflict| (StructureId(i), conflict))
})
.collect()
}
fn outgoing(&self, src: StructureId) -> Vec<StructureId> {
self.morphisms
.keys()
.filter_map(|&(a, b)| (a == src).then_some(b))
.collect()
}
fn push_forward(&mut self, src: StructureId) -> bool {
let mut changed = false;
for tgt in self.outgoing(src) {
changed |= self.push_morphism(src, tgt);
}
changed
}
fn push_morphism(&mut self, src: StructureId, tgt: StructureId) -> bool {
let StructureCat {
structures,
morphisms,
..
} = self;
let (left, right) = structures.split_at_mut(tgt.0);
let src_st = &left[src.0];
let tgt_st = &mut right[0];
let map = morphisms
.get_mut(&(src, tgt))
.expect("morphism disappeared");
let mut changed = false;
let old = mem::take(map);
for (k, v) in old {
let root_k = src_st.unification.root_const(k);
let root_v = tgt_st.unification.root_const(v);
match map.entry(root_k) {
Entry::Vacant(vac) => {
vac.insert(root_v);
}
Entry::Occupied(occ) => {
let existing = *occ.get();
if existing != root_v && tgt_st.equate(existing, root_v) {
changed = true;
}
}
}
}
let image = |e: ElId| -> ElId {
*map.get(&src_st.unification.root_const(e))
.expect("morphism not defined on element")
};
for pa in &src_st.pred_apps {
changed |= tgt_st.pred_apps.insert(PredApp {
pred: pa.pred,
parents: pa.parents.iter().copied().map(image).collect(),
args: pa.args.iter().copied().map(image).collect(),
});
}
let src_func_apps: Vec<(FuncApp, ElId)> = src_st
.func_apps
.iter()
.map(|(a, r)| (a.clone(), *r))
.collect();
for (fa, result) in src_func_apps {
let mapped = FuncApp {
func: fa.func,
parents: fa.parents.iter().copied().map(image).collect(),
args: fa.args.iter().copied().map(image).collect(),
};
let mapped_result = image(result);
match tgt_st.func_apps.entry(mapped) {
Entry::Vacant(vac) => {
vac.insert(mapped_result);
changed = true;
}
Entry::Occupied(occ) => {
let existing = *occ.get();
if existing != mapped_result {
changed |= tgt_st.equate(existing, mapped_result);
}
}
}
}
let src_var_els: Vec<(String, ElId)> = src_st
.var_els
.iter()
.map(|(n, e)| (n.clone(), *e))
.collect();
for (name, el) in src_var_els {
let mapped_el = image(el);
match tgt_st.var_els.entry(name) {
Entry::Vacant(vac) => {
vac.insert(mapped_el);
changed = true;
}
Entry::Occupied(occ) => {
let existing = *occ.get();
if existing != mapped_el {
changed |= tgt_st.equate(existing, mapped_el);
}
}
}
}
let src_ambient: Vec<(TypeId, ElId)> = src_st
.ambient_model_els
.iter()
.map(|(t, e)| (*t, *e))
.collect();
for (typ, el) in src_ambient {
let mapped_el = image(el);
match tgt_st.ambient_model_els.entry(typ) {
Entry::Vacant(vac) => {
vac.insert(mapped_el);
changed = true;
}
Entry::Occupied(occ) => {
let existing = *occ.get();
if existing != mapped_el {
changed |= tgt_st.equate(existing, mapped_el);
}
}
}
}
let src_typed_els: Vec<(ElId, ConcreteType)> = src_st
.els
.iter()
.flat_map(|(&el, _)| {
src_st
.concrete_types_of(el)
.into_iter()
.map(move |ct| (el, ct))
})
.collect();
for (el, ct) in src_typed_els {
let mapped_el = image(el);
let mapped_ct = ConcreteType {
typ: ct.typ,
parents: ct.parents.iter().copied().map(image).collect(),
};
changed |= tgt_st.impose_concrete_type(mapped_el, mapped_ct);
}
changed
}
fn pull_types_backward(&mut self, src: StructureId) -> bool {
let mut changed = false;
for tgt in self.outgoing(src) {
changed |= self.pull_morphism_types(src, tgt);
}
changed
}
fn pull_morphism_types(&mut self, src: StructureId, tgt: StructureId) -> bool {
let StructureCat {
structures,
morphisms,
..
} = self;
let (left, right) = structures.split_at_mut(tgt.0);
let src_st = &mut left[src.0];
let tgt_st = &right[0];
let map = morphisms.get(&(src, tgt)).expect("morphism disappeared");
let mut changed = false;
let tgt_ambient_by_root: BTreeMap<ElId, TypeId> = tgt_st
.ambient_model_els
.iter()
.map(|(t, e)| (tgt_st.unification.root_const(*e), *t))
.collect();
for (&src_el, &tgt_el) in map.iter() {
let tgt_root = tgt_st.unification.root_const(tgt_el);
let Some(tgt_cts) = tgt_st.els.get(&tgt_root) else {
continue;
};
for ct in tgt_cts {
let parent_types: Option<Vec<TypeId>> = ct
.parents
.iter()
.map(|p| {
tgt_ambient_by_root
.get(&tgt_st.unification.root_const(*p))
.copied()
})
.collect();
let Some(parent_types) = parent_types else {
continue;
};
let new_parents: Option<Vec<ElId>> = parent_types
.iter()
.map(|t| src_st.ambient_model_els.get(t).copied())
.collect();
let Some(new_parents) = new_parents else {
continue;
};
let new_ct = ConcreteType {
typ: ct.typ,
parents: new_parents,
};
let existing = src_st.concrete_types_of(src_el);
if existing.is_empty()
|| existing.iter().any(|existing| {
existing.typ == new_ct.typ
&& parents_match(
&src_st.unification,
&existing.parents,
&new_ct.parents,
)
})
{
changed |= src_st.impose_concrete_type(src_el, new_ct);
}
}
}
changed
}
fn saturate_under_prods(&mut self) -> bool {
let mut changed = false;
let n = self.under_prods.len();
for i in 0..n {
let up = self.under_prods[i].clone();
changed |= self.saturate_one_under_prod(&up);
}
changed
}
fn saturate_one_under_prod(&mut self, up: &UnderProd) -> bool {
if up.ends.is_empty() {
return false;
}
for &end_id in &up.ends {
if !self.morphisms.contains_key(&(up.meet, end_id)) {
return false;
}
}
let mut changed = false;
changed |= self.saturate_under_prod_equalities(up);
changed |= self.saturate_under_prod_pred_apps(up);
changed |= self.saturate_under_prod_func_apps(up);
changed
}
fn saturate_under_prod_equalities(&mut self, up: &UnderProd) -> bool {
let groups = self.group_meet_roots_by_end_images(up);
let mut changed = false;
let meet_st = &mut self.structures[up.meet.0];
for (_, members) in groups {
if members.len() < 2 {
continue;
}
let first = members[0];
for &m in &members[1..] {
if meet_st.equate(first, m) {
changed = true;
}
}
}
changed
}
fn group_meet_roots_by_end_images(&self, up: &UnderProd) -> BTreeMap<Vec<ElId>, Vec<ElId>> {
let meet_st = &self.structures[up.meet.0];
let mut groups: BTreeMap<Vec<ElId>, Vec<ElId>> = BTreeMap::new();
for &m in meet_st.els.keys() {
if meet_st.unification.root_const(m) != m {
continue;
}
let mut key = Vec::with_capacity(up.ends.len());
let mut ok = true;
for &end_id in &up.ends {
let map = self.morphisms.get(&(up.meet, end_id)).unwrap();
let Some(&img) = map.get(&m) else {
ok = false;
break;
};
key.push(self.structures[end_id.0].unification.root_const(img));
}
if ok {
groups.entry(key).or_default().push(m);
}
}
groups
}
fn saturate_under_prod_pred_apps(&mut self, up: &UnderProd) -> bool {
let end_0 = up.ends[0];
let inv = self.invert_projection(up.meet, end_0);
let candidates: Vec<PredApp> = self.structures[end_0.0].pred_apps.iter().cloned().collect();
let mut to_insert: Vec<PredApp> = Vec::new();
for pa in &candidates {
let Some(meet_parents) = self.preimage_seq(end_0, &inv, &pa.parents) else {
continue;
};
let Some(meet_args) = self.preimage_seq(end_0, &inv, &pa.args) else {
continue;
};
let mut all_ends_have = true;
for &end_j in &up.ends[1..] {
let Some(translated_parents) = self.project_seq(up.meet, end_j, &meet_parents)
else {
all_ends_have = false;
break;
};
let Some(translated_args) = self.project_seq(up.meet, end_j, &meet_args) else {
all_ends_have = false;
break;
};
let candidate = PredApp {
pred: pa.pred,
parents: translated_parents,
args: translated_args,
};
if !self.structures[end_j.0].pred_apps.contains(&candidate) {
all_ends_have = false;
break;
}
}
if all_ends_have {
to_insert.push(PredApp {
pred: pa.pred,
parents: meet_parents,
args: meet_args,
});
}
}
let mut changed = false;
let meet_st = &mut self.structures[up.meet.0];
for pa in to_insert {
let canon = PredApp {
pred: pa.pred,
parents: pa
.parents
.iter()
.map(|e| meet_st.unification.root_const(*e))
.collect(),
args: pa
.args
.iter()
.map(|e| meet_st.unification.root_const(*e))
.collect(),
};
if meet_st.pred_apps.insert(canon) {
changed = true;
}
}
changed
}
fn saturate_under_prod_func_apps(&mut self, up: &UnderProd) -> bool {
let end_0 = up.ends[0];
let inv = self.invert_projection(up.meet, end_0);
let candidates: Vec<(FuncApp, ElId)> = self.structures[end_0.0]
.func_apps
.iter()
.map(|(a, r)| (a.clone(), *r))
.collect();
let mut to_add: Vec<(FuncApp, Vec<ElId>)> = Vec::new();
for (fa, r0) in &candidates {
let Some(meet_parents) = self.preimage_seq(end_0, &inv, &fa.parents) else {
continue;
};
let Some(meet_args) = self.preimage_seq(end_0, &inv, &fa.args) else {
continue;
};
let mut end_results: Vec<ElId> = Vec::with_capacity(up.ends.len());
end_results.push(self.structures[end_0.0].unification.root_const(*r0));
let mut ok = true;
for &end_j in &up.ends[1..] {
let Some(translated_parents) = self.project_seq(up.meet, end_j, &meet_parents)
else {
ok = false;
break;
};
let Some(translated_args) = self.project_seq(up.meet, end_j, &meet_args) else {
ok = false;
break;
};
let candidate = FuncApp {
func: fa.func,
parents: translated_parents,
args: translated_args,
};
match self.structures[end_j.0].func_apps.get(&candidate) {
Some(&r) => {
end_results.push(self.structures[end_j.0].unification.root_const(r));
}
None => {
ok = false;
break;
}
}
}
if ok {
to_add.push((
FuncApp {
func: fa.func,
parents: meet_parents,
args: meet_args,
},
end_results,
));
}
}
let mut changed = false;
for (meet_app, end_results) in to_add {
let canon_app = {
let meet_st = &self.structures[up.meet.0];
FuncApp {
func: meet_app.func,
parents: meet_app
.parents
.iter()
.map(|e| meet_st.unification.root_const(*e))
.collect(),
args: meet_app
.args
.iter()
.map(|e| meet_st.unification.root_const(*e))
.collect(),
}
};
if self.structures[up.meet.0]
.func_apps
.contains_key(&canon_app)
{
continue;
}
let r = self.structures[up.meet.0].push_el();
self.structures[up.meet.0].func_apps.insert(canon_app, r);
changed = true;
for (j, &end_id) in up.ends.iter().enumerate() {
let map = self
.morphisms
.get_mut(&(up.meet, end_id))
.expect("projection missing");
map.insert(r, end_results[j]);
}
}
changed
}
fn invert_projection(&self, meet: StructureId, end: StructureId) -> BTreeMap<ElId, ElId> {
let map = self
.morphisms
.get(&(meet, end))
.expect("projection missing");
let meet_st = &self.structures[meet.0];
let end_st = &self.structures[end.0];
let mut inv: BTreeMap<ElId, ElId> = BTreeMap::new();
for (&m, &e) in map {
let canon_m = meet_st.unification.root_const(m);
let canon_e = end_st.unification.root_const(e);
inv.entry(canon_e)
.and_modify(|cur| {
if canon_m < *cur {
*cur = canon_m;
}
})
.or_insert(canon_m);
}
inv
}
fn preimage_seq(
&self,
end: StructureId,
inv: &BTreeMap<ElId, ElId>,
xs: &[ElId],
) -> Option<Vec<ElId>> {
let end_st = &self.structures[end.0];
xs.iter()
.map(|e| inv.get(&end_st.unification.root_const(*e)).copied())
.collect()
}
fn project_seq(&self, meet: StructureId, end: StructureId, xs: &[ElId]) -> Option<Vec<ElId>> {
let map = self.morphisms.get(&(meet, end))?;
let meet_st = &self.structures[meet.0];
let end_st = &self.structures[end.0];
xs.iter()
.map(|m| {
let canon_m = meet_st.unification.root_const(*m);
let img = map.get(&canon_m).copied()?;
Some(end_st.unification.root_const(img))
})
.collect()
}
fn canonicalise_morphisms(&mut self) {
let keys: Vec<(StructureId, StructureId)> = self.morphisms.keys().copied().collect();
for (src, tgt) in keys {
let StructureCat {
structures,
morphisms,
..
} = self;
let src_st = &structures[src.0];
let tgt_st = &structures[tgt.0];
let map = morphisms.get_mut(&(src, tgt)).unwrap();
let old = mem::take(map);
for (k, v) in old {
let root_k = src_st.unification.root_const(k);
let root_v = tgt_st.unification.root_const(v);
map.insert(root_k, root_v);
}
}
}
}
fn parents_match(unification: &Unification<ElId>, lhs: &[ElId], rhs: &[ElId]) -> bool {
let n = lhs.len().min(rhs.len());
for i in 0..n {
if unification.root_const(lhs[i]) != unification.root_const(rhs[i]) {
return false;
}
}
true
}
fn func_domain_type_at(signature: &Signature, app: &FuncApp, index: usize) -> Option<ConcreteType> {
if signature.type_for_mor_app_func(app.func).is_some() && index > 0 {
return None;
}
let tid = *signature.func(app.func).domain.get(index)?;
concrete_type_at(signature, tid, &app.parents)
}
fn func_codomain_type_at(signature: &Signature, app: &FuncApp) -> Option<ConcreteType> {
if signature.type_for_mor_app_func(app.func).is_some() {
return None;
}
concrete_type_at(signature, signature.func(app.func).codomain, &app.parents)
}
fn concrete_type_at(signature: &Signature, tid: TypeId, parents: &[ElId]) -> Option<ConcreteType> {
let n = signature.type_(tid).parents.len();
if n > parents.len() {
return None;
}
Some(ConcreteType {
typ: tid,
parents: parents[..n].to_vec(),
})
}