Usage
In this section, we will see how to use the FuzzyDL reasoner to query a knowledge base defined in the FDL language, and how to translate between FDL and OWL 2 ontologies. We will define a knowledge base in an FDL file, and then we will use the DLParser class to parse the file and execute the queries defined in it. We will also see how to translate an FDL knowledge base into an OWL 2 ontology, and vice versa.
Setting up the CONFIG.ini file
Before running the examples, make sure to set up the CONFIG.ini file in the root directory of the project. This file contains configuration settings for the FuzzyDL reasoner, such as the debug print option, the epsilon value for numerical comparisons, the maximum number of individuals to consider in reasoning, and the label used for OWL annotations. You can adjust these settings according to your needs. For example, you can set debugPrint to True to enable debug output, or set maxIndividuals to a specific number to limit the number of individuals considered in reasoning.
Sample CONFIG.ini file:
[DEFAULT]
debugPrint = False
epsilon = 0.001
maxIndividuals = -1
owlAnnotationLabel = fuzzyLabel
milpProvider = mip
Reasoning
In this section, we will see how to use the FuzzyDL reasoner to query a knowledge base defined in the FDL language. We will define a knowledge base in an FDL file, and then we will use the DLParser class to parse the file and execute the queries defined in it.
Knowledge base in example.fdl
In the following example, we define a knowledge base in the FDL language, which includes concepts, modifiers, and instances. We then query the knowledge base to determine the membership degree of specific instances with respect to a complex concept.
Specifically, we define a fuzzy logic (Łukasiewicz), a linear modifier very, crisp concepts for speed, a crisp concept eq243 with a crisp value of \(243\), a crisp concept geq300 with a crisp interval in \([300, 400]\), a fuzzy concept High with a right shoulder function in \([180, 250]\), and a modified concept VeryHigh.
We then define a complex concept SportCar that combines the concept of Car with the condition that its speed is VeryHigh.
Finally, we create two instances of Car with different speeds and query their membership degrees with respect to the SportCar concept.
The instances audi and ferrari will have different membership degrees to the SportCar concept based on their defined speeds and the modifiers applied to the High concept. The queries will return the membership degrees, which indicate how well each instance fits the definition of a SportCar.
# Defining the logic to be used in the knowledge base, in this case, we are using the Łukasiewicz fuzzy logic.
(define-fuzzy-logic lukasiewicz)
# Defining a linear modifier "very" with a parameter of 0.8, which will be used to modify the membership degree of concepts.
(define-modifier very linear-modifier(0.8))
# Defining crisp concepts for speed with specific values
(define-fuzzy-concept eq243 crisp(0, 400, 243, 243))
(define-fuzzy-concept geq300 crisp(0, 400, 300, 400))
# Defining a fuzzy concept for speed with a right shoulder function, where the membership degree starts to increase from 180, reaches 1 at 250, and remains 1 afterwards.
(define-fuzzy-concept High right-shoulder(0, 400, 180, 250))
# Defining a modified concept "VeryHigh" by applying "very" to "High".
(define-fuzzy-concept VeryHigh modified(very, High))
# Defining the complex concept "SportCar" as a Car with a speed that is "VeryHigh".
(define-concept SportCar (and Car (some speed VeryHigh)))
# Defining two instances of Car with different speeds.
(instance ferrari (and Car (some speed geq300)) 1)
(instance audi (and Car (some speed eq243)) 1)
# What is the membership degree of "audi" with respect to the concept "SportCar"?
(min-instance? audi SportCar)
# What is the membership degree of "ferrari" with respect to the concept "SportCar"?
(min-instance? ferrari SportCar)
Python code with the main function
In this case, the main function will parse the knowledge base and execute the query, printing the result in the log output.
The log output will be written in a file in the subdirectory ./logs/reasoner/CURRENT_YEAR/CURRENT_MONTH/CURRENT_DAY/ with a name that includes the time of the execution, for example fuzzydl_HH-MM-SS.log.
from fuzzy_dl_owl2.fuzzydl.parser import DLParser
DLParser.main("./example.fdl")
# "Is audi instance of SportCar ? >= 0.92"
# "Is ferrari instance of SportCar ? >= 1.0"
An example of the log output is given below, where DATETIME is the date and time of the execution.
DATETIME - INFO -- Knowledge Base parsed in 0.015450833s
DATETIME - INFO -- Using Python-MIP package version 1.16rc0
DATETIME - INFO -- Is audi instance of SportCar? >= 0.92
DATETIME - INFO -- Time (s): 0.171397584
DATETIME - INFO -- Is ferrari instance of SportCar? >= 1.0
DATETIME - INFO -- Time (s): 0.004942084
Python code with more control on the output
In this case, the parser will parse the knowledge base and execute the query, but it will not print the result in the log output. Instead, it will return a Solution object that contains the result of the query, which can be printed in a more readable format. The Solution object has a method is_consistent_kb() that checks if the knowledge base is consistent, and a __str__() method that returns a string representation of the solution, which includes the membership degree of the instance with respect to the concept.
from fuzzy_dl_owl2.fuzzydl.parser import DLParser
from fuzzy_dl_owl2.fuzzydl.milp.solution import Solution
kb, queries = DLParser.get_kb("./example.fdl") # parse the knowledge base and get the queries
kb.solve_kb() # solve the knowledge base to check for consistency and prepare for answering queries
# Execute the queries and print the results
for query in queries:
# Execute the query and get the result as a Solution object
result: Solution = query.solve(kb)
# Check if the knowledge base is consistent before printing the result
if not result.is_consistent_kb():
continue
# Print the query and the result in a readable format
print(f"{query}{result}")
# Is audi instance of SportCar ? >= 0.92
# Is ferrari instance of SportCar ? >= 1.0
Fuzzy OWL 2
From *.fdl to *.owl
In this example, the example.fdl file will be parsed and translated into an OWL 2 ontology, which will be saved in the subdirectory ./results/ with the name example.owl. The resulting OWL 2 ontology will contain the same knowledge base as the original FDL file, but in a format that can be used with OWL 2 reasoners.
from fuzzy_dl_owl2.fuzzydl.fuzzydl_to_owl2 import FuzzydlToOwl2
# The FuzzydlToOwl2 class is used to translate an FDL knowledge base into an OWL 2 ontology. The constructor takes two arguments: the path to the input FDL file and the path to the output OWL file. The run() method performs the translation and saves the resulting OWL ontology in the specified location.
fdl = FuzzydlToOwl2("./example.fdl", "example.owl")
fdl.run() # save example.owl in the subdirectory "./results"
From *.owl to *.fdl
In this example, the example.owl file will be parsed and translated into an FDL knowledge base, which will be saved in the subdirectory ./results/ with the name example.fdl. The resulting FDL knowledge base will contain the same knowledge as the original OWL 2 ontology, but in a format that can be used with FDL reasoners.
from fuzzy_dl_owl2.fuzzyowl2.fuzzyowl2_to_fuzzydl import FuzzyOwl2ToFuzzyDL
# The FuzzyOwl2ToFuzzyDL class is used to translate an OWL 2 ontology into an FDL knowledge base. The constructor takes two arguments: the path to the input OWL file and the path to the output FDL file. The translate_owl2ontology() method performs the translation and saves the resulting FDL knowledge base in the specified location.
fdl = FuzzyOwl2ToFuzzyDL("./results/example.owl", "example.fdl")
fdl.translate_owl2ontology() # save example.fdl in the subdirectory "./results"