add eoEvalCmd, an eval that call a system command
This commit is contained in:
parent
9056ed8989
commit
ccb4b3787b
4 changed files with 173 additions and 0 deletions
|
|
@ -78,6 +78,7 @@
|
|||
#include "eoEvalCounterThrowException.h"
|
||||
#include "eoEvalTimeThrowException.h"
|
||||
#include "eoEvalUserTimeThrowException.h"
|
||||
#include "eoEvalCmd.h"
|
||||
|
||||
// Continuators - all include eoContinue.h
|
||||
#include "eoCombinedContinue.h"
|
||||
|
|
|
|||
142
eo/src/eoEvalCmd.h
Normal file
142
eo/src/eoEvalCmd.h
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
(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 interpreted as a float by `atof`.
|
||||
*
|
||||
* @todo Use the serialization of fitness instead of atof.
|
||||
*
|
||||
* 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),
|
||||
_suffix(suffix),
|
||||
_infix(infix),
|
||||
_prefix(prefix),
|
||||
_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::array<char, BUFFER_SIZE> buffer;
|
||||
std::string result;
|
||||
|
||||
std::ostringstream cmd;
|
||||
|
||||
cmd << _prefix << " " << _cmd << " "
|
||||
<< _infix << " " << sol << " " << _suffix;
|
||||
|
||||
// Keep track of the built command for debugging purpose.
|
||||
_last_call = cmd.str();
|
||||
|
||||
FILE* pipe = popen(cmd.str().c_str(), "r");
|
||||
if(not pipe) {
|
||||
throw eoSystemError(cmd.str());
|
||||
}
|
||||
while(fgets(buffer.data(), BUFFER_SIZE, pipe) != NULL) {
|
||||
result += buffer.data();
|
||||
}
|
||||
auto return_code = pclose(pipe);
|
||||
|
||||
if(return_code != 0) {
|
||||
throw eoSystemError(cmd.str(), return_code, result);
|
||||
}
|
||||
|
||||
// FIXME Use serialized input for the fitness instead of atof.
|
||||
Fitness f = std::atof(result.c_str());
|
||||
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // eoEvalCmd_H
|
||||
|
|
@ -70,6 +70,7 @@ set (TEST_LIST
|
|||
#t-eoDualFitness
|
||||
t-eoParser
|
||||
t-eoPartiallyMappedXover
|
||||
t-eoEvalCmd
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
29
eo/test/t-eoEvalCmd.cpp
Normal file
29
eo/test/t-eoEvalCmd.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <eo>
|
||||
#include <es.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int /*argc*/, char* /*argv[]*/)
|
||||
{
|
||||
typedef eoReal<eoMinimizingFitness> EOT;
|
||||
|
||||
// Build something like: ">&1 echo 1.2; # INVALID 2 1 2"
|
||||
eoEvalCmd<EOT> eval("echo 1.2", ">&1", "; #");
|
||||
|
||||
EOT sol = {1,2};
|
||||
std::clog << sol << std::endl;
|
||||
|
||||
try {
|
||||
eval(sol);
|
||||
} catch(eoSystemError& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::clog << eval.last_call() << std::endl;
|
||||
EOT::Fitness f = sol.fitness();
|
||||
std::clog << "fitness: " << f << std::endl;
|
||||
assert(f = 1.2);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue