Skip to content

Conversation

LAJW
Copy link
Contributor

@LAJW LAJW commented Oct 19, 2017

New options:

--random-seed 13121110 # seed for randomizer - floating point number
--random-var-freq 0...1 # random generator frequency - floating point number

If unset defaults those values as defined in sat checker (works as before).

Also simplifies the satcheck wrapper implementation.

Review tips: Each commit contains changes as described in the title. There's one massive commit, which forces parametrization of satcheck. I tried to make it as small as possible, given in how many places satcheck is used.

TODO: Prettier messages if arguments are not valid, floating point numbers, restrict random-var-freq to 0...1 in command line parser, lintage.

Implements this ticket: https://diffblue.atlassian.net/browse/TG-925

@LAJW
Copy link
Contributor Author

LAJW commented Oct 19, 2017

@antlechner Checkout the branch, see if it does what you think it should.
@allredj Take a look.

Copy link
Collaborator

@tautschnig tautschnig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have serious concerns about the design used here as detailed, and I have several "Why?" questions. The true blocker, however, is making it impossible to use any other solver than MiniSat2.

add_variables();
solver->setPolarity(a.var_no(), value);
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind explaining what is broken about this?

@@ -310,13 +287,13 @@ void satcheck_minisat_simplifiert::set_frozen(literalt a)
if(!a.is_constant())
{
add_variables();
solver->setFrozen(a.var_no(), true);
static_cast<Minisat::SimpSolver*>(solver)->setFrozen(a.var_no(), true);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this better than the previous code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only point of CRTP and declaring every single member as a template was to avoid a single cast. With virtual functions on top it is rather difficult to read. If you still don't like this raw cast could be wrapper in a method.

The intended use of CRTP is to avoid code duplication between unrelated classes while avoiding virtual functions in performance critical code. Since class was already virtual, there was no point in using CRTP here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW I don't see how class satcheck_minisat_no_simplifiert: public satcheck_minisat2_baset<Minisat::Solver> ever was an instance of CRTP. There was a templated base class that could be instantiated in a number of ways. What happened was that not all instantiations would support the full interface. That seemed like a perfectly legitimate use of templates and template instantiation to me?

int acceleratet::accelerate_loop(
goto_programt::targett &loop_header,
const double random_seed,
const double random_var_freq)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is some design problem here: passing in completely unrelated options to some function. At bare minimum pass along optionst so that it isn't necessary to add one parameter for each future option.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The design problem is that the number of arguments might grow in the future. I agree.

But I think that concerns should remain separated. Minisat should not parse command line arguments. I'd humbly suggest passing a reference to typed "config" struct. Which in this case would take only 2 arguments.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I largely don't mind whether it's an optionst passed around (optionst being the result of parsed cmdlinet arguments) or actually going for config, which is global anyway and would drastically reduce the size of this PR.

Copy link
Contributor Author

@LAJW LAJW Oct 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Globals are not a solution. Since every object (and many functions) requires its own, often large configuration, storing all arguments in a global uncategorized, untyped hashmap would be an architectural disaster.

Globals are not an answer. Better parsing and grouping is.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Globals are what we have at the moment. Whether we should have them or not is a different question to implementing this feature.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW: "storing all arguments in a global uncategorized, untyped hashmap would be an architectural disaster." is not what configt is/does.

@@ -29,6 +29,9 @@ Author: Daniel Kroening, kroening@kroening.com
#error "Expected HAVE_MINISAT2"
#endif

const double satcheck_minisat2_baset::default_random_seed=91648253.;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this magic number come from? Explain and move it to util/magic.h.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was copied from minisat2 internals.

@@ -47,14 +47,14 @@ tvt satcheck_minisat2_baset::l_get(literalt a) const

tvt result;

if(a.var_no()>=(unsigned)solver->model.size())
if(a.var_no()>=(unsigned)solver_->model.size())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WHY?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub, Vim, Emacs, Visual Studio, QT, VS Code and AFAIK Clion do not highlight member variables or member functions. C++ does not enforce this->. Therefore it's often difficult to discern whether a variable is a member or local. Every time such variable is encountered, the reader has to spend considerable amount of time going through the entire file looking for globals, statics, members and/or child classes.

We've spent months arguing about this and finally postfix underscore was agreed upon to signify a member variable. On top of that solver_ was already used as an argument name.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this documented in the coding standard?

At the same time: this PR is already way too large, why include such style changes in there?

}

#endif

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has only been added as recently as 0ee4933 - maybe just revert the entire commit (assuming @smowton approves)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a part of an experiment to stop perl script with CTRL+C (which only had to be implemented in the perl script).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it was intended to facilitate input synthesis, the idea being if you're using a sub-solver to synthesise inputs then you should only give it a little time, since it's not worth losing your solution because of an input synthesis timeout. However there turned out to be too many sources of possible timeouts in CBMC to be practical, so I concluded we should do this by splitting the test-generation process into multiple processes and use process granularity crash/timeout isolation instead.

Long story short, revert that commit at your leisure.

@@ -32,7 +32,7 @@ Author: Daniel Kroening, kroening@kroening.com
const double satcheck_minisat2_baset::default_random_seed=91648253.;
const double satcheck_minisat2_baset::default_random_var_freq=0.;

void convert(const bvt &bv, Minisat::vec<Minisat::Lit> &dest)
static void convert(const bvt &bv, Minisat::vec<Minisat::Lit> &dest)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the rationale for "stacheck_minisat2_baset - refactor prop_solve " ?

@@ -15,6 +15,7 @@ Author: Daniel Kroening, kroening@kroening.com
#include <util/ui_message.h>

#include <solvers/flattening/bv_pointers.h>
#include <solvers/sat/satcheck_minisat2.h>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implies that no solver other than Minisat2 could be used. This is certainly a blocker.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested move of constant definitions to the constant file should alleviate that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep; that's a blocker for several other industrial users.

@martin-cs
Copy link
Collaborator

@tautschnig : The why, @antlechner can best explain, but they were after a low cost way of getting a variety of models. We had a long discussion including my reservations about the amount of variation vs. performance trade-off and that universal hashing is actually the best way of get model variety. However we felt that as a hidden option, it was relatively low harm.

The PR does not look anything like the minimum code required to implement this feature. It seems to mix up refactorings, code removal, new features and so on, while breaking various interfaces and supporting code. As such I would oppose it's merge in the current form.

Copy link
Collaborator

@martin-cs martin-cs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Start from a blank sheet and see how small (in lines of code) you can make the diff.

@@ -994,6 +1001,8 @@ void cbmc_parse_optionst::help()
" --object-bits n number of bits used for object addresses\n"
" --dimacs generate CNF in DIMACS format\n"
" --beautify beautify the counterexample (greedy heuristic)\n" // NOLINT(*)
" --random-seed %f SAT checker randomizer seed\n" // NOLINT(*)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seed should probably be treated as an opaque 64 bit bit-vector. Minisat's use of it as a double is just implementational convenience. If we use it to seed other random number generators such as srand() (which is probably a good idea) they will want it as an integer.

if (cmdline.isset("random-var-freq"))
options.set_option(
"random-var-freq", cmdline.get_values("random-var-freq"));

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These could have default values set here. This is especially useful for random-seeds.

@@ -994,6 +1001,8 @@ void cbmc_parse_optionst::help()
" --object-bits n number of bits used for object addresses\n"
" --dimacs generate CNF in DIMACS format\n"
" --beautify beautify the counterexample (greedy heuristic)\n" // NOLINT(*)
" --random-seed %f SAT checker randomizer seed\n" // NOLINT(*)
" --random-var-freq %f SAT checker randomization frequency\n" // NOLINT(*)
" --localize-faults localize faults (experimental)\n"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure we use "%" in other options.

if(options.get_bool_option("random-var-freq"))
random_var_freq=std::stod(options.get_option("random-var-freq"));
return { random_seed, random_var_freq };
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Option parsing shouldn't be done here.


solver->prop().set_message_handler(get_message_handler());
solver->set_prop(make_satcheck(options, use_simplifier, get_message_handler()));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frankly this all seems a bit unnecessary.

@@ -1935,7 +1935,7 @@ static optionalt<exprt> find_counter_example(
const exprt &axiom,
const symbol_exprt &var)
{
satcheck_no_simplifiert sat_check;
satcheck_no_simplifiert sat_check(0., 0.);
bv_refinementt::infot info;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How are these values related to the satcheck_minisat2_baset::default_random_seed. Also, this is probably the one place this patch is actually needed.

@@ -28,7 +29,10 @@ Author: Daniel Kroening, kroening@kroening.com
#error "Expected HAVE_MINISAT2"
#endif

void convert(const bvt &bv, Minisat::vec<Minisat::Lit> &dest)
const double satcheck_minisat2_baset::default_random_seed=91648253.;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this number?


void satcheck_minisat_simplifiert::set_frozen(literalt a)
{
if(!a.is_constant())
{
add_variables();
solver->setFrozen(a.var_no(), true);
static_cast<Minisat::SimpSolver*>(solver_.get())->setFrozen(a.var_no(), true);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this an improvement?

}
}

bool satcheck_minisat_simplifiert::is_eliminated(literalt a) const
{
assert(!a.is_constant());

return solver->isEliminated(a.var_no());
return static_cast<const Minisat::SimpSolver*>(solver_.get())->
isEliminated(a.var_no());
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seem to be an awful lot of "refactorings" here which are not related to the actual PR. Please do not do this. Refactorings should be a separate commit.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be said that @LAJW has done this in a pretty clean series of commits. I do not know what the exact request in TG-925 is; if it is what the PR subject says, then surely refactorings have no place in here. If TG-925 requested refactoring, then these should be better be considered for other solvers as well.

private:
resultt prop_solve_impl();

bvt assumptions_;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why rename variables? Our coding standard doesn't require private variables to be named with underscores.

@allredj allredj self-requested a review October 19, 2017 20:24
@smowton
Copy link
Contributor

smowton commented Oct 20, 2017

@tautschnig @martin-cs in defence of parameterising from above (threading an option through from driver to user class) as opposed to global parameters, there have already been several cases in the unit tests where changes to config accidentally spilled into neighbouring tests, leading to surprising breakages depending on the order the tests happened to run; similarly when designing the input synthesis solver (which admittedly I now advocate pushing into a separate process for performance reasons) I was repeatedly tripped by an apparently-clean solvert instance inheriting a previous session's configuration via config. There are surely similar tripwires lurking for future developers when information flow is hidden. Whether or not we want to port the existing config settings, I advocate adding new ones to some solver_configt and passing that into classes that need a solver such that the scope of their effect is clear.

@tautschnig
Copy link
Collaborator

On the global-config-object story: I very much agree that global objects are bad, and removing config from solvers has already been happening as far as possible. I fully support any attempt towards "solver options" or the likes. What I cannot agree to is explicitly listing all options that may pop up, and may in fact only be useful for selected solvers, as parameters to all bits of code that eventually create a solver object. This would yield an endless stream of changes of the same size as this PR, and that is clearly unhealthy.

@martin-cs
Copy link
Collaborator

martin-cs commented Oct 20, 2017 via email

@LAJW
Copy link
Contributor Author

LAJW commented Oct 20, 2017

Removed all refactors.

@martin-cs @tautschnig @smowton @thk123 Review please.

Copy link
Collaborator

@tautschnig tautschnig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do like this version much better, but a final fix to avoid linking failures if a SAT solver other than MiniSat2 is being used will be required.

FWIW, the huge amount of changes to loop acceleration highlight a design problem in that code, which the changes proposed now are just a symptom of.

/// Parse satcheck options
/// \param options Options object
/// \return An instance of satcheck_minisat_info object
static satcheck_minisat_infot parse(const optionst &options);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about making this a constructor (in addition to a default constructor)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to use a function, but assigning a function pointer behind an ifdef proved to be a little too cumbersome.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure you've got good reasons for not doing it, but I don't really understand your explanation as I don't know which function pointer or ifdef that would be?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The one in satcheck.h which switches between solvers. I'd have to create another one in .cpp file I think.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about declaring the interface in satcheck.h and then provide an implementation in each solver? Thus different solvers could happily parse/ignore different options? Maybe that's a bad idea for other reasons?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's "beyond the scope of this PR". The common interface isn't specified anywhere, macros just switch between different typedefs.

satcheck_info.random_var_freq
=std::stod(cmdline.get_value("random-var-freq"));
accelerate_functions(
goto_model, cmdline.isset("z3"), satcheck_info);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command-line options are never added to goto-instrument, are they? It seems they just exist in cbmc.

@@ -23,6 +23,12 @@ class Solver; // NOLINT(readability/identifiers)
class SimpSolver; // NOLINT(readability/identifiers)
}

struct satcheck_minisat_infot final
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file will only be included when SATCHECK_MINISAT2 is defined, hence all other cases will cause linking failures under the subsequent commits.

Copy link
Contributor

@smowton smowton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, one documentation suggestion

}();

prop->set_message_handler(get_message_handler());
const bool use_simplifier=options.get_bool_option("sat-preprocessor");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest commenting that this definition intentionally differs from the one on line 115

@kroening
Copy link
Member

Why is it desirable to randomise SAT?

@smowton
Copy link
Contributor

smowton commented Oct 21, 2017

@kroening AFAIK the goal is to encourage alternate test-cases and thus fuzz the validity of the Java models

@kroening
Copy link
Member

Randomizing the solver is really not how this should be attempted to be achieved.

@smowton
Copy link
Contributor

smowton commented Oct 21, 2017

@kroening that discussion has already been around a few times -- see Martin's comment here #1501 (comment) for example

@thk123
Copy link
Contributor

thk123 commented Oct 23, 2017

I don't think I have the knowledge of the relevant files in this PR for which I am a code owner. Happy to review if needed, but looks like plenty of eyes are already going through this.

Copy link
Contributor

@romainbrenguier romainbrenguier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed only the changes in src/solvers and they make sense for me.

{
if(info.random_var_freq<0. || 1.<info.random_var_freq)
throw std::invalid_argument(
"random_var_freq should be a floating point number between 0 and 1");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this check be done in parse instead?

@kroening
Copy link
Member

Does that need to be in CBMC? Not just testgen?

@kroening
Copy link
Member

Also, the use-case does not justify changing the API.
There must be constructors that produce the current behaviour without the satcheck_info.

@LAJW
Copy link
Contributor Author

LAJW commented Oct 23, 2017

@kroening The satcheckers themselves are hidden behind those wrappers. The only way to add extra options is to modify wrappers. But each wrapper has to have its own set of arguments, as each solver is different.

satcheck_infot - @tautschnig pointed out that it's a bad idea to pull those arguments explicitly, and they should be grouped and passed together to the solver.

In general I like to create _info struct for functions exceeding 3 arguments. With C++11 in-header initialisers it's possible to assign sensible defaults to unassigned fields. structs can also be composed, so often constructors can accept less arguments. Also new arguments can be easily added, and looking for function documentation is no longer necessary to figure out which value is set to which argument. Better solution is coming to C++20, but for now this is the best tool available.

@LAJW
Copy link
Contributor Author

LAJW commented Oct 23, 2017

@tautschnig The remaining satcheckers' interfaces have been updated to work with the _infot struct.

@LAJW
Copy link
Contributor Author

LAJW commented Oct 24, 2017

@tautschnig @martin-cs @thk123 Please, re-review.

/// \return An instance of satcheck_minisat_info object
static satcheck_minisat_infot parse(const optionst &options);
size_t random_seed=91648253; // Default copied from minisat2
double random_var_freq=0.;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As these have default values, wouldn't it be possible to follow @kroening consideration to maintain the existing interface of solvers that can be default-constructed without such options?

@tautschnig
Copy link
Collaborator

Does that need to be in CBMC? Not just testgen?

Does testgen invoke CBMC, or is it a new command-line front end? If the latter is the case, then indeed I don't understand why the changes have been implemented as is done here. Back in my work on FShell I never made any modifications to CBMC, but just derived my own implementations of classes as needed (for example for computing multiple test inputs covering the same test goals).

@peterschrammel
Copy link
Member

I think this PR mixes up two issues that should be done independently:

  1. Providing a seed (and other randomisation) options to the sat solver
  2. Refactoring the way how we create and configure solver instances

I'd suggest to do only 1. here, which should probably be done by using similar mechanisms as already available in propt for setting assumptions, e.g. add a function set_seed and a function has_set_seed. The only other changes besides adding the command line options are then overriding these functions in the minisat wrapper and calling them from cbmc_solvers. I think that this is the least invasive solution.

Improving 2. is a different story that should be discussed elsewhere. I'm very much in favour of having a generic configuration data structure that replaces optionst (and configt and other integers and flags passed around) that is built in *_parse_optionst and passed down to the various components of the system (#1319 could be a candidate for doing that). cbmc_solvers should be moved to solvers/ so that it can be used by all tools and should be the only interface for constructing a solver instance.

symbol_table(_symbol_table),
ns(symbol_table),
goto_functions(_goto_functions),
goto_program(_goto_program),
loop(_loop),
loop_header(_loop_header),
utils(symbol_table, goto_functions, loop_counter)
utils(symbol_table, goto_functions, loop_counter),
satcheck_info_(satcheck_info)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Underscores at the beginning, underscores at the end... -- this is super-inconsistent. Please follow the style of the code that you are editing instead of making it incoherent on purpose!

@@ -116,6 +116,11 @@ class propt:public messaget, public prop_assignmentt
warning() << "CPU limit ignored (not implemented)" << eom;
}

