use std::collections::HashSet;
use nibli_types::error::NibliError;
use nibli_types::logic::{
AggregateOp, FactSummary, LogicBuffer, LogicalTerm, ProofTrace, QueryResult, WitnessBinding,
};
pub fn compile_unmarked(text: &str) -> Result<LogicBuffer, NibliError> {
let ast = nibli_kr::parse_checked(text)?;
nibli_semantics::compile_from_ast(ast)
}
pub fn compile_text(
text: &str,
compute_predicates: &HashSet<String>,
) -> Result<LogicBuffer, NibliError> {
let mut buf = compile_unmarked(text)?;
nibli_reason::transform_compute_nodes(&mut buf, compute_predicates);
Ok(buf)
}
pub struct CoreSession {
kb: nibli_reason::KnowledgeBase,
compute_predicates: HashSet<String>,
}
impl Default for CoreSession {
fn default() -> Self {
Self::new()
}
}
impl CoreSession {
pub fn new() -> Self {
Self::with_kb(nibli_reason::KnowledgeBase::new())
}
pub fn with_kb(kb: nibli_reason::KnowledgeBase) -> Self {
CoreSession {
kb,
compute_predicates: nibli_reason::default_compute_predicates(),
}
}
pub fn kb(&self) -> &nibli_reason::KnowledgeBase {
&self.kb
}
pub fn compute_predicates(&self) -> &HashSet<String> {
&self.compute_predicates
}
pub fn register_compute_predicate(&mut self, name: String) {
self.compute_predicates.insert(name);
}
pub fn set_compute_dispatch(
&self,
eval: fn(&str, &[LogicalTerm]) -> Result<bool, String>,
batch_eval: fn(&[nibli_reason::ComputeRequest]) -> Vec<Result<bool, String>>,
) {
self.kb.set_compute_dispatch(eval, batch_eval);
}
pub fn set_verbose(&self, verbose: bool) {
self.kb.set_verbose(verbose);
}
pub fn set_strict(&self, strict: bool) {
self.kb.set_strict(strict);
}
pub fn set_existential_import(&self, on: bool) {
self.kb.set_existential_import(on);
}
pub fn set_materialization(&self, on: bool) {
self.kb.set_materialization(on);
}
pub fn materialization_report(&self) -> (Vec<String>, Vec<(String, String)>) {
self.kb.materialization_report()
}
pub fn compile_text(&self, text: &str) -> Result<LogicBuffer, NibliError> {
compile_text(text, &self.compute_predicates)
}
pub fn assert_text(&self, text: &str) -> Result<Vec<(u64, LogicBuffer)>, NibliError> {
let buf = self.compile_text(text)?;
let mut out = Vec::new();
for sub in buf.split_roots() {
let id = self.kb.assert_fact(sub.clone(), text.to_string())?;
out.push((id, sub));
}
Ok(out)
}
pub fn assert_fact_direct(
&self,
relation: &str,
args: &[LogicalTerm],
id: Option<u64>,
) -> Result<u64, NibliError> {
let label = format!(":assert {}", relation);
let buf = nibli_semantics::compile_injected_fact(relation, args)?;
match id {
Some(i) => {
self.kb
.assert_fact_with_id(buf, label, i)
.map_err(NibliError::Reasoning)?;
Ok(i)
}
None => self.kb.assert_fact(buf, label),
}
}
pub fn query_text(&self, text: &str) -> Result<QueryResult, NibliError> {
let buf = self.compile_text(text)?;
self.kb.query_entailment(buf)
}
pub fn query_text_with_proof(
&self,
text: &str,
) -> Result<(QueryResult, ProofTrace), NibliError> {
let buf = self.compile_text(text)?;
self.kb.query_entailment_with_proof(buf)
}
pub fn query_find_text(&self, text: &str) -> Result<Vec<Vec<WitnessBinding>>, NibliError> {
let buf = self.compile_text(text)?;
self.kb.query_find(buf)
}
pub fn count_witnesses_text(&self, text: &str) -> Result<usize, NibliError> {
let buf = self.compile_text(text)?;
self.kb.count_witnesses(buf)
}
pub fn aggregate_text(
&self,
text: &str,
variable: &str,
op: AggregateOp,
) -> Result<Option<f64>, NibliError> {
let buf = self.compile_text(text)?;
self.kb.aggregate(buf, variable, op)
}
pub fn retract_fact(&self, id: u64) -> Result<(), NibliError> {
self.kb.retract_fact(id)
}
pub fn reset(&self) -> Result<(), NibliError> {
self.kb.reset()
}
pub fn list_facts(&self) -> Result<Vec<FactSummary>, NibliError> {
self.kb.list_facts()
}
}