add eoEvalNamedPipe

- a class to connect an external objective function through file(s)
- fix doc error in eoEvalCmd
This commit is contained in:
Johann Dreo 2020-03-08 21:44:42 +01:00
commit 6232ff2f21
3 changed files with 122 additions and 3 deletions

View file

@ -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"

View file

@ -38,9 +38,7 @@ Johann Dréo <johann.dreo@thalesgroup.com>
* 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```

120
eo/src/eoEvalNamedPipe.h Normal file
View file

@ -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 <johann.dreo@thalesgroup.com>
*/
#ifndef eoEvalNamedPipe_H
#define eoEvalNamedPipe_H
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <array>
#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 EOT>
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