/// Set Random variable frequency (Exclusive to minisat2)
virtual void random_var_freq(std::size_t i) { }
/// Set Random variable seed (Exclusive to minisat2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also glucose supports both settings. I suggest to add a has_random_seed() etc so that cbmc_solvers can check whether the selected solver supports the feature and can output an appropriate error message.

options.set_option(
"random-var-freq", cmdline.get_value("random-var-freq"));
accelerate_functions(
goto_model, cmdline.isset("z3"), parse_satcheck_info(options));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a weird way of doing that. I suggest to pass optionst only and sort out the mess inside accelerate_functions.

@@ -253,8 +254,8 @@ void satcheck_minisat2_baset<T>::set_assignment(literalt a, bool value)
}

template<typename T>
satcheck_minisat2_baset<T>::satcheck_minisat2_baset(T *_solver):
solver(_solver), time_limit_seconds(0)
satcheck_minisat2_baset<T>::satcheck_minisat2_baset(T* solver_):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unnecessary and violates coding style. Please undo.

@@ -81,3 +82,14 @@ const optionst::value_listt &optionst::get_list_option(
else
return it->second;
}

satcheck_infot parse_satcheck_info(const optionst &options)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cannot live here. Move to solvers/sat

@@ -116,6 +116,11 @@ class propt:public messaget, public prop_assignmentt
warning() << "CPU limit ignored (not implemented)" << eom;
}

/// Set Random variable frequency (Exclusive to minisat2)
virtual void random_var_freq(std::size_t i) { }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to set_random_var_freq for consistency.

/// Set Random variable frequency (Exclusive to minisat2)
virtual void random_var_freq(std::size_t i) { }
/// Set Random variable seed (Exclusive to minisat2)
virtual void random_seed(std::size_t i) { }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to set_random_seed for consistency.

@peterschrammel
Copy link
Member

peterschrammel commented Dec 2, 2017

@LAJW, please rebase and fix the linting issues.

@@ -906,123 +913,178 @@ void cbmc_parse_optionst::help()

std::cout << " * *\n";

std::cout <<
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please exclude the help text from clang-formatting (// clang-format off/on)

@@ -24,47 +24,48 @@ class bmct;
class goto_functionst;
class optionst;

#define CBMC_OPTIONS \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please exclude this from clang-formatting

else
satcheck = util_make_unique<satcheck_no_simplifiert>();
satcheck->set_message_handler(message_handler);
satcheck->set_random_seed(satcheck_info.random_seed);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to check here whether the solver has the feature (satcheck->has_random_seed() and output an error message otherwise. Alternatively, at least output a warning in the base class (see below).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning added.

@@ -116,6 +116,15 @@ class propt:public messaget, public prop_assignmentt
warning() << "CPU limit ignored (not implemented)" << eom;
}

/// Set random variable frequency (Exclusive to minisat2)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also glucose has this feature. Output at least a warning if the solver does not implement this feature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glucose build doesn't seem to want to work, I'm not sure which parameters to add. I'm skipping it. Maybe we can add this later.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure which problem you've run into, but marek-trtik@2548e7f might be helpful.

@@ -51,6 +53,9 @@ class satcheck_minisat2_baset:public cnf_solvert
time_limit_seconds=lim;
}

void set_random_var_freq(std::size_t) override;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the same for glucose to see whether this can be used with at least two solvers without hiccup.

@LAJW
Copy link
Contributor Author

LAJW commented Dec 11, 2017

@peterschrammel Rebased, fixed lintage, added warning. I don't know how to test the glucose changes, so not adding them.

@peterschrammel
Copy link
Member

@martin-cs, @tautschnig, I cleaned this up a bit and pulled apart the two purposes of this PR (1. randomisation, 2. unify solver instantation). I recommend reviewing the commits related to these two purposes separately. I think it's a bit clearer now, but mixing up 1. and 2. is still quite distracting - let me know if I should create two PRs instead.
To further improve 2. I propose a refactoring #1700 (to come in a follow-up PR).

satcheck = util_make_unique<satcheck_no_simplifiert>();
satcheck->set_message_handler(message_handler);
satcheck->set_random_seed(satcheck_info.random_seed);
satcheck->set_random_var_freq(satcheck_info.random_var_freq);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this will always attempt to set the random_var_freq even if neither the solver supports it nor the user ever requested it? The resulting warning will be rather confusing to the user, isn't it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With all the updates by @LAJW and discussion (thanks!) this is the only remaining blocker for me.

