diff --git a/eo/src/eo b/eo/src/eo index 35fa13d9a..c415c214b 100644 --- a/eo/src/eo +++ b/eo/src/eo @@ -74,6 +74,7 @@ // Evaluation functions (all include eoEvalFunc.h) #include "eoPopEvalFunc.h" +#include "eoEvalNamedPipe.h" #include "eoEvalCmd.h" #include "eoEvalCounterThrowException.h" #include "eoEvalDump.h" diff --git a/eo/src/eoEvalCmd.h b/eo/src/eoEvalCmd.h index afc3d60fb..e34dd3eee 100644 --- a/eo/src/eoEvalCmd.h +++ b/eo/src/eoEvalCmd.h @@ -38,9 +38,7 @@ Johann Dréo * 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. + * 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``` diff --git a/eo/src/eoEvalNamedPipe.h b/eo/src/eoEvalNamedPipe.h new file mode 100644 index 000000000..02d6dc67a --- /dev/null +++ b/eo/src/eoEvalNamedPipe.h @@ -0,0 +1,120 @@ +/* +(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 +*/ + +#ifndef eoEvalNamedPipe_H +#define eoEvalNamedPipe_H + +#include +#include +#include +#include + +#include "eoEvalFunc.h" +#include "eoExceptions.h" + +/** Communicate through a named pipe FIFO to evaluate an individual. + * + * With this class, you can plug an external process computing the fitness + * of a serialized solution with a process hosting the EO algorithm. + * Both processes just have to read/write solutions/fitness in files. + * + * The code would work with any file, but it is actually only useful with + * FIFO pipes, which are blocking on I/O. + * Thus, the process actually computing the fitness will ait for the solution to be wrote, + * then compute and write the fitness back, waiting it to be read. + * Conversely, the EO process will wait after having wrote the solution, that the other process + * actually read it, then wait itself for the fitness to be read in the pipe. + * With pipes, the synchronization of the two processes is guaranteed. + * + * To create a named FIFO pipe under Linux, see the command `mkfifo`. + * + * @note: if you use a single pipe for input/output, take care + * of the synchronization with the process handling the fitness computation. + * In particular, the first call of eoEvalNamedPipe + * is to write the solution, THEN to read the fitness. + * + * @note Tested only under Unix systems, may not be portable as is. + * + * Use the default string serialization of the EOT and + * the default deserialization of the fitness. + * + *@ingroup Evaluation + */ +template +class eoEvalNamedPipe : public eoEvalFunc< EOT > +{ +public: + using Fitness = typename EOT::Fitness; + + /** Constructor + * + * @param output_pipe_name The named pipe in which to write the serialized solution. + * @param input_pipe_name The named pipe in which to read the serialized fitness. If it is "", use the output pipe. + */ + eoEvalNamedPipe( + const std::string output_pipe_name, + const std::string input_pipe_name = "" + ) : + _output_pipe_name(output_pipe_name), + _input_pipe_name(input_pipe_name) + { + if( _input_pipe_name == "") { + _input_pipe_name = _output_pipe_name; + } + } + + 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 ) ); + } + +private: + const std::string _output_pipe_name; + std::string _input_pipe_name; + + Fitness call( EOT& sol ) + { + // Write the passed solution. + std::ofstream out(_output_pipe_name); + out << sol << std::endl; + out.close(); + + // Read the output string in a valid fitness object. + Fitness fit; + std::ifstream if_fit(_input_pipe_name); + std::stringstream ss_fit; + ss_fit << if_fit.rdbuf(); + if_fit.close(); + ss_fit >> fit; + + return fit; + } +}; + +#endif // eoEvalNamedPipe_H