#![allow(missing_docs)]
use exocortex_kernel::{EntityId, MemoryId, RelKindId};
const SOLVES: RelKindId = exocortex_kernel::kinds::SOLVES;
const FIXES: RelKindId = exocortex_kernel::kinds::FIXES;
const CAUSES: RelKindId = exocortex_kernel::kinds::CAUSES;
const IN_SESSION: RelKindId = exocortex_kernel::kinds::IN_SESSION;
const SOLUTION_TYPE: u8 = exocortex_pack_dev_v1::MemoryType::Solution.id();
const FIX_TYPE: u8 = exocortex_pack_dev_v1::MemoryType::Fix.id();
const PROBLEM_TYPE: u8 = exocortex_pack_dev_v1::MemoryType::Problem.id();
pub struct PackKinds {
pub depends_on: RelKindId,
pub requires: RelKindId,
pub builds_on: RelKindId,
pub blocks: RelKindId,
pub contradicts: RelKindId,
pub confirms: RelKindId,
}
use std::sync::OnceLock;
static PACK_KINDS: OnceLock<PackKinds> = OnceLock::new();
fn pk() -> &'static PackKinds {
PACK_KINDS
.get()
.expect("call Rules::prime(onto) before evaluation")
}
pub fn prime(onto: &exocortex_kernel::Ontology) {
let kind = |name: &str| onto.kind_id(name).expect("pack kind registered");
let _ = PACK_KINDS.set(PackKinds {
depends_on: kind("DependsOn"),
requires: kind("Requires"),
builds_on: kind("BuildsOn"),
blocks: kind("Blocks"),
contradicts: kind("Contradicts"),
confirms: kind("Confirms"),
});
}
crepe::crepe! {
@input
#[derive(Debug)]
pub struct Edge(pub MemoryId, pub MemoryId, pub RelKindId);
@input
#[derive(Debug)]
pub struct EntityFact(pub MemoryId, pub EntityId);
@input
#[derive(Debug)]
pub struct TagFact(pub MemoryId, pub u32);
@output
#[derive(Debug)]
pub struct TypeFromSolves(MemoryId, u8);
@output
#[derive(Debug)]
pub struct TypeFromFixes(MemoryId, u8);
@output
#[derive(Debug)]
pub struct TypeFromCauses(MemoryId, u8);
@output
#[derive(Debug)]
pub struct TransitiveDependsOn(MemoryId, MemoryId);
@output
#[derive(Debug)]
pub struct TransitiveRequires(MemoryId, MemoryId);
@output
#[derive(Debug)]
pub struct CoOccurrenceAffinity(MemoryId, MemoryId);
@output
#[derive(Debug)]
pub struct ProblemSolutionBridge(MemoryId, MemoryId);
@output
#[derive(Debug)]
pub struct SimilarTagsAffinity(MemoryId, MemoryId);
@output
#[derive(Debug)]
pub struct ImpliedSolves(MemoryId, MemoryId);
@output
#[derive(Debug)]
pub struct TransitiveBuildsOn(MemoryId, MemoryId);
@output
#[derive(Debug)]
pub struct IndirectBlocker(MemoryId, MemoryId);
@output
#[derive(Debug)]
pub struct ContradictionPropagates(MemoryId, MemoryId);
@output
#[derive(Debug)]
pub struct SessionCohort(MemoryId, MemoryId);
TypeFromSolves(a, SOLUTION_TYPE) <-
Edge(a, _, k), (k == SOLVES);
TypeFromFixes(a, FIX_TYPE) <-
Edge(a, _, k), (k == FIXES);
TypeFromCauses(b, PROBLEM_TYPE) <-
Edge(_, b, k), (k == CAUSES);
TransitiveDependsOn(a, c) <-
Edge(a, b, k1), Edge(b, c, k2),
(k1 == pk_ref().depends_on), (k2 == pk_ref().depends_on);
TransitiveRequires(a, c) <-
Edge(a, b, k1), Edge(b, c, k2),
(k1 == pk_ref().requires), (k2 == pk_ref().requires);
CoOccurrenceAffinity(a, b) <-
EntityFact(a, e), EntityFact(b, e), (a != b);
ProblemSolutionBridge(x, y) <-
Edge(x, p, kx), Edge(y, p, ky), (kx == SOLVES), (ky == SOLVES), (x != y);
SimilarTagsAffinity(a, b) <-
TagFact(a, t), TagFact(b, t), (a != b);
ImpliedSolves(a, b) <- Edge(a, b, k), (k == FIXES);
TransitiveBuildsOn(a, c) <-
Edge(a, b, k1), Edge(b, c, k2),
(k1 == pk_ref().builds_on), (k2 == pk_ref().builds_on);
IndirectBlocker(a, c) <-
Edge(a, b, k1), Edge(b, c, k2),
(k1 == pk_ref().blocks), (k2 == pk_ref().requires);
ContradictionPropagates(a, c) <-
Edge(a, b, k1), Edge(b, c, k2),
(k1 == pk_ref().contradicts), (k2 == pk_ref().confirms);
SessionCohort(m, s) <- Edge(m, s, k), (k == IN_SESSION);
}
fn pk_ref() -> &'static PackKinds {
pk()
}
#[derive(Debug, Default)]
pub struct Derived {
pub type_from_solves: Vec<(MemoryId, u8)>,
pub type_from_fixes: Vec<(MemoryId, u8)>,
pub type_from_causes: Vec<(MemoryId, u8)>,
pub transitive_depends_on: Vec<(MemoryId, MemoryId)>,
pub transitive_requires: Vec<(MemoryId, MemoryId)>,
pub co_occurrence_affinity: Vec<(MemoryId, MemoryId)>,
pub problem_solution_bridge: Vec<(MemoryId, MemoryId)>,
pub similar_tags_affinity: Vec<(MemoryId, MemoryId)>,
pub implied_solves: Vec<(MemoryId, MemoryId)>,
pub transitive_builds_on: Vec<(MemoryId, MemoryId)>,
pub indirect_blocker: Vec<(MemoryId, MemoryId)>,
pub contradiction_propagates: Vec<(MemoryId, MemoryId)>,
pub session_cohort: Vec<(MemoryId, MemoryId)>,
}
impl Derived {
pub fn total(&self) -> usize {
self.type_from_solves.len()
+ self.type_from_fixes.len()
+ self.type_from_causes.len()
+ self.transitive_depends_on.len()
+ self.transitive_requires.len()
+ self.co_occurrence_affinity.len()
+ self.problem_solution_bridge.len()
+ self.similar_tags_affinity.len()
+ self.implied_solves.len()
+ self.transitive_builds_on.len()
+ self.indirect_blocker.len()
+ self.contradiction_propagates.len()
+ self.session_cohort.len()
}
}
pub fn evaluate(edges: Vec<Edge>, entities: Vec<EntityFact>, tags: Vec<TagFact>) -> Derived {
let mut rt = Crepe::new();
rt.extend(edges);
rt.extend(entities);
rt.extend(tags);
let (
type_from_solves,
type_from_fixes,
type_from_causes,
transitive_depends_on,
transitive_requires,
co_occurrence_affinity,
problem_solution_bridge,
similar_tags_affinity,
implied_solves,
transitive_builds_on,
indirect_blocker,
contradiction_propagates,
session_cohort,
) = rt.run();
macro_rules! pairs {
($s:expr) => {
$s.into_iter().map(|x| (x.0, x.1)).collect()
};
}
Derived {
type_from_solves: pairs!(type_from_solves),
type_from_fixes: pairs!(type_from_fixes),
type_from_causes: pairs!(type_from_causes),
transitive_depends_on: pairs!(transitive_depends_on),
transitive_requires: pairs!(transitive_requires),
co_occurrence_affinity: pairs!(co_occurrence_affinity),
problem_solution_bridge: pairs!(problem_solution_bridge),
similar_tags_affinity: pairs!(similar_tags_affinity),
implied_solves: pairs!(implied_solves),
transitive_builds_on: pairs!(transitive_builds_on),
indirect_blocker: pairs!(indirect_blocker),
contradiction_propagates: pairs!(contradiction_propagates),
session_cohort: pairs!(session_cohort),
}
}