154 lines
5.4 KiB
Python
154 lines
5.4 KiB
Python
"""Ontology sublimation agent for OntoCast.
|
|
|
|
This module provides functionality for refining and enhancing ontologies through
|
|
a process of sublimation, which involves improving the structure, consistency,
|
|
and expressiveness of the ontological knowledge.
|
|
"""
|
|
|
|
import logging
|
|
from typing import Iterable, cast
|
|
|
|
from rdflib.term import Node
|
|
|
|
from ontocast.onto.constants import DEFAULT_IRI
|
|
from ontocast.onto.enum import FailureStage
|
|
from ontocast.onto.rdfgraph import RDFGraph
|
|
from ontocast.onto.state import AgentState
|
|
from ontocast.toolbox import ToolBox
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _sublimate_ontology(state: AgentState) -> tuple[RDFGraph, RDFGraph]:
|
|
graph_onto_addendum = RDFGraph()
|
|
graph_facts_pure = RDFGraph()
|
|
|
|
# Copy all prefixes from the original graph to both new graphs
|
|
for prefix, namespace in state.current_content_unit.graph.namespaces():
|
|
graph_onto_addendum.bind(prefix, namespace)
|
|
graph_facts_pure.bind(prefix, namespace)
|
|
|
|
query_ontology = f"""
|
|
PREFIX cd: <{DEFAULT_IRI}>
|
|
|
|
SELECT ?s ?p ?o
|
|
WHERE {{
|
|
?s ?p ?o .
|
|
FILTER (
|
|
!(
|
|
STRSTARTS(STR(?s), STR(cd:)) ||
|
|
STRSTARTS(STR(?p), STR(cd:)) ||
|
|
(isIRI(?o) && STRSTARTS(STR(?o), STR(cd:)))
|
|
)
|
|
)
|
|
}}
|
|
"""
|
|
results = cast(
|
|
Iterable[tuple[Node, Node, Node]],
|
|
state.current_content_unit.graph.query(query_ontology),
|
|
)
|
|
|
|
# Add filtered triples to the new graph
|
|
for s, p, o in results:
|
|
graph_onto_addendum.add((s, p, o))
|
|
|
|
query_facts = f"""
|
|
PREFIX cd: <{DEFAULT_IRI}>
|
|
|
|
SELECT ?s ?p ?o
|
|
WHERE {{
|
|
?s ?p ?o .
|
|
FILTER (
|
|
STRSTARTS(STR(?s), STR(cd:)) ||
|
|
STRSTARTS(STR(?p), STR(cd:)) ||
|
|
(isIRI(?o) && STRSTARTS(STR(?o), STR(cd:)))
|
|
)
|
|
}}
|
|
"""
|
|
|
|
results = cast(
|
|
Iterable[tuple[Node, Node, Node]],
|
|
state.current_content_unit.graph.query(query_facts),
|
|
)
|
|
|
|
# Add filtered triples to the new graph
|
|
for s, p, o in results:
|
|
graph_facts_pure.add((s, p, o))
|
|
|
|
logger.info(
|
|
f"Found triples: facts {len(graph_facts_pure)}; ontology {len(graph_onto_addendum)}"
|
|
)
|
|
return graph_onto_addendum, graph_facts_pure
|
|
|
|
|
|
def sublimate_ontology(state: AgentState, tools: ToolBox):
|
|
logger.debug("Starting ontology sublimation")
|
|
|
|
if state.current_ontology is None:
|
|
return state
|
|
try:
|
|
state.update_facts()
|
|
graph_onto_addendum, graph_facts = _sublimate_ontology(state=state)
|
|
|
|
# Ensure ontology is not null and ontology_id is set before updating
|
|
if len(graph_onto_addendum) > 0:
|
|
logger.info("ontology seeped into facts:")
|
|
logger.info(f"graph: {graph_onto_addendum.serialize()}")
|
|
if state.current_ontology.is_null():
|
|
logger.warning(
|
|
"Cannot update ontology: null ontology cannot be updated"
|
|
)
|
|
elif state.current_ontology.ontology_id:
|
|
# Check if adding triples would exceed max_triples limit
|
|
max_triples = state.ontology_max_triples
|
|
if max_triples is not None:
|
|
current_size = len(state.current_ontology.graph)
|
|
addendum_size = len(graph_onto_addendum)
|
|
if current_size + addendum_size > max_triples:
|
|
logger.warning(
|
|
f"Ontology sublimation skipped: would exceed limit "
|
|
f"({current_size + addendum_size} > {max_triples} triples). "
|
|
f"Current size: {current_size} triples."
|
|
)
|
|
else:
|
|
# Only update state.current_ontology, not OntologyManager
|
|
# OntologyManager will be updated in serialize() during final serialization
|
|
state.current_ontology.graph += graph_onto_addendum
|
|
logger.debug(
|
|
f"Updated state.current_ontology with {len(graph_onto_addendum)} triples from sublimation"
|
|
)
|
|
else:
|
|
# No limit set, proceed with update
|
|
state.current_ontology.graph += graph_onto_addendum
|
|
logger.debug(
|
|
f"Updated state.current_ontology with {len(graph_onto_addendum)} triples from sublimation"
|
|
)
|
|
else:
|
|
logger.warning("Cannot update ontology: ontology_id is None")
|
|
|
|
# Ensure graph_facts is an RDFGraph instance
|
|
if not isinstance(graph_facts, RDFGraph):
|
|
logger.warning("received an rdflib.Graph rather than RDFGraph")
|
|
new_graph = RDFGraph()
|
|
graph_facts_rdflib = cast(Iterable[tuple[Node, Node, Node]], graph_facts)
|
|
for triple in graph_facts_rdflib:
|
|
new_graph.add(triple)
|
|
graph_facts_namespaces = cast(
|
|
Iterable[tuple[str, str]], graph_facts.namespaces()
|
|
)
|
|
for prefix, namespace in graph_facts_namespaces:
|
|
new_graph.bind(prefix, namespace)
|
|
graph_facts = new_graph
|
|
|
|
state.current_content_unit.graph = graph_facts
|
|
|
|
state.clear_failure()
|
|
except Exception as e:
|
|
logger.error(f"Error in sublimate_ontology: {str(e)}")
|
|
state.set_failure(
|
|
FailureStage.SUBLIMATE_ONTOLOGY,
|
|
str(e),
|
|
)
|
|
|
|
return state
|