SWRL rules logic confusion

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

SWRL rules logic confusion

Bluer
Hi everyone,

I've made over a dozen sets of SWRL rules now and still don't seem to completely understand what makes them work in some places and not in others. In the past I've sought help from here and solved problems regarding fake IRIs from Protege and now I seem to have cases where only slightly different rules suddenly don't work anymore and it's making me want to give up completely if I can't seem to get an intuition for them.

Anyway, here's the first problem:

I have rules made for certain assessment of patients with scores, so I'm using classes with conditions, ranges, and scores as a consequence, like so:

   news_spo2_rule = [
        f"""{patient.iri}(?p), {hypercapnic_resp_failure_class.iri}(?c), {has_not_condition.iri}(?p, ?c) -> {has_news_spo2_score.iri}(?p, 0)""",

        f"""{patient.iri}(?p), {hypercapnic_resp_failure_class.iri}(?c), {has_condition.iri}(?p, ?c),
            {spo2_class.iri}(?a), {has_assessment.iri}(?p, ?a), {has_value.iri}(?a, ?n), lessThan(?n, 84) -> {has_news_spo2_score.iri}(?p, 3)""",

...]

There's also a summing rule for different scores together:

    news_rule = [
        f"""{patient.iri}(?p), {has_news_resp_rate_score.iri}(?p, ?n1), {has_news_spo2_score.iri}(?p, ?n2), {has_news_air_or_oxygen_score.iri}(?p, ?n3),
            {has_news_systolic_blood_pressure_score.iri}(?p, ?n4), {has_news_pulse_score.iri}(?p, ?n5), {has_news_consciousness_score.iri}(?p, ?n6),
            {has_news_temperature_score.iri}(?p, ?n7), add(?nt, ?n1, ?n2, ?n3, ?n4, ?n5, ?n6, ?n7) -> {has_news_total_score.iri}(?p, ?nt)"""
    ]

There are more rules for more ranges and scores applied, and different sets of rules for different parts of the overall asessment(featured below). Every rule except the first one works for my test patients. The below patient (COPH.patient2) is tested to trigger from having the hypercapnic_resp_failure_class appended to hasCondition as a property and be within one of the ranges I set for hasNEWSSpO2Scale2Score to be 3, and then that score added up with other sets of rules and scores into a summing and totalling rule for the total score:

This works fine with COPH.Patient 2:

* Owlready * Adding relation COPH.patient2 hasNEWSTotalScore 15
* Owlready * Adding relation COPH.patient2 hasNEWSRespirationsScore 3.0
* Owlready * Adding relation COPH.patient2 hasNEWSAirOrOxygenScore 2.0
* Owlready * Adding relation COPH.patient2 hasNEWSSpO2Scale2Score 3.0
* Owlready * Adding relation COPH.patient2 hasNEWSConsciousnessScore 3.0
* Owlready * Adding relation COPH.patient2 hasNEWSSystolicBloodPressureScore 1.0
* Owlready * Adding relation COPH.patient2 hasNEWSPulseScore 3.0
* Owlready * Adding relation COPH.patient2 hasNEWSTemperatureScore 0.0

But COPH.patient3 ends up with a score of 0 for hasNEWSSpO2Scale2Score, triggering the rule for has_not_condition on hypercapnic_resp_failure_class, and then for some reason the hasNEWSTotalScore does not like it and doesn't summarise:

* Owlready * Adding relation COPH.patient3 hasNEWSRespirationsScore 2.0
* Owlready * Adding relation COPH.patient3 hasNEWSAirOrOxygenScore 0.0
* Owlready * Adding relation COPH.patient3 hasNEWSSpO2Scale2Score 0.0
* Owlready * Adding relation COPH.patient3 hasNEWSConsciousnessScore 3.0
* Owlready * Adding relation COPH.patient3 hasNEWSSystolicBloodPressureScore 0.0
* Owlready * Adding relation COPH.patient3 hasNEWSPulseScore 1.0
* Owlready * Adding relation COPH.patient3 hasNEWSTemperatureScore 0.0

The second problem is that I've also made alert rules that are supposed to be triggered to be created based on the hasNEWSTotalScore, but in none of my tests has this been triggered at all:

   
    news_alerts_rule = [
        f"""{patient.iri}(?p), {has_news_total_score.iri}(?p, ?s), lessThan(?s, 2), {alert_grade_one.iri}(?a), {news_total.iri}(?t) -> {has_alert.iri}(?p, ?a), {has_trigger.iri}(?a, ?t), {has_value.iri}(?t, ?s)""",
        f"""{patient.iri}(?p), {has_news_total_score.iri}(?p, ?s), greaterThan(?s, 2), lessThan(?s, 7), {alert_grade_two.iri}(?a), {news_total.iri}(?t) ->  {has_alert.iri}(?p, ?a), {has_trigger.iri}(?a, ?t), {has_value.iri}(?t, ?s)""",
        f"""{patient.iri}(?p), {has_news_total_score.iri}(?p, ?s), greaterThan(?s, 6), {alert_grade_three.iri}(?a), {news_total.iri}(?t) -> {has_alert.iri}(?p, ?a), {has_trigger.iri}(?a, ?t), {has_value.iri}(?t, ?s)"""
    ]

Could these be datatype issues? I have no idea what else could cause this, but I've looked all through the documentation I could find and forum answers to no avail.

Thanks in advance

Bluer
Reply | Threaded
Open this post in threaded view
|

Re: SWRL rules logic confusion

Jiba
Administrator
Hi,

I've read your rules, and they seem correct. I think you should try to simplify the rules in order to identify where is the problem. For example, you can remove one or more score in the sum, and see whether it works after the removal, in order to identify the problematic member of the sum.

You should also try to run the reasoner several times -- Pellet is not exempt of bug especially when using SWRL.

Finally, do you have tried to test patient3 without having patient2? There might be some conflict?

Jiba
Reply | Threaded
Open this post in threaded view
|

Re: SWRL rules logic confusion

Bluer
Hi Jiba,

Thanks for the reply! I've spent some time playing with it more and it turns out adding an additional run after everything gives the extra total score I'm after  So it does seem like a Pellet issue.

The only thing that isn't seeming to work still is the alert rules. I've tried to build up from scratch to see at what point it breaks again and as soon as I use a class it won't work.

"""
with onto:
    news_super = onto.search_one(iri="http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C171356")
    class NEWS2Result(news_super):
        pass
"""

As an example, I created the above class (or preferably wanted to use one already in my OWL ontology but it didn't like that either, despite me making sure the fake IRI issue isn't a thing) and then used it in this:

"""
    news_alerts_rule = [
        f"""{patient.iri}(?p), {has_news_total_score.iri}(?p, ?s), greaterThan(?s, 6), NEWS2Result(?t) -> {has_cat_1_score.iri}(?p, 8)""",...
"""

(the has_cat_1_score is just anything I knew that worked that I could use to test the consequence happened).

Unfortunately this above isn't working, but it worked without the NEWS2Result.

The only thing I've been able to speculate is that it needs an instance/individual of NEWS2Result, or anything else I try to use, to already exist, and it can't create a new instance in the consequence but only relationships. Is this true, or is there some other setup I need to get it working?

Daniel
Reply | Threaded
Open this post in threaded view
|

Re: SWRL rules logic confusion

Jiba
Administrator
Hi,

I'm not sure I fully understand your problem, but "NEWS2Result(?t)" indeed requires that an instance of NEWS2Result exists. In your rule example, is seems weird because the variable ?t is not used elsewhere in the rule.

If your ontology has no instances of NEWS2Result, the rule cannot trigger.

Jiba
Reply | Threaded
Open this post in threaded view
|

Re: SWRL rules logic confusion

Bluer
Hi Jiba,

I only included NEWS2Result like that as a test for if it broke there or not, rather than it being a genuine rule I use.

Apologies for the confusion regarding instance existence and the rules. To give proper context, what I originally was hoping for was being able to create instances as a consequence (as in only if I need them), but needing an instance in the first place makes it a bit of a heavier solution that I need if I want something dynamic for new data (needing all of the instances already made regardless of if I'll be using them for a relationship). I'm sure I'll figure something out. For now I'm just glad we have my confusion resolved.

Thanks again.

Daniel