Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to pass fzn via stdin instead of temp file #317

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 89 additions & 2 deletions include/minizinc/process.hh
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,87 @@ namespace MiniZinc {

#endif

class InputProvider {

private:
#ifdef _WIN32
HANDLE _h_pipe = nullptr;
#else
int _pipe = 0;
#endif

public:
InputProvider() : stream(this) {}

std::ostream* getStream() {
return &stream;
}

virtual void provide() {}

#ifdef _WIN32
void setHandle(HANDLE h_pipe) {
_h_pipe = h_pipe;
}
#else
void setPipe(int pipe) {
_pipe = pipe;
}
#endif

class PipeStream : public std::ostream {

public:
explicit PipeStream(InputProvider* input) : std::ostream(new PipeBuf(input)) {}

class PipeBuf : public std::streambuf {

public:
explicit PipeBuf(InputProvider* input) : _input(input) {}

protected:
std::streamsize xsputn(const char_type* s, std::streamsize n) override {
return write(s, n);
}

int_type overflow(int_type ch) override {
return write(&ch, 1);
}

private:
InputProvider* _input;

std::streamsize write(const void* s, std::streamsize n) {
#ifdef _WIN32
if (_input->_h_pipe == nullptr) {
return 0;
}
DWORD count;
BOOL success = WriteFile(_input->_h_pipe, reinterpret_cast<const char*>(s), n, &count, nullptr);
return count;
#else
if (_input->_pipe == 0) {
return 0;
}
return ::write(_input->_pipe, s, n);
#endif
}
};
};

protected:
InputProvider::PipeStream stream;

};

template<class S2O>
class Process {
protected:
std::vector<std::string> _fzncmd;
S2O* pS2Out;
int timelimit;
bool sigint;
InputProvider* _input;
#ifndef _WIN32
static void handleInterrupt(int signal) {
if (signal==SIGINT)
Expand All @@ -90,8 +164,8 @@ namespace MiniZinc {
static bool hadTerm;
#endif
public:
Process(std::vector<std::string>& fzncmd, S2O* pso, int tl, bool si)
: _fzncmd(fzncmd), pS2Out(pso), timelimit(tl), sigint(si) {
Process(std::vector<std::string>& fzncmd, S2O* pso, int tl, bool si, InputProvider* input)
: _fzncmd(fzncmd), pS2Out(pso), timelimit(tl), sigint(si), _input(input) {
assert( 0!=pS2Out );
}
int run(void) {
Expand Down Expand Up @@ -173,6 +247,13 @@ namespace MiniZinc {
// Stop ReadFile from blocking
CloseHandle(g_hChildStd_OUT_Wr);
CloseHandle(g_hChildStd_ERR_Wr);

if (_input != NULL) {
_input->setHandle(g_hChildStd_IN_Wr);
_input->provide();
CloseHandle(g_hChildStd_IN_Wr);
}

// Just close the child's in pipe here
CloseHandle(g_hChildStd_IN_Rd);
bool doneStdout = false;
Expand Down Expand Up @@ -208,6 +289,12 @@ namespace MiniZinc {
close(pipes[0][0]);
close(pipes[1][1]);
close(pipes[2][1]);

if (_input != NULL) {
_input->setPipe(pipes[0][1]);
_input->provide();
}

close(pipes[0][1]);

fd_set fdset;
Expand Down
3 changes: 3 additions & 0 deletions include/minizinc/solvers/fzn_solverinstance.hh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ namespace MiniZinc {
int fzn_time_limit_ms = 0;
int solver_time_limit_ms = 0;
bool fzn_sigint = false;
bool fzn_use_stdin = false;

bool fzn_needs_paths = false;
bool fzn_output_passthrough = false;
Expand Down Expand Up @@ -63,6 +64,8 @@ namespace MiniZinc {

void resetSolver(void);

void printModel(Printer p);

protected:
Expression* getSolutionValue(Id* id);
};
Expand Down
84 changes: 58 additions & 26 deletions solvers/fzn/fzn_solverinstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ namespace MiniZinc {
<< " -k, --keep-files\n For compatibility only: to produce .ozn and .fzn, use mzn2fzn\n"
" or <this_exe> --fzn ..., --ozn ...\n"
<< " -r <n>, --seed <n>, --random-seed <n>\n For compatibility only: use solver flags instead.\n"
<< " --use-stdin\n Pass flatzinc to solver via stdin instead of temp file.\n"
;
}

Expand Down Expand Up @@ -143,6 +144,8 @@ namespace MiniZinc {
} else if ( cop.getOption( "-f --free-search") ) {
if (_opt.supports_f)
_opt.fzn_flags.push_back("-f");
} else if ( cop.getOption( "--use-stdin") ) {
_opt.fzn_use_stdin = true;
} else {
for (auto& fznf : _opt.fzn_solver_flags) {
if (fznf.t==MZNFZNSolverFlag::FT_ARG && cop.getOption(fznf.n.c_str(), &buffer)) {
Expand Down Expand Up @@ -186,6 +189,20 @@ namespace MiniZinc {
}
}

class FZN_Provider : public InputProvider {

protected:
FZNSolverInstance* _inst;
Printer p;

public:
explicit FZN_Provider(FZNSolverInstance* inst) : _inst(inst), p(*getStream(), 0, true) {};

void provide() override {
_inst->printModel(p);
}

};

FZNSolverInstance::FZNSolverInstance(Env& env, std::ostream& log, SolverInstanceBase::Options* options)
: SolverInstanceBase(env, log, options), _fzn(env.flat()), _ozn(env.output()) {}
Expand Down Expand Up @@ -244,30 +261,6 @@ namespace MiniZinc {
}
int timelimit = opt.fzn_time_limit_ms;
bool sigint = opt.fzn_sigint;

FileUtils::TmpFile fznFile(".fzn");
std::ofstream os(fznFile.name());
Printer p(os, 0, true);
for (FunctionIterator it = _fzn->begin_functions(); it != _fzn->end_functions(); ++it) {
if(!it->removed()) {
Item& item = *it;
p.print(&item);
}
}
for (VarDeclIterator it = _fzn->begin_vardecls(); it != _fzn->end_vardecls(); ++it) {
if(!it->removed()) {
Item& item = *it;
p.print(&item);
}
}
for (ConstraintIterator it = _fzn->begin_constraints(); it != _fzn->end_constraints(); ++it) {
if(!it->removed()) {
Item& item = *it;
p.print(&item);
}
}
p.print(_fzn->solveItem());
cmd_line.push_back(fznFile.name());

FileUtils::TmpFile* pathsFile = NULL;
if(opt.fzn_needs_paths) {
Expand All @@ -280,15 +273,29 @@ namespace MiniZinc {
cmd_line.push_back(pathsFile->name());
}

FZN_Provider* input = nullptr;
FileUtils::TmpFile* fznFile = nullptr;
if (opt.fzn_use_stdin) {
input = new FZN_Provider(this);
} else {
fznFile = new FileUtils::TmpFile(".fzn");
std::ofstream os(fznFile->name());
Printer p(os, 0, true);
printModel(p);
cmd_line.push_back(fznFile->name());
}

if(!opt.fzn_output_passthrough) {
Process<Solns2Out> proc(cmd_line, getSolns2Out(), timelimit, sigint);
Process<Solns2Out> proc(cmd_line, getSolns2Out(), timelimit, sigint, input);
int exitStatus = proc.run();
delete fznFile;
delete pathsFile;
return exitStatus == 0 ? getSolns2Out()->status : SolverInstance::ERROR;
} else {
Solns2Log s2l(getSolns2Out()->getOutput(), _log);
Process<Solns2Log> proc(cmd_line, &s2l, timelimit, sigint);
Process<Solns2Log> proc(cmd_line, &s2l, timelimit, sigint, input);
int exitStatus = proc.run();
delete fznFile;
delete pathsFile;
return exitStatus==0 ? SolverInstance::NONE : SolverInstance::ERROR;
}
Expand All @@ -303,4 +310,29 @@ namespace MiniZinc {
assert(false);
return NULL;
}

void FZNSolverInstance::printModel(Printer p) {

for (FunctionIterator it = _fzn->begin_functions(); it != _fzn->end_functions(); ++it) {
if(!it->removed()) {
Item& item = *it;
p.print(&item);
}
}
for (VarDeclIterator it = _fzn->begin_vardecls(); it != _fzn->end_vardecls(); ++it) {
if(!it->removed()) {
Item& item = *it;
p.print(&item);
}
}
for (ConstraintIterator it = _fzn->begin_constraints(); it != _fzn->end_constraints(); ++it) {
if(!it->removed()) {
Item& item = *it;
p.print(&item);
}
}
p.print(_fzn->solveItem());

}

}
2 changes: 1 addition & 1 deletion solvers/mzn/mzn_solverinstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ namespace MiniZinc {
int timelimit = opt.mzn_time_limit_ms;
bool sigint = opt.mzn_sigint;
Solns2Log s2l(getSolns2Out()->getOutput(), _log);
Process<Solns2Log> proc(cmd_line, &s2l, timelimit, sigint);
Process<Solns2Log> proc(cmd_line, &s2l, timelimit, sigint, nullptr);
int exitCode = proc.run();

return exitCode == 0 ? SolverInstance::UNKNOWN : SolverInstance::ERROR;
Expand Down
2 changes: 1 addition & 1 deletion solvers/nl/nl_solverinstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ namespace MiniZinc {
cmd_line.push_back(opt.nl_solver);
cmd_line.push_back(file_nl);
cmd_line.push_back("-AMPL");
Process<NLSolns2Out> proc(cmd_line, &s2o, 0, true);
Process<NLSolns2Out> proc(cmd_line, &s2o, 0, true, nullptr);
exitStatus = proc.run();

if (exitStatus == 0) {
Expand Down