I'm implementing a DPLL algorithm in C++ as described in wikipedia:
function DPLL(Φ)
if Φ is a consistent set of literals
then return true;
if Φ contains an empty clause
then return false;
for every unit clause l in Φ
Φ ← unit-propagate(l, Φ);
for every literal l that occurs pure in Φ
Φ ← pure-literal-assign(l, Φ);
l ← choose-literal(Φ);
return DPLL(Φ ∧ l) or DPLL(Φ ∧ not(l));
but having an awful performance. In this step:
return DPLL(Φ ∧ l) or DPLL(Φ ∧ not(l));
currently I'm trying to avoid creating copies of Φ but instead adding l or not(l) to the one and only copy of Φ and remove them when/if DPLL()'s return false. This seems to break the algorithm giving wrong results (UNSATISFIABLE even though the set is SATISFIABLE).
Any suggestions on how to avoid explicit copies in this step?
A less naive approach to DPLL avoids copying the formula by recording the variable assignments and the changes made to the clauses in the unit-propagation and pure-literal assignment steps and then undoes the changes (backtracks) when an empty clause is produced. So when a variable x is assigned true, you would mark all clauses containing a positive literal of x as inactive (and ignore them thereafter since they are satisfied) and remove -x from all clauses that contain it. Record which clauses had -x in them so you can backtrack later. Also record which clauses you marked inactive, for the same reason.
Another approach is to keep track of the number of unassigned variables in each unsatisfied clause. Record when the number decreases so you can backtrack later. Do unit propagation if the count reaches 1, backtrack if the number reaches 0 and all the literals are false.
I wrote "less naive" above because there are still better approaches. Modern DPLL-type SAT solvers use a lazy clause updating scheme called "two watched literals" that has the advantage of not needing to remove literals from clauses and thus not needing to restore them when a bad assignment is found. The variable assignments still have to be recorded and backtracked, but not having to update the clause-related structures makes two watched literals faster than any other known backtracking scheme for SAT solvers. You'll no doubt learn about this later in your class.
Related
I have got to write an algorithm programatically using haskell. The program takes a regular expression r made up of the unary alphabet Σ = {a} and check if the regular expression r defines the language L(r) = a^* (Kleene star). I am looking for any kind of tip. I know that I can translate any regular expression to the corresponding NFA then to the DFA and at the very end minimize DFA then compare, but is there any other way to achieve my goal? I am asking because it is clearly said that this is the unary alphabet, so I suppose that I have to use this information somehow to make this exercise much easier.
This is how my regular expression data type looks like
data Reg = Epsilon | -- epsilon regex
Literal Char | -- a
Or Reg Reg | -- (a|a)
Then Reg Reg | -- (aa)
Star Reg -- (a)*
deriving Eq
Yes, there is another way. Every DFA for regular languages on the single-letter alphabet is a "lollipop"1: an initial string of nodes that each point to each other (some of which are marked as final and some not) followed by a loop of nodes (again, some of which are marked as final and some not). So instead of doing a full compilation pass, you can go directly to a DFA, where you simply store two [Bool] saying which nodes in the lead-in and in the loop are marked final (or perhaps two [Integer] giving the indices and two Integer giving the lengths may be easier, depending on your implementation plans). You don't need to ensure the compiled version is minimal; it's easy enough to check that all the Bools are True. The base cases for Epsilon and Literal are pretty straightforward, and with a bit of work and thought you should be able to work out how to implement the combining functions for "or", "then", and "star" (hint: think about gcd's and stuff).
1 You should try to prove this before you begin implementing, so you can be sure you believe me.
Edit 1: Hm, while on my afternoon walk today, I realized the idea I had in mind for "then" (and therefore "star") doesn't work. I'm not giving up on this idea (and deleting this answer) yet, but those operations may be trickier than I gave them credit for at first. This approach definitely isn't for the faint of heart!
Edit 2: Okay, I believe now that I have access to pencil and paper I've worked out how to do concatenation and iteration. Iteration is actually easier than concatenation. I'll give a hint for each -- though I have no idea whether the hint is a good one or not!
Suppose your two lollipops have a length m lead-in and a length n loop for the first one, and m'/n' for the second one. Then:
For iteration of the first lollipop, there's a fairly mechanical/simple way to produce a lollipop with a 2*m + 2*n-long lead-in and n-long loop.
For concatenation, you can produce a lollipop with m + n + m' + lcm(n, n')-long lead-in and n-long loop (yes, that short!).
I have a function which will fail if there has being any change on the term/list it is using since the generation of this term/list. I would like to avoid to check that each parameter still the same. So I had thought about each time I generate the term/list to perform a CRC or something similar. Before making use of it I would generate again the CRC so I can be 99,9999% sure the term/list still the same.
Going to a specfic answer, I am programming in Erlang, I am thinking on using a function of the following type:
-spec(list_crc32(List :: [term()]) -> CRC32 :: integer()).
I use term, because it is a list of terms, (erlang has already a default fast CRC libraries but for binary values). I have consider to use "erlang:crc32(term_to_binary(Term))", but not sure if there could be a better approach.
What do you think?
Regards, Borja.
Without more context it is a little bit difficult to understand why you would have this problem, particularly since Erlang terms are immutable -- once assigned no other operation can change the value of a variable, not even in the same function.
So if your question is "How do I quickly assert that true = A == A?" then consider this code:
A = generate_list()
% other things in this function happen
A = A.
The above snippet will always assert that A is still A, because it is not possible to change A like you might do in, say, Python.
If your question is "How do I assert that the value of a new list generated exactly the same value as a different known list?" then using either matching or an actual assertion is the fastest way:
start() ->
A = generate_list(),
assert_loop(A).
assert_loop(A) ->
ok = do_stuff(),
A = generate_list(),
assert_loop(A).
The assert_loop/1 function above is forcing an assertion that the output of generate_list/0 is still exactly A. There is no telling what other things in the system might be happening which may have affected the result of that function, but the line A = generate_list() will crash if the list returned is not exactly the same value as A.
In fact, there is no way to change the A in this example, no matter how many times we execute assert_loop/1 above.
Now consider a different style:
compare_loop(A) ->
ok = do_stuff(),
case A =:= generate_list() of
true -> compare_loop(A);
false -> terminate_gracefully()
end.
Here we have given ourselves the option to do something other than crash, but the effect is ultimately the same, as the =:= is not merely a test of equality, it is a match test meaning that the two do not evaluate to the same values, but that they actually match.
Consider:
1> 1 == 1.0.
true
2> 1 =:= 1.0.
false
The fastest way to compare two terms will depend partly on the sizes of the lists involved but especially on whether or not you expect the assertion to pass or fail more often.
If the check is expected to fail more often then the fastest check is to use an assertion with =, an equivalence test with == or a match test with =:= instead of using erlang:phash2/1. Why? Because these tests can return false as soon as a non-matching element is encountered -- and if this non-match occurs near the beginning of the list then a full traverse of both lists is avoided entirely.
If the check is expected to pass more often then something like erlang:phash2/1 will be faster, but only if the lists are long, because only one list will be fully traversed each iteration (the hash of the original list is already stored). It is possible, though, on a short list that a simple comparison will still be faster than computing a hash, storing it, computing another hash, and then comparing the hashes (obviously). So, as always, benchmark.
A phash2 version could look like:
start() ->
A = generate_list(),
Hash = erlang:phash2(A),
assert_loop(Hash).
assert_loop(Hash) ->
ok = do_stuff(),
Hash = erlang:phash2(generate_list()),
loop(Hash).
Again, this is an assertive loop that will crash instead of exit cleanly, so it would need to be adapted to your needs.
The basic mystery still remains, though: in a language with immutable variables why is it that you don't know whether something will have changed? This is almost certainly a symptom of an underlying architectural problem elsewhere in the program -- either that or simply a misunderstanding of immutability in Erlang.
Hey I am a little bit confused over prolog recursion and iteration. I am giving code for sum of a list in recursion and iteration respectively and want to know if each of them is correct or not...
add_r([],0).
add_r([H|T],X) :- add_r(T,X1),X is H + X1.
add_i(List,Sum) :- add_i(List,0,Sum).
add_i([H|T],I,Sum) :- I1 is I + H , add_i(T,I1,Sum).
add_i([], I1, I1).
here add_r is recursive program and add_i is iterative (according to me)...I may be wrong.Here "I" is used for iteration control.
Please correct me if I am wrong.
If you use the terminology of Abelson & Sussman (Structure and Interpretation of Computer Programs) you are quite correct.
In this case "iterative" means the state of the process is fully described by just a few variables and "recursive" means the number of variables grows with each call. Also, a "recursive" process has 2 stages: grow and reduction and when it grows it leaves "choice-points" etc (all the differences are described in SICP).
In Prolog the term "tail recursion" is used more often than "iterative" in regard to your second example.
Strictly speaking, Prolog doesn't allow iteration, because variables are 'write once' (kind of...).
Both predicates are recursive, and seem correct to me.
The difference between them it's that add_i is tail recursive (the recursive call appears as last), and thus the compiler can optimize it (see last call optimization, or Tail Call), replacing the recursive call with a jump, thus avoiding the linear stack space required by add_r .
I am trying to get a feel for Prolog programming by going through Ulle Endriss' lecture notes. When my solution to an exercise does not behave as expected, I find it difficult to give a good explanation. I think this has to do with my shaky understanding of the way Prolog evaluates expressions.
Exercise 2.6 on page 20 calls for a recursive implementation of a predicate last1 which behaves like the built-in predicate last. My attempt is as follows:
last1([_ | Rest], Last) :- last1(Rest, Last).
last1([Last], Last).
It gives the correct answer, but for lists with more than one element, I have to key in the semicolon to terminate the query. This makes last1 different from the built-in last.
?- last1([1], Last).
Last = 1.
?- last1([1, 2], Last).
Last = 2 ;
false.
If I switch the order in which I declared the rule and fact, then I need to key in the semicolon in both cases.
I think I know why Prolog thinks that last1 may have one more solution (thus the semicolon). I imagine it follows the evaluation sequence
last1([1, 2], Last).
==> last1([2], Last).
==> last1([], Last). OR Last = 2.
==> false OR Last = 2.
That seems to suggest that I should look for a way to avoid matching Rest with []. Regardless, I have no explanation why switching the order of declaration ought to have any effect at all.
Question 1: What is the correct explanation for the behavior of last1?
Question 2: How can I implement a predicate last1 which is indistinguishable from the built-in last?
Question 1:
Prolog systems are not always able to decide whether or not a clause will apply prior to executing it. The precise circumstances are implementation dependent. That is, you cannot rely on that decision in general. Systems do improve here from release to release. Consider as the simplest case:
?- X = 1 ; 1 = 2.
X = 1
; false.
A very clever Prolog could detect that 1 = 2 always fails, and thus simply answer X = 1. instead. On the other hand, such "cleverness" is very costly to implement and time is better spent for optimizing more frequent cases.
So why do Prologs show this at all? The primary reason is to avoid asking meekly for another answer, if Prolog already knows that there is no further answer. So prior to this improvement, you were prompted for another answer for all queries containing variables and got the false or "no" on each and every query with exactly one answer. This used to be so cumbersome that many programmers never asked for the next answer and thus were not alerted about unintended answers.
And the secondary reason is to keep you aware of the limitations of the implementation: If Prolog asks for another answer on this general query, this means that it still uses some space which might accumulate and eat up all your computing resources.
In your example with last1/2 you encounter such a case. And you already did something very smart, BTW: You tried to minimize the query to see the first occurrence of the unexpected behavior.
In your example query last1([1,2],X) the Prolog system does not look at the entire list [1,2] but only looks at the principal functor. So for the Prolog system the query looks the same as last1([_|_],X) when it decides which clauses to apply. This goal now fits to both clauses, and this is the reason why Prolog will remember the second clause as an alternative to try out.
But, think of it: This choice is now possible for all elements but the last! Which means that you pay some memory for each element! You can actually observe this by using a very long list. This I get on my tiny 32-bit laptop — you might need to add another zero or two on a larger system:
?- length(L,10000000), last1(L,E).
resource_error(_). % ERROR: Out of local stack
On the other hand, the predefined last/2 works smoothly:
?- length(L,10000000), last(L,E).
L = [_A,_B,_C,_D,_E,_F,_G,_H,_I|...].
In fact, it uses constant space!
There are now two ways out of this:
Try to optimize your definition. Yes, you can do this, but you need to be very smart! The definition by #back_dragon for example is incorrect. It often happens that beginners try to optimize a program when in fact they are destroying its semantics.
Ask yourself if you are actually defining the same predicate as last/2. In fact, you're not.
Question 2:
Consider:
?- last(Xs, X).
Xs = [X]
; Xs = [_A,X]
; Xs = [_A,_B,X]
; Xs = [_A,_B,_C,X]
; Xs = [_A,_B,_C,_D,X]
; ... .
and
?- last1(Xs, X).
loops.
So your definition differs in this case with SWI's definition. Exchange the order of the clauses.
?- length(L,10000000), last2(L,E).
L = [_A,_B,_C,_D,_E,_F,_G,_H,_I|...]
; false.
Again, this false! But this time, the big list works. And this time, the minimal query is:
?- last2([1],E).
E = 1
; false.
And the situation is quite similar: Again, Prolog will look at the query in the same way as last2([_|_],E) and will conclude that both clauses apply. At least, we now have constant overhead instead of linear overhead.
There are several ways to overcome this overhead in a clean fashion - but they all very much depend on the innards of an implementation.
SWI-Prolog attempts to avoid prompting for more solutions when it can determine that there are none. I think that the interpreter inspect the memory looking for some choice point left, and if it can't find any, simply state the termination. Otherwise it waits to let user choice the move.
I would attempt to make last1 deterministic in this way:
last1([_,H|Rest], Last) :- !, last1([H|Rest], Last).
last1([Last], Last).
but I don't think it's indistinguishable from last. Lurking at the source code of the library (it's simple as ?- edit(last).)
%% last(?List, ?Last)
%
% Succeeds when Last is the last element of List. This
% predicate is =semidet= if List is a list and =multi= if List is
% a partial list.
%
% #compat There is no de-facto standard for the argument order of
% last/2. Be careful when porting code or use
% append(_, [Last], List) as a portable alternative.
last([X|Xs], Last) :-
last_(Xs, X, Last).
last_([], Last, Last).
last_([X|Xs], _, Last) :-
last_(Xs, X, Last).
we can appreciate a well thought implementation.
this code would work:
last1([Last], Last).
last1([_ | Rest], Last) :- last1(Rest, Last), !.
it is because prolog things there might be more combinations but, with this symbol: !, prolog won't go back after reaching this point
I am trying to implement DPLL algorithm in C++, I am wondering what kind of data structure would be best for solving this type of recursion problem. Right now I am using vectors, but the code is long and ugly. Are there any suggestions?
function DPLL(Φ)
if Φ is a consistent set of literals
then return true;
if Φ contains an empty clause
then return false;
for every unit clause l in Φ
Φ ← unit-propagate(l, Φ);
for every literal l that occurs pure in Φ
Φ ← pure-literal-assign(l, Φ);
l ← choose-literal(Φ);
return DPLL(ΦΛl) or DPLL(ΦΛnot(l));
An array is good for representing the current assignment, as it provides random access to any of the propositions. To represent clauses, one can use STL's sets of the proposition indices.
To implement a very efficient SAT solver you will need some more data structures (for storing watched literals and explanations). A very readable introduction to these concepts can be found at http://poincare.matf.bg.ac.rs/~filip/phd/sat-tutorial.pdf.