Mixing Python, OWL, SWRL and Reasoning

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Mixing Python, OWL, SWRL and Reasoning

cknoll
Hello,

on [1] https://owlready2.readthedocs.io/en/latest/mixing_python_owl.html it is documented how to mix Python and OWL.

I think this is already very useful, but I want to to a step further: I want to reason over SWRL rules which evaluate data_properties which are defined by (simple) Python methods.


To demonstrate what I want I adapted the example from [1]: I added a class "ExpensiveDrug" and a SWRL rule which should classify a Drug as expensive depending on the return value of get_per_tablet_cost.


However I cannot construct the rule that way. I get  ValueError: Cannot find entity 'get_per_tablet_cost'!

Is it even possible to do what I want (i.e. software defined data properties)?


from owlready2 import *
onto = get_ontology("http://test.org/onto.owl")


with onto:
    class Drug(Thing):
        def get_per_tablet_cost(self):
            return self.cost / self.number_of_tablets

    class has_for_cost(Drug >> float, FunctionalProperty):
        python_name = "cost"

    class has_for_number_of_tablets(Drug >> int, FunctionalProperty):
        python_name = "number_of_tablets"
       
    class ExpensiveDrug(Drug):
        pass

my_drug1 = Drug(cost=10.0, number_of_tablets=5)
my_drug2 = Drug(cost=500.0, number_of_tablets=5)
print(my_drug1.get_per_tablet_cost()) # -> 2
print(my_drug2.get_per_tablet_cost()) # -> 100

with onto:
    rule = Imp()
    rule.set_as_rule(
        "Drug(?d), get_per_tablet_cost(?d, ?c), greaterThanOrEqual(?c, 10) -> ExpensiveDrug(?d)"
    )


Best,
Carsten
Reply | Threaded
Open this post in threaded view
|

Re: Mixing Python, OWL, SWRL and Reasoning

felix
Hi Carsten,

just my 2 cents, I might be wrong here tho:
a rule is specified using a string of a valid SWRL rule. i.e., it is not possible to evaluate a python function within the SWRL rule, simply because the reasoner is unable to do so.
in your example, what you intended to be a function call "get_per_tablet_cost" is interpreted as an entity, which cannot be found within the ontology

instead, you could use two separate SWRL rules. as a nice side effect, this also increases cohesion:
1. Insert costs per tablet into the ontology, see https://owlready2.readthedocs.io/en/latest/rule.html: 'Drug(?d), price(?d, ?p), number_of_tablets(?d, ?n), divide(?r, ?p, ?n) -> price_per_tablet(?d, ?r)'
2. Classification regarding the class "ExpensiveDrug" depending on the price: 'Drug(?d), price_per_tablet(?d, ?p), greaterThanOrEqual(?p, 10) -> ExpensiveDrug(?d)'
if there is a large number of rules, it may make sense to generate the SWRL strings using python functions defined within the respective classes. for this, mixing python and owl will probably come in real handy

Best,
Felix
Reply | Threaded
Open this post in threaded view
|

Re: Mixing Python, OWL, SWRL and Reasoning

cknoll
Hi Felix,

thank you for your quick reply. I already suspected that the reasoner is not able to directly execute Python code. On the other hand it would not surprise me if there is a possibility to somehow sneak in a "callback-mechanism".

Your solution works for the presented example. However, I want to perform some more sophisticated calculations than mere arithmetic (say, calculating roots of polynomials etc.). I think that this will not be possible with pure SWRL but would be quite simple in Python code. At the end from the reasoners point of view it should not make too much difference, between calling a builtin function like "divide" or calling an external function. I might however be a technical challenge and break decidability (if one does not restrict the content of those external functions).

Anyway, your solution gave me the idea to run Python code and the reasoner alternately.

Best,
Carsten
Reply | Threaded
Open this post in threaded view
|

Re: Mixing Python, OWL, SWRL and Reasoning

Jiba
Administrator
In reply to this post by cknoll
Hello,

As you guessed, it is not possible to call Python from the SWRL rule interpreted by the Java reasoner. Having a callback system would be very difficult to set up, especially between Java and Python.

The easier solution is to compute all per-tablet cost before calling the reasoner and to store the value in a dataproperty.

Jiba