fuzzy-dl-owl2 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fuzzy_dl_owl2/__init__.py +2 -0
- fuzzy_dl_owl2/fuzzydl/__init__.py +23 -0
- fuzzy_dl_owl2/fuzzydl/assertion/__init__.py +2 -0
- fuzzy_dl_owl2/fuzzydl/assertion/assertion.py +72 -0
- fuzzy_dl_owl2/fuzzydl/assertion/atomic_assertion.py +19 -0
- fuzzy_dl_owl2/fuzzydl/concept/__init__.py +13 -0
- fuzzy_dl_owl2/fuzzydl/concept/all_some_concept.py +85 -0
- fuzzy_dl_owl2/fuzzydl/concept/approximation_concept.py +147 -0
- fuzzy_dl_owl2/fuzzydl/concept/atomic_concept.py +91 -0
- fuzzy_dl_owl2/fuzzydl/concept/choquet_integral.py +64 -0
- fuzzy_dl_owl2/fuzzydl/concept/concept.py +230 -0
- fuzzy_dl_owl2/fuzzydl/concept/concrete/__init__.py +10 -0
- fuzzy_dl_owl2/fuzzydl/concept/concrete/crisp_concrete_concept.py +60 -0
- fuzzy_dl_owl2/fuzzydl/concept/concrete/fuzzy_concrete_concept.py +63 -0
- fuzzy_dl_owl2/fuzzydl/concept/concrete/fuzzy_number/__init__.py +1 -0
- fuzzy_dl_owl2/fuzzydl/concept/concrete/fuzzy_number/triangular_fuzzy_number.py +127 -0
- fuzzy_dl_owl2/fuzzydl/concept/concrete/left_concrete_concept.py +70 -0
- fuzzy_dl_owl2/fuzzydl/concept/concrete/linear_concrete_concept.py +70 -0
- fuzzy_dl_owl2/fuzzydl/concept/concrete/modified_concrete_concept.py +66 -0
- fuzzy_dl_owl2/fuzzydl/concept/concrete/right_concrete_concept.py +70 -0
- fuzzy_dl_owl2/fuzzydl/concept/concrete/trapezoidal_concrete_concept.py +96 -0
- fuzzy_dl_owl2/fuzzydl/concept/concrete/triangular_concrete_concept.py +89 -0
- fuzzy_dl_owl2/fuzzydl/concept/ext_threshold_concept.py +77 -0
- fuzzy_dl_owl2/fuzzydl/concept/has_value_concept.py +51 -0
- fuzzy_dl_owl2/fuzzydl/concept/implies_concept.py +144 -0
- fuzzy_dl_owl2/fuzzydl/concept/interface/__init__.py +6 -0
- fuzzy_dl_owl2/fuzzydl/concept/interface/has_concept_interface.py +17 -0
- fuzzy_dl_owl2/fuzzydl/concept/interface/has_concepts_interface.py +18 -0
- fuzzy_dl_owl2/fuzzydl/concept/interface/has_role_concept_interface.py +14 -0
- fuzzy_dl_owl2/fuzzydl/concept/interface/has_role_interface.py +15 -0
- fuzzy_dl_owl2/fuzzydl/concept/interface/has_value_interface.py +21 -0
- fuzzy_dl_owl2/fuzzydl/concept/interface/has_weighted_concepts_interface.py +29 -0
- fuzzy_dl_owl2/fuzzydl/concept/modified/__init__.py +3 -0
- fuzzy_dl_owl2/fuzzydl/concept/modified/linearly_modified_concept.py +32 -0
- fuzzy_dl_owl2/fuzzydl/concept/modified/modified_concept.py +59 -0
- fuzzy_dl_owl2/fuzzydl/concept/modified/triangularly_modified_concept.py +33 -0
- fuzzy_dl_owl2/fuzzydl/concept/negated_nominal.py +42 -0
- fuzzy_dl_owl2/fuzzydl/concept/operator_concept.py +707 -0
- fuzzy_dl_owl2/fuzzydl/concept/owa_concept.py +57 -0
- fuzzy_dl_owl2/fuzzydl/concept/qowa_concept.py +62 -0
- fuzzy_dl_owl2/fuzzydl/concept/quasi_sugeno_integral.py +46 -0
- fuzzy_dl_owl2/fuzzydl/concept/self_concept.py +45 -0
- fuzzy_dl_owl2/fuzzydl/concept/string_concept.py +35 -0
- fuzzy_dl_owl2/fuzzydl/concept/sugeno_integral.py +83 -0
- fuzzy_dl_owl2/fuzzydl/concept/threshold_concept.py +81 -0
- fuzzy_dl_owl2/fuzzydl/concept/truth_concept.py +83 -0
- fuzzy_dl_owl2/fuzzydl/concept/value_concept.py +67 -0
- fuzzy_dl_owl2/fuzzydl/concept/weighted_concept.py +55 -0
- fuzzy_dl_owl2/fuzzydl/concept/weighted_max_concept.py +63 -0
- fuzzy_dl_owl2/fuzzydl/concept/weighted_min_concept.py +57 -0
- fuzzy_dl_owl2/fuzzydl/concept/weighted_sum_concept.py +62 -0
- fuzzy_dl_owl2/fuzzydl/concept/weighted_sum_zero_concept.py +62 -0
- fuzzy_dl_owl2/fuzzydl/concept_equivalence.py +20 -0
- fuzzy_dl_owl2/fuzzydl/concrete_feature.py +94 -0
- fuzzy_dl_owl2/fuzzydl/degree/__init__.py +4 -0
- fuzzy_dl_owl2/fuzzydl/degree/degree.py +79 -0
- fuzzy_dl_owl2/fuzzydl/degree/degree_expression.py +57 -0
- fuzzy_dl_owl2/fuzzydl/degree/degree_numeric.py +57 -0
- fuzzy_dl_owl2/fuzzydl/degree/degree_variable.py +54 -0
- fuzzy_dl_owl2/fuzzydl/domain_axiom.py +8 -0
- fuzzy_dl_owl2/fuzzydl/exception/__init__.py +2 -0
- fuzzy_dl_owl2/fuzzydl/exception/fuzzy_ontology_exception.py +4 -0
- fuzzy_dl_owl2/fuzzydl/exception/inconsistent_ontology_exception.py +4 -0
- fuzzy_dl_owl2/fuzzydl/feature_function.py +148 -0
- fuzzy_dl_owl2/fuzzydl/fuzzydl_to_owl2.py +920 -0
- fuzzy_dl_owl2/fuzzydl/fuzzydl_to_owl2_java.py +953 -0
- fuzzy_dl_owl2/fuzzydl/general_concept_inclusion.py +82 -0
- fuzzy_dl_owl2/fuzzydl/individual/__init__.py +3 -0
- fuzzy_dl_owl2/fuzzydl/individual/created_individual.py +219 -0
- fuzzy_dl_owl2/fuzzydl/individual/individual.py +113 -0
- fuzzy_dl_owl2/fuzzydl/individual/representative_individual.py +37 -0
- fuzzy_dl_owl2/fuzzydl/knowledge_base.py +9037 -0
- fuzzy_dl_owl2/fuzzydl/label.py +32 -0
- fuzzy_dl_owl2/fuzzydl/milp/__init__.py +7 -0
- fuzzy_dl_owl2/fuzzydl/milp/expression.py +186 -0
- fuzzy_dl_owl2/fuzzydl/milp/inequation.py +55 -0
- fuzzy_dl_owl2/fuzzydl/milp/milp_helper.py +787 -0
- fuzzy_dl_owl2/fuzzydl/milp/show_variables_helper.py +151 -0
- fuzzy_dl_owl2/fuzzydl/milp/solution.py +45 -0
- fuzzy_dl_owl2/fuzzydl/milp/term.py +76 -0
- fuzzy_dl_owl2/fuzzydl/milp/variable.py +89 -0
- fuzzy_dl_owl2/fuzzydl/modifier/__init__.py +3 -0
- fuzzy_dl_owl2/fuzzydl/modifier/linear_modifier.py +76 -0
- fuzzy_dl_owl2/fuzzydl/modifier/modifier.py +39 -0
- fuzzy_dl_owl2/fuzzydl/modifier/triangular_modifier.py +76 -0
- fuzzy_dl_owl2/fuzzydl/parser/ParserConstants.py +406 -0
- fuzzy_dl_owl2/fuzzydl/parser/__init__.py +1 -0
- fuzzy_dl_owl2/fuzzydl/parser/dl_parser.py +2029 -0
- fuzzy_dl_owl2/fuzzydl/parser/ebnf.lark +290 -0
- fuzzy_dl_owl2/fuzzydl/parser/larkx.py +70 -0
- fuzzy_dl_owl2/fuzzydl/primitive_concept_definition.py +81 -0
- fuzzy_dl_owl2/fuzzydl/query/__init__.py +14 -0
- fuzzy_dl_owl2/fuzzydl/query/all_instances_query.py +50 -0
- fuzzy_dl_owl2/fuzzydl/query/bnp_query.py +22 -0
- fuzzy_dl_owl2/fuzzydl/query/defuzzify/__init__.py +4 -0
- fuzzy_dl_owl2/fuzzydl/query/defuzzify/defuzzify_query.py +76 -0
- fuzzy_dl_owl2/fuzzydl/query/defuzzify/lom_defuzzify_query.py +19 -0
- fuzzy_dl_owl2/fuzzydl/query/defuzzify/mom_defuzzify_query.py +88 -0
- fuzzy_dl_owl2/fuzzydl/query/defuzzify/som_defuzzify_query.py +20 -0
- fuzzy_dl_owl2/fuzzydl/query/instance_query.py +19 -0
- fuzzy_dl_owl2/fuzzydl/query/kb_satisfiable_query.py +32 -0
- fuzzy_dl_owl2/fuzzydl/query/max/__init__.py +5 -0
- fuzzy_dl_owl2/fuzzydl/query/max/max_instance_query.py +45 -0
- fuzzy_dl_owl2/fuzzydl/query/max/max_query.py +31 -0
- fuzzy_dl_owl2/fuzzydl/query/max/max_related_query.py +45 -0
- fuzzy_dl_owl2/fuzzydl/query/max/max_satisfiable_query.py +73 -0
- fuzzy_dl_owl2/fuzzydl/query/max/max_subsumes_query.py +64 -0
- fuzzy_dl_owl2/fuzzydl/query/min/__init__.py +5 -0
- fuzzy_dl_owl2/fuzzydl/query/min/min_instance_query.py +50 -0
- fuzzy_dl_owl2/fuzzydl/query/min/min_query.py +31 -0
- fuzzy_dl_owl2/fuzzydl/query/min/min_related_query.py +57 -0
- fuzzy_dl_owl2/fuzzydl/query/min/min_satisfiable_query.py +80 -0
- fuzzy_dl_owl2/fuzzydl/query/min/min_subsumes_query.py +65 -0
- fuzzy_dl_owl2/fuzzydl/query/query.py +38 -0
- fuzzy_dl_owl2/fuzzydl/query/related_query.py +15 -0
- fuzzy_dl_owl2/fuzzydl/query/satisfiable_query.py +37 -0
- fuzzy_dl_owl2/fuzzydl/query/subsumption_query.py +20 -0
- fuzzy_dl_owl2/fuzzydl/range_axiom.py +7 -0
- fuzzy_dl_owl2/fuzzydl/relation.py +47 -0
- fuzzy_dl_owl2/fuzzydl/restriction/__init__.py +2 -0
- fuzzy_dl_owl2/fuzzydl/restriction/has_value_restriction.py +16 -0
- fuzzy_dl_owl2/fuzzydl/restriction/restriction.py +34 -0
- fuzzy_dl_owl2/fuzzydl/role_parent_with_degree.py +10 -0
- fuzzy_dl_owl2/fuzzydl/util/__init__.py +3 -0
- fuzzy_dl_owl2/fuzzydl/util/config_reader.py +56 -0
- fuzzy_dl_owl2/fuzzydl/util/constants.py +424 -0
- fuzzy_dl_owl2/fuzzydl/util/util.py +73 -0
- fuzzy_dl_owl2/fuzzyowl2/__init__.py +5 -0
- fuzzy_dl_owl2/fuzzyowl2/fuzzyowl2.py +1513 -0
- fuzzy_dl_owl2/fuzzyowl2/fuzzyowl2_java.py +1409 -0
- fuzzy_dl_owl2/fuzzyowl2/fuzzyowl2_to_fuzzydl.py +917 -0
- fuzzy_dl_owl2/fuzzyowl2/fuzzyowl2_to_fuzzydl_java.py +956 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/__init__.py +0 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/choquet_concept.py +19 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/concept_definition.py +14 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/fuzzy_datatype.py +22 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/fuzzy_modifier.py +4 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/fuzzy_nominal_concept.py +19 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/fuzzy_property.py +5 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/left_shoulder_function.py +17 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/linear_function.py +17 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/linear_modifier.py +13 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/modified_concept.py +19 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/modified_function.py +17 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/modified_property.py +15 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/owa_concept.py +19 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/property_definition.py +10 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/qowa_concept.py +19 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/quasi_sugeno_concept.py +21 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/right_shoulder_function.py +17 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/sugeno_concept.py +21 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/trapezoidal_function.py +25 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/triangular_function.py +21 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/triangular_modifer.py +21 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/weighted_concept.py +19 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/weighted_max_concept.py +15 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/weighted_min_concept.py +15 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/weighted_sum_concept.py +15 -0
- fuzzy_dl_owl2/fuzzyowl2/owl_types/weighted_sum_zero_concept.py +15 -0
- fuzzy_dl_owl2/fuzzyowl2/parser/__init__.py +1 -0
- fuzzy_dl_owl2/fuzzyowl2/parser/owl2_parser.py +491 -0
- fuzzy_dl_owl2/fuzzyowl2/util/__init__.py +1 -0
- fuzzy_dl_owl2/fuzzyowl2/util/constants.py +112 -0
- fuzzy_dl_owl2-1.0.0.dist-info/LICENSE +427 -0
- fuzzy_dl_owl2-1.0.0.dist-info/METADATA +299 -0
- fuzzy_dl_owl2-1.0.0.dist-info/RECORD +167 -0
- fuzzy_dl_owl2-1.0.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
from functools import partial
|
|
3
|
+
|
|
4
|
+
from fuzzy_dl_owl2.fuzzydl.concept.all_some_concept import AllSomeConcept
|
|
5
|
+
from fuzzy_dl_owl2.fuzzydl.concept.concept import Concept
|
|
6
|
+
from fuzzy_dl_owl2.fuzzydl.concept.interface.has_concepts_interface import (
|
|
7
|
+
HasConceptsInterface,
|
|
8
|
+
)
|
|
9
|
+
from fuzzy_dl_owl2.fuzzydl.concept.truth_concept import TruthConcept
|
|
10
|
+
from fuzzy_dl_owl2.fuzzydl.util import constants
|
|
11
|
+
from fuzzy_dl_owl2.fuzzydl.util.constants import ConceptType, FuzzyLogic
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class OperatorConcept(Concept, HasConceptsInterface):
|
|
15
|
+
AND_OPERATORS: list[ConceptType] = [
|
|
16
|
+
ConceptType.AND,
|
|
17
|
+
ConceptType.GOEDEL_AND,
|
|
18
|
+
ConceptType.LUKASIEWICZ_AND,
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
OR_OPERATORS: list[ConceptType] = [
|
|
22
|
+
ConceptType.OR,
|
|
23
|
+
ConceptType.GOEDEL_OR,
|
|
24
|
+
ConceptType.LUKASIEWICZ_OR,
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
BINARY_OPERATORS: list[ConceptType] = AND_OPERATORS + OR_OPERATORS
|
|
28
|
+
|
|
29
|
+
COMPLEMENT_LAW_OPERATORS: list[ConceptType] = [
|
|
30
|
+
ConceptType.AND,
|
|
31
|
+
ConceptType.LUKASIEWICZ_AND,
|
|
32
|
+
ConceptType.OR,
|
|
33
|
+
ConceptType.LUKASIEWICZ_OR,
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
DISTRIBUTIVE_OPERATORS: list[ConceptType] = [
|
|
37
|
+
ConceptType.AND,
|
|
38
|
+
ConceptType.OR,
|
|
39
|
+
ConceptType.GOEDEL_AND,
|
|
40
|
+
ConceptType.GOEDEL_OR,
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
ABSORPTION_OPERATORS: list[ConceptType] = DISTRIBUTIVE_OPERATORS
|
|
44
|
+
|
|
45
|
+
ALL_OPERATORS: list[ConceptType] = BINARY_OPERATORS + [ConceptType.COMPLEMENT]
|
|
46
|
+
|
|
47
|
+
OPERATORS: dict[ConceptType, ConceptType] = {
|
|
48
|
+
k: v for k, v in zip(AND_OPERATORS + OR_OPERATORS, OR_OPERATORS + AND_OPERATORS)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
def __init__(self, c_type: ConceptType, concepts: typing.Iterable[Concept]) -> None:
|
|
52
|
+
Concept.__init__(self, c_type, None)
|
|
53
|
+
HasConceptsInterface.__init__(self, concepts)
|
|
54
|
+
|
|
55
|
+
assert c_type in OperatorConcept.ALL_OPERATORS, f"Type {c_type} is not valid."
|
|
56
|
+
|
|
57
|
+
self.type: ConceptType = c_type
|
|
58
|
+
self.name = self.compute_name()
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def concepts(self) -> list[Concept]:
|
|
62
|
+
return self._concepts
|
|
63
|
+
|
|
64
|
+
@concepts.setter
|
|
65
|
+
def concepts(self, value: typing.Iterable[Concept]) -> None:
|
|
66
|
+
self._concepts = list(value)
|
|
67
|
+
self.name = self.compute_name()
|
|
68
|
+
|
|
69
|
+
def clone(self) -> Concept:
|
|
70
|
+
return OperatorConcept(
|
|
71
|
+
self.type,
|
|
72
|
+
[c for c in self.concepts],
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def __op(c_type: ConceptType, concepts: typing.Iterable[Concept]) -> Concept:
|
|
77
|
+
assert len(concepts) > 0, "You must have at least one argument"
|
|
78
|
+
if c_type != ConceptType.COMPLEMENT and len(concepts) == 1:
|
|
79
|
+
return concepts[0]
|
|
80
|
+
concepts: list[Concept] = list(concepts)
|
|
81
|
+
if c_type in OperatorConcept.BINARY_OPERATORS:
|
|
82
|
+
changes: bool = True
|
|
83
|
+
while changes:
|
|
84
|
+
i: int = 0
|
|
85
|
+
changes = False
|
|
86
|
+
while len(concepts) > 0 and i < len(concepts):
|
|
87
|
+
c: Concept = concepts[i]
|
|
88
|
+
if c.type == c_type:
|
|
89
|
+
concepts.extend(typing.cast(OperatorConcept, c).concepts)
|
|
90
|
+
concepts.pop(i)
|
|
91
|
+
changes = True
|
|
92
|
+
else:
|
|
93
|
+
i += 1
|
|
94
|
+
return OperatorConcept(c_type, sorted(concepts))
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def and_(*concepts: Concept) -> Concept:
|
|
98
|
+
if constants.KNOWLEDGE_BASE_SEMANTICS == FuzzyLogic.CLASSICAL:
|
|
99
|
+
return OperatorConcept.__op(ConceptType.AND, concepts).classic_cnf()
|
|
100
|
+
if constants.KNOWLEDGE_BASE_SEMANTICS == FuzzyLogic.LUKASIEWICZ:
|
|
101
|
+
return OperatorConcept.__op(
|
|
102
|
+
ConceptType.LUKASIEWICZ_AND, concepts
|
|
103
|
+
).lukasiewicz_cnf()
|
|
104
|
+
if constants.KNOWLEDGE_BASE_SEMANTICS == FuzzyLogic.ZADEH:
|
|
105
|
+
return OperatorConcept.__op(ConceptType.GOEDEL_AND, concepts).goedel_cnf()
|
|
106
|
+
|
|
107
|
+
@staticmethod
|
|
108
|
+
def goedel_and(*concepts: Concept) -> Concept:
|
|
109
|
+
return OperatorConcept.__op(ConceptType.GOEDEL_AND, concepts).goedel_cnf()
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def lukasiewicz_and(*concepts: Concept) -> Concept:
|
|
113
|
+
return OperatorConcept.__op(
|
|
114
|
+
ConceptType.LUKASIEWICZ_AND, concepts
|
|
115
|
+
).lukasiewicz_cnf()
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def or_(*concepts: Concept) -> Concept:
|
|
119
|
+
if constants.KNOWLEDGE_BASE_SEMANTICS == FuzzyLogic.CLASSICAL:
|
|
120
|
+
return OperatorConcept.__op(ConceptType.OR, concepts).classic_cnf()
|
|
121
|
+
if constants.KNOWLEDGE_BASE_SEMANTICS == FuzzyLogic.LUKASIEWICZ:
|
|
122
|
+
return OperatorConcept.__op(
|
|
123
|
+
ConceptType.LUKASIEWICZ_OR, concepts
|
|
124
|
+
).lukasiewicz_cnf()
|
|
125
|
+
if constants.KNOWLEDGE_BASE_SEMANTICS == FuzzyLogic.ZADEH:
|
|
126
|
+
return OperatorConcept.__op(ConceptType.GOEDEL_OR, concepts).goedel_cnf()
|
|
127
|
+
|
|
128
|
+
@staticmethod
|
|
129
|
+
def goedel_or(*concepts: Concept) -> Concept:
|
|
130
|
+
return OperatorConcept.__op(ConceptType.GOEDEL_OR, concepts).goedel_cnf()
|
|
131
|
+
|
|
132
|
+
@staticmethod
|
|
133
|
+
def lukasiewicz_or(*concepts: Concept) -> Concept:
|
|
134
|
+
return OperatorConcept.__op(
|
|
135
|
+
ConceptType.LUKASIEWICZ_OR, concepts
|
|
136
|
+
).lukasiewicz_cnf()
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def not_(concept: Concept) -> Concept:
|
|
140
|
+
if concept.type == ConceptType.TOP:
|
|
141
|
+
return TruthConcept.get_bottom()
|
|
142
|
+
if concept.type == ConceptType.BOTTOM:
|
|
143
|
+
return TruthConcept.get_top()
|
|
144
|
+
if concept.type != ConceptType.COMPLEMENT:
|
|
145
|
+
return OperatorConcept(ConceptType.COMPLEMENT, [concept])
|
|
146
|
+
else:
|
|
147
|
+
return typing.cast(OperatorConcept, concept).concepts[0]
|
|
148
|
+
|
|
149
|
+
@staticmethod
|
|
150
|
+
def is_or(c_type: ConceptType) -> bool:
|
|
151
|
+
return c_type in OperatorConcept.OR_OPERATORS
|
|
152
|
+
|
|
153
|
+
@staticmethod
|
|
154
|
+
def is_and(c_type: ConceptType) -> bool:
|
|
155
|
+
return c_type in OperatorConcept.AND_OPERATORS
|
|
156
|
+
|
|
157
|
+
@staticmethod
|
|
158
|
+
def is_not_type(op: Concept, c_type: ConceptType) -> bool:
|
|
159
|
+
if not isinstance(op, OperatorConcept):
|
|
160
|
+
return False
|
|
161
|
+
if op.type != ConceptType.COMPLEMENT:
|
|
162
|
+
return False
|
|
163
|
+
return op.concepts[0].type == c_type
|
|
164
|
+
|
|
165
|
+
@staticmethod
|
|
166
|
+
def is_not_fuzzy_number(op: Concept) -> bool:
|
|
167
|
+
return OperatorConcept.is_not_type(op, ConceptType.FUZZY_NUMBER)
|
|
168
|
+
|
|
169
|
+
@staticmethod
|
|
170
|
+
def is_not_concrete(op: Concept) -> bool:
|
|
171
|
+
return OperatorConcept.is_not_type(op, ConceptType.CONCRETE)
|
|
172
|
+
|
|
173
|
+
@staticmethod
|
|
174
|
+
def is_not_has_value(op: Concept) -> bool:
|
|
175
|
+
return OperatorConcept.is_not_type(op, ConceptType.HAS_VALUE)
|
|
176
|
+
|
|
177
|
+
@staticmethod
|
|
178
|
+
def is_not_goedel_implies(op: Concept) -> bool:
|
|
179
|
+
return OperatorConcept.is_not_type(op, ConceptType.GOEDEL_IMPLIES)
|
|
180
|
+
|
|
181
|
+
@staticmethod
|
|
182
|
+
def is_not_at_most_value(op: Concept) -> bool:
|
|
183
|
+
return OperatorConcept.is_not_type(op, ConceptType.AT_MOST_VALUE)
|
|
184
|
+
|
|
185
|
+
@staticmethod
|
|
186
|
+
def is_not_at_least_value(op: Concept) -> bool:
|
|
187
|
+
return OperatorConcept.is_not_type(op, ConceptType.AT_LEAST_VALUE)
|
|
188
|
+
|
|
189
|
+
@staticmethod
|
|
190
|
+
def is_not_exact_value(op: Concept) -> bool:
|
|
191
|
+
return OperatorConcept.is_not_type(op, ConceptType.EXACT_VALUE)
|
|
192
|
+
|
|
193
|
+
@staticmethod
|
|
194
|
+
def is_not_weighted(op: Concept) -> bool:
|
|
195
|
+
return OperatorConcept.is_not_type(op, ConceptType.WEIGHTED)
|
|
196
|
+
|
|
197
|
+
@staticmethod
|
|
198
|
+
def is_not_weighted_min(op: Concept) -> bool:
|
|
199
|
+
return OperatorConcept.is_not_type(op, ConceptType.W_MIN)
|
|
200
|
+
|
|
201
|
+
@staticmethod
|
|
202
|
+
def is_not_weighted_max(op: Concept) -> bool:
|
|
203
|
+
return OperatorConcept.is_not_type(op, ConceptType.W_MAX)
|
|
204
|
+
|
|
205
|
+
@staticmethod
|
|
206
|
+
def is_not_weighted_sum(op: Concept) -> bool:
|
|
207
|
+
return OperatorConcept.is_not_type(op, ConceptType.W_SUM)
|
|
208
|
+
|
|
209
|
+
@staticmethod
|
|
210
|
+
def is_not_weighted_sum_zero(op: Concept) -> bool:
|
|
211
|
+
return OperatorConcept.is_not_type(op, ConceptType.W_SUM_ZERO)
|
|
212
|
+
|
|
213
|
+
@staticmethod
|
|
214
|
+
def is_not_pos_threshold(op: Concept) -> bool:
|
|
215
|
+
return OperatorConcept.is_not_type(op, ConceptType.POS_THRESHOLD)
|
|
216
|
+
|
|
217
|
+
@staticmethod
|
|
218
|
+
def is_not_neg_threshold(op: Concept) -> bool:
|
|
219
|
+
return OperatorConcept.is_not_type(op, ConceptType.NEG_THRESHOLD)
|
|
220
|
+
|
|
221
|
+
@staticmethod
|
|
222
|
+
def is_not_ext_pos_threshold(op: Concept) -> bool:
|
|
223
|
+
return OperatorConcept.is_not_type(op, ConceptType.EXT_POS_THRESHOLD)
|
|
224
|
+
|
|
225
|
+
@staticmethod
|
|
226
|
+
def is_not_ext_neg_threshold(op: Concept) -> bool:
|
|
227
|
+
return OperatorConcept.is_not_type(op, ConceptType.EXT_NEG_THRESHOLD)
|
|
228
|
+
|
|
229
|
+
@staticmethod
|
|
230
|
+
def is_not_concrete(op: Concept) -> bool:
|
|
231
|
+
return OperatorConcept.is_not_type(op, ConceptType.CONCRETE)
|
|
232
|
+
|
|
233
|
+
@staticmethod
|
|
234
|
+
def is_not_modified(op: Concept) -> bool:
|
|
235
|
+
return OperatorConcept.is_not_type(op, ConceptType.MODIFIED)
|
|
236
|
+
|
|
237
|
+
@staticmethod
|
|
238
|
+
def is_not_owa(op: Concept) -> bool:
|
|
239
|
+
return OperatorConcept.is_not_type(op, ConceptType.OWA)
|
|
240
|
+
|
|
241
|
+
@staticmethod
|
|
242
|
+
def is_not_qowa(op: Concept) -> bool:
|
|
243
|
+
return OperatorConcept.is_not_type(op, ConceptType.QUANTIFIED_OWA)
|
|
244
|
+
|
|
245
|
+
@staticmethod
|
|
246
|
+
def is_not_choquet(op: Concept) -> bool:
|
|
247
|
+
return OperatorConcept.is_not_type(op, ConceptType.CHOQUET_INTEGRAL)
|
|
248
|
+
|
|
249
|
+
@staticmethod
|
|
250
|
+
def is_not_sugeno(op: Concept) -> bool:
|
|
251
|
+
return OperatorConcept.is_not_type(op, ConceptType.SUGENO_INTEGRAL)
|
|
252
|
+
|
|
253
|
+
@staticmethod
|
|
254
|
+
def is_not_quasi_sugeno(op: Concept) -> bool:
|
|
255
|
+
return OperatorConcept.is_not_type(op, ConceptType.QUASI_SUGENO_INTEGRAL)
|
|
256
|
+
|
|
257
|
+
@staticmethod
|
|
258
|
+
def is_not_self(op: Concept) -> bool:
|
|
259
|
+
return OperatorConcept.is_not_type(op, ConceptType.SELF)
|
|
260
|
+
|
|
261
|
+
@staticmethod
|
|
262
|
+
def is_not_zadeh_implies(op: Concept) -> bool:
|
|
263
|
+
return OperatorConcept.is_not_type(op, ConceptType.ZADEH_IMPLIES)
|
|
264
|
+
|
|
265
|
+
def is_concrete(self) -> bool:
|
|
266
|
+
if OperatorConcept.is_not_concrete(self) or OperatorConcept.is_not_fuzzy_number(
|
|
267
|
+
self
|
|
268
|
+
):
|
|
269
|
+
return True
|
|
270
|
+
if OperatorConcept.is_not_modified(self):
|
|
271
|
+
return self.concepts[0].is_concrete()
|
|
272
|
+
return False
|
|
273
|
+
|
|
274
|
+
def is_atomic(self) -> bool:
|
|
275
|
+
return False
|
|
276
|
+
|
|
277
|
+
def is_complemented_atomic(self) -> bool:
|
|
278
|
+
return self.type == ConceptType.COMPLEMENT and (
|
|
279
|
+
self.concepts[0].is_atomic()
|
|
280
|
+
# or self.concepts[0].type
|
|
281
|
+
# in (ConceptType.MODIFIED, ConceptType.FUZZY_NUMBER, ConceptType.CONCRETE)
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
def get_atom(self) -> typing.Optional[typing.Self]:
|
|
285
|
+
return self.concepts[0] if self.type == ConceptType.COMPLEMENT else None
|
|
286
|
+
|
|
287
|
+
def get_atoms(self) -> list[typing.Self]:
|
|
288
|
+
if self.type == ConceptType.COMPLEMENT:
|
|
289
|
+
if self.is_complemented_atomic():
|
|
290
|
+
return [self]
|
|
291
|
+
else:
|
|
292
|
+
return self.concepts[0].get_atoms()
|
|
293
|
+
else:
|
|
294
|
+
return list.extend(*[c.get_atoms() for c in self.concepts])
|
|
295
|
+
|
|
296
|
+
def is_simplified(self) -> bool:
|
|
297
|
+
"""
|
|
298
|
+
This function check if current formula is simplified, i.e., if:
|
|
299
|
+
- The only negated elements are literal of kind (~ A), where A is an AtomicProposition
|
|
300
|
+
- The OR operator is between:
|
|
301
|
+
- Two literals => A | B
|
|
302
|
+
- One literal and a AND => A | (B & C) - (A & B) | C
|
|
303
|
+
- Two (or more) OR => (A & B) | (C & D) | (E & F)
|
|
304
|
+
- The AND operator is between:
|
|
305
|
+
- Two literals => A & B
|
|
306
|
+
- One literal and a OR => A & (B | C) - (A | B) & C
|
|
307
|
+
- Two (or more) AND => (A | B) & (C | D) & (E | F)
|
|
308
|
+
- The only operators are AND, OR and NOT
|
|
309
|
+
"""
|
|
310
|
+
if self.is_complemented_atomic():
|
|
311
|
+
return True
|
|
312
|
+
return all(c.type != self.type for c in self.concepts)
|
|
313
|
+
|
|
314
|
+
def de_morgan(self) -> typing.Self:
|
|
315
|
+
self.concepts: Concept = [c.de_morgan() for c in self._concepts]
|
|
316
|
+
if (
|
|
317
|
+
self.type == ConceptType.COMPLEMENT
|
|
318
|
+
and isinstance(self.concepts[0], OperatorConcept)
|
|
319
|
+
and self.concepts[0].type in OperatorConcept.BINARY_OPERATORS
|
|
320
|
+
):
|
|
321
|
+
# ~(A & B) = (~A | ~B)
|
|
322
|
+
# ~(A | B) = (~A & ~B)
|
|
323
|
+
op: ConceptType = OperatorConcept.OPERATORS[self.concepts[0].type]
|
|
324
|
+
concepts: list[Concept] = [
|
|
325
|
+
(-c).de_morgan()
|
|
326
|
+
for c in typing.cast(OperatorConcept, self.concepts[0]).concepts
|
|
327
|
+
]
|
|
328
|
+
return OperatorConcept(op, concepts).de_morgan()
|
|
329
|
+
return self
|
|
330
|
+
|
|
331
|
+
def reduce_truth_values(self) -> typing.Self:
|
|
332
|
+
self.concepts: list[Concept] = [c.reduce_truth_values() for c in self._concepts]
|
|
333
|
+
if self.type == ConceptType.COMPLEMENT and self.concepts[0].type in (
|
|
334
|
+
ConceptType.TOP,
|
|
335
|
+
ConceptType.BOTTOM,
|
|
336
|
+
):
|
|
337
|
+
"""
|
|
338
|
+
~ ⊤ = ⊥
|
|
339
|
+
~ ⊥ = ⊤
|
|
340
|
+
"""
|
|
341
|
+
return -self.concepts[0]
|
|
342
|
+
elif self.type in OperatorConcept.BINARY_OPERATORS:
|
|
343
|
+
"""
|
|
344
|
+
⊤ & ⊤ = ⊤
|
|
345
|
+
⊤ & A = A & ⊤ = A
|
|
346
|
+
|
|
347
|
+
⊥ & ⊤ = ⊥
|
|
348
|
+
⊥ & A = A & ⊥ = ⊥
|
|
349
|
+
|
|
350
|
+
A & ~A = ⊥
|
|
351
|
+
A & A = A
|
|
352
|
+
|
|
353
|
+
⊥ | ⊥ = ⊥
|
|
354
|
+
⊥ | A = A | ⊥ = A
|
|
355
|
+
|
|
356
|
+
⊤ | ⊥ = ⊤
|
|
357
|
+
⊤ | A = A | ⊤ = ⊤
|
|
358
|
+
|
|
359
|
+
A | ~A = ⊤
|
|
360
|
+
A | A = A
|
|
361
|
+
"""
|
|
362
|
+
if OperatorConcept.is_and(self.type):
|
|
363
|
+
if ConceptType.BOTTOM in [c.type for c in self.concepts] or any(
|
|
364
|
+
-c in self.concepts for c in self.concepts
|
|
365
|
+
):
|
|
366
|
+
return TruthConcept.get_bottom()
|
|
367
|
+
if self.type in OperatorConcept.ABSORPTION_OPERATORS:
|
|
368
|
+
self.concepts = sorted(set(self.concepts))
|
|
369
|
+
self.concepts = [c for c in self.concepts if c.type != ConceptType.TOP]
|
|
370
|
+
elif OperatorConcept.is_or(self.type):
|
|
371
|
+
if ConceptType.TOP in [c.type for c in self.concepts] or any(
|
|
372
|
+
-c in self.concepts for c in self.concepts
|
|
373
|
+
):
|
|
374
|
+
return TruthConcept.get_top()
|
|
375
|
+
if self.type in OperatorConcept.ABSORPTION_OPERATORS:
|
|
376
|
+
self.concepts = sorted(set(self.concepts))
|
|
377
|
+
self.concepts = [
|
|
378
|
+
c for c in self.concepts if c.type != ConceptType.BOTTOM
|
|
379
|
+
]
|
|
380
|
+
return self
|
|
381
|
+
|
|
382
|
+
def reduce_double_negation(self) -> typing.Self:
|
|
383
|
+
self.concepts: list[Concept] = [
|
|
384
|
+
c.reduce_double_negation() for c in self._concepts
|
|
385
|
+
]
|
|
386
|
+
# ~(~A) = A
|
|
387
|
+
if self.type == ConceptType.COMPLEMENT:
|
|
388
|
+
if (
|
|
389
|
+
isinstance(self.concepts[0], OperatorConcept)
|
|
390
|
+
and self.concepts[0].type == ConceptType.COMPLEMENT
|
|
391
|
+
):
|
|
392
|
+
return self.concepts[0].concepts[0].reduce_double_negation()
|
|
393
|
+
return self
|
|
394
|
+
|
|
395
|
+
def distribute(self, c_type: ConceptType) -> typing.Self:
|
|
396
|
+
if self.type == ConceptType.COMPLEMENT:
|
|
397
|
+
self.concepts: list[Concept] = [self._concepts[0].distribute(c_type)]
|
|
398
|
+
return self
|
|
399
|
+
|
|
400
|
+
if self.type not in OperatorConcept.DISTRIBUTIVE_OPERATORS:
|
|
401
|
+
return self
|
|
402
|
+
|
|
403
|
+
outer_operator = partial(OperatorConcept.__op, c_type)
|
|
404
|
+
inner_operator = partial(
|
|
405
|
+
OperatorConcept.__op, OperatorConcept.OPERATORS[c_type]
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
self.concepts: list[Concept] = [c.distribute(c_type) for c in self._concepts]
|
|
409
|
+
if self.type == c_type:
|
|
410
|
+
# A & (B | C) = (A & B) | (A & C), where A is literal of DNF clause (A = A_1 & A_2 & ... & A_n)
|
|
411
|
+
# (A | B) & (C | D) = ((A | B) & C) | ((A | B) & D)
|
|
412
|
+
# A | (B & C) = (A | B) & (A | C), where A is literal of CNF clause (A = A_1 | A_2 | ... | A_n)
|
|
413
|
+
# (A & B) | (C & D) = (A & B | C) & (A & B | D)
|
|
414
|
+
# (A | B) & C = (A & C) | (B & C), where C is literal of DNF clause (C = C_1 & C_2 & ... & C_n)
|
|
415
|
+
# (A & B) | C = (A | C) & (B | C), where C is literal of CNF clause (C = C_1 | C_2 | ... | C_n)
|
|
416
|
+
c1: list[OperatorConcept] = [
|
|
417
|
+
c for c in self.concepts if c.type == OperatorConcept.OPERATORS[c_type]
|
|
418
|
+
]
|
|
419
|
+
c2: list[Concept] = [
|
|
420
|
+
c for c in self.concepts if c.type != OperatorConcept.OPERATORS[c_type]
|
|
421
|
+
]
|
|
422
|
+
if len(c1) > 0:
|
|
423
|
+
return inner_operator(
|
|
424
|
+
[outer_operator(c2 + [c]) for ci in c1 for c in ci.concepts]
|
|
425
|
+
)
|
|
426
|
+
return self
|
|
427
|
+
|
|
428
|
+
def reduce_idempotency(self, is_type: typing.Callable) -> typing.Self:
|
|
429
|
+
self.concepts: list[Concept] = [
|
|
430
|
+
c.reduce_idempotency(is_type) for c in self._concepts
|
|
431
|
+
]
|
|
432
|
+
if self.is_complemented_atomic():
|
|
433
|
+
return self
|
|
434
|
+
if self.type in OperatorConcept.ABSORPTION_OPERATORS:
|
|
435
|
+
self.concepts = sorted(set(self.concepts))
|
|
436
|
+
if TruthConcept.get_top() in self.concepts and OperatorConcept.is_or(self.type):
|
|
437
|
+
return TruthConcept.get_top()
|
|
438
|
+
elif TruthConcept.get_bottom() in self.concepts and OperatorConcept.is_and(
|
|
439
|
+
self.type
|
|
440
|
+
):
|
|
441
|
+
return TruthConcept.get_bottom()
|
|
442
|
+
if (
|
|
443
|
+
self.type
|
|
444
|
+
in OperatorConcept.COMPLEMENT_LAW_OPERATORS
|
|
445
|
+
# or constants.KNOWLEDGE_BASE_SEMANTICS == FuzzyLogic.CLASSICAL
|
|
446
|
+
# and (OperatorConcept.is_and(self.type) or OperatorConcept.is_or(self.type))
|
|
447
|
+
):
|
|
448
|
+
if any(-c in self.concepts for c in self.concepts):
|
|
449
|
+
return (
|
|
450
|
+
TruthConcept.get_top()
|
|
451
|
+
if OperatorConcept.is_or(self.type)
|
|
452
|
+
else TruthConcept.get_bottom()
|
|
453
|
+
)
|
|
454
|
+
self.concepts: list[Concept] = sorted(
|
|
455
|
+
[
|
|
456
|
+
a
|
|
457
|
+
for a in self.concepts
|
|
458
|
+
if a not in [TruthConcept.get_bottom(), TruthConcept.get_top()]
|
|
459
|
+
]
|
|
460
|
+
)
|
|
461
|
+
if len(self.concepts) == 1:
|
|
462
|
+
return self.concepts[0]
|
|
463
|
+
return OperatorConcept.__op(self.type, self.concepts)
|
|
464
|
+
|
|
465
|
+
def reduce_quantifiers(self) -> typing.Self:
|
|
466
|
+
self.concepts: list[Concept] = [c.reduce_quantifiers() for c in self._concepts]
|
|
467
|
+
remaining_concepts: list[Concept] = []
|
|
468
|
+
all_groups: dict[str, list[Concept]] = dict()
|
|
469
|
+
some_groups: dict[str, list[Concept]] = dict()
|
|
470
|
+
all_reduced_concepts: list[Concept] = []
|
|
471
|
+
some_reduced_concepts: list[Concept] = []
|
|
472
|
+
for c in self.concepts:
|
|
473
|
+
if c.type not in (ConceptType.ALL, ConceptType.SOME):
|
|
474
|
+
remaining_concepts.append(c)
|
|
475
|
+
continue
|
|
476
|
+
c: AllSomeConcept = typing.cast(AllSomeConcept, c)
|
|
477
|
+
if c.type == ConceptType.ALL:
|
|
478
|
+
all_groups[c.role] = all_groups.get(c.role, []) + [c]
|
|
479
|
+
else:
|
|
480
|
+
some_groups[c.role] = some_groups.get(c.role, []) + [c]
|
|
481
|
+
if (
|
|
482
|
+
self.type in (ConceptType.AND, ConceptType.GOEDEL_AND)
|
|
483
|
+
or constants.KNOWLEDGE_BASE_SEMANTICS == FuzzyLogic.CLASSICAL
|
|
484
|
+
and OperatorConcept.is_and(self.type)
|
|
485
|
+
):
|
|
486
|
+
if (
|
|
487
|
+
constants.KNOWLEDGE_BASE_SEMANTICS == FuzzyLogic.CLASSICAL
|
|
488
|
+
and OperatorConcept.is_and(self.type)
|
|
489
|
+
):
|
|
490
|
+
and_: typing.Callable = OperatorConcept.and_
|
|
491
|
+
else:
|
|
492
|
+
and_: typing.Callable = OperatorConcept.goedel_and
|
|
493
|
+
for role in all_groups:
|
|
494
|
+
curr_concepts: list[AllSomeConcept] = all_groups[role]
|
|
495
|
+
if len(curr_concepts) == 1:
|
|
496
|
+
remaining_concepts.extend(curr_concepts)
|
|
497
|
+
continue
|
|
498
|
+
all_reduced_concepts.append(
|
|
499
|
+
AllSomeConcept.all(
|
|
500
|
+
role, and_(*[c.curr_concept for c in curr_concepts])
|
|
501
|
+
)
|
|
502
|
+
)
|
|
503
|
+
for role in some_groups:
|
|
504
|
+
curr_concepts: list[AllSomeConcept] = some_groups[role]
|
|
505
|
+
if len(curr_concepts) == 1:
|
|
506
|
+
remaining_concepts.extend(curr_concepts)
|
|
507
|
+
continue
|
|
508
|
+
some_reduced_concepts.extend(
|
|
509
|
+
[
|
|
510
|
+
AllSomeConcept.some(role, c.curr_concept)
|
|
511
|
+
for c in curr_concepts
|
|
512
|
+
if c.curr_concept.type != ConceptType.TOP
|
|
513
|
+
]
|
|
514
|
+
)
|
|
515
|
+
return OperatorConcept.__op(
|
|
516
|
+
self.type,
|
|
517
|
+
remaining_concepts + all_reduced_concepts + some_reduced_concepts,
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
if self.type not in (ConceptType.OR, ConceptType.GOEDEL_OR) and (
|
|
521
|
+
constants.KNOWLEDGE_BASE_SEMANTICS != FuzzyLogic.CLASSICAL
|
|
522
|
+
or not OperatorConcept.is_or(self.type)
|
|
523
|
+
):
|
|
524
|
+
return self
|
|
525
|
+
if (
|
|
526
|
+
constants.KNOWLEDGE_BASE_SEMANTICS == FuzzyLogic.CLASSICAL
|
|
527
|
+
and OperatorConcept.is_or(self.type)
|
|
528
|
+
):
|
|
529
|
+
or_: typing.Callable = OperatorConcept.or_
|
|
530
|
+
else:
|
|
531
|
+
or_: typing.Callable = OperatorConcept.goedel_or
|
|
532
|
+
|
|
533
|
+
for role in all_groups:
|
|
534
|
+
remaining_concepts.extend(all_groups[role])
|
|
535
|
+
|
|
536
|
+
some_reduced_concepts = []
|
|
537
|
+
for role in some_groups:
|
|
538
|
+
curr_concepts: list[AllSomeConcept] = some_groups[role]
|
|
539
|
+
if len(curr_concepts) == 1:
|
|
540
|
+
remaining_concepts.extend(curr_concepts)
|
|
541
|
+
continue
|
|
542
|
+
some_reduced_concepts.append(
|
|
543
|
+
AllSomeConcept.some(role, or_(*[c.curr_concept for c in curr_concepts]))
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
return OperatorConcept.__op(
|
|
547
|
+
self.type,
|
|
548
|
+
remaining_concepts + all_reduced_concepts + some_reduced_concepts,
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
def normal_form(self, is_type: typing.Callable) -> typing.Self:
|
|
552
|
+
c_type: ConceptType = next(
|
|
553
|
+
filter(
|
|
554
|
+
is_type,
|
|
555
|
+
OperatorConcept.BINARY_OPERATORS,
|
|
556
|
+
)
|
|
557
|
+
)
|
|
558
|
+
while True:
|
|
559
|
+
self: Concept = self.de_morgan()
|
|
560
|
+
self: Concept = self.reduce_double_negation()
|
|
561
|
+
self: Concept = self.distribute(c_type)
|
|
562
|
+
self: Concept = self.reduce_idempotency(is_type)
|
|
563
|
+
self: Concept = self.reduce_truth_values()
|
|
564
|
+
self: Concept = self.reduce_quantifiers()
|
|
565
|
+
if self.is_simplified():
|
|
566
|
+
break
|
|
567
|
+
return self
|
|
568
|
+
|
|
569
|
+
def get_clauses(self, is_type: typing.Callable) -> list[Concept]:
|
|
570
|
+
if self.type == ConceptType.COMPLEMENT:
|
|
571
|
+
return [self]
|
|
572
|
+
return self.concepts
|
|
573
|
+
|
|
574
|
+
def replace(self, a: Concept, c: Concept) -> Concept:
|
|
575
|
+
c_type: ConceptType = c.type
|
|
576
|
+
replaced_concepts: list[Concept] = [ci.replace(a, c) for ci in self.concepts]
|
|
577
|
+
if c_type == ConceptType.AND:
|
|
578
|
+
return OperatorConcept.and_(replaced_concepts)
|
|
579
|
+
elif c_type == ConceptType.GOEDEL_AND:
|
|
580
|
+
return OperatorConcept.goedel_and(replaced_concepts)
|
|
581
|
+
elif c_type == ConceptType.LUKASIEWICZ_AND:
|
|
582
|
+
return OperatorConcept.lukasiewicz_and(replaced_concepts)
|
|
583
|
+
if c_type == ConceptType.OR:
|
|
584
|
+
return OperatorConcept.or_(replaced_concepts)
|
|
585
|
+
elif c_type == ConceptType.GOEDEL_AND:
|
|
586
|
+
return OperatorConcept.goedel_or(replaced_concepts)
|
|
587
|
+
elif c_type == ConceptType.LUKASIEWICZ_AND:
|
|
588
|
+
return OperatorConcept.lukasiewicz_or(replaced_concepts)
|
|
589
|
+
elif c_type == ConceptType.COMPLEMENT:
|
|
590
|
+
if self.concepts[0] == a:
|
|
591
|
+
return -c
|
|
592
|
+
return self
|
|
593
|
+
|
|
594
|
+
def compute_name(self) -> typing.Optional[str]:
|
|
595
|
+
concepts: str = " ".join(map(str, self.concepts))
|
|
596
|
+
if self.type == ConceptType.AND:
|
|
597
|
+
return f"(and {concepts})"
|
|
598
|
+
elif self.type == ConceptType.GOEDEL_AND:
|
|
599
|
+
return f"(g-and {concepts})"
|
|
600
|
+
elif self.type == ConceptType.LUKASIEWICZ_AND:
|
|
601
|
+
return f"(l-and {concepts})"
|
|
602
|
+
elif self.type == ConceptType.OR:
|
|
603
|
+
return f"(or {concepts})"
|
|
604
|
+
elif self.type == ConceptType.GOEDEL_OR:
|
|
605
|
+
return f"(g-or {concepts})"
|
|
606
|
+
elif self.type == ConceptType.LUKASIEWICZ_OR:
|
|
607
|
+
return f"(l-or {concepts})"
|
|
608
|
+
elif self.type == ConceptType.COMPLEMENT:
|
|
609
|
+
return f"(not {concepts})"
|
|
610
|
+
|
|
611
|
+
def compute_atomic_concepts(self) -> set[Concept]:
|
|
612
|
+
result: set[Concept] = set()
|
|
613
|
+
for c in self.concepts:
|
|
614
|
+
result.update(c.compute_atomic_concepts())
|
|
615
|
+
return result
|
|
616
|
+
|
|
617
|
+
def get_roles(self) -> set[str]:
|
|
618
|
+
return set().union(*[c.get_roles() for c in self.concepts])
|
|
619
|
+
|
|
620
|
+
def __neg__(self) -> Concept:
|
|
621
|
+
concepts: list[Concept] = [-ci for ci in self.concepts]
|
|
622
|
+
if self.type == ConceptType.AND:
|
|
623
|
+
return OperatorConcept.or_(*concepts)
|
|
624
|
+
elif self.type == ConceptType.GOEDEL_AND:
|
|
625
|
+
return OperatorConcept.goedel_or(*concepts)
|
|
626
|
+
elif self.type == ConceptType.LUKASIEWICZ_AND:
|
|
627
|
+
return OperatorConcept.lukasiewicz_or(*concepts)
|
|
628
|
+
elif self.type == ConceptType.OR:
|
|
629
|
+
return OperatorConcept.and_(*concepts)
|
|
630
|
+
elif self.type == ConceptType.GOEDEL_OR:
|
|
631
|
+
return OperatorConcept.goedel_and(*concepts)
|
|
632
|
+
elif self.type == ConceptType.LUKASIEWICZ_OR:
|
|
633
|
+
return OperatorConcept.lukasiewicz_and(*concepts)
|
|
634
|
+
elif self.type == ConceptType.COMPLEMENT:
|
|
635
|
+
return self.concepts[0]
|
|
636
|
+
raise NotImplementedError
|
|
637
|
+
|
|
638
|
+
def __and__(self, value: typing.Self) -> typing.Self:
|
|
639
|
+
if OperatorConcept.is_and(self.type):
|
|
640
|
+
return OperatorConcept.__op(self.type, [self, value])
|
|
641
|
+
elif OperatorConcept.is_or(self.type):
|
|
642
|
+
return OperatorConcept.__op(
|
|
643
|
+
OperatorConcept.OPERATORS[self.type], [self, value]
|
|
644
|
+
)
|
|
645
|
+
return OperatorConcept.and_([self, value])
|
|
646
|
+
|
|
647
|
+
def __or__(self, value: typing.Self) -> typing.Self:
|
|
648
|
+
if OperatorConcept.is_or(self.type):
|
|
649
|
+
return OperatorConcept.__op(self.type, [self, value])
|
|
650
|
+
elif OperatorConcept.is_and(self.type):
|
|
651
|
+
return OperatorConcept.__op(
|
|
652
|
+
OperatorConcept.OPERATORS[self.type], [self, value]
|
|
653
|
+
)
|
|
654
|
+
return OperatorConcept.or_([self, value])
|
|
655
|
+
|
|
656
|
+
def __eq__(self, value: typing.Self) -> bool:
|
|
657
|
+
return isinstance(value, OperatorConcept) and str(self) == str(value)
|
|
658
|
+
|
|
659
|
+
def __ne__(self, value: typing.Self) -> bool:
|
|
660
|
+
return not (self == value)
|
|
661
|
+
|
|
662
|
+
def __hash__(self) -> int:
|
|
663
|
+
return hash(str(self))
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
# class Not(OperatorConcept):
|
|
667
|
+
# def __call__(self, *args) -> typing.Self:
|
|
668
|
+
# return OperatorConcept.not_(args)
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
# class And(OperatorConcept):
|
|
672
|
+
# def __call__(self, *args) -> typing.Self:
|
|
673
|
+
# return OperatorConcept.and_(args)
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
# class GoedelAnd(OperatorConcept):
|
|
677
|
+
# def __call__(self, *args) -> typing.Self:
|
|
678
|
+
# return OperatorConcept.goedel_and(args)
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
# class LukasiewiczAnd(OperatorConcept):
|
|
682
|
+
# def __call__(self, *args) -> typing.Self:
|
|
683
|
+
# return OperatorConcept.lukasiewicz_and(args)
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
# class Or(OperatorConcept):
|
|
687
|
+
# def __call__(self, *args) -> typing.Self:
|
|
688
|
+
# return OperatorConcept.or_(args)
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
# class GoedelOr(OperatorConcept):
|
|
692
|
+
# def __call__(self, *args) -> typing.Self:
|
|
693
|
+
# return OperatorConcept.goedel_or(args)
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
# class LukasiewiczOr(OperatorConcept):
|
|
697
|
+
# def __call__(self, *args) -> typing.Self:
|
|
698
|
+
# return OperatorConcept.lukasiewicz_or(args)
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
Not = OperatorConcept.not_
|
|
702
|
+
And = OperatorConcept.and_
|
|
703
|
+
GoedelAnd = OperatorConcept.goedel_and
|
|
704
|
+
LukasiewiczAnd = OperatorConcept.lukasiewicz_and
|
|
705
|
+
Or = OperatorConcept.or_
|
|
706
|
+
GoedelOr = OperatorConcept.goedel_or
|
|
707
|
+
LukasiewiczOr = OperatorConcept.lukasiewicz_or
|