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

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!

Related

Prolog CLP order of operations?

Hi hopefully someone can help me. I was just wondering if my code below was sufficient in setting up a matrix of 12 x 12 and, assuming the 'constrain(M)' calls all the correct constraints which are defined in rules lower down, labelling each of the rows? It's failing at the moment and I've traced my constraints so I know they all work but didn't know whether it was because I'm calling them outside of the main predicate?
matrix(M) :-
M = [R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12],
R1 = [A,B,C,D,E,F,G,H,I,J,K,L],
R2 = [A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2],
R3 = [A3,B3,C3,D3,E3,F3,G3,H3,I3,J3,K3,L3],
R4 = [A4,B4,C4,D4,E4,F4,G4,H4,I4,J4,K4,L4],
R5 = [A5,B5,C5,D5,E5,F5,G5,H5,I5,J5,K5,L5],
R6 = [A6,B6,C6,D6,E6,F6,G6,H6,I6,J6,K6,L6],
R7 = [A7,B7,C7,D7,E7,F7,G7,H7,I7,J7,K7,L7],
R8 = [A8,B8,C8,D8,E8,F8,G8,H8,I8,J8,K8,L8],
R9 = [A9,B9,C9,D9,E9,F9,G9,H9,I9,J9,K9,L9],
R10 = [A10,B10,C10,D10,E10,F10,G10,H10,I10,J10,K10,L10],
R11 = [A11,B11,C11,D11,E11,F11,G11,H11,I11,J11,K11,L11],
R12 = [A12,B12,C12,D12,E12,F12,G12,H12,I12,J12,K12,L12],
constrain(M),
labeling([],R1),
labeling([],R2),
labeling([],R3),
labeling([],R4),
labeling([],R5),
labeling([],R6),
labeling([],R7),
labeling([],R8),
labeling([],R9),
labeling([],R10),
labeling([],R11),
labeling([],R12).
You should always separate the constraint posting from the actual search (labeling/2).
The reason is clear: It can often be extremely expensive to search for concrete solutions. Posting the constraints, on the other hand, is often very fast.
If, as in your case, the two parts are uncleanly mixed, you cannot tell easily which part is responsible if there are unexpected problems such as nontermination.
In your case, the only thing you should improve in the main predicate is enforcing said separation between constraint posting and search.
The mistake that causes unexpected failure is most likely contained in one of the rules you did not post here. You can find out which rules are involved in the failure by systematically replacing the goals in which they are called by true. Thus, there's no need for tracing: You can debug CLP(FD) programs declaratively in this way.
EDIT: Here is more information about the separation between posting constraints and the search for concrete solutions. As introduced in GUPU, we will use the notion of core relation, which has the following properties:
By convention, its name ends with an underscore _.
Also by convention, its last argument is the list of variables that need to be labeled.
It posts the CLP(FD) constraints. This is also called the (constraint) modeling part or (constraint) model.
It doesn't use labeling/2.
The search part is usually performed by label/1 or labeling/2.
Suppose you have a predicate where you intermingle these two aspects, such as in your current case:
matrix(M) :-
constraints_hold(M),
... relate M to variables Vs ...
labeling(Strategy, Vs).
Obviously, for the reasons explained above, the call of labeling/2 is the part we want to remove from this predicate. Of course, as you observe, we still want to somehow access the variables that are supposed to be labeled.
We do this as follows:
We introduce a new argument to the core relation to pass around the list of finite domain variables that need to be labeled.
By convention, we reflect the additional argument by appending an underscore (_) to the predicate name.
So, we obtain the following core relation:
matrix_(M, Vs) :-
constraints_hold(M),
... relate M to variables Vs ...
The only missing part (which you haven't done yet, but which you should have done in any case), is stating the relation between the object of interest (in this case: the matrix) and the finite domain variables. This is the part I leave as a simple exercise for you. Hint: append/2.
Once you have done all this, you can solve the whole task by combining the core relation and labeling/2 in a single query or predicate:
?- matrix_(M, Vs), labeling(Strategy, Vs).
Note that this separation between core relation and search:
makes it extremely easy to try different labeling strategies without recompiling your program.
allows you to determine important procedural properties of the core relation without needing to search for concrete solutions.
Use the introduction and explanation of this important separation as an indicator when judging the quality of any text about CLP(FD) constraints.

How to recognize variables that don't affect the output of a program?

Sometimes the value of a variable accessed within the control-flow of a program cannot possibly have any effect on a its output. For example:
global var_1
global var_2
start program hello(var_3, var_4)
if (var_2 < 0) then
save-log-to-disk (var_1, var_3, var_4)
end-if
return ("Hello " + var_3 + ", my name is " + var_1)
end program
Here only var_1 and var_3 have any influence on the output, while var_2 and var_4 are only used for side effects.
Do variables such as var_1 and var_3 have a name in dataflow-theory/compiler-theory?
Which static dataflow analysis techniques can be used to discover them?
References to academic literature on the subject would be particularly appreciated.
The problem that you stated is undecidable in general,
even for the following very narrow special case:
Given a single routine P(x), where x is a parameter of type integer. Is the output of P(x) independent of the value of x, i.e., does
P(0) = P(1) = P(2) = ...?
We can reduce the following still undecidable version of the halting problem to the question above: Given a Turing machine M(), does the program
never stop on the empty input?
I assume that we use a (Turing-complete) language in which we can build a "Turing machine simulator":
Given the program M(), construct this routine:
P(x):
if x == 0:
return 0
Run M() for x steps
if M() has terminated then:
return 1
else:
return 0
Now:
P(0) = P(1) = P(2) = ...
=>
M() does not terminate.
M() does terminate
=> P(x) = 1 for a sufficiently large x
=> P(x) != P(0) = 0
So, it is very difficult for a compiler to decide whether a variable actually does not influence the return value of a routine; in your example, the "side effect routine" might manipulate one of its values (or even loop infinitely, which would most definitely change the return value of the routine ;-)
Of course overapproximations are still possible. For example, one might conclude that a variable does not influence the return value if it does not appear in the routine body at all. You can also see some classical compiler analyses (like Expression Simplification, Constant propagation) having the side effect of eliminating appearances of such redundant variables.
Pachelbel has discussed the fact that you cannot do this perfectly. OK, I'm an engineer, I'm willing to accept some dirt in my answer.
The classic way to answer you question is to do dataflow tracing from program outputs back to program inputs. A dataflow is the connection of a program assignment (or sideeffect) to a variable value, to a place in the application that consumes that value.
If there is (transitive) dataflow from a program output that you care about (in your example, the printed text stream) to an input you supplied (var2), then that input "affects" the output. A variable that does not flow from the input to your desired output is useless from your point of view.
If you focus your attention only the computations involved in the dataflows, and display them, you get what is generally called a "program slice" . There are (very few) commercial tools that can show this to you.
Grammatech has a good reputation here for C and C++.
There are standard compiler algorithms for constructing such dataflow graphs; see any competent compiler book.
They all suffer from some limitation due to Turing's impossibility proofs as pointed out by Pachelbel. When you implement such a dataflow algorithm, there will be places that it cannot know the right answer; simply pick one.
If your algorithm chooses to answer "there is no dataflow" in certain places where it is not sure, then it may miss a valid dataflow and it might report that a variable does not affect the answer incorrectly. (This is called a "false negative"). This occasional error may be satisfactory if
the algorithm has some other nice properties, e.g, it runs really fast on a millions of code. (The trivial algorithm simply says "no dataflow" in all places, and it is really fast :)
If your algorithm chooses to answer "yes there is a dataflow", then it may claim that some variable affects the answer when it does not. (This is called a "false positive").
You get to decide which is more important; many people prefer false positives when looking for a problem, because then you have to at least look at possibilities detected by the tool. A false negative means it didn't report something you might care about. YMMV.
Here's a starting reference: http://en.wikipedia.org/wiki/Data-flow_analysis
Any of the books on that page will be pretty good. I have Muchnick's book and like it lot. See also this page: (http://en.wikipedia.org/wiki/Program_slicing)
You will discover that implementing this is pretty big effort, for any real langauge. You are probably better off finding a tool framework that does most or all this for you already.
I use the following algorithm: a variable is used if it is a parameter or it occurs anywhere in an expression, excluding as the LHS of an assignment. First, count the number of uses of all variables. Delete unused variables and assignments to unused variables. Repeat until no variables are deleted.
This algorithm only implements a subset of the OP's requirement, it is horribly inefficient because it requires multiple passes. A garbage collection may be faster but is harder to write: my algorithm only requires a list of variables with usage counts. Each pass is linear in the size of the program. The algorithm effectively does a limited kind of dataflow analysis by elimination of the tail of a flow ending in an assignment.
For my language the elimination of side effects in the RHS of an assignment to an unused variable is mandated by the language specification, it may not be suitable for other languages. Effectiveness is improved by running before inlining to reduce the cost of inlining unused function applications, then running it again afterwards which eliminates parameters of inlined functions.
Just as an example of the utility of the language specification, the library constructs a thread pool and assigns a pointer to it to a global variable. If the thread pool is not used, the assignment is deleted, and hence the construction of the thread pool elided.
IMHO compiler optimisations are almost invariably heuristics whose performance matters more than effectiveness achieving a theoretical goal (like removing unused variables). Simple reductions are useful not only because they're fast and easy to write, but because a programmer using a language who understand basics of the compiler operation can leverage this knowledge to help the compiler. The most well known example of this is probably the refactoring of recursive functions to place the recursion in tail position: a pointless exercise unless the programmer knows the compiler can do tail-recursion optimisation.

How can you count, the amount of backtracks in Prolog SWI or CHR Prolog SWI

I'm creating several puzzle solvers in Prolog SWI with CHR (Constraint Handling Rules)
Everything works great but, I like to test which solver is best one.
Therefore I like to find out, which solver uses the least amount of backtracks.
Is there a clever way to find out (or print out), the amount of backtracks that the solver had needed for solving a particular puzzle?
Logically, counting would help, but it doesn't --> backtracking ! <-- .
Also, printing a new line on the screen isn't effective, because of SWI's GUI. You can't print more than +/- 50 lines and can't select properly
It is indeed not trivial to accomplish this, given Constraint Handling Rules maintain a 'constraint store' and execution of rules may add, rewrite or remove rules from this store at runtime. This changes the state of the program and makes it somewhat difficult to keep track of global states throughout execution.
However, since CHR is integrated in SWI, you can make use of the non-logical operation nb_setarg/3 to keep count of the backtracks.
Notes from the doc:
Compatible with GNU-Prolog's setarg(A,T,V,false)
This implementation is thread-safe, reentrant and capable of handling exceptions
EDIT
As regarding where to count the backtracks, this of course depends on your program, but will usually occur in the CHR constraint rule that defines the fail condition of your search, allowing it to 'branch' (= rewrite CHR rules). Every time a rewrite of the constraint store occurs during search, it represents a backtrack and you can increase a counter accordingly using the operation as defined above.
Consider a small, abstract example:
invalid_state ==> increment_backtracks, fail.
guess <=> branch

Find a non-deterministic CFL whose reverse is deterministic

I have a homework assignment, and i am finished other then one question (see title)
For the life of my, i cannot figure this out... so i started to think it was a trick question.
the current answer that i will submit is:
L1 = {a^n b^n: n>=1} is deterministic. And the reverse,
L2 = {b^n a^n: n>=1} is also deterministic.
However, since all deterministic languages are a subset of Non-deterministic languages, L2 can be considered non-deterministic.
On a side note, the only other example i was trying to make work is:
L3= {{a,b}a}
This seems possible because forward there is non-determinism, since the input could be either a, or b as long as its followed by an a.
and in reverse there is determinism since it will accept only an 'a'. But, it introduces new non-determinism since the second input could be either a or b.
any help / guidance would be great.
I know the deadline has passed, but somebody might find this useful in the future.
(a+b+c)*WcW^R, where W is in (a+b)+; this is non-deterministic because you don't know where the "WcW" bit starts.
W^RcW(a+b+c)*, where W is in (a+b)+; this is deterministic because you can write a deterministic PDA to accept simple palindromes of the form "W^RcW" and modify the accepting state to loop to itself on any of a, b and c.
The trick here is that PDAs have to read input from left to right.

Circular buffer in Turbo Prolog 2.0

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.

Resources