Skip to content

Commit

Permalink
Add compilation message to user facing FlatZinc files
Browse files Browse the repository at this point in the history
  • Loading branch information
Dekker1 committed Nov 29, 2024
1 parent 550e169 commit 23adc36
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 20 deletions.
4 changes: 3 additions & 1 deletion changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ Changes:
previous behaviour) you can use ``--solver default``.
- Add the ``--fzn-format`` flag to influence whether the generated FlatZinc from
``--compile`` or ``--fzn`` is given in the traditional FlatZinc format or the
new JSON-based format.
new JSON-based format. (:bugref:`868`)
- Comments regarding the compilation invocation are now included in user-facing
FlatZinc (``.fzn``) files, created by the ``--compile`` or ``--fzn`` flags.

Bug fixes:
^^^^^^^^^^
Expand Down
2 changes: 2 additions & 0 deletions include/minizinc/flattener.hh
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public:
void setFlagOutputJSON(bool f) {
_flags.fznFormat = f ? FlattenerFlags::FF_JSON : FlattenerFlags::FF_FZN;
}
void setCmdLineStr(std::string&& cmdline) { _cmdlineStr = std::move(cmdline); }
Env* getEnv() const {
assert(_pEnv.get());
return _pEnv.get();
Expand Down Expand Up @@ -133,6 +134,7 @@ private:

std::string _stdLibDir;
std::string _globalsDir;
std::string _cmdlineStr;

std::string _flagOutputBase;
std::string _flagOutputFzn;
Expand Down
22 changes: 14 additions & 8 deletions lib/flattener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,9 @@ void Flattener::printHelp(ostream& os) const {
? " -o <file>, --fzn <file>, --output-to-file <file>, --output-fzn-to-file <file>\n"
: " --fzn <file>, --output-fzn-to-file <file>\n")
<< " Filename for generated FlatZinc output" << std::endl
<< " --fzn-format <fzn|json>\n Whether the FlatZinc generated for the user is formatted traditionally or as JSON.\n (Does not affect the FlatZinc directly passed to the solver.)"
<< " --fzn-format <fzn|json>\n Whether the FlatZinc generated for the user is formatted "
"traditionally or as JSON.\n (Does not affect the FlatZinc directly passed to the "
"solver.)"
<< std::endl
<< " --ozn, --output-ozn-to-file <file>\n Filename for model output specification "
"(--ozn- "
Expand Down Expand Up @@ -207,13 +209,13 @@ bool Flattener::processOption(int& i, std::vector<std::string>& argv,
&buffer)) {
_flagOutputFzn = FileUtils::file_path(buffer, workingDir);
} else if (cop.getOption("--fzn-format", &buffer)) {
if (buffer == "fzn") {
_flags.fznFormat = FlattenerFlags::FF_FZN;
} else if (buffer == "json") {
_flags.fznFormat = FlattenerFlags::FF_JSON;
} else {
return false;
}
if (buffer == "fzn") {
_flags.fznFormat = FlattenerFlags::FF_FZN;
} else if (buffer == "json") {
_flags.fznFormat = FlattenerFlags::FF_JSON;
} else {
return false;
}
} else if (cop.getOption("--output-paths")) {
_fopts.collectMznPaths = true;
} else if (cop.getOption("--output-paths-to-file", &buffer)) {
Expand Down Expand Up @@ -995,6 +997,10 @@ void Flattener::flatten(const std::string& modelString, const std::string& model
check_io_status(ofs.good(), " I/O error: cannot open fzn output file. ");
switch (_flags.fznFormat) {
case FlattenerFlags::FF_FZN: {
ofs << "% Generated by MiniZinc " << MZN_VERSION_MAJOR << "." << MZN_VERSION_MINOR
<< "." << MZN_VERSION_PATCH << std::endl;
ofs << "% Solver library: " << _globalsDir << std::endl;
ofs << "% Command line invocation: " << _cmdlineStr << std::endl << std::endl;
Printer p(ofs, 0, true, &env->envi());
p.print(env->flat());
} break;
Expand Down
19 changes: 16 additions & 3 deletions lib/solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <iomanip>
#include <iostream>
#include <ratio>
#include <sstream>

#ifdef HAS_OSICBC
#include <minizinc/solvers/MIP/MIP_osicbc_solverfactory.hh>
Expand Down Expand Up @@ -65,13 +66,13 @@
#ifdef HAS_HIGHS
#include <minizinc/solvers/MIP/MIP_highs_solverfactory.hh>
#endif
#include <minizinc/exception.hh>
#include <minizinc/solvers/fzn_solverfactory.hh>
#include <minizinc/solvers/fzn_solverinstance.hh>
#include <minizinc/solvers/mzn_solverfactory.hh>
#include <minizinc/solvers/mzn_solverinstance.hh>
#include <minizinc/solvers/nl/nl_solverfactory.hh>
#include <minizinc/solvers/nl/nl_solverinstance.hh>
#include <minizinc/exception.hh>

using namespace std;
using namespace MiniZinc;
Expand Down Expand Up @@ -257,7 +258,8 @@ void MznSolver::printHelp(std::ostream& os, const std::string& selectedSolver) {
<< " --solvers\n Print list of available solvers." << std::endl
<< " --time-limit <ms>\n Stop after <ms> milliseconds (includes compilation and solving)."
<< std::endl
<< " --solver <solver id>, --solver <solver config file>.msc, --solver default\n Select solver to use, or explicitly specify using the default solver."
<< " --solver <solver id>, --solver <solver config file>.msc, --solver default\n Select "
"solver to use, or explicitly specify using the default solver."
<< std::endl
<< " --help <solver id>\n Print help for a particular solver." << std::endl
<< " -v, -l, --verbose\n Print progress/log statements. Note that some solvers may log "
Expand Down Expand Up @@ -349,6 +351,11 @@ void add_flags(const std::string& sep, const std::vector<std::string>& in_args,
}

MznSolver::OptionStatus MznSolver::processOptions(std::vector<std::string>& argv) {
std::ostringstream cmdline_ss;
for (const auto& arg : argv) {
cmdline_ss << arg << " ";
}

_executableName = argv[0];
_executableName = _executableName.substr(_executableName.find_last_of("/\\") + 1);
size_t lastdot = _executableName.find_last_of('.');
Expand Down Expand Up @@ -658,7 +665,9 @@ MznSolver::OptionStatus MznSolver::processOptions(std::vector<std::string>& argv
if (ifMzn2Fzn()) {
_flt.setFlagOutputByDefault(true);
if (solver.empty()) {
throw BadOption("Using the --compile (or -c) flag requires that a solver is selected explicitly using the --solver flag");
throw BadOption(
"Using the --compile (or -c) flag requires that a solver is selected explicitly using "
"the --solver flag");
}
}

Expand Down Expand Up @@ -928,6 +937,10 @@ MznSolver::OptionStatus MznSolver::processOptions(std::vector<std::string>& argv
throw BadOption(ss.str());
}
}

/// Set the command line string for printing user FlatZinc
_flt.setCmdLineStr(std::move(cmdline_ss.str()));

return OPTION_OK;
}
for (i = 1; i < argc; ++i) {
Expand Down
9 changes: 5 additions & 4 deletions lib/solver_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,9 @@ SolverConfig SolverConfig::load(const string& filename) {
sc._needsPathsFile = get_bool(ai);
} else if (ai->id() == "tags") {
std::vector<std::string> loaded = get_string_list(ai);
std::vector<std::string> tags;
std::copy_if (loaded.begin(), loaded.end(), std::back_inserter(tags), [](std::string s){return s != "default";} );
std::vector<std::string> tags;
std::copy_if(loaded.begin(), loaded.end(), std::back_inserter(tags),
[](std::string s) { return s != "default"; });
sc._tags = tags;
} else if (ai->id() == "stdFlags") {
sc._stdFlags = get_string_list(ai);
Expand Down Expand Up @@ -582,8 +583,8 @@ void SolverConfigs::addConfig(const MiniZinc::SolverConfig& sc) {
// Add default tag if the solver is marked as the overall default
DefaultMap::const_iterator def_it = _tagDefault.find("");
if (def_it != _tagDefault.end() && def_it->second == id) {
sc_tags.emplace_back("default");
}
sc_tags.emplace_back("default");
}

for (const auto& t : sc_tags) {
auto it = _tags.find(t);
Expand Down
2 changes: 1 addition & 1 deletion tests/minizinc_testing/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def normalized(self):
count=1,
)
for line in fzn.split("\n")
if len(line.strip()) > 0
if len(line.strip()) > 0 and not line.strip().startswith("%")
]
return "\n".join(sorted(lines)) # Sort the FlatZinc lines

Expand Down
6 changes: 3 additions & 3 deletions tests/spec/unit/driver/test_model_interface_only.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
def test_model_interface_only_1():
assert isinstance(default_driver, Driver)
p = subprocess.Popen(
[default_driver._executable, "-", "--model-interface-only", "-c"],
[default_driver._executable, "-", "--model-interface-only",],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
Expand All @@ -31,7 +31,7 @@ def test_model_interface_only_1():
def test_model_interface_only_2():
assert isinstance(default_driver, Driver)
p = subprocess.Popen(
[default_driver._executable, "-", "--model-interface-only", "-c"],
[default_driver._executable, "-", "--model-interface-only"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
Expand All @@ -53,7 +53,7 @@ def test_model_interface_only_2():
def test_model_interface_only_3():
assert isinstance(default_driver, Driver)
p = subprocess.Popen(
[default_driver._executable, "-", "--model-interface-only", "-c"],
[default_driver._executable, "-", "--model-interface-only"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
Expand Down

0 comments on commit 23adc36

Please sign in to comment.