Gorgias port

Discussion on porting Prolog applications to Logtalk

Moderator: Paulo Moura

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Tue May 27, 2008 4:03 pm

So, I come for help to refactor gorgias :)

Before doing this, I have a question :
Is it normal that an object importing gorgias and declared as dynamic can't be abolished ? When I try to do it, I get an error telling me that the object is static !
I tried to look for the reason, like not dynamic predicates declared in the object and used by gorgias but it doesn't seem to be the reason ...

Back to my refactoring problem :
There is 3 files in gorgias :
gorgias, lpwnf and resolve

resolve is doing what it means : it has a resolve/2 pred which is a meta prolog that try to resolve goal but using rule/3 as extended logic clause, and it keep the name of the rule (their first argument, while the second is the head and the third is the body) in a list while resolving.

So if I have :
rule(a(A), test(1), [foo(A)])
rule(foorule, foo(5), [])

and try to resolve(test(1), D), I will get D = [a(5), foorule]

resolve add to the resolving process abducibles (it is just predicates that can be assumed even if they are not in the head of a rule/3)

For now, I decided that is the one responsible of rule/3, abducible/1 (and background for the built_in predicates)

lpwnf has a predicate attack that takes a list of rule names (found by resolve for example, but also by attacks itself before) and try to "attack" each of the predicate with the attack0 rules : the attacks are for example on an abducible by a fact that contradict it, or for a rule, that there is another rule that is prefered to it (because you can put in the head of rule/3 a preference declaration), etc ...

In lpwnf I put too : complement/2 that let the user theory to specify that two predicates are in conflict and conflict/2 that generates conflicts between predicates, based on complement/2 and neg/1 which is the explicit negation as a predicate (lpwnf means : logic programmin without negation as failure :)
There is also isconsistent/2 that checks that a list of pred is consistent according to conflict/2

in gorgias there is the general algorithm for argumentation : it take a goal, resolve it, check for attacks on it, and then try to defend them, and again try to attack until there is no more attack or it can defend all.

So :
rule/3 are used by resolve and lpwnf
abducible/1 by resolve and lpwnf
background/1 by resolve
resolve/2 is used by gorgias and lpwnf
attacks/5 and isconsistent/2 by gorgias

A user trying to use gorgias will use :
rule/3 to declare rules and preference over rules
complement/2 to specify conflicts between predicates (for example complement(man(A), woman(A)))
abducible/1 to declare predicate that can be assumed (for example abducible(man(_)) that means that if man(test) is to be proved it will be assumed, but not if the contrary holds (so for example if woman(test) hold))
background/1 to declare predicates that should only be evaluated while doing resolve and not added to the list.

And he will call prove/2 to solve the problem.

This explanation is not very good, but I hope it will be sufficient to explain how things are working :)

Thanks you.

Paulo Moura
Logtalk developer
Posts: 473
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Gorgias port

Post by Paulo Moura » Tue May 27, 2008 4:47 pm

Victor NOEL wrote: Before doing this, I have a question :
Is it normal that an object importing gorgias and declared as dynamic can't be abolished ? When I try to do it, I get an error telling me that the object is static !
I tried to look for the reason, like not dynamic predicates declared in the object and used by gorgias but it doesn't seem to be the reason ...
I cannot reproduce the problem using a simple example of dynamic objects importing categories. An object is dynamic if it's either created using the built-in predicate create_object/4 or, when defined in a source file, when you use the directive dynamic/0. You can check the properties of any loaded object using the built-in predicate object_property/2. I will need more details in order to be able to help you solve the issue.
Victor NOEL wrote: Back to my refactoring problem :
There is 3 files in gorgias :
gorgias, lpwnf and resolve

resolve is doing what it means : it has a resolve/2 pred which is a meta prolog that try to resolve goal but using rule/3 as extended logic clause, and it keep the name of the rule (their first argument, while the second is the head and the third is the body) in a list while resolving.
In my initial port, "gorgias", "lpwnf", and "resolve" are categories, as they provide different functionality. Does the "resolve" category implements a default meta-interpreter? I.e. is is possible to define alternative meta-interpreters? This would be a good reason to use a category as each theory (implemented as an object) could import a different resolver, which, provided that all resolvers implement the same protocol, would work seamlessly with the other two categories. Bit I digress. Back to your post...
Victor NOEL wrote: So if I have :
rule(a(A), test(1), [foo(A)])
rule(foorule, foo(5), [])

and try to resolve(test(1), D), I will get D = [a(5), foorule]

resolve add to the resolving process abducibles (it is just predicates that can be assumed even if they are not in the head of a rule/3)

For now, I decided that is the one responsible of rule/3, abducible/1 (and background for the built_in predicates)

lpwnf has a predicate attack that takes a list of rule names (found by resolve for example, but also by attacks itself before) and try to "attack" each of the predicate with the attack0 rules : the attacks are for example on an abducible by a fact that contradict it, or for a rule, that there is another rule that is prefered to it (because you can put in the head of rule/3 a preference declaration), etc ...

In lpwnf I put too : complement/2 that let the user theory to specify that two predicates are in conflict and conflict/2 that generates conflicts between predicates, based on complement/2 and neg/1 which is the explicit negation as a predicate (lpwnf means : logic programmin without negation as failure :)
There is also isconsistent/2 that checks that a list of pred is consistent according to conflict/2
We could ask here the same question above about the "resolve" category. It is possible, likely, or desirable to be able to cope with different rule attack algorithms?
Victor NOEL wrote: in gorgias there is the general algorithm for argumentation : it take a goal, resolve it, check for attacks on it, and then try to defend them, and again try to attack until there is no more attack or it can defend all.
Can this general algorithm for argumentation be specialized in some way unrelated to the functionality in either the "resolve" or the "lpwnf" categories?
Victor NOEL wrote: So :
rule/3 are used by resolve and lpwnf
abducible/1 by resolve and lpwnf
background/1 by resolve
resolve/2 is used by gorgias and lpwnf
attacks/5 and isconsistent/2 by gorgias

A user trying to use gorgias will use :
rule/3 to declare rules and preference over rules
complement/2 to specify conflicts between predicates (for example complement(man(A), woman(A)))
abducible/1 to declare predicate that can be assumed (for example abducible(man(_)) that means that if man(test) is to be proved it will be assumed, but not if the contrary holds (so for example if woman(test) hold))
background/1 to declare predicates that should only be evaluated while doing resolve and not added to the list.

And he will call prove/2 to solve the problem.
So, a user defines an object representing its theory, which is described using a set of predicates declared in a set of imported categories. Is there any reason (other than a slight simplification for the user) for not importing all three categories instead of somehow subverting the idea of extended categories by having one category, "gorgias", extending the other two categories? This is the only thing that I find questionable in the current design. My fault really, one should not quick port other people's applications without a sensible understating of the problem domain :-).
Victor NOEL wrote: This explanation is not very good, but I hope it will be sufficient to explain how things are working :)
That's a nice explanation, but I'm afraid I raised more questions than provided you with answers :-)!

Best regards,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Wed May 28, 2008 8:41 am

Paulo Moura wrote: I cannot reproduce the problem using a simple example of dynamic objects importing categories. An object is dynamic if it's either created using the built-in predicate create_object/4 or, when defined in a source file, when you use the directive dynamic/0. You can check the properties of any loaded object using the built-in predicate object_property/2. I will need more details in order to be able to help you solve the issue.
Ok, I will try to reduce the problem to a simple one, I tried a little, but I didn't find it.
Paulo Moura wrote: In my initial port, "gorgias", "lpwnf", and "resolve" are categories, as they provide different functionality. Does the "resolve" category implements a default meta-interpreter? I.e. is is possible to define alternative meta-interpreters? This would be a good reason to use a category as each theory (implemented as an object) could import a different resolver, which, provided that all resolvers implement the same protocol, would work seamlessly with the other two categories. Bit I digress. Back to your post...
It is a good question, and, for example, at first, abducibles weren't here (at less in the paper presenting the proof procedure) and some resolveone/3 rules were added to handle it. So yes, it is a meta-interpreter that can be extended in my opinion. Now I am not sure it will, but it is not my problem :)
Paulo Moura wrote: We could ask here the same question above about the "resolve" category. It is possible, likely, or desirable to be able to cope with different rule attack algorithms?
Here it is more desirable to extend it. Gorgias was coded with extension of attacks in mind, for example for domain specific attacks, or things like that.
What can arise, is that, sometimes, some things are added by attacks0/5 to the list of attacks, but need to be removed later, and this is done in gorgias, and also attacks/5 filters them when looking for attacks ...

There is not such thing in the version you have, but I have it in a modified version. (I don't think it is a big problem if we can't address it, but maybe it is possible ...)
Paulo Moura wrote: Can this general algorithm for argumentation be specialized in some way unrelated to the functionality in either the "resolve" or the "lpwnf" categories?
This one no. It is a fixed proof procedure, and if is has to be changed, it will not be extended but modified.
Paulo Moura wrote: So, a user defines an object representing its theory, which is described using a set of predicates declared in a set of imported categories. Is there any reason (other than a slight simplification for the user) for not importing all three categories instead of somehow subverting the idea of extended categories by having one category, "gorgias", extending the other two categories? This is the only thing that I find questionable in the current design. My fault really, one should not quick port other people's applications without a sensible understating of the problem domain :-).
I think that there is two kind of users :
The ones who want to add attacks or way to resolve, and the ones that make theories.
The latters just want to call gorgias (and maybe, I don't know, sometimes most specific predicate like conflict or isconsistent to maintain consistence when adding knowledge to the base for example).
Paulo Moura wrote: That's a nice explanation, but I'm afraid I raised more questions than provided you with answers :-)!
Hehe, your questions were the good ones :)
I hope my answers will be clear enough to let you understand how things are working and be used.

Thanks you again.

Paulo Moura
Logtalk developer
Posts: 473
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Gorgias port

Post by Paulo Moura » Wed May 28, 2008 11:32 am

Victor NOEL wrote:
Paulo Moura wrote: In my initial port, "gorgias", "lpwnf", and "resolve" are categories, as they provide different functionality. Does the "resolve" category implements a default meta-interpreter? I.e. is is possible to define alternative meta-interpreters? This would be a good reason to use a category as each theory (implemented as an object) could import a different resolver, which, provided that all resolvers implement the same protocol, would work seamlessly with the other two categories. Bit I digress. Back to your post...
It is a good question, and, for example, at first, abducibles weren't here (at less in the paper presenting the proof procedure) and some resolveone/3 rules were added to handle it. So yes, it is a meta-interpreter that can be extended in my opinion. Now I am not sure it will, but it is not my problem :)
But maybe is a good idea if you plan ahead for it in behalf of your users. If the meta-interpreter can be specialized, the best solution is to import the existing "resolve" category into an object that can be extended (if using prototypes) or specialized (if using classes). On the other hand, if the meta-predicate would be typically replaced by a different one, then define an explicit protocol that the current "resolve" category and any alternative categories with different meta-interpreters can implement (in order to clearly specify an interface that will be used by the remaining code to invoke the meta-interpreter predicates).
Victor NOEL wrote:
Paulo Moura wrote: We could ask here the same question above about the "resolve" category. It is possible, likely, or desirable to be able to cope with different rule attack algorithms?
Here it is more desirable to extend it. Gorgias was coded with extension of attacks in mind, for example for domain specific attacks, or things like that. What can arise, is that, sometimes, some things are added by attacks0/5 to the list of attacks, but need to be removed later, and this is done in gorgias, and also attacks/5 filters them when looking for attacks ...

There is not such thing in the version you have, but I have it in a modified version. (I don't think it is a big problem if we can't address it, but maybe it is possible ...)
Same remarks as above.
Victor NOEL wrote:
Paulo Moura wrote: Can this general algorithm for argumentation be specialized in some way unrelated to the functionality in either the "resolve" or the "lpwnf" categories?
This one no. It is a fixed proof procedure, and if is has to be changed, it will not be extended but modified.
I would consider adding a "theory" object that imports the three default categories. If you define this object as a prototype, users implementing concrete theories simply extend it:

Code: Select all

:- object(my_theory,
    extends(theory)).
    ...
:- end_object.
Another option is to define "theory" as a class that is instantiated by the users:

Code: Select all

:- object(my_theory,
    instantiates(theory)).
    ...
:- end_object.
Note that this does not imply the dynamic creation of "theory" instances. Users can still simply define their theories as static objects in a source file. If this clashes too hard with the Java programmer in you, try to think the e.g. "instantiates", "specializes", "extends" relations as different patterns of code reuse.
Victor NOEL wrote: I think that there is two kind of users :
The ones who want to add attacks or way to resolve, and the ones that make theories.
The latters just want to call gorgias (and maybe, I don't know, sometimes most specific predicate like conflict or isconsistent to maintain consistence when adding knowledge to the base for example).
So, the users that make theories can simply use the solution suggested above. The more sophisticated users that want to extend and modify the existing code may extend or specialize objects such as "theory" or define their own categories (implementing the same protocols as the default ones) that get imported into their descendant "theory" objects, thus overriding the default definitions of e.g attack rules or meta-interpreters.
Victor NOEL wrote:
Paulo Moura wrote: That's a nice explanation, but I'm afraid I raised more questions than provided you with answers :-)!
Hehe, your questions were the good ones :)
I hope my answers will be clear enough to let you understand how things are working and be used.
Nice and clear :-)

Best regards,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Wed Jun 04, 2008 11:52 am

Hello,

I need your help again for my refactor of gorgias.

I think I found a good way to express extensibility of gorgias :
What I do is :
gorgias is still a category, like before, but I add to it the attacks/5 and resolve/2 predicates, attacks0/6 (called by attacks/5) and resolveone/3 (called by resolve/2) will be defined elsewhere.
Then I have two protocol : attackp and resolvep, they are used by categories that want to define one or more way to attack and resolve, with attacks0/6 and resolveone/3.

Then a user theory will import gorgias and the implementing categories they want, and these one will be used by gorgias to do the resolving and the attack.

For now, I made a first category that implements attackp and resolverp, that do what were doing lpwnf.lgt and resolver.lgt, without the abducible part because I want it in another category that can be loaded or not.

Like that it works.

But when I do create this second category, named abducible, my final object is importing : gorgias, lpwnf and abducible.

But the problem is that only the first of the two categories implementing my protocols is used ! it looks like logtalk doesn't try to look for the predicates in the second one.

Is it normal ?
Maybe this is not the good way to do it ?

If it can help you to understand what I mean I can make this version available on the web :)

Thanks you for your help.

Victor

Paulo Moura
Logtalk developer
Posts: 473
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Gorgias port

Post by Paulo Moura » Wed Jun 04, 2008 5:09 pm

Victor NOEL wrote: But the problem is that only the first of the two categories implementing my protocols is used ! it looks like logtalk doesn't try to look for the predicates in the second one.
This sounds like a possible bug. Hard to say if it's either a Gorgias problem or a Logtalk problem without looking at your code.
Victor NOEL wrote: Is it normal ?
Maybe this is not the good way to do it ?

If it can help you to understand what I mean I can make this version available on the web :)
For now, just send me an archive with that version by mail. I will take a look later.

Best regards,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Thu Jun 05, 2008 8:12 am

Paulo Moura wrote: For now, just send me an archive with that version by mail. I will take a look later.
I was able to make a little example that show what I want to do :

Code: Select all

:- object(test, imports([cata, catb, catc])).
:- end_object.
:- protocol(a).
	:- public([test1/1]).
:- end_protocol.
:- category(cata).
	:- calls(a).
	:- public([test/1]).
	test(A) :-
		::test1(A).
:- end_category.
:- category(catb, implements(a)).
	:- public([test1/1]).
	test1(b).
:- end_category.
:- category(catc, implements(a)).
	:- public([test1/1]).
	test1(c).
:- end_category.
Now when I run it :

Code: Select all

?- test::test(A).
A = b.
And if in the object test, I replace "imports([cata, catb, catc])" by "imports([cata, catc, catb])", I get :

Code: Select all

?- test::test(A).
A = c.
Maybe it is normal, I have read somewhere in the documentation :
When an object inherits two different declarations for the same predicate, by default only the first one will be considered.
Thanks for your help

Paulo Moura
Logtalk developer
Posts: 473
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Gorgias port

Post by Paulo Moura » Thu Jun 05, 2008 10:33 am

Hi!

The behavior of your sample code when you send the message test/1 to your object is the expected and correct one. The imported categories are always searched in the order of their declarations. I.e. by default Logtalk uses a depth-first lookup for both predicate declarations and predicate definitions. You can override this behavior by using alias/3 directives if needed. Note that the test1/1 message id sent to self. Thus, the declaration lookup follows the path "test" -> "cata" while the definition lookup follows the path "test" -> "catb" (after failing to find a definition for the predicate in "cata"). When you search the order of the categories "catb" and "catc", the category "catc" is searched before category "catb", hence the second result. This topic is explained in the user manual, in the inheritance section.

Best regards,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Thu Jun 05, 2008 12:05 pm

Paulo Moura wrote: The behavior of your sample code when you send the message test/1 to your object is the expected and correct one. The imported categories are always searched in the order of their declarations. I.e. by default Logtalk uses a depth-first lookup for both predicate declarations and predicate definitions. You can override this behavior by using alias/3 directives if needed. Note that the test1/1 message id sent to self. Thus, the declaration lookup follows the path "test" -> "cata" while the definition lookup follows the path "test" -> "catb" (after failing to find a definition for the predicate in "cata"). When you search the order of the categories "catb" and "catc", the category "catc" is searched before category "catb", hence the second result. This topic is explained in the user manual, in the inheritance section.
Yes, this is what I thought, and understood from the sentence of the documentation I quoted.

And now I am wondering how can I have the same behavior... Is there a way to do this ? I can't see how it would be possible with alias/3.

Do you have an idea that can help me ?

Paulo Moura
Logtalk developer
Posts: 473
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Gorgias port

Post by Paulo Moura » Thu Jun 05, 2008 2:38 pm

Victor NOEL wrote: And now I am wondering how can I have the same behavior... Is there a way to do this ? I can't see how it would be possible with alias/3.

Do you have an idea that can help me ?
What do you mean by "the same behavior"? Making the result on the test/1 message independent of the category order? The alias/3 predicate directive allows you to give an alias to a predicate when the lookup operations access the specified entity. So, if you want to use an overridden definition, you can just give it an alias and then use the alias name (check the "aliases" example).

Regarding your example code, category predicates shouldn't refer to other category predicates. This breaks category functional cohesion. The proper place to "combine" different category predicates is the object importing the categories as it's the only entity that brings all the category predicates into the same scope.

Best regards,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Thu Jun 05, 2008 3:02 pm

Paulo Moura wrote: What do you mean by "the same behavior"? Making the result on the test/1 message independent of the category order? The alias/3 predicate directive allows you to give an alias to a predicate when the lookup operations access the specified entity. So, if you want to use an overridden definition, you can just give it an alias and then use the alias name (check the "aliases" example).
But what I want is not to use one of the definition, but both !
This is where is my problem, I want test/1 to look up for predicate test1/1 from catb AND catc.

So maybe using category is not the way to go, but I thought about inheritance like extends, and it works if I have 2 categories, but what if I want 5 categories that implements test1/1 and that test/1 call the definitions of test1/1 in the 5 categories ?

Thanks you

Paulo Moura
Logtalk developer
Posts: 473
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Gorgias port

Post by Paulo Moura » Thu Jun 05, 2008 3:19 pm

Victor NOEL wrote:
Paulo Moura wrote: What do you mean by "the same behavior"? Making the result on the test/1 message independent of the category order? The alias/3 predicate directive allows you to give an alias to a predicate when the lookup operations access the specified entity. So, if you want to use an overridden definition, you can just give it an alias and then use the alias name (check the "aliases" example).
But what I want is not to use one of the definition, but both !
This is where is my problem, I want test/1 to look up for predicate test1/1 from catb AND catc.

So maybe using category is not the way to go, but I thought about inheritance like extends, and it works if I have 2 categories, but what if I want 5 categories that implements test1/1 and that test/1 call the definitions of test1/1 in the 5 categories ?
That's a matter of defining an alias/3 directive per imported category. You should add the directives, however, to the object importing the categories, not to one of the categories (see my updated post above).

Best regards,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Thu Jun 05, 2008 3:32 pm

Paulo Moura wrote: That's a matter of defining an alias/3 directive per imported category. You should add the directives, however, to the object importing the categories, not one of the categories (see my updated post above).
You are absolutely right ! I can't understand how I didn't see that :)

Thanks for your help, I will try to make it works now.

Victor

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Fri Jun 06, 2008 8:53 am

Hello,

I think I have something good, using term_expansion to add the correct alias and clauses for imported categories. (in hooks.lgt)

If you have some time and can take a look at it, it would be cool :)

You can see it here : https://dev.crazydwarves.org/trac/Gorgias/browser

There is 3 categories that can be imported : vanilla resolver, abducible (resolver + attacks) and lpwnf (attacks).

there is an example in test.

Thanks you for all your help, I am really happy to have been able to do it :]

Paulo Moura
Logtalk developer
Posts: 473
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: Gorgias port

Post by Paulo Moura » Fri Jun 06, 2008 2:10 pm

Victor NOEL wrote: I think I have something good, using term_expansion to add the correct alias and clauses for imported categories. (in hooks.lgt)
I use a similar solution in a Logtalk application that validates STEP (CAD/CAM) files.
Victor NOEL wrote: If you have some time and can take a look at it, it would be cool :)

You can see it here : https://dev.crazydwarves.org/trac/Gorgias/browser

There is 3 categories that can be imported : vanilla resolver, abducible (resolver + attacks) and lpwnf (attacks).

there is an example in test.

Thanks you for all your help, I am really happy to have been able to do it :]
Thanks. I will take a closer look during the weekend. Glad you found a nice programming solution. Just two quick observations: (1) regarding the "import_hooks" object, it would be nice (as far as portability goes) if you can do without using discontiguous/1 directives; (2) categories such as "abducible" contain redundant public/1 directives as they are already contained in the implemented protocols.

Best regards,

Paulo

P.S. I see that you're already taking advantage of my recent work on Pygments :)
Paulo Moura
Logtalk developer

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest