Assignment 4, Fall 2016 [pdf format] |
All the points below must be addressed in any order:
In addition, the submission system will execute your program and compare it against your peers on new unseen instances. Therefore you should submit your best algorithm early and eventually revise your submission. Before submitting, test your implementation on the IMADA machines.
You must upload your program and report at:
The web page will compile your files, run your program, store and verify the solution and provide an analysis of results for the assessment of your algorithm. You can continue to submit new results until the deadline and it is recommended to try early to submit in order to ensure the format is as required.
Before continuing reading download the SAT package.
Two sets of test instances will be used: satisfiable instances and unsatisfiable instances. The comparison of the sat_sls_* algorithms will be based, on the first class, on the computation time to find a model that satisfies the instance, and, on the second class, on the number of violated clauses that has to be minimized.
In the directory data
from the SAT Start package nine instances
are made available: three satisfiable instances of size 20, three
satisfiable instances of size 250, three unsatisfiable instances of size
250. These instances are training instances and mustbe used for your
local tests. On the submission page, your program will be tested on
different but similar instances.
In the following it is described the format of these instances.
The file can start with comments, that is lines beginning with the characters “c “. Right after the comments, there is the line “p cnf nbvar nbclauses” indicating that the instance is in CNF format; “nbvar” is the exact number of variables appearing in the file; “nbclauses” is the exact number of clauses contained in the file. Then the clauses follow. Each clause is a sequence of distinct non-null numbers between “-nbvar” and “nbvar” ending with 0 on the same line; it cannot contain the opposite literals i and −i simultaneously. Positive numbers denote the corresponding variables. Negative numbers denote the negations of the corresponding variables.
Example:
c c start with comments c c p cnf 5 3 1 -5 4 0 -1 5 3 4 0 -3 -4 0
s SATISFIABLE s UNSATISFIABLE s UNKNOWN
If the solver outputs SATISFIABLE, it must provide a model (or a certificate) that will be used to check the correctness of the answer. I.e., it must provide a 0-terminated sequence of distinct non-contradictory literals that makes every clause of the input formula true. It is NOT necessary to list the literals corresponding to all variables if a smaller amount of literals suffices. The order of the literals does not matter. Arbitrary white space characters, including ordinary white spaces and tabulation characters, are allowed between the literals, as long as the line containing the literals is a values line, i.e. it begins with the two chars “v “.
For instance, the following outputs are valid for the instances given in example:
mycomputer:~$ ./mysolver --main::instance myinstance-sat c mysolver 6.55957 starting with SATTIMEOUT fixed to 1000s c Trying to guess a solution... s SATISFIABLE v -3 4 -6 18 21 1 -7 0 c Done (mycputime is 234s).
mycomputer:~$ ./mysolver --main::instance myinstance-unsat c mysolver 6.55957 starting with SATTIMEOUT fixed to 1000s c Trying to guess a solution... c Contradiction found! s UNSATISFIABLE c Done (mycputime is 2s).
SAT_Input
in input.hh
as
follows:
// your data members unsigned nbvar, nbclauses; vector<vector<int> > formula; |
// File input.cc #include "input.hh" #include <fstream> #include <cassert> #include <sstream> SAT_Input::SAT_Input(string file_name) { // Insert the code that reads the input from the file // and stored it into the data structures of the object ifstream is(file_name.c_str()); if (!is) { cerr << "Cannot open file " << file_name << endl; exit(1); } string line; istringstream iss; do { getline(is, line); } while (line[0] == 'c'); iss.str(line.substr(1,string::npos)); string ch; iss >> ch >> nbvar >> nbclauses; formula.resize(nbclauses); unsigned c = 0; do { getline(is, line); if (line[0] == '%' || line[0] == '0') break; iss.clear(); iss.str(line); int lit; formula[c].clear(); iss >> lit; while (lit != 0) { assert(lit <= static_cast<int>(nbvar) && lit >= -static_cast<int>(nbvar)); formula[c].push_back(lit); iss >> lit; } c++; } while (true); assert(c == nbclauses); } |
Note the use of the function push_back
for dynamic vectors from
the STL. We added assertions to ensure the data are consistent. These
assertions can be disabled by defining the variable NDEBUG. A way to
do this is by adding a declaration in the Makefile:
COMPOPTS = $(COMPOPTS) -DNDEBUG
. You should check that the
instance is correctly read. To do this there is an implementation of the
operator <<
of the class SAT_Input
.
ostream& operator<<(ostream& os, const SAT_Input& pa) { // Insert the code that write the input object (needed for debugging purposes) for (unsigned int c=0;c<pa.nbclauses;c++) { for (unsigned int l=0;l<pa.formula[c].size();l++) os<<pa.formula[c][l]<<" "; os<<endl; } return os; } |
Once this function is implemented it is possible to check the output using the EasyLocal menu. From the starting menu select (1) Random state then (4) State menu and finally (7) Show input. This should call the friend operator implemented above and print the input data. Of course, the good old way of testing by adding in the code debugging lines that print on standard output relevant data is also a worth practice.
xyz --main::instance data/uf20-010.cnf --main::method mymethod
However, nothing is implemented yet for the local search. This is left to you.
Start early to test your submission. You can submit as many times as you wish within the deadline. Every new valid submission overwrites the previous submission.
Your archive must uncompress as follows:
src
and
produce an executable called xyz
.
Your program will be compiled calling make xyz
. Hence make sure
that your Makefile is present and that it has the task xyz
. Use
the same Makefile as the one that has been delivered in the
Practice. In particular, make sure that there is the following include:
include ./make.local
Use make.local
to set the path to the EasyLocal library and to
the Boost library. The executable file xyz
generated in
src
will be used for the tests. Locally, you are recommended to
have additionally the following content, which however you do not need
to submit:
To prepare your submission create an archive as follows:
tar czvf sat.tgz src doc
Any other type of archive will not work.
The programs will run on a machine with ubuntu 14.04.
The executable xyz
must run with the default arguments of
easylocal. In particular, the instance, the output file and
the seed will be specified.
xyz --main::instance ../data/uf20-010.cnf --main::output_file uf20-010.sol --main::seed 1
No other parameter can be specified. If you have any, then you will need to hard code them. You can do this as follows. For main parameters just add in the main file, for example:
method="SD";
For other parameters, pass them to the SearchEngine or Solvers. For example, you will need to set the time limit by passing it to the Parametrized instance of SimpleLocalSearch:
SAT_solver.SetParameter("timeout",20.0);
The program will be killed externally at the time limit if it did not terminate already. Hence make sure you hard code the time limit and that you output in time the best solution found during the search.
All output must go in the standard output and in the output file. Do not
create other files. The files must be in ASCII format and the output
file must contain the solution certificate in the format described
above. The output class to produce the output is already implemented but
you need to pass your solution to an object of this class. Your
solutions will be verified by an external program. You find this program
in your start package. You can compile (make verifier
) and use it.
Make sure you report the following three result data:
output_file
)
For example:
xyz --main::instance ../data/uf20-010.cnf --main::seed 1 v -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 17 18 19 20 0 Cost: 10 Time: 0.00028879
It is important that you use this format and that Time:
is the
first word in a new line reporting the computation time.
To achieve this you can make sure that in your main
you have the
following lines:
os << out << endl; os << "Cost: " << result.cost << endl; os << "Time: " << result.running_time << endl;
Note that the upload and analysis system is still under test and therefore it may have to be fine tuned, hence be patient and contact the teacher if something is not working as it should.