Circular buffer in Turbo Prolog 2.0 - prolog

I need to write something like circular buffer in TurboProlog 2.0 for calculating average. I don't know what predicates i need to write, and have no idea how link them together.

I'm not sure what functionality of "a circular buffer" needs to be realized for your application. In general a "buffer" would be reusable storage, often associated with I/O processes that handle asynchronous communications (hence the need for a buffer that allows one process to get ahead of the other). A "circular buffer" denotes a way of managing the available storage with pointers (both to the beginning and end of valid/unprocessed data) that wraparound through a (linear) contiguous region. This has an advantage over maintaining a FIFO queue with a fixed location for the beginning of valid data because no "shuffling" of unprocessed items is required.
In the general context of standard Prolog, where rewriting memory locations is not directly supported, that advantage doesn't make sense. Even in Turbo Prolog it has to be asked exactly what you want to accomplish, so that a skillful use of the extended/nonstandard features available can be made.
Here are some ideas:
Turbo Prolog supports lists that are in some ways more restrictive and perhaps in other ways more elaborate than the proper lists of standard Prolog. One of the restrictions is that in Turbo Prolog all items of a list must belong to the same "domain", a notion foreign to the weakly-typed character of standard Prolog. Also domains may be designated as "reference" domains in Turbo Prolog, a level of indirection that permits partially bound compound terms to be passed between subgoals. Without going into too much detail, one sense of "circular buffer" might be a "list" (formed from a reference domain) which wraps back around on itself (a cyclical reference). Such a term can be created in many other Prologs, the distinction being that it is not a proper list. Circular though such a term might be, it would not be much of a buffer (once created) because items in the list could not be rewritten.
Turbo Prolog supports dynamic assertion and retraction of facts, with metapredicates like asserta/1 and assertz/1 that allow serial positioning of new facts at the beginning or the end of those existing facts for the same predicate (and also if desired within a specified named "module" or factbase to use the Turbo Prolog terminology). If the simple management of items in a FIFO queue is your objective, then this is most likely the approach you want (at least for an initial implementation), with items encapsulated as facts.
Turbo Prolog also supports "external" factbases with some additional features, external in the sense of being stored (either in memory or on disk) in a way that allows persistence and expanded space beyond what is allocated for internal factbases. Given the modest fixed sizes usually associated with circular buffers (because they are meant for reuse and overflow is usually dealt with by blocking on the input process until the output process has a chance to catch up), external factbases don't seem to offer much of interest, though possibly the ability to persist "buffers" might be of interest for long-running processes.
Hopefully these suggestions will elicit some clarification on what really needs to be accomplished here.

After much thought, was written the following program
% Consumer predicate. If buffer is empty, nothing to take, need to wait for producer predicate.
consumer(BufferBefore, [], _) :-
length(BufferBefore, BuffSize),
BuffSize = 0,
write("Buffer is empty. Waiting for producer"), nl, !, fail.
% If the buffer is not empty, returns first element and removes them from the buffer
consumer(BufferBefore, BufferAfter, Result) :-
car(BufferBefore, Result),
deletefirst(BufferBefore, BufferAfter).
% Producer predicate. If data and buffer is empty, nothing taken from the data to put in buffer.
producer([], [], [], [], _) :- write("End of data!."), !, fail.
% Else if buffer is not empty, add first elem from data (and removes them from here) to last position in buffer.
producer(DataBefore, BufferBefore, DataAfter, BufferAfter, Size) :-
length(BufferBefore, BuffSize), BuffSize < Size, !,
car(DataBefore, Elem),
addlast(Elem, BufferBefore, BufferAfter),
deletefirst(DataBefore, DataAfter).
Several examples of running
consumer([1,2,3,4,5], BufferAfter, Result)
returns
BufferAfter = [2,3,4,5], Result = 1.
And
producer([1,2,3,4,5,6],[7,8,9],DataAfter, BufferAfter, %">3 here"%)
returns
DataAfrer = [2,3,4,5,6], BufferAfter = [7,8,9,1].
Now, to demonstrate any calculation, we need to write a program that, which will run "consumer" until the buffer is empty will be. And "consumer" will run "producer", when buffer is empty. And stop the process, when data and buffer will be empty.
Hope will be useful to anyone.

Related

How do you logically formulate the problem of operating systems deadlocks?

It is a programming assignment in Prolog to write a program that takes in input of processes, resources, etc and either print out the safe order of execution or simply return false if there is no safe order of execution.
I am very new to Prolog and I just simply can't get myself to think in the way it is demanding me to think (which is, formulating the problem logically and letting the compiler figure out how to do the operations) and I am stuck just thinking procedurally. How would you formulate such a problem logically, in terms of predicates and whatnot?
The sample input goes as follows: a list of processes, a list of pairs of resource and the number of available instances of that resource and facts allocated(x,y) with x being a process and y being a list of resources allocated to x and finally requested(x,y) such that x is a process and y is a list of resources requested by x.
For the life of me I can't think of it in terms of anything but C++. I am too stuck. I don't even need code, just clarity.
edit: here's a sample input. I seriously just need to see what I need to do. I am completely clueless.
processes([p1, p2, p3, p4, p5]).
available_resources([[r1, 2], [r2, 2], [r3, 2], [r4, 1], [r5, 2]]).
allocated(p1, [r1, r2]).
allocated(p2, [r1, r3]).
allocated(p3, [r2]).
allocated(p4, [r3]).
allocated(p5, [r4]).
requested(p5, [r5]).
What you want to do is apply the "state search" approach.
Start with an initial state S0.
Apply a transformation to S0 according to allowed rules, giving S1. The rules must allowed only consistent states to be created. For example, the rules may not allow to generate new resources ex nihilo.
Check whether the new state S1 fulfills the condition of a "final state" or "solution state" permitting you to declare victory.
If not, apply a transformation to S1, according to allowed rules, giving S2.
etc.
Applying transformations may get you to generate a state from which no progress is possible but which is not a "final state" either. You are stuck. In that case, dump a few of the latest transformations, moving back to an earlier state, and try other transformations.
Through this you get a tree of states through the state space as you explore the different possibilites to reach one of the final states (or the single final state, depending on the problem).
What we need is:
A state description ;
A set of allowed state transformations (sometimes called "operators") ;
A criterium to decide whether we are blocked in a state ;
A criterium to decide whether we have found a final state ;
Maybe a heuristic to decide which state to try next. If the state space is small enough, we can try everything blindly, otherwise something like A* might be useful.
The exploration algorithm itself. Starting with an initial state, it applies operators, generating new states, backtracks if blocked, and terminates if a final state has been reached.
State description
A state (at any time t) is described by the following relevant information:
a number of processes
a number of resources, several of the same kind
information about which processes have allocated which resources
information about which processes have requested which resources
As with anything else in informatics, we need a data structure for the above.
The default data structure in Prolog is the term, a tree of symbols. The extremely useful list is only another representation of a particular tree. One has to a representation so that it speaks to the human and can still be manipulated easily by Prolog code. So how about a term like this:
[process(p1),owns(r1),owns(r1),owns(r2),wants(r3)]
This expresses the fact that process p1 owns two resources r1 and one resource r2 and wants r3 next.
The full state is then a list of list specifying information about each process, for example:
[[process(p1),owns(r1),owns(r1),owns(r2),wants(r3)],
[process(p2),owns(r3),wants(r1)],
[process(p3),owns(r3)]]
Operator description
Prolog does not allow "mutable state", so an operator is a transformation from one state to another, rather than a patching of a state to represent some other state.
The fact that states are not modified in-place is of course very important because we (probably) want to retain the states already visited so as to be able to "back track" to an earlier state in case we are blocked.
I suppose the following operators may apply:
In state StateIn, process P requests resource R which it needs but can't obtain.
request(StateIn, StateOut, P, R) :- .... code that builds StateOut from StateIn
In state StateIn, process P obtains resource R which is free.
obtain(StateIn, StateOut, P, R) :- .... code that builds StateOut from StateIn
In state StateIn, process P frees resource R which is owns.
free(StateIn, StateOut, P, R) :- .... code that builds StateOut from StateIn
The code would be written such that if StateIn were
[[process(p1),owns(r1),owns(r1),owns(r2),wants(r3)],
[process(p2),owns(r3),wants(r1)],
[process(p3),owns(r3)]]
then free(StateIn, StateOut, p1, r2) would construct a StateOut
[[process(p1),owns(r1),owns(r1),wants(r3)],
[process(p2),owns(r3),wants(r1)],
[process(p3),owns(r3)]]
which becomes the new current state in the search loop. Etc. Etc.
A criterium to decide whether we are blocked in the current state
Often being "blocked" means that no operators are applicable to the state because for none of the operators, valid preconditions hold.
In this case the criterium seems to be "the state implies a deadlock".
So a predicate check_deadlock(StateIn) needs to be written. It has to test the state description for any deadlock conditions (performing its own little search, in fact).
A criterium to decide whether we have found a final state
This is underspecified. What is a final state for this problem?
In any case, there must be a check_final(StateIn) predicate which returns true if StateIn is, indeed, a final state.
Note that the finality criterium may also be about the whole path from the start state to the current state. In that case: check_path([StartState,NextState,...,CurrentState]).
The exploration algorithm
This can be relatively short in Prolog as you get depth-first search & backtracking for free if you don't use specific heuristics and keep things primitive.
You are all set!

Does `setup_call_cleanup/3` detect determinism portably?

There is a very detailed Draft proposal for setup_call_cleanup/3.
Let me quote the relevant part for my question:
c) The cleanup handler is called exactly once; no later than upon failure of G. Earlier moments are:
If G is true or false, C is called at an implementation dependent moment after the last solution and after the last observable effect of G.
And this example:
setup_call_cleanup(S=1,G=2,write(S+G)).
Succeeds, unifying S = 1, G = 2.
Either: outputs '1+2'
Or: outputs on backtracking '1+_' prior to failure.
Or (?): outputs on backtracking '1+2' prior to failure.
In my understanding, this is basically because a unification is a
backtrackable goal; it simply fails on reexecution. Therefore, it is
up to the implementation to decide whether to call the cleanup just
after the fist execution (because there will be no more observable
effects of the goal), or postpone until the second execution of the
goal which now fails.
So it seems to me that this cannot be used to detect determinism
portably. Only a few built-in constructs like true, fail, !
etc. are genuinely non-backtrackable.
Is there any other way to check determinism without executing a goal twice?
I'm currently using SWI-prolog's deterministic/1, but I'd certainly
appreciate portability.
No. setup_call_cleanup/3 cannot detect determinism in a portable manner. For this would restrict an implementation in its freedom. Systems have different ways how they implement indexing. They have different trade-offs. Some have only first argument indexing, others have more than that. But systems which offer "better" indexing behave often quite randomly. Some systems do indexing only for nonvar terms, others also permit clauses that simply have a variable in the head - provided it is the last clause. Some may do "manual" choice point avoidance with safe tests prior to cuts and others just omit this. Brief, this is really a non-functional issue, and insisting on portability in this area is tantamount to slowing systems down.
However, what still holds is this: If setup_call_cleanup/3 detects determinism, then there is no further need to use a second goal to determine determinism! So it can be used to implement determinism detection more efficiently. In the general case, however, you will have to execute a goal twice.
The current definition of setup_call_cleanup/3 was also crafted such as to permit an implementation to also remove unnecessary choicepoints dynamically.
It is thinkable (not that I have seen such an implementation) that upon success of Call and the internal presence of a choicepoint, an implementation may examine the current choicepoints and remove them if determinism could be detected. Another possibility might be to perform some asynchronous garbage collection in between. All these options are not excluded by the current specification. It is unclear if they will ever be implemented, but it might happen, once some applications depend on such a feature. This has happened in Prolog already a couple of times, so a repetition is not completely fantasy. In fact I am thinking of a particular case to help DCGs to become more determinate. Who knows, maybe you will go that path!
Here is an example how indexing in SWI depends on the history of previous queries:
?- [user].
p(_,a). p(_,b). end_of_file.
true.
?- p(1,a).
true ;
false.
?- p(_,a).
true.
?- p(1,a).
true. % now, it's determinate!
Here is an example, how indexing on the second argument is strictly weaker than first argument indexing:
?- [user].
q(_,_). q(0,0). end_of_file.
true.
?- q(X,1).
true ; % weak
false.
?- q(1,X).
true.
As you're interested in portability, Logtalk's lgtunit tool defines a portable deterministic/1 predicate for 10 of its supported backend Prolog compilers:
http://logtalk.org/library/lgtunit_0.html
https://github.com/LogtalkDotOrg/logtalk3/blob/master/tools/lgtunit/lgtunit.lgt (starting around line 1051)
Note that different systems use different built-in predicates that approximate the intended functionality.

How to avoid using assert and retractall in Prolog to implement global (or state) variables

I often end up writing code in Prolog which involves some arithmetic calculation (or state information important throughout the program), by means of first obtaining the value stored in a predicate, then recalculating the value and finally storing the value using retractall and assert because in Prolog we cannot assign values to variable twice using is (thus making almost every variable that needs modification, global). I have come to know that this is not a good practice in Prolog. In this regard I would like to ask:
Why is it a bad practice in Prolog (though i myself don't like to go through the above mentioned steps just to have have a kind of flexible (modifiable) variable)?
What are some general ways to avoid this practice? Small examples will be greatly appreciated.
P.S. I just started learning Prolog. I do have programming experience in languages like C.
Edited for further clarification
A bad example (in win-prolog) of what I want to say is given below:
:- dynamic(value/1).
:- assert(value(0)).
adds :-
value(X),
NewX is X + 4,
retractall(value(_)),
assert(value(NewX)).
mults :-
value(Y),
NewY is Y * 2,
retractall(value(_)),
assert(value(NewY)).
start :-
retractall(value(_)),
assert(value(3)),
adds,
mults,
value(Q),
write(Q).
Then we can query like:
?- start.
Here, it is very trivial, but in real program and application, the above shown method of global variable becomes unavoidable. Sometimes the list given above like assert(value(0))... grows very long with many more assert predicates for defining more variables. This is done to make communication of the values between different functions possible and to store states of variables during the runtime of program.
Finally, I'd like to know one more thing:
When does the practice mentioned above become unavoidable in spite of various solutions suggested by you to avoid it?
The general way to avoid this is to think in terms of relations between states of your computations: You use one argument to hold the state that is relevant to your program before a calculation, and a second argument that describes the state after some calculation. For example, to describe a sequence of arithmetic operations on a value V0, you can use:
state0_state(V0, V) :-
operation1_result(V0, V1),
operation2_result(V1, V2),
operation3_result(V2, V).
Notice how the state (in your case: the arithmetic value) is threaded through the predicates. The naming convention V0 -> V1 -> ... -> V scales easily to any number of operations and helps to keep in mind that V0 is the initial value, and V is the value after the various operations have been applied. Each predicate that needs to access or modify the state will have an argument that allows you to pass it the state.
A huge advantage of threading the state through like this is that you can easily reason about each operation in isolation: You can test it, debug it, analyze it with other tools etc., without having to set up any implicit global state. As another huge benefit, you can then use your programs in more directions provided you are using sufficiently general predicates. For example, you can ask: Which initial values lead to a given outcome?
?- state0_state(V0, given_outcome).
This is of course not readily possible when using the imperative style. You should therefore use constraints instead of is/2, because is/2 only works in one direction. Constraints are much easier to use and a more general modern alternative to low-level arithmetic.
The dynamic database is also slower than threading states through in variables, because it performs indexing etc. on each assertz/1.
1 - it's bad practice because destroys the declarative model that (pure) Prolog programs exhibit.
Then the programmer must think in procedural terms, and the procedural model of Prolog is rather complicate and difficult to follow.
Specifically, we must be able to decide about the validity of asserted knowledge while the programs backtracks, i.e. follow alternative paths to those already tried, that (maybe) caused the assertions.
2 - We need additional variables to keep the state. A practical, maybe not very intuitive way, is using grammar rules (a DCG) instead of plain predicates. Grammar rules are translated adding two list arguments, normally hidden, and we can use those arguments to pass around the state implicitly, and reference/change it only where needed.
A really interesting introduction is here: DCGs in Prolog by Markus Triska. Look for Implicitly passing states around: you'll find this enlighting small example:
num_leaves(nil), [N1] --> [N0], { N1 is N0 + 1 }.
num_leaves(node(_,Left,Right)) -->
num_leaves(Left),
num_leaves(Right).
More generally, and for further practical examples, see Thinking in States, from the same author.
edit: generally, assert/retract are required only if you need to change the database, or keep track of computation result along backtracking. A simple example from my (very) old Prolog interpreter:
findall_p(X,G,_):-
asserta(found('$mark')),
call(G),
asserta(found(X)),
fail.
findall_p(_,_,N) :-
collect_found([],N),
!.
collect_found(S,L) :-
getnext(X),
!,
collect_found([X|S],L).
collect_found(L,L).
getnext(X) :-
retract(found(X)),
!,
X \= '$mark'.
findall/3 can be seen as the basic all solutions predicate. That code should be the very same from Clockins-Mellish textbook - Programming in Prolog. I used it while testing the 'real' findall/3 I implemented. You can see that it's not 'reentrant', because of the '$mark' aliased.

State propagation during bactracking in Prolog

Let's assume, that I have a simple program in Prolog, which is searching through a certain state space:
search(State, State) :-
is_solution(State).
search(State, Solution) :-
generate(State, NewState),
search(NewState, Solution).
And I know that:
generate(State, NewState) is producing at least one NewState for any given State
the whole states space is finite
I want to modify the search predicate to ensure that it always manages to check in a finite time. So I write something like:
search(State, Solution) :-
empty_memory(EmptyMem),
add(State, EmptyMem, Memory),
search(State, Memory, Solution).
search(State, _, State) :-
is_solution(State).
search(State, Memory, Solution) :-
generate(State, NewState),
\+ exist(NewState, Memory),
add(NewState, Memory, NewMemory),
search(NewState, NewMemory, Solution).
which is working, but it's losing computed states during backtracking, so now I have a search tree with maximum height of space size.
Is it any way to propagate a state during the backtracking without losing any computed information? I want to have a whole search tree with O(space_size) nodes. Is it possible?
EDIT:
It seems that I should use assert/[1,2] in order to dynamically create new clauses which will serve as a global memory.
In SICStus Prolog, you can use the blackboard to store information across backtracks: see Blackboard Primitives in the manual. Use bb_put(Key, Value) to store something on the blackboard, and bb_get(Key, Value) to retrieve it. Note that the bloackboard is defined per module.
The most clean solution will likely be to use a Prolog compiler that supports tabling like B-Prolog, Ciao, XSB, or YAP. In this case, you would simply declare the generate/2 predicate as tabled.
Instead of using assert, why not generate all possible states with findall(N, generate(S,N),ALL). This will eliminate the need for backtracking and will explicate the search space tree, which then could be preorder-traversed while passing along the visited-so-far states as additional argument.

Alternatives to the WAM

I remember once reading that there were at least two other alternatives invented roughly at the same time as the WAM. Any pointers?
Prior to the WAM, there was the ZIP by Clocksin. Its design is still very interesting. SWI-Prolog uses it. And also B-Prolog has slowly migrated from a WAM design towards the ZIP. Of course, on that way many new innovations were developed. Another alternative is the VAM.
A comparison as of 1993 is:
http://www.complang.tuwien.ac.at/ulrich/papers/PDF/binwam-nov93.pdf
In the meantime, the most interesting architectural developments are related to B-Prolog.
WAM vs. ZIP
The key difference between the WAM and the ZIP is the precise interface for a predicate's arguments. In the WAM, the arguments are all passed via registers, that is, either real registers or at least fixed locations in memory. The ZIP passes all arguments via the stack.
Let's consider a minimal example:
p(R1,R2,R3,L1,L2,L3) :- % WAM % ZIP
% store L1..L3 % nothing
% nothing % push R1..R3
% init X1..X3 % push X1..X3
q(R1,R2,R3,X1,X2,X3),
% put unsafe X1..X3 % push X1..X3
% load L1..L3 % push L1..L3
r(X1,X2,X3,L1,L2,L3).
Prior to calling q:
The WAM does not need to do any action for arguments that are passed on to the first goal at the very same positions (R1..R3). This is particularly interesting for binary clauses - that is, clauses with exactly one regular goal at the end. Here the WAM excels.
The other arguments L1..L3 need to be stored locally. So for these arguments, the register interface did not do anything good.
The ZIP on the other hand does not need to save arguments - they are already saved on the stack. This is not only good for clauses with more than one goal, but also for other interrupting goals like constraints or interrupts.
As a downside, the ZIP must push again R1..R3.
Both have to initialize X1..X3 and store them on the stack.
Calling q:
When calling q, the WAM has to allocate stack space for X1..X3 and L1..L3 thus 6 cells, whereas the ZIP needs R1..R3,L1..L3,X1..X3. So here, the WAM is more space efficient. Also, the WAM permits environment trimming (for more complex situations) which is next-to-impossible for the ZIP.
Prior to calling r:
This r is the last call, and systems try to free the space for this clause, provided no choice point is present.
For the WAM, the existential variables X1..X3 have to be checked for being still uninstantiated local variables (put_unsafe), and if, they are moved onto the heap - that's expensive, but occurs rarely. L1..L3 are just loaded. That's all, the WAM can now safely deallocate the local frame. So last call optimization is dirt cheap.
For the ZIP, everything has to be pushed as usual. Then only, an extra scan has to examine all the values on the stack and moves them accordingly. That's rather expensive. Some optimizations are possible, but it is still much more than what the WAM does. ((A possible improvement would be to push arguments in reverse order. Then the variables L1..L3 might be left in their location. So these variables would not need any handling. I have not seen such an implementation (yet).))
In the technical note entitled An abstract Prolog instruction set, Warren also references another compiler by Bowen, Byrd, and Clocksin. However, he says that the two architectures have much in common, so I don't know whether that compiler could be really considered as an alternative.
Not sure if this is what you mean, but the first two Prolog implementations were an interpreter written in Fortran by Colmerauer et al. and a DEC PDP-10 native compiler by Warren et al.
Warren mentions these in his foreword to Ait-Kaci's Tutorial Reconstruction of the WAM. If this is not what you mean, you may find it in that document or its references.

Resources