{
satcheck_infot satcheck_info;
if(!options.get_option("random-seed").empty())
satcheck_info.random_seed = std::stoul(options.get_option("random-seed"));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use safe_string2size_t as sizeof(unsigned long)!=sizeof(std::size_t) on Windows.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. But why not stoull (unsigned long long)?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because that wouldn't be correct on 32-bit architectures as sizeof(unsigned long long)!=sizeof(std::size_t) on those?

solver(_solver), time_limit_seconds(0)
template <typename T>
satcheck_minisat2_baset<T>::satcheck_minisat2_baset(T *_solver)
: solver(_solver), time_limit_seconds(0)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace changes?

satcheck_minisat_simplifiert::satcheck_minisat_simplifiert():
satcheck_minisat2_baset<Minisat::SimpSolver>(new Minisat::SimpSolver)
satcheck_minisat_simplifiert::satcheck_minisat_simplifiert()
: satcheck_minisat2_baset<Minisat::SimpSolver>(new Minisat::SimpSolver())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace changes?

virtual void set_random_var_freq(double value)
{
warning() << "random-var-freq not supported" << eom;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design idea/question: instead of introducing a new set_... function for each future option, can't we have a prop_configt made up of optionalt<T> fields (presently an optionalt<std::size_t> and an optionalt<double>) and one set_config(prop_configt)? The default implementation here would then check each field for being none, and else yield a warning. That would also address one of my comments made elsewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @peterschrammel might want to answer this question.

Copy link
Member

@peterschrammel peterschrammel Jan 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am against introducing more and more custom configuration classes: They are likely to become incompatible with each other, requiring to copy/adapt configuration data at interfaces.
I'm in favour of having a single dictionary-like data structure such as optionst, which is passed along throughout the codebase and carries all the configuration data. Optionst should be enhanced with proper 'optional' behaviour and a way to override individual items without requiring a full copy. @LAJW had a go at such an optionst replacement some time ago (#1319).

For this PR, I could propose to get rid of set_* functions and replace them by an optionst-based solution.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't satcheck_infot such a custom configuration class? I was just thinking to move this to propt. My rationale being the present need to add additional set_... calls at each site whenever new ones are added, plus the problem that there may be spurious warnings as said in my other comment: #1501 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@peterschrammel Map from #1319 is an overkill. If you want dictionaries, just use std::unordered_map. I'm in favour of structs, as they lean towards parsing done in one spot, rather than spreading throughout the entire application (they separate UI from business logic). It's bad enough that we print to standard output all over the place, I didn't want to contribute to the problem.

satcheck_infot was a common satcheck constructor argument in one of the earlier revisions of this PR. If we truly cannot change satcheck constructor signature, then putting that as a set_config method (which would serve the role of a constructor) might be the next best thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't matter what is the name of the class to which we're printing. The fact that we're printing raw strings right next to the business logic is the problem.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what would you be doing instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it were up to me, I'd build a view instead and delegate formatting to that. View would be passed as argument or functions could return what to print to view as their result. Views could easily be swapped (CLI/JSON/Dummy, etc.). But it's not up to me.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constructive ideas will always be appreciated, rambling less so. Everyone should feel empowered to create an issue to trigger discussion, or directly start with a pull request (at the risk of it being handed back for major rework).

Supposedly it is up to a message handler to take care of formatting. Surely that isn't fully done this way and needs fixing (hence, e.g., #1359). Yet your comments sound like you see a need for much bigger changes?

Copy link
Contributor Author

@LAJW LAJW Jan 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what would you be doing instead?

You've requested my opinion, I gave it to you. Yes, slightly bigger changes than just hotfixes.

But I think we've strayed much too far away from the original point, and it's up to @peterschrammel to decide how he would like argument passing to look like. Current state is what he specifically requested, so I'm not going to go against his design.

bool do_assumptions(
std::map<exprt, polynomialt> polynomials,
patht &body,
exprt &guard);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace change

@@ -66,8 +71,7 @@ class acceleration_utilst
std::set<std::pair<expr_listt, exprt> > &coefficients,
polynomialt &polynomial);

bool check_inductive(std::map<exprt, polynomialt> polynomials,
patht &path);
bool check_inductive(std::map<exprt, polynomialt> polynomials, patht &path);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace change

@@ -246,7 +246,7 @@ bool disjunctive_polynomial_accelerationt::accelerate(

try
{
path_is_monotone=utils.do_assumptions(polynomials, path, guard);
path_is_monotone = utils.do_assumptions(polynomials, path, guard);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace change

@@ -179,7 +179,7 @@ bool polynomial_acceleratort::accelerate(

try
{
path_is_monotone=utils.do_assumptions(polynomials, loop, guard);
path_is_monotone = utils.do_assumptions(polynomials, loop, guard);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace change

const symbol_tablet &_symbol_table,
const goto_functionst &_goto_functions,
exprt &_loop_counter)
const exprt &_loop_counter = nil_exprt())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default argument removing the need for 2 separate functions.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this related to this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was adding an extra constructor argument. In this case it was clunky, as there was a default parameter implemented manually, rather than using the language construct. I rolled that into one to reduce PR's size.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I would have preferred delegating constructors instead, out of some dislike for default arguments. But I guess I don't have solid facts to back this up. Just make sure the commit messages states includes a note about this refactoring.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change has been separated into another commit.

@LAJW
Copy link
Contributor Author

LAJW commented Jan 5, 2018

@peterschrammel I've noticed that intermediate commits no longer build. What's the point of splitting, if commits are not atomic?

@LAJW LAJW changed the title TG-925 Add command line options for setting up satcheck randomizer [TG-925] Add command line options for setting up satcheck randomizer Mar 14, 2018
@tautschnig tautschnig mentioned this pull request Feb 8, 2019
7 tasks
@thk123 thk123 removed their request for review September 18, 2019 14:18
@LAJW
Copy link
Contributor Author

LAJW commented Jan 9, 2020

At this stage this has to be re-done. I don't want to argue about global state being bad. Closing.

@LAJW LAJW closed this Jan 9, 2020
@LAJW LAJW deleted the sat-random branch January 9, 2020 23:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants