Skip to content

Commit

Permalink
Added reasoner arg to ModelAdapter
Browse files Browse the repository at this point in the history
  • Loading branch information
alkidbaci committed Aug 8, 2023
1 parent 53b4e97 commit af14fbb
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 25 deletions.
17 changes: 14 additions & 3 deletions examples/concept_learning_with_celoe_heuristic_ma.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
import os
import random

from ontolearn.concept_learner import CELOE
from ontolearn.knowledge_base import KnowledgeBase
from ontolearn.model_adapter import ModelAdapter
from owlapy.model import OWLClass, OWLNamedIndividual, IRI
from ontolearn.utils import setup_logging

from owlapy.owlready2 import BaseReasoner_Owlready2, OWLOntology_Owlready2
from owlapy.owlready2.complex_ce_instances import OWLReasoner_Owlready2_ComplexCEInstances
from typing import cast
setup_logging()

try:
Expand All @@ -25,7 +29,7 @@
print('Target concept: ', str_target_concept)

concepts_to_ignore = None
# lets inject more background info
# let's inject more background info
if str_target_concept in ['Granddaughter', 'Aunt', 'Sister']:
NS = 'http://www.benchmark.org/family#'
concepts_to_ignore = {
Expand All @@ -48,9 +52,16 @@

typed_pos = set(map(OWLNamedIndividual, map(IRI.create, p)))
typed_neg = set(map(OWLNamedIndividual, map(IRI.create, n)))

kb = KnowledgeBase(path=settings['data_path'])
reasoner = OWLReasoner_Owlready2_ComplexCEInstances(cast(OWLOntology_Owlready2, kb.ontology()),
BaseReasoner_Owlready2.HERMIT)

model = ModelAdapter(path=settings['data_path'],
ignore=concepts_to_ignore,
max_runtime=600,
reasoner=reasoner,
learner_type=CELOE,
max_runtime=60,
max_num_of_concepts_tested=10_000_000_000,
iter_bound=10_000_000_000,
expansionPenaltyFactor=0.01)
Expand Down
21 changes: 12 additions & 9 deletions ontolearn/base_concept_learner.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ class BaseConceptLearner(Generic[_N], metaclass=ABCMeta):
** E^+ \\cup E^- \\subseteq K_N
** E^+ \\cap E^- = \\emptyset
The goal is to to learn a set of concepts $\\hypotheses \\subseteq \\ALCConcepts$ such that
The goal is to learn a set of concepts $\\hypotheses \\subseteq \\ALCConcepts$ such that
∀ H \\in \\hypotheses: { (K \\wedge H \\models E^+) \\wedge \\neg( K \\wedge H \\models E^-) }.
"""
__slots__ = 'kb', 'quality_func', 'max_num_of_concepts_tested', 'terminate_on_goal', 'max_runtime', \
__slots__ = 'kb', 'reasoner', 'quality_func', 'max_num_of_concepts_tested', 'terminate_on_goal', 'max_runtime', \
'start_time', '_goal_found', '_number_of_tested_concepts'

name: ClassVar[str]
Expand All @@ -67,6 +67,7 @@ class BaseConceptLearner(Generic[_N], metaclass=ABCMeta):
@abstractmethod
def __init__(self,
knowledge_base: KnowledgeBase,
reasoner: Optional[OWLReasoner] = None,
quality_func: Optional[AbstractScorer] = None,
max_num_of_concepts_tested: Optional[int] = None,
max_runtime: Optional[int] = None,
Expand All @@ -80,8 +81,11 @@ def __init__(self,
max_num_of_concepts_tested: limit to stop the algorithm after n concepts tested. defaults to 10_000
max_runtime: limit to stop the algorithm after n seconds. defaults to 5
terminate_on_goal: whether to stop the algorithm if a perfect solution is found. defaults to True
reasoner: Optionally use a different reasoner. If reasoner=None, the knowledge base of the concept
learner is used.
"""
self.kb = knowledge_base
self.reasoner = reasoner
self.quality_func = quality_func
self.max_num_of_concepts_tested = max_num_of_concepts_tested
self.terminate_on_goal = terminate_on_goal
Expand Down Expand Up @@ -198,8 +202,6 @@ def _assign_labels_to_individuals(self, individuals: List[OWLNamedIndividual],
Args:
individuals: A list of OWL individuals.
hypotheses: A list of class expressions.
reasoner: Optionally use a different reasoner. If reasoner=None, the knowledge base of the concept
learner is used.
Returns:
matrix of \\|individuals\\| x \\|hypotheses\\|
Expand All @@ -217,8 +219,7 @@ def _assign_labels_to_individuals(self, individuals: List[OWLNamedIndividual],
def predict(self, individuals: List[OWLNamedIndividual],
hypotheses: Optional[List[Union[_N, OWLClassExpression]]] = None,
axioms: Optional[List[OWLAxiom]] = None,
n: int = 10,
reasoner: Optional[OWLReasoner] = None) -> pd.DataFrame:
n: int = 10) -> pd.DataFrame:
"""Creates a binary data frame showing for each individual whether it is entailed in the given hypotheses
(class expressions). The individuals do not have to be in the ontology/knowledge base yet. In that case,
axioms describing these individuals must be provided.
Expand All @@ -234,13 +235,12 @@ def predict(self, individuals: List[OWLNamedIndividual],
describing these individuals must be provided. The argument can also be used to add
arbitrary axioms to the ontology for the prediction.
n: Integer denoting number of ALC concepts to extract from search tree if hypotheses=None.
reasoner: (Optional) Use a different reasoner. If reasoner=None, the knowledge base of the concept
learner is used.
Returns:
Pandas data frame with dimensions |individuals|*|hypotheses| indicating for each individual and each
hypothesis whether the individual is entailed in the hypothesis
"""
reasoner = self.reasoner
new_individuals = set(individuals) - self.kb.individuals_set(OWLThing)
if len(new_individuals) > 0 and (axioms is None or len(axioms) == 0):
raise RuntimeError('If individuals are provided that are not in the knowledge base yet, a list of axioms '
Expand All @@ -252,7 +252,8 @@ def predict(self, individuals: List[OWLNamedIndividual],
manager: OWLOntologyManager = ontology.get_owl_ontology_manager()
for axiom in axioms:
manager.add_axiom(ontology, axiom)
reasoner = OWLReasoner_Owlready2_ComplexCEInstances(ontology) if reasoner is None else reasoner
if reasoner is None:
reasoner = OWLReasoner_Owlready2_ComplexCEInstances(ontology)

if hypotheses is None:
hypotheses = [hyp.concept for hyp in self.best_hypotheses(n)]
Expand Down Expand Up @@ -357,6 +358,7 @@ class RefinementBasedConceptLearner(BaseConceptLearner[_N]):
@abstractmethod
def __init__(self,
knowledge_base: KnowledgeBase,
reasoner: Optional[OWLReasoner] = None,
refinement_operator: Optional[BaseRefinement] = None,
heuristic_func: Optional[AbstractHeuristic] = None,
quality_func: Optional[AbstractScorer] = None,
Expand All @@ -383,6 +385,7 @@ def __init__(self,
root_concept: the start concept to begin the search from. defaults to OWL Thing
"""
super().__init__(knowledge_base=knowledge_base,
reasoner=reasoner,
quality_func=quality_func,
max_num_of_concepts_tested=max_num_of_concepts_tested,
max_runtime=max_runtime,
Expand Down
27 changes: 16 additions & 11 deletions ontolearn/concept_learner.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
from ontolearn.nces_architectures import LSTM, GRU, SetTransformer
from ontolearn.nces_trainer import NCESTrainer, before_pad
from ontolearn.nces_utils import SimpleSolution
from owlapy.model import OWLClassExpression, OWLDataProperty, OWLLiteral, OWLNamedIndividual
from owlapy.model import OWLClassExpression, OWLDataProperty, OWLLiteral, OWLNamedIndividual, OWLReasoner
from owlapy.render import DLSyntaxObjectRenderer
from owlapy.parser import DLSyntaxParser
from owlapy.util import OrderedOWLObject
Expand All @@ -60,7 +60,6 @@ class CELOE(RefinementBasedConceptLearner[OENode]):
name = 'celoe_python'

kb: KnowledgeBase

max_he: int
min_he: int
best_only: bool
Expand All @@ -74,6 +73,7 @@ class CELOE(RefinementBasedConceptLearner[OENode]):

def __init__(self,
knowledge_base: KnowledgeBase,
reasoner: Optional[OWLReasoner] = None,
refinement_operator: Optional[BaseRefinement[OENode]] = None,
quality_func: Optional[AbstractScorer] = None,
heuristic_func: Optional[AbstractHeuristic] = None,
Expand All @@ -85,6 +85,7 @@ def __init__(self,
best_only: bool = False,
calculate_min_max: bool = True):
super().__init__(knowledge_base=knowledge_base,
reasoner=reasoner,
refinement_operator=refinement_operator,
quality_func=quality_func,
heuristic_func=heuristic_func,
Expand Down Expand Up @@ -471,6 +472,7 @@ class OCEL(CELOE):

def __init__(self,
knowledge_base: KnowledgeBase,
reasoner: Optional[OWLReasoner] = None,
refinement_operator: Optional[BaseRefinement[OENode]] = None,
quality_func: Optional[AbstractScorer] = None,
heuristic_func: Optional[AbstractHeuristic] = None,
Expand All @@ -486,6 +488,7 @@ def __init__(self,
heuristic_func = OCELHeuristic()

super().__init__(knowledge_base=knowledge_base,
reasoner=reasoner,
refinement_operator=refinement_operator,
quality_func=quality_func,
heuristic_func=heuristic_func,
Expand Down Expand Up @@ -1278,15 +1281,14 @@ def forward(self, X: torch.FloatTensor):


class CustomConceptLearner(CELOE):
def __init__(self, knowledge_base, quality_func=None, iter_bound=None, max_num_of_concepts_tested=None,
heuristic_func=None,
ignored_concepts=None, verbose=None, terminate_on_goal=None):
def __init__(self, knowledge_base, reasoner=None, quality_func=None, iter_bound=None,
max_num_of_concepts_tested=None, heuristic_func=None, terminate_on_goal=None):
super().__init__(knowledge_base=knowledge_base,
reasoner=reasoner,
quality_func=quality_func,
heuristic_func=heuristic_func,
ignored_concepts=ignored_concepts,
terminate_on_goal=terminate_on_goal,
iter_bound=iter_bound, max_num_of_concepts_tested=max_num_of_concepts_tested, verbose=verbose)
iter_bound=iter_bound, max_num_of_concepts_tested=max_num_of_concepts_tested)
self.name = heuristic_func.name


Expand Down Expand Up @@ -1325,6 +1327,7 @@ class EvoLearner(BaseConceptLearner[EvoLearnerNode]):

def __init__(self,
knowledge_base: KnowledgeBase,
reasoner: Optional[OWLReasoner] = None,
quality_func: Optional[AbstractScorer] = None,
fitness_func: Optional[AbstractFitness] = None,
init_method: Optional[AbstractEAInitialization] = None,
Expand All @@ -1346,10 +1349,11 @@ def __init__(self,
quality_func = Accuracy()

super().__init__(knowledge_base=knowledge_base,
reasoner=reasoner,
quality_func=quality_func,
terminate_on_goal=terminate_on_goal,
max_runtime=max_runtime)

self.reasoner = reasoner
self.fitness_func = fitness_func
self.init_method = init_method
self.algorithm = algorithm
Expand Down Expand Up @@ -1546,17 +1550,18 @@ def fit(self, *args, **kwargs) -> 'EvoLearner':
return self.terminate()

def _initialize(self, pos: FrozenSet[OWLNamedIndividual], neg: FrozenSet[OWLNamedIndividual]) -> List[Tree]:
reasoner = self.kb.reasoner() if self.reasoner is None else self.reasoner
if self.use_data_properties:
if isinstance(self.value_splitter, BinningValueSplitter):
self._dp_splits = self.value_splitter.compute_splits_properties(self.kb.reasoner(),
self._dp_splits = self.value_splitter.compute_splits_properties(reasoner,
self._split_properties)
elif isinstance(self.value_splitter, EntropyValueSplitter):
entropy_splits = self.value_splitter.compute_splits_properties(self.kb.reasoner(),
entropy_splits = self.value_splitter.compute_splits_properties(reasoner,
self._split_properties,
pos, neg)
no_splits = [prop for prop in entropy_splits if len(entropy_splits[prop]) == 0]
temp_splitter = BinningValueSplitter(max_nr_splits=10)
binning_splits = temp_splitter.compute_splits_properties(self.kb.reasoner(), no_splits)
binning_splits = temp_splitter.compute_splits_properties(reasoner, no_splits)
self._dp_splits = {**entropy_splits, **binning_splits}
else:
raise ValueError(self.value_splitter)
Expand Down
24 changes: 22 additions & 2 deletions ontolearn/model_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
from ontolearn.abstracts import AbstractHeuristic, AbstractScorer, BaseRefinement, AbstractKnowledgeBase, \
AbstractNode
from ontolearn.base_concept_learner import BaseConceptLearner
from owlapy.model import OWLReasoner
from owlapy.owlready2.complex_ce_instances import OWLReasoner_Owlready2_ComplexCEInstances
from owlapy.fast_instance_checker import OWLReasoner_FastInstanceChecker

logger = logging.getLogger(__name__)
# TODO:CD: Move all imports to the top of the file
Expand Down Expand Up @@ -58,7 +61,6 @@ def ModelAdapter(*args, **kwargs): # noqa: C901
learner_type: a Base Concept Learner type
...: arguments for the learning algorithm
"""

if "knowledge_base" in kwargs:
kb = kwargs.pop("knowledge_base")
if "knowledge_base_type" in kwargs:
Expand All @@ -70,7 +72,8 @@ def ModelAdapter(*args, **kwargs): # noqa: C901
kb_type = KnowledgeBase
else:
kb_type = kb_type

if "reasoner" in kwargs:
kwargs["cl_reasoner"] = kwargs["reasoner"]
kb_args = _get_matching_opts(kb_type, {}, kwargs)
try:
kb = kb_type(**kb_args)
Expand All @@ -86,6 +89,21 @@ def ModelAdapter(*args, **kwargs): # noqa: C901
else:
target_kb = kb

if "cl_reasoner" in kwargs:
reasoner = kwargs.pop("cl_reasoner")
if "reasoner_type" in kwargs:
raise ValueError("both reasoner and _type specified")
else:
reasoner_type = kwargs.pop("reasoner_type", None)
if reasoner_type is None:
reasoner_type = OWLReasoner_Owlready2_ComplexCEInstances
assert issubclass(reasoner_type, OWLReasoner)
reasoner = reasoner_type(**_get_matching_opts(
reasoner_type, {
'ontology': target_kb.ontology()
}, kwargs))
assert isinstance(reasoner, OWLReasoner)

if "refinement_operator" in kwargs:
operator = kwargs.pop("refinement_operator")
if "refinement_operator_type" in kwargs:
Expand Down Expand Up @@ -165,6 +183,7 @@ def ModelAdapter(*args, **kwargs): # noqa: C901
# noinspection PyArgumentList
inst = cls(**_get_matching_opts(cls, {
'knowledge_base': target_kb,
'reasoner': reasoner,
'refinement_operator': operator,
'quality_func': qual,
'heuristic_func': heur,
Expand All @@ -176,6 +195,7 @@ def ModelAdapter(*args, **kwargs): # noqa: C901
learner_type, {
**other_instances,
'knowledge_base': target_kb,
'reasoner': reasoner,
'refinement_operator': operator,
'quality_func': qual,
'heuristic_func': heur,
Expand Down

0 comments on commit af14fbb

Please sign in to comment.