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 » Sat Apr 05, 2008 10:07 am

Take a look to the multi-threading examples in the current Logtalk development version, especially to the "primes" example.
Ok, I started to look at them, but I didn't see this one :)
If you chose to use the latest development version of Logtalk to take advantage of the multi-threading features, be sure to use the latest development versions of SWI-Prolog or YAP. There is at the moment an incompatibility with the development version of XSB that I hope to be solved soon.
For now I am using lgt 2.31.4 and swi-prolog available at the university ... I don't really know the version, but I think I will get the last one for my experiments :)

Thanks you for your help

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

Re: Gorgias port

Post by Victor NOEL » Sat Apr 05, 2008 1:32 pm

After I tried a lot of things, this what I got :

The idea is to try to prove a Query and get in return a list of instancied queries with their corresponding Deltas constructed by extend.
The differents queries are found by resolve with a list (Delta0) of predicate that support it, and extend construct Delta from Delta0.

Code: Select all

prove(Query, Delta, Querys, Deltas) :-
	findall(qd(Query, Delta0), ::resolve(Query, Delta0), QDs),             % resolve using "vanilla" interpreter
	spawn_extend(QDs, Querys, Deltas, Goals),
	collect(Goals).

spawn_extend([], [], [], []).
spawn_extend([qd(Query,Delta0)|QDs], [Query|Qs], [Delta|Ds], [extend(Delta0, [], Delta)|Goals]) :-
	threaded_call(extend(Delta0, [], Delta)),
	spawn_extend(QDs, Qs, Ds, Goals).

collect([]).
collect([extend(Delta0, [], Delta)|Goals]) :-
	threaded_exit(extend(Delta0, [], Delta)),
	collect(Goals).
I thought it would work but I get this error when I try to run it :

Code: Select all

ERROR: goal_thread `wa::extend([short_distance, r2], [], _G330)' does not exist
([short_distance, r2] is one of the possible Delta0 found by the findall)

I am not even sure this code is correct.

Edit :

You didn't answered my question about lists :
Another question :

Is there a reason why there is no set operation on unordered set like in the lists.pl from swi-prolog ? Or maybe there is but I couldn't see it :)

Because lists order is important for gorgias (or at least for me about how I can understand the semantic of the results it give me :) so I don't want to use ordered sets but unordered sets !

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

Re: Gorgias port

Post by Paulo Moura » Sun Apr 06, 2008 10:12 am

Victor NOEL wrote:After I tried a lot of things, this what I got :

The idea is to try to prove a Query and get in return a list of instancied queries with their corresponding Deltas constructed by extend.
The differents queries are found by resolve with a list (Delta0) of predicate that support it, and extend construct Delta from Delta0.

Code: Select all

prove(Query, Delta, Querys, Deltas) :-
	findall(qd(Query, Delta0), ::resolve(Query, Delta0), QDs),             % resolve using "vanilla" interpreter
	spawn_extend(QDs, Querys, Deltas, Goals),
	collect(Goals).

spawn_extend([], [], [], []).
spawn_extend([qd(Query,Delta0)|QDs], [Query|Qs], [Delta|Ds], [extend(Delta0, [], Delta)|Goals]) :-
	threaded_call(extend(Delta0, [], Delta)),
	spawn_extend(QDs, Qs, Ds, Goals).

collect([]).
collect([extend(Delta0, [], Delta)|Goals]) :-
	threaded_exit(extend(Delta0, [], Delta)),
	collect(Goals).
I thought it would work but I get this error when I try to run it :

Code: Select all

ERROR: goal_thread `wa::extend([short_distance, r2], [], _G330)' does not exist
([short_distance, r2] is one of the possible Delta0 found by the findall)

I am not even sure this code is correct.
The code above seems correct to me. Follows an equivalent use of the multi-threading predicates within categories:

Code: Select all

:- category(ctg).

	:- public(test/3).

	test(X, Y, Z) :-
		spawn([a(1,X), a(2,Y), a(3,Z)]),
		collect([a(1,X), a(2,Y), a(3,Z)]).

	spawn([]).
	spawn([a(X, Y) |Gs]) :-
		threaded_once(a(X, Y)),
		spawn(Gs).

	collect([]).
	collect([a(X, Y) |Gs]) :-
		threaded_exit(a(X, Y)),
		collect(Gs).

	a(1, a).
	a(2, b).
	a(3, c).

:- end_category.


:- object(obj,
	imports(ctg)).

	:- threaded.

:- end_object.
With the current development versions of Logtalk, SWI-Prolog, and YAP I get:

Code: Select all

 ?- obj::test(X, Y, Z).
X = a,
Y = b,
Z = c.
There are a number of bugs fixed in the support for threads on the current development versions of SWI-Prolog, YAP, and XSB (and, unfortunately, a few more needing fixing). These bugs often show up when using Logtalk. I'm working closely with the authors of these Prolog compilers in fixing these bugs (and also on the ISO standardization of Prolog support for threads). Which version of SWI-Prolog are you using? One pitfall to avoid is reloading your code after fixing a problem instead of restarting Logtalk. Reloading code can be problematic because there is no standard behavior among Prolog compilers on its consequences, specially if dynamic predicates are used. Using threads only aggravate the problem.
Victor NOEL wrote:Edit :

You didn't answered my question about lists :
Another question :

Is there a reason why there is no set operation on unordered set like in the lists.pl from swi-prolog ? Or maybe there is but I couldn't see it :)
The current Logtalk libraries do not support unordered sets (represented using lists), mostly because performance will be lousy compared with ordered sets (again represented as lists) for sets with more than a few items.
Victor NOEL wrote:
Because lists order is important for gorgias (or at least for me about how I can understand the semantic of the results it give me :) so I don't want to use ordered sets but unordered sets !
I will look into adding support for unordered sets (represented using lists) to the Logtalk library for the next version. I will keep you posted.

Cheers,

Paulo
Paulo Moura
Logtalk developer

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

Re: Gorgias port

Post by Paulo Moura » Sun Apr 06, 2008 3:27 pm

Hi!
Paulo Moura wrote: I will look into adding support for unordered sets (represented using lists) to the Logtalk library for the next version. I will keep you posted.
I've already implemented a new library object, "unordset", which provides and implementation of the library protocol "setp" for sets using non-ordered lists.
Victor NOEL wrote: Because lists order is important for gorgias (or at least for me about how I can understand the semantic of the results it give me so I don't want to use ordered sets but unordered sets !
The problem, however, is that Gorgias uses operations such as intersection/3 or union/3 where it's not clear which order should be preserved. For example, consider the following query:

Code: Select all

| ?- unordset::union([1,2,3,4], [0,2,4,5], Union).      

Union = [1,3,0,2,4,5]
yes
Depending on how you define the union/3 predicate, the order of the elements in "Union" can be different. Compounded with the intrinsic lousy performance of using a non-ordered representation for sets, my advise is for you to switch to an ordered set representation if possible.

Cheers,

Paulo
Paulo Moura
Logtalk developer

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

Re: Gorgias port

Post by Victor NOEL » Sun Apr 06, 2008 5:02 pm

Paulo Moura wrote: The problem, however, is that Gorgias uses operations such as intersection/3 or union/3 where it's not clear which order should be preserved. For example, consider the following query:

Code: Select all

| ?- unordset::union([1,2,3,4], [0,2,4,5], Union).      

Union = [1,3,0,2,4,5]
yes
Depending on how you define the union/3 predicate, the order of the elements in "Union" can be different. Compounded with the intrinsic lousy performance of using a non-ordered representation for sets, my advise is for you to switch to an ordered set representation if possible.
You are right, it is a real problem.

I will try to see if I really need to use unordered sets, and if I do, maybe there is some way to express order without using unordered sets !

Another way is to use my own implementation of these predicates that only do what I need them to do.

Thanks you for your help :)

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

Re: Gorgias port

Post by Victor NOEL » Mon Apr 07, 2008 9:47 am

I have installed the git version of swi-prolog, the svn version of logtalk, and the problem still occurs.

This is the code I use.

Code: Select all

prove(Query, QDs) :-
	findall(qd(Query, Delta0), ::resolve(Query, Delta0), QDs),             % resolve using "vanilla" interpreter
	spawn_extend(QDs, Goals),
	collect(Goals).

spawn_extend([], []).
spawn_extend([qd(Query,Delta0)|QDs], [extend_t(Delta0, Delta, Tag)|Goals]) :-
	threaded_call(extend(Delta0, [], Delta), Tag),
	spawn_extend(QDs, Goals).

collect([]).
collect([extend_t(Delta0, Delta, Tag)|Goals]) :-
	threaded_exit(extend(Delta0, [], Delta, Tag)),
	collect(Goals).
I guess there is an error somewhere in my code, because, if I display the value of Goals in prove/2 after calling spawn_extend/2, this is what I get :

Code: Select all

extend_t([mpm(bus), r1], _G478, -9223372036854775807)
extend_t([short_distance, r2], _G616, -9223372036854775806)
extend_t([heart_rate(anormal), r3], _G752, -9223372036854775805)
And the error is :

Code: Select all

ERROR: goal_thread `wa::extend([mpm(bus), r1], [], _G311, -9223372036854775807)' does not exist
As you can see, the variables for [mpm(bus), r1] are in Goals : _G478 and in the error : _G311

I guess the variable is lost somewhere :)

If you have an idea, it will be of great help.

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

Re: Gorgias port

Post by Paulo Moura » Mon Apr 07, 2008 10:30 am

Victor NOEL wrote:I have installed the git version of swi-prolog, the svn version of logtalk, and the problem still occurs.
...
This is the code I use.

Code: Select all

prove(Query, QDs) :-
	findall(qd(Query, Delta0), ::resolve(Query, Delta0), QDs),             % resolve using "vanilla" interpreter
	spawn_extend(QDs, Goals),
	collect(Goals).

spawn_extend([], []).
spawn_extend([qd(Query,Delta0)|QDs], [extend_t(Delta0, Delta, Tag)|Goals]) :-
	threaded_call(extend(Delta0, [], Delta), Tag),
	spawn_extend(QDs, Goals).

collect([]).
collect([extend_t(Delta0, Delta, Tag)|Goals]) :-
	threaded_exit(extend(Delta0, [], Delta, Tag)),
	collect(Goals).
I guess there is an error somewhere in my code (...)
You have a typo on the definition of the collect/1 predicate, in the threaded_exit/2 call. It should be:

Code: Select all

collect([]).
collect([extend_t(Delta0, Delta, Tag)|Goals]) :-
	threaded_exit(extend(Delta0, [], Delta), Tag),
	collect(Goals).
In addition, you should use threaded_once/2 instead of threaded_call/2 in the spawn_extend/2 predicate. The threaded_call/2 is non-deterministic and will leave choice points behind that I guess you're not interested in exploring.

Cheers,

Paulo
Paulo Moura
Logtalk developer

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

Re: Gorgias port

Post by Victor NOEL » Mon Apr 07, 2008 11:03 am

You have a typo on the definition of the collect/1 predicate, in the threaded_exit/2 call. It should be
You are right, but I just added the Tag and when it wasn't here, it wasn't working neither.
In addition, you should use threaded_once/2 instead of threaded_call/2 in the spawn_extend/2 predicate. The threaded_call/2 is non-deterministic and will leave choice points behind that I guess you're not interested in exploring.
I am using threaded_call because there can be several Delta for each Delta0, isn't it for that ?

I tried to use threaded_once, and I did not got the error about the inexistent goal_thread, but I just got the first answer which is a fail and doesn't interest me :)

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

Re: Gorgias port

Post by Paulo Moura » Mon Apr 07, 2008 11:16 am

Victor NOEL wrote:
You have a typo on the definition of the collect/1 predicate, in the threaded_exit/2 call. It should be
You are right, but I just added the Tag and when it wasn't here, it wasn't working neither.
Hard to help you locate the problem using only snippets of code. Consider sending me by email the files that allow me to try to reproduce the problem. If by chance you're using a Mac with SubEthaEdit installed we can work together in the code, using also Skype for chat.
Victor NOEL wrote:
In addition, you should use threaded_once/2 instead of threaded_call/2 in the spawn_extend/2 predicate. The threaded_call/2 is non-deterministic and will leave choice points behind that I guess you're not interested in exploring.
I am using threaded_call because there can be several Delta for each Delta0, isn't it for that ?

I tried to use threaded_once, and I did not got the error about the inexistent goal_thread, but I just got the first answer which is a fail and doesn't interest me :)
Make sure that the non-threaded version of your code is working properly before trying to multi-thread it. In order to get all the solutions from a threaded_call/1-2 call, you need to backtrack over the threaded_exit/1-2 call. Your snippet of code does not do that, hence my suggestion for using threaded_once/1.

If your application will be creating more than a few threads, you may need to compile SWI-Prolog 64 bits. With SWI-Prolog compiled 32 bits is easy to bump into memory limitations.

Cheers,

Paulo
Paulo Moura
Logtalk developer

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

Re: Gorgias port

Post by Victor NOEL » Mon Apr 07, 2008 11:41 am

Paulo Moura wrote: Make sure that the non-threaded version of your code is working properly before trying to multi-thread it. In order to get all the solutions from a threaded_call/1-2 call, you need to backtrack over the threaded_exit/1-2 call. Your snippet of code does not do that, hence my suggestion for using threaded_once/1.
I didn't know that, it explain why it did not work.
For now, I resolved my problem by calling findall on my goal in a threaded_once predicate.
It works well, and the result is put in a list.
Paulo Moura wrote: Hard to help you locate the problem using only snippets of code. Consider sending me by email the files that allow me to try to reproduce the problem. If by chance you're using a Mac with SubEthaEdit installed we can work together in the code, using also Skype for chat.
Ok, next time I will produce example of code that doesn't work :)
Paulo Moura wrote: If your application will be creating more than a few threads, you may need to compile SWI-Prolog 64 bits. With SWI-Prolog compiled 32 bits is easy to bump into memory limitations.
Does SWI-Prolog 64 bits work on 32 bits CPU ? I will take a look at that too :)

Thanks for all your help. I think all is working like I want.

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

Re: Gorgias port

Post by Victor NOEL » Tue Apr 08, 2008 8:42 am

I have a new question now :)

Is there a way to put in gorgias code some debugging information that would be compiled only if logtalk debug is on ?

Something that would not impact performance when I don't need it ...

Like that I would be able to make gorgias developer friendly :)

Thanks

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

Re: Gorgias port

Post by Paulo Moura » Tue Apr 08, 2008 9:25 am

Victor NOEL wrote:I have a new question now :)

Is there a way to put in gorgias code some debugging information that would be compiled only if logtalk debug is on ?

Something that would not impact performance when I don't need it ...

Like that I would be able to make gorgias developer friendly :)

Thanks
You may use Logtalk support for event-driven programming. Define appropriate "before" and "after" event handlers for the predicates in the Gorgias category that you may want to trace at runtime. When debugging, turn events support on. For production code, run with events support off (which also implies better performance). Note, however, that you can only attach events to predicates called using the ::/2 message sending control construct.

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 » Tue Apr 08, 2008 10:12 am

Paulo Moura wrote: You may use Logtalk support for event-driven programming. Define appropriate "before" and "after" event handlers for the predicates in the Gorgias category that you may want to trace at runtime. When debugging, turn events support on. For production code, run with events support off (which also implies better performance). Note, however, that you can only attach events to predicates called using the ::/2 message sending control construct.
This is exactly the kind of thing I was looking for.

I started investigating it and I have a few questions :
What is best :
Each category implements monitoring and defines before and after event handlers ;
Or an object implements monitoring and defines the events handler for all the category ?

I tried the first idea, but I couldn't find how to activate it, if I call define_events with Monitor = gorgias it tells me an object named gorgias doesn't exist. And if I call define_events with Monitor as the object importing the category, it fails !

Edit :
I tried to implement the second idea, and the call define_events always fail if there is only after defined in the object Monitor !

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

Re: Gorgias port

Post by Paulo Moura » Tue Apr 08, 2008 10:53 am

Victor NOEL wrote:
Paulo Moura wrote: You may use Logtalk support for event-driven programming. Define appropriate "before" and "after" event handlers for the predicates in the Gorgias category that you may want to trace at runtime. When debugging, turn events support on. For production code, run with events support off (which also implies better performance). Note, however, that you can only attach events to predicates called using the ::/2 message sending control construct.
This is exactly the kind of thing I was looking for.

I started investigating it and I have a few questions :
What is best :
Each category implements monitoring and defines before and after event handlers ;
Or an object implements monitoring and defines the events handler for all the category ?
Both solutions are possible. When the event handlers are defined in a category, you still have to define them in the object that imports the category. Just write (within the object):

Code: Select all

before(Object, Message, Sender) :-
	:before(Object, Message, Sender).

after(Object, Message, Sender) :-
	:after(Object, Message, Sender).
This is necessary because the built-in predicate define_events/5 expects the event handlers to be defined in the monitor object. In turn, this is necessary for acceptable performance when using events, otherwise the check for event handlers everytime you send a message using the ::/2 control construct would be too high.
Victor NOEL wrote:I tried the first idea, but I couldn't find how to activate it, if I call define_events with Monitor = gorgias it tells me an object named gorgias doesn't exist.
The second and fifth argument of the built-in predicate define_events/5 must be object identifiers.
Victor NOEL wrote:And if I call define_events with Monitor as the object importing the category, it fails !

Edit :
I tried to implement the second idea, and the call define_events always fail if there is only after defined in the object Monitor !
The first argument of the built-in predicate define_events/5 can be a variable (when you want to use both "before" and "after" events), the atom "before", or the atom "after". My guess is that you called the predicate with a non-instantiated first argument.

Best regards,

Paulo

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

Re: Gorgias port

Post by Victor NOEL » Tue Apr 08, 2008 11:20 am

I understand more now, so I applied your advices and wrote a little example like that :

Code: Select all

:- category(ctg, implements(monitoring)).

	:- public(test1/3).

	test1(X, Y, Z) :-
		test(X, Y, Z).

	test(X, Y, Z) :-
		a(1, X), a(2, Y), a(3, Z).

	after(_, test(X, Y, Z), _) :-
		writeq(X), write(' '), writeq(Y), write(' '), writeq(Z), nl.

	a(1, a).
	a(2, b).
	a(3, c).

:- end_category.


:- object(obj,
	implements(monitoring),
	imports(ctg)).

	:- threaded.
	
	after(Object, Message, Sender) :-
	   ::after(Object, Message, Sender).

:- end_object.
And if I activate the event handler, I get a out of local stack error :

Code: Select all

?- obj::test1(X, Y, Z).
X = a,
Y = b,
Z = c.

?- define_events(after, _, _, _, obj).
true.

?- obj::test1(X, Y, Z).
ERROR: Out of local stack
I guess there is something wrong in what I wrote :) Maybe the after event (in obj) is called every time the after event (in ctg) is called ?

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest