143 lines
4.1 KiB
C++
143 lines
4.1 KiB
C++
/*
|
|
(c) Thales group, 2020
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation;
|
|
version 2 of the License.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
Contact: http://eodev.sourceforge.net
|
|
|
|
Authors:
|
|
Johann Dréo <johann.dreo@thalesgroup.com>
|
|
*/
|
|
|
|
#ifndef eoEvalCmd_H
|
|
#define eoEvalCmd_H
|
|
|
|
#include <cstdlib>
|
|
#include <array>
|
|
|
|
#include "eoEvalFunc.h"
|
|
#include "eoExceptions.h"
|
|
|
|
|
|
/** Call a system command to evaluate an individual.
|
|
*
|
|
* @note Tested only under Unix systems, may not be portable as is.
|
|
*
|
|
* Use the default string serialization of the EOT
|
|
* and pass it as command line arguments of the command.
|
|
* The command is expected to output on stdout a string
|
|
* that can be deserialized as a fitness.
|
|
*
|
|
* For example, an eoReal would lead to a call like:
|
|
* ```>&2 cmd INVALID 3 1.0 2.1 3.2```
|
|
*
|
|
* Throw an eoSystemError exception if the command exited with
|
|
* a return code different from zero.
|
|
*
|
|
*@ingroup Evaluation
|
|
*/
|
|
template<class EOT, int BUFFER_SIZE = 128>
|
|
class eoEvalCmd : public eoEvalFunc< EOT >
|
|
{
|
|
public:
|
|
using Fitness = typename EOT::Fitness;
|
|
|
|
/** Constructor
|
|
*
|
|
* @note The prefix and suffix are automatically
|
|
* separated from the command by a space.
|
|
*
|
|
* The formated command looks like: `prefix cmd infix sol suffix`
|
|
*
|
|
* The default prefix allows to redirect any output to stdout under Unix.
|
|
*
|
|
* @param cmd The command to run.
|
|
* @param prefix Inserted before the command
|
|
* @param suffix Inserted between cmd and the serialized solution.
|
|
* @param suffix Append after the solution.
|
|
*/
|
|
eoEvalCmd( const std::string cmd,
|
|
const std::string prefix = ">&1",
|
|
const std::string infix = "",
|
|
const std::string suffix = ""
|
|
) :
|
|
_cmd(cmd),
|
|
_prefix(prefix),
|
|
_infix(infix),
|
|
_suffix(suffix),
|
|
_last_call("")
|
|
{}
|
|
|
|
virtual void operator()( EOT& sol )
|
|
{
|
|
// Any modification to sol would makes it invalid,
|
|
// it is thus useless to evaluate it, if it is not invalid.
|
|
if(not sol.invalid()) {
|
|
return;
|
|
}
|
|
|
|
sol.fitness( call( sol ) );
|
|
}
|
|
|
|
//! Return the last command string that was called.
|
|
std::string last_call() const
|
|
{
|
|
return _last_call;
|
|
}
|
|
|
|
private:
|
|
const std::string _cmd;
|
|
const std::string _prefix;
|
|
const std::string _infix;
|
|
const std::string _suffix;
|
|
std::string _last_call;
|
|
|
|
Fitness call( EOT& sol )
|
|
{
|
|
std::ostringstream cmd;
|
|
cmd << _prefix << " " << _cmd << " "
|
|
<< _infix << " " << sol << " " << _suffix;
|
|
|
|
// Keep track of the built command for debugging purpose.
|
|
_last_call = cmd.str();
|
|
|
|
// Run the command and read its output.
|
|
std::array<char, BUFFER_SIZE> buffer;
|
|
std::string output;
|
|
FILE* pipe = popen(cmd.str().c_str(), "r");
|
|
if(not pipe) {
|
|
throw eoSystemError(cmd.str());
|
|
}
|
|
while(fgets(buffer.data(), BUFFER_SIZE, pipe) != NULL) {
|
|
output += buffer.data();
|
|
}
|
|
auto return_code = pclose(pipe);
|
|
|
|
// We want the evaluation to fail if the command failed
|
|
// (you can still catch the exception if you do not want your program to exit).
|
|
if(return_code != 0) {
|
|
throw eoSystemError(cmd.str(), return_code, output);
|
|
}
|
|
|
|
// Convert the output string in a valid fitness object.
|
|
Fitness f;
|
|
std::istringstream result(output);
|
|
result >> f;
|
|
|
|
return f;
|
|
}
|
|
};
|
|
|
|
#endif // eoEvalCmd_H
|