« Return to Thread: 'not' as atomic symbol

Re: message queue put-back and backtracking

by Samer Abdallah :: Rate this Message:

Reply to Author | View in Thread

Just to set the record straight and in case anyone else tries to
implement this, I had to introduce an extra cut in ndet_getmsg1/2
to get this to work properly, because the choice-point created by
retract(pushed_message(Q,M)) was messing things up in a way that
I don't fully understand, but seems to be because of the interaction
between asserta/1 and retract/1 when asserta is called while retract
is active. This is all because I took the cut out of bt_call/2  
thinking it
was a good idea...

So, the solution in full is
----------------------------------------------------

:- dynamic pushed_message/2.

ndet_getmsg(Queue,Message) :-
        bt_call(ndet_getmsg1(Queue,Message),push_back(Queue,Message)).

ndet_getmsg1(Queue, Message) :-
    retract(pushed_message(Queue, Message)), !.   % This is the extra  
necessary cut.

ndet_getmsg1(Queue, Message) :-
    thread_get_message(Queue, Message), !. % This cut is probably not  
necessary.

push_back(Queue, Message) :-
    asserta(pushed_message(Queue, Message)).

bt_call(Do,Undo) :- Do, (true; once(Undo), fail).

---------------------------------------------------
With this it is possible to extract successive elements from the
queue and apply non-deterministic predicates to them in a
fully backtrackable way.

Richard, re your suggestion
> Why not simply represent the queue as a process,
> and let that process store the data any way it feels like?
Forgive me if I'm being dense but what exactly do you mean by
a process in this context? Do you have a particular Prolog  
implementation
in mind?

Cheers,
Samer



On 13 Jan 2007, at 17:11, Samer Abdallah wrote:

>
> On 12 Jan 2007, at 20:04, Jan Wielemaker wrote:
>
>> On Friday 12 January 2007 20:19, Samer Abdallah wrote:
>>> On 12 Jan 2007, at 16:27, Jan Wielemaker wrote:
>>>> Another disadvantage is that it makes thread_get_message
>>>> non-deterministic.  Somewhat more in line with the desing might be
>>>> a thread_send_message that puts the new message at the head rather
>>>> than at the tail.  That allows for a design like:
>>>>
>>>> ndet_get_message(Queue, Message) :-
>>>>        thread_get_message(Queue, Message),
>>>> (   true
>>>> ;   thread_send_message(Queue, Message, [at(head)]),
>>>>    fail
>>>> ).
>>>>
>>>> Note however that this implementation is not correct with respect
>>>> to the
>>>> cut.
>>
>> Simply consider
>>
>> (   ndet_get_message(Queue, Message)
>> ->  fail
>> ;   true
>> ).
>>
>> With a truly logical predicate this would not change Queue.  After
>> pruning the choicepoint however the message will not be put back.
>>
>> You can do the above with the current system easily (not tested):
>>
>> :- dynamic
>> pushed_message/2.
>>
>> ndet_getmsg(Queue, Message) :-
>> ndet_getmsg1(Queue, Message),
>> (   true
>> ;   push_back(Queue, Message)
>> ).
>>
>> ndet_getmsg1(Queue, Message) :-
>> retract(pushed_message(Queue, Message)).
>> ndet_getmsg1(Queue, Message) :-
>> thread_get_message(Queue, Message).
>>
>> push_back(Queue, Message) :-
>> asserta(pushed_message(Queue, Message)).
> Thanks Jan, that did the trick, except that I used a backtracking  
> meta-predicate
> that I was already using elsewhere (to manage backtrackable  
> database updates)
>
> ndet_getmsg(Queue,Message) :-
> bt_call(ndet_getmsg1(Queue,Message),push_back(Queue,Message)).
>
> bt_call(Do,Undo) :- Do, on_backtracking(Undo).
>
> on_backtracking(_).
> on_backtracking(G) :- G, !, fail.
>
> though now I'm getting paranoid about cuts and whether or not they're
> doing the right thing! For example, I originally had
> bt_call(Do,Undo) :- Do, !, on_backtracking(Undo).
> but just now I removed the cut so that Do can be non-deterministic.
>
>>
>>>> So, I'd prefer to consider the problem at a somewhat higher level
>>>> first
>>>> to see whether there is an elegant solution you missed there.
>>>
>>> Well, I would like to be able to solve the problem without invoking
>>> another thread - essentially what I want is a findall that returns
>>> a *lazy* list that carries enough information about the state of
>>> solution search to build itself on demand as it goes along. I can't
>>> see how to do it without using a meta-interpreter which handles
>>> the search tree explicitly at the meta level.
>>> My current transaction logic interpreter still relies on  
>>> backtracking
>>> in the underlying interpreter - doing otherwise would make it much
>>> more complex. Hence the quick and i hope not-too-dirty  
>>> multithreading
>>> approach.
>>
>> I'm not very good at that, but you can hack some of these things  
>> using
>> coroutining or attributed variables.  Its a really nice puzzle :-)
> corouting --> next rainy sunday!
>
> Thanks,
> Samer
>
>>
>> Success --- Jan
>>
>>
>> ------------
>> For further info, please visit http://www.swi-prolog.org/
>>
>> To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-
>> mail>"
>> in its body to majordomo@...
>
>
> ------------
> For further info, please visit http://www.swi-prolog.org/
>
> To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-
> mail>"
> in its body to majordomo@...


------------
For further info, please visit http://www.swi-prolog.org/

To unsubscribe, send a plaintext mail with "unsubscribe prolog <e-mail>"
in its body to majordomo@...

 « Return to Thread: 'not' as atomic symbol

LightInTheBox - Buy quality products at wholesale price