- From: Jos De Roo <josderoo@gmail.com>
- Date: Wed, 15 Dec 2021 20:16:19 +0100
- To: William Van Woensel <william.vanwoensel@gmail.com>
- Cc: "public-n3-dev@w3.org" <public-n3-dev@w3.org>
- Message-ID: <CAJbsTZcZs5y-c4XUaNvh_N_4FFuY_hqkKr3OZu83tgJafWg4Wg@mail.gmail.com>
Thank you very much William, your approach hinted us to make log:collectAllIn premis order independent in https://github.com/josd/eye/releases/tag/v21.1215.1908 So when you could install that version, http://ppr.cs.dal.ca:3002/n3/editor/s/Io4Pby3y should then give :cmp1 :empty1 :true. :cmp1 :empty2 :true. :cmp1 :empty3 :true. :cmp1 :empty4 :true. :cmp1 :empty5 :true. :cmp1 :empty6 :true. So now we might declare victory :-) Kind regards, Jos -- https://josd.github.io On Wed, Dec 15, 2021 at 3:52 PM William Van Woensel < william.vanwoensel@gmail.com> wrote: > Rather miraculously, a rule like > > > > :cmp0 a :task. > > :cmp1 a :task. > > > > :cmp0 :subTask :task99. > > > > {(?task {?x :subTask ?task.} ?ys) log:collectAllIn <> . ?x a :task. ?ys > log:equalTo ().} > > => { ?x :empty1 :true }. > > > > Works in jen3 because of its particular clause ordering – clauses with > “universals” (such as log:collectAllIn) are pushed to the very back of the > rule body, unless there’s a clause with (some) terms that are not yet > bound: for a triple pattern, all s/p/o need to be bound; for a builtin > clause, it depends on the particular builtin whether s, o, or both need to > be bound. > > > > For instance, in the case of the rule above, this ordering is: > > > > “?x a :task.” “?ys log:equalTo ()” “{(?task {?x :subTask ?task.} ?ys) > log:collectAllIn <>” > > > > Re the log:equalTo builtin in the second clause: it only requires one of > its arguments to be bound (“?ys” will be bound to the empty list) so it is > not pushed back. E.g., the builtin log:notEqualTo would require all its > arguments to be bound. But, the universal is pushed to the back of the rule > body. > > > > In more detail: > > > > if current variable bindings *do not* match the builtin’s domain, then: > > do not delay this clause (priority 0) (we want this clause to fail as > quick as possible) > > > > if current variable bindings *do* match the builtin’s domain, then: > > if *not all* required terms are bound, then: > > delay this clause as long as possible (priority -2) > > if *all* required terms are bound, then: > > if the builtin is a “universal”, then: > > delay (priority -1) > > else, then: > > do not delay (priority 0) > > > > (e.g., the domain for math:sum would require a subject to be a concrete > list with numbers, and an object that is either numeric or unbound) > > > > The reasoning behind this delay for universal builtins (e.g., > log:collectAllIn) is that we want any co-referring variable, i.e., that > also occurs in other rule premises (in this case, “?x”), to be bound before > the universal builtin is executed. Else, log:collectAllIn will simply > iterate over all “x’s” with a :subTask relation, and it will be unclear > what “?x” in the other premise (and rule conclusion) is referring to. > > > > This is a very straightforward heuristic and I’m sure this will fail in > some cases, but it seems to work for the cases I’ve considered until now. > > > > > > W > > > > *From: *Jos De Roo <josderoo@gmail.com> > *Date: *Wednesday, December 15, 2021 at 9:38 AM > *To: *William Van Woensel <william.vanwoensel@gmail.com> > *Cc: *public-n3-dev@w3.org <public-n3-dev@w3.org> > *Subject: *Re: FW: Discussion on log:notIncludes > > Was declaring victory for http://ppr.cs.dal.ca:3002/n3/editor/s/0HrLHpgS too > early .. > > There is still an issue with premis order dependency as none of the > following gives an answer: > > > > {?Scope e:findall (?task {?x :subTask ?task.} ?ys). ?x a :task. ?ys > log:equalTo ().} => { ?x :empty1 :true }. > {?Scope e:find (?task {?x :subTask ?task.} ?ys). ?x a :task. ?ys > log:equalTo ().} => { ?x :empty2 :true }. > {(?task {?x :subTask ?task.} ?ys) log:collectAllIn ?Scope. ?x a :task. ?ys > log:equalTo ().} => { ?x :empty3 :true }. > > {?Scope e:findall (?task {?x :subTask ?task.} ?ys). ?ys log:equalTo (). ?x > a :task.} => { ?x :empty1 :true }. > {?Scope e:find (?task {?x :subTask ?task.} ?ys). ?ys log:equalTo (). ?x a > :task.} => { ?x :empty2 :true }. > {(?task {?x :subTask ?task.} ?ys) log:collectAllIn ?Scope. ?ys log:equalTo > (). ?x a :task.} => { ?x :empty3 :true }. > > {?ys log:equalTo (). ?Scope e:findall (?task {?x :subTask ?task.} ?ys). ?x > a :task.} => { ?x :empty1 :true }. > {?ys log:equalTo (). ?Scope e:find (?task {?x :subTask ?task.} ?ys). ?x a > :task.} => { ?x :empty2 :true }. > {?ys log:equalTo (). (?task {?x :subTask ?task.} ?ys) log:collectAllIn > ?Scope. ?x a :task.} => { ?x :empty3 :true }. > > > > For the moment I see only one solution which is with log:notIncludes and > bind all the variables in its object > > via extra :subTask declarations like in > http://ppr.cs.dal.ca:3002/n3/editor/s/fCR2HSVh > > That gives the expected answer > > :cmp1 :empty :true. > > > > Kind regards, > > Jos > > > -- https://josd.github.io > > > > > > On Mon, Dec 13, 2021 at 8:15 PM Jos De Roo <josderoo@gmail.com> wrote: > > Doerthe was testing alternative SNAF ways in > http://ppr.cs.dal.ca:3002/n3/editor/s/0HrLHpgS > > but there is an issue with e:find which is now solved in > https://github.com/josd/eye/releases/tag/v21.1213.1906 > > So if William could do an upgrade, the results should then be > > > > :cmp1 :empty1 :true. > :cmp1 :empty2 :true. > :cmp1 :empty3 :true. > :cmp1 :empty4 :true. > :cmp1 :empty5 :true. > :cmp1 :empty6 :true. > > > > Kind regards, > > Jos > > > -- https://josd.github.io > > > > > > On Mon, Dec 13, 2021 at 6:12 PM William Van Woensel < > william.vanwoensel@gmail.com> wrote: > > Dear mailing list, > > > > Below you can find a conversation on log:notIncludes that may be of > interest! > > > > > > Regards, > > > > William > > > > *From: *Doerthe Arndt <doerthe.arndt@tu-dresden.de> > *Date: *Monday, December 13, 2021 at 9:29 AM > *To: *William Van Woensel <william.vanwoensel@gmail.com> > *Cc: *Jos De Roo <josderoo@gmail.com>, Pierre-Antoine Champin < > pierre-antoine.champin@ercim.eu>, Gregg Kellogg <gregg@greggkellogg.net> > *Subject: *Re: Discussion on log:notIncludes > > Dear William, > > > > Sorry for my late answer. I agree with your explanation and I also think > that the main question is: what does the local scoping of variables mean? > Related to that, it is also important to know where exactly our negation is > (so we have „implicit negation :) ). > > > > > > To come to your examples > > > > > > To continue our discussion on log:notIncludes (and in general the > floundering issue) I found a good link yesterday: > https://github.com/dtonhofer/prolog_notes/blob/master/other_notes/about_negation/floundering.md > > > > I was wondering why my particular example made sense, but the one in the > above article does not, even when *not* exposing variables outside of the > “notIncludes” statement. > > > > Starting from the beginning, the following doesn’t make sense much sense > because of floundering (as mentioned in the article): > > > > :bart :allergicTo :penicillin . > > > > { <> log:notIncludes { :bart :allergicTo ?y } } => { :bart :canTake ?y } . > # no > > { <> log:notIncludes { :bart :allergicTo :eyrthromycin } } => { :bart > :canTake :eyrthromycin } . # yes (contradiction; above rule did not output > anything, meaning that bart cannot take anything) > > { <> log:notIncludes { :lisa :allergicTo ?y } } => { :lisa :canTake ?y } . > # yes, but don't know what to bind to y > > > > (there is much more in the article, such as possible general solutions to > this problem) > > > > This actually made clear to me why having “builtin-local” variables, i.e., > not exposing “y” to the rule consequent, could be a solution to the > problem, as they would at least prevent these use cases. I believe this was > implied during our last discussion but I hadn’t gotten that far yet :-) > > The examples here seems to assume that the variable here is universally > quantified on top level. > > > > > > > > The problem is indeed, that if we wanted the rule to work as it might was > intended by its inventor, we would have to list everything which :bart can > take which would be everything (in the world) except :penicillin. We can’t > list everything except penicillin. > > > > In the last rule we have the same, but here, there is no exception. We can > state :lisa :canTake ?y., if we allow universal variables on top level > and have some shorthand for „Lisa can take everything“. > > > > > > > > > > However, if we slightly re-write these examples to not expose any > builtin-local variables: > > > > :bart :allergicTo :penicillin . > > > > { <> log:notIncludes { :bart :allergicTo ?y } } => { :bart > :canTakeSomeDrug true } . # still no > > { <> log:notIncludes { :lisa :allergicTo ?y } } => { :lisa > :canTakeSomeDrug true } # still yes > > > > This still doesn’t make much sense to me – due to the intuition that, just > because bart has an allergy to one particular drug, it doesn’t mean they > cannot take some other drug. (This is similar to the first statement in the > first example: just because bart has an allergy to one particular drug, it > doesn’t mean they cannot take some other drug.) > > Here, it depends on the meaning you assume for the universal. If you are > consistent with the example above, you would still have universal scoping > on top level. So, what you say here would be in FOL: > > > > \forall y: (\not allegicTo(bart,y))-> canTakeSomeDrug(bart, true). > > > > Which means the same as: > > > > (*\exists y: \not (*allegicTo(bart,y)))-> canTakeSomeDrug(bart, true). > > > > In that interpretation, the rule makes sense. > > > > What you describe (and what is also implemented) is different. From your > lines above I see that you understand the rule as: > > > > (* \not (\exists y: *allegicTo(bart,y)))-> canTakeSomeDrug(bart, true). > > > > With that interpretation, the rule does not make sense, but the behavior > of the reasoner does. > > > > > > Now, compare with my use case: > > > > :cmp0 :subTask :s0 . > > > > { <> log:notIncludes { :cmp0 :subTask ?y } } => { :cmp0 :empty :true } . # > no (e.g., “cmp0” could have been bound in an earlier triple) > > { <> log:notIncludes { :cmp1 :subTask ?y } } => { :cmp1 :empty :true } . # > yes (idem) > > > > Here, the mere mentioning of a composite task with the property “subTask" > *indeed means* that it is not empty. Having one subtask means something is > not empty (counter-example). > > > > > > I can again translate. > > > > The rule you want to express is: > > (* \not (\exists y: *subTask(cmp0,y)))-> isEmpty(cmp0, true). > > > > What we would get if we had the y quantified on top level would be: > > > > *\forall y: *( * \not (*subTask(cmp0,y)))-> isEmpty(cmp0, true). > > > > which can be transformed to: > > > > ( *\exists y: \not (*subTask(cmp0,y)))-> isEmpty(cmp0, true). > > > > But, in the drug example, the mere mentioning of a person with property > “allergicTo” property *does not mean* that they cannot take something. > Having one drug allergy does not mean one cannot take some (other) drug > (not a counter-example). > > > > > > > > > > So it is related to the meaning we assign to the inference. E.g., the > following would make much more sense: > > > > { <> log:notIncludes { :bart :allergicTo ?y } } => { :bart :hasAllergies > false } . # still no, but this is good > > > > Or > > > > { <> log:notIncludes { :bart :allergicTo ?y } } => { :bart :canTakeAnyDrug > true } . # still no, but this is good > > > > > > Hence I feel that the second drug example (“canTakeSomeDrug”) is rather an > anti-pattern, as it does not search for the non-existence of a > counter-example – this could be mentioned in the N3 spec (yes remember that > thing? >:). Could this, combined with a “builtin-local” scoping of the > variables, be a solution for the notIncludes problem? (Sorry if some of you > may have already gotten to this point – I just needed a bit more exposition) > > > > > > > > As I pointed out above with the examples. I think that the examples of > negation where we have „floundering“ are actually cases where the universal > quantification which is supposed to be on top-level suddenly switched to a > local level. This is something which should not happen and therefore, I > agree with Jos that we should be very strict here. > > > > I also see, that the use of negated predicates as you describe them has > many use cases and I know that I did similar things before (but with > e:findAll, where it is easier to understand the variable as locally > quantified). So, I would suggest, that we go for some kind of local > variable here. > > > > We could for example use blank nodes in that context and use their > specification as it was in the original proposal. There, they are local. > > > > It even works if they are existential quantified. In that case, it still > depends on the position of the implicit negation, whether or not we get the > meaning you intended in your example. But if we say that the existential > quantifier comes before the negation, then your example would work. > > > > It is interesting to see that this is also how cwm sees it. With the > original meaning of blank nodes (so no re-interpretation), your example > works. You can see that in Cwm: > http://ppr.cs.dal.ca:3002/n3/editor/s/yRnwKhdK > > > > Kind regards, > > Dörthe > > > > > > > >
Received on Wednesday, 15 December 2021 19:17:46 UTC