new application gprop
This commit is contained in:
parent
265be972ef
commit
8527bd8378
9 changed files with 1405 additions and 0 deletions
17
eo/app/Makefile.am
Normal file
17
eo/app/Makefile.am
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
###############################################################################
|
||||
##
|
||||
## Makefile.am for app
|
||||
##
|
||||
###############################################################################
|
||||
|
||||
SUBDIRS = gprop
|
||||
|
||||
###############################################################################
|
||||
|
||||
all:
|
||||
for i in $(SUBDIRS); do pushd $$i && $(MAKE) all; popd; done
|
||||
|
||||
clean:
|
||||
for i in $(SUBDIRS); do pushd $$i && $(MAKE) clean; popd; done
|
||||
|
||||
###############################################################################
|
||||
25
eo/app/gprop/Makefile.am
Normal file
25
eo/app/gprop/Makefile.am
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
###############################################################################
|
||||
#
|
||||
# Makefile.am for app/gprop
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
DEPS = $(top_builddir)/src/libeo.a $(top_builddir)/src/utils/libeoutils.a
|
||||
|
||||
###############################################################################
|
||||
|
||||
INCLUDES = -I$(top_builddir)/src
|
||||
LDADDS = $(top_builddir)/src/libeo.a $(top_builddir)/src/utils/libeoutils.a
|
||||
|
||||
###############################################################################
|
||||
|
||||
bin_PROGRAMS = gprop
|
||||
|
||||
###############################################################################
|
||||
|
||||
gprop_SOURCES = gprop.cc
|
||||
gprop_DEPENDENCIES = $(DEPS)
|
||||
gprop_LDFLAGS = -lm
|
||||
gprop_LDADD = $(LDADDS)
|
||||
|
||||
###############################################################################
|
||||
146
eo/app/gprop/gprop.cc
Normal file
146
eo/app/gprop/gprop.cc
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// gprop
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <stdlib.h> // EXIT_SUCCESS EXIT_FAILURE
|
||||
#include <stdexcept> // exception
|
||||
#include <iostream> // cerr cout
|
||||
#include <fstream> // ifstream
|
||||
#include <string> // string
|
||||
#include <utils/eoParser.h> // eoParser
|
||||
#include <eoPop.h> // eoPop
|
||||
#include <eoGenContinue.h> // eoGenContinue
|
||||
#include <eoProportional.h> // eoProportional
|
||||
#include <eoSGA.h> // eoSGA
|
||||
#include "gprop.h" // Chrom eoChromInit eoChromMutation eoChromXover eoChromEvaluator
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// global variables
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// parameters
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
eoValueParam<unsigned> pop_size(10, "pop_size", "default population size", 'p');
|
||||
eoValueParam<unsigned> generations(10, "generations", "default generation number", 'g');
|
||||
eoValueParam<double> mut_rate(0.1, "mut_rate", "default mutation rate", 'm');
|
||||
eoValueParam<double> xover_rate(0.1, "xover_rate", "default crossover rate", 'x');
|
||||
eoValueParam<string> file("", "file", "common part of patterns filenames *.trn *.val and *.tst", 'f');
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// auxiliar functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void arg(int argc, char** argv);
|
||||
void load_file(mlp::set& s, const string& s);
|
||||
void ga();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// main
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
try
|
||||
{
|
||||
arg(argc, argv);
|
||||
ga();
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
cerr << argv[0] << ": " << e.what() << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void arg(int argc, char** argv)
|
||||
{
|
||||
eoParser parser(argc, argv);
|
||||
|
||||
parser.processParam(pop_size, "genetic operators");
|
||||
parser.processParam(generations, "genetic operators");
|
||||
parser.processParam(mut_rate, "genetic operators");
|
||||
parser.processParam(xover_rate, "genetic operators");
|
||||
parser.processParam(file, "files");
|
||||
|
||||
if (parser.userNeedsHelp())
|
||||
{
|
||||
parser.printHelp(cout);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
load_file(trn_set, "trn");
|
||||
load_file(val_set, "val");
|
||||
load_file(tst_set, "tst");
|
||||
|
||||
phenotype::trn_max = trn_set.size();
|
||||
phenotype::val_max = val_set.size();
|
||||
phenotype::tst_max = tst_set.size();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void load_file(mlp::set& set, const string& ext)
|
||||
{
|
||||
string filename = file.value(); filename += "." + ext;
|
||||
|
||||
ifstream ifs(filename.c_str());
|
||||
if (!ifs)
|
||||
{
|
||||
cerr << "can't open file \"" << filename << "\"" << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ifs >> set;
|
||||
|
||||
cout << "set.size() = " << set.size() << endl;
|
||||
|
||||
if (set.size() == 0)
|
||||
{
|
||||
cerr << filename << " data file is empty!";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void ga()
|
||||
{
|
||||
eoGenContinue<Chrom> continuator(generations.value());
|
||||
|
||||
eoProportional<Chrom> select;
|
||||
eoChromMutation mutation(generations);
|
||||
eoChromXover xover;
|
||||
eoEvalFuncPtr<Chrom> evaluator(eoChromEvaluator);
|
||||
|
||||
eoSGA<Chrom> sga(select,
|
||||
xover, xover_rate.value(),
|
||||
mutation, mut_rate.value(),
|
||||
evaluator,
|
||||
continuator);
|
||||
|
||||
eoInitChrom init;
|
||||
eoPop<Chrom> pop(pop_size.value(), init);
|
||||
apply<Chrom>(evaluator, pop);
|
||||
|
||||
cout << pop << endl;
|
||||
|
||||
sga(pop);
|
||||
|
||||
cout << pop << endl;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode:C++
|
||||
// End:
|
||||
183
eo/app/gprop/gprop.h
Normal file
183
eo/app/gprop/gprop.h
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// gprop.h
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef gprop_h
|
||||
#define gprop_h
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <iostream> // istream ostream
|
||||
#include <string> // string
|
||||
#include <EO.h> // EO
|
||||
#include <eoOp.h> // eoMonOp eoQuadraticOp
|
||||
#include <eoEvalFuncPtr.h> // eoEvalFunc
|
||||
#include <eoInit.h> // eoInit
|
||||
#include <utils/rnd_generators.h> // normal_generator
|
||||
#include "mlp.h" // mlp::net mlp::set
|
||||
#include "qp.h" // qp::set
|
||||
#include "mse.h" // mse::error
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// phenotype
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct phenotype
|
||||
{
|
||||
unsigned trn_ok, val_ok, tst_ok;
|
||||
double mse_error;
|
||||
|
||||
static unsigned trn_max, val_max, tst_max;
|
||||
|
||||
phenotype(const double& _mse_error = 0): mse_error(_mse_error) {}
|
||||
|
||||
operator double(void) const { return mse_error; }
|
||||
|
||||
friend bool operator<(const phenotype& a, const phenotype& b)
|
||||
{
|
||||
return a.mse_error < b.mse_error;
|
||||
}
|
||||
|
||||
friend ostream& operator<<(ostream& os, const phenotype& p)
|
||||
{
|
||||
return os << p.trn_ok << "/" << p.trn_max << " "
|
||||
<< p.val_ok << "/" << p.val_max << " "
|
||||
<< p.tst_ok << "/" << p.tst_max << " "
|
||||
<< p.mse_error;
|
||||
}
|
||||
|
||||
friend istream& operator>>(istream& is, phenotype& p)
|
||||
{
|
||||
return is;
|
||||
}
|
||||
};
|
||||
|
||||
unsigned phenotype::trn_max = 0, phenotype::val_max = 0, phenotype::tst_max = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// genotype
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
typedef mlp::net genotype;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Chrom
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class Chrom: public EO<phenotype>, public genotype
|
||||
{
|
||||
public:
|
||||
Chrom(): genotype(25, 2) {}
|
||||
|
||||
string className() const { return "Chrom"; }
|
||||
|
||||
void printOn (ostream& os) const
|
||||
{
|
||||
// os << static_cast<genotype>(*this) << " " << fitness();
|
||||
os << fitness();
|
||||
}
|
||||
|
||||
void readFrom (istream& is)
|
||||
{
|
||||
invalidate();
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// eoChromInit
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class eoInitChrom: public eoInit<Chrom>
|
||||
{
|
||||
public:
|
||||
void operator()(Chrom& chrom)
|
||||
{
|
||||
chrom.reset();
|
||||
chrom.invalidate();
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// global variables
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
mlp::set trn_set, val_set, tst_set;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// eoChromMutation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class eoChromMutation: public eoMonOp<Chrom>
|
||||
{
|
||||
public:
|
||||
eoChromMutation(eoValueParam<unsigned>& _generation):
|
||||
generation(_generation) {}
|
||||
|
||||
void operator()(Chrom& chrom)
|
||||
{
|
||||
mse::net tmp(chrom);
|
||||
tmp.train(trn_set, 10, 0, 0.001);
|
||||
}
|
||||
|
||||
private:
|
||||
eoValueParam<unsigned>& generation;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// eoChromXover
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class eoChromXover: public eoQuadraticOp<Chrom>
|
||||
{
|
||||
public:
|
||||
void operator()(Chrom& chrom1, Chrom& chrom2)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// eoChromEvaluator
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
unsigned correct(const mlp::net& net, const qp::set& set)
|
||||
{
|
||||
unsigned sum = 0;
|
||||
|
||||
for (qp::set::const_iterator s = set.begin(); s != set.end(); ++s)
|
||||
{
|
||||
unsigned partial = 0;
|
||||
|
||||
for (unsigned i = 0; i < s->output.size(); ++i)
|
||||
if (s->output[i] < 0.5 && net(s->input)[i] < 0.5 ||
|
||||
s->output[i] > 0.5 && net(s->input)[i] > 0.5)
|
||||
++partial;
|
||||
|
||||
if (partial == s->output.size())
|
||||
++sum;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
|
||||
phenotype eoChromEvaluator(const Chrom& chrom)
|
||||
{
|
||||
// extern mlp::set trn_set, val_set, tst_set;
|
||||
|
||||
phenotype p;
|
||||
p.trn_ok = correct(chrom, trn_set);
|
||||
p.val_ok = correct(chrom, val_set);
|
||||
p.tst_ok = correct(chrom, tst_set);
|
||||
p.mse_error = mse::error(chrom, val_set);
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // gprop_h
|
||||
|
||||
// Local Variables:
|
||||
// mode:C++
|
||||
// End:
|
||||
140
eo/app/gprop/l2.h
Normal file
140
eo/app/gprop/l2.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// l2.h
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef l2_h
|
||||
#define l2_h
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <math.h> // log
|
||||
#include <qp.h> // neuron layer net set
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace l2
|
||||
{
|
||||
//---------------------------------------------------------------------------
|
||||
// useful typedefs
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
using qp::real;
|
||||
using qp::vector;
|
||||
using qp::max_real;
|
||||
using qp::min_real;
|
||||
using qp::set;
|
||||
using qp::neuron;
|
||||
using qp::layer;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// error
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
real error(const mlp::net& net, const set& ts)
|
||||
{
|
||||
real error_ = 0.0;
|
||||
|
||||
for (set::const_iterator s = ts.begin(); s != ts.end(); ++s)
|
||||
{
|
||||
vector out = net(s->input);
|
||||
|
||||
for (unsigned i = 0; i < out.size(); ++i)
|
||||
{
|
||||
real target = s->output[i];
|
||||
real value = out[i];
|
||||
error_ -= target * log(value + min_real) +
|
||||
(1.0 - target) * log(1.0 - value + min_real);
|
||||
}
|
||||
}
|
||||
|
||||
return error_;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// l2
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
class net: public qp::net
|
||||
{
|
||||
public:
|
||||
net(mlp::net& n): qp::net(n) {}
|
||||
|
||||
real error(const set& ts)
|
||||
{
|
||||
real error_ = 0;
|
||||
|
||||
for (set::const_iterator s = ts.begin(); s != ts.end(); ++s)
|
||||
{
|
||||
forward(s->input);
|
||||
error_ -= backward(s->input, s->output);
|
||||
}
|
||||
|
||||
return error_;
|
||||
}
|
||||
|
||||
private:
|
||||
real backward(const vector& input, const vector& output)
|
||||
{
|
||||
reverse_iterator current_layer = rbegin();
|
||||
reverse_iterator backward_layer = current_layer + 1;
|
||||
real error_ = 0;
|
||||
|
||||
// output layer
|
||||
for (unsigned j = 0; j < current_layer->size(); ++j)
|
||||
{
|
||||
neuron& n = (*current_layer)[j];
|
||||
real out = output[j];
|
||||
n.ndelta += n.delta = (out - n.out) /
|
||||
(n.out * (1.0 - n.out) + min_real) * n.out * (1.0 - n.out);
|
||||
|
||||
if (size() == 1) // monolayer
|
||||
n.dxo += n.delta * input;
|
||||
else // multilayer
|
||||
for (unsigned k = 0; k < n.dxo.size(); ++k)
|
||||
n.dxo[k] += n.delta * (*backward_layer)[k].out;
|
||||
|
||||
error_ += out * log(n.out + min_real) +
|
||||
(1.0 - out) * log(1.0 - n.out + min_real);
|
||||
}
|
||||
|
||||
// hidden layers
|
||||
while (++current_layer != rend())
|
||||
{
|
||||
reverse_iterator forward_layer = current_layer - 1;
|
||||
reverse_iterator backward_layer = current_layer + 1;
|
||||
|
||||
for (unsigned j = 0; j < current_layer->size(); ++j)
|
||||
{
|
||||
neuron& n = (*current_layer)[j];
|
||||
real sum = 0;
|
||||
for (unsigned k = 0; k < forward_layer->size(); ++k)
|
||||
{
|
||||
neuron& nf = (*forward_layer)[k];
|
||||
sum += nf.delta * (nf.n->weight[j] + nf.dweight1[j]);
|
||||
}
|
||||
n.delta = n.out * (1.0 - n.out) * sum;
|
||||
n.ndelta += n.delta;
|
||||
|
||||
if (backward_layer == rend()) // first hidden layer
|
||||
n.dxo += n.delta * input;
|
||||
else // rest of hidden layers
|
||||
for (unsigned k = 0; k < n.dxo.size(); ++k)
|
||||
n.dxo[k] += n.delta * (*backward_layer)[k].out;
|
||||
}
|
||||
}
|
||||
|
||||
return error_;
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
} // namespace l2
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // l2_h
|
||||
|
||||
// Local Variables:
|
||||
// mode:C++
|
||||
// End:
|
||||
290
eo/app/gprop/mlp.h
Normal file
290
eo/app/gprop/mlp.h
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// mlp.h
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef mlp_h
|
||||
#define mlp_h
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <values.h> // MAXFLOAT MINFLOAT
|
||||
#include <math.h> // exp
|
||||
#include <stdexcept> // invalid_argument
|
||||
#include <iostream> // istream ostream
|
||||
#include <algorithm> // generate
|
||||
#include <vector> // vector
|
||||
#include <utils/eoRNG.h> // eoRng
|
||||
#include <utils/rnd_generators.h> // normal_geneurator
|
||||
#include <vecop.h> // *
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace mlp
|
||||
{
|
||||
//---------------------------------------------------------------------------
|
||||
// useful typedefs
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
typedef double real;
|
||||
typedef std::vector<real> vector;
|
||||
|
||||
const real max_real = MAXFLOAT;
|
||||
const real min_real = MINFLOAT;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// sigmoid
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
real sigmoid(const real& x)
|
||||
{
|
||||
return 1.0 / (1.0 + exp(-x));
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// neuron
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
struct neuron
|
||||
{
|
||||
real bias;
|
||||
vector weight;
|
||||
|
||||
neuron(const unsigned& num_inputs = 0): weight(num_inputs) {}
|
||||
|
||||
void reset()
|
||||
{
|
||||
normal_generator<real> rnd(1.0);
|
||||
bias = rnd();
|
||||
generate(weight.begin(), weight.end(), rnd);
|
||||
}
|
||||
|
||||
real operator()(const vector& input) const
|
||||
{
|
||||
return sigmoid(bias + weight * input);
|
||||
}
|
||||
|
||||
unsigned length() { return weight.size() + 1; }
|
||||
|
||||
void normalize()
|
||||
{
|
||||
real n = sqrt(bias * bias + weight * weight);
|
||||
bias /= n;
|
||||
weight /= n;
|
||||
}
|
||||
|
||||
void desaturate()
|
||||
{
|
||||
bias = -5.0 + 10.0 / (1.0 + exp(bias / -5.0));
|
||||
|
||||
for (vector::iterator w = weight.begin(); w != weight.end(); ++w)
|
||||
*w = -5.0 + 10.0 / (1.0 + exp(*w / -5.0));
|
||||
}
|
||||
};
|
||||
|
||||
ostream& operator<<(ostream& os, const neuron& n)
|
||||
{
|
||||
return os << n.bias << " " << n.weight;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// layer
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class layer: public std::vector<neuron>
|
||||
{
|
||||
public:
|
||||
layer(const unsigned& num_inputs = 0, const unsigned& num_neurons = 0):
|
||||
std::vector<neuron>(num_neurons, neuron(num_inputs)) {}
|
||||
|
||||
void reset()
|
||||
{
|
||||
normal_generator<real> rnd(1.0);
|
||||
for(iterator n = begin(); n != end(); ++n)
|
||||
n->reset();
|
||||
}
|
||||
|
||||
vector operator()(const vector& input) const
|
||||
{
|
||||
vector output(size());
|
||||
|
||||
for(unsigned i = 0; i < output.size(); ++i)
|
||||
output[i] = (*this)[i](input);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
unsigned length() { return front().length() * size(); }
|
||||
|
||||
void normalize()
|
||||
{
|
||||
for(iterator n = begin(); n != end(); ++n)
|
||||
n->normalize();
|
||||
}
|
||||
|
||||
void desaturate()
|
||||
{
|
||||
for(iterator n = begin(); n != end(); ++n)
|
||||
n->desaturate();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// net
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class net: public std::vector<layer>
|
||||
{
|
||||
public:
|
||||
net(const unsigned& num_inputs = 0,
|
||||
const unsigned& num_outputs = 0,
|
||||
const std::vector<unsigned>& hidden = std::vector<unsigned>())
|
||||
{
|
||||
switch(hidden.size())
|
||||
{
|
||||
case 0:
|
||||
push_back(layer(num_inputs, num_outputs));
|
||||
break;
|
||||
default:
|
||||
push_back(layer(num_inputs, hidden.front()));
|
||||
for (unsigned i = 0; i < hidden.size() - 1; ++i)
|
||||
push_back(layer(hidden[i], hidden[i + 1]));
|
||||
push_back(layer(hidden.back(), num_outputs));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
normal_generator<real> rnd(1.0);
|
||||
for(iterator l = begin(); l != end(); ++l)
|
||||
l->reset();
|
||||
}
|
||||
|
||||
vector operator()(const vector& input) const
|
||||
{
|
||||
vector tmp = input;
|
||||
|
||||
for(const_iterator l = begin(); l != end(); ++l)
|
||||
tmp = (*l)(tmp);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
unsigned winner(const vector& input) const
|
||||
{
|
||||
vector tmp = (*this)(input);
|
||||
return (max_element(tmp.begin(), tmp.end()) - tmp.begin());
|
||||
}
|
||||
|
||||
unsigned length()
|
||||
{
|
||||
unsigned sum = 0;
|
||||
|
||||
for(iterator l = begin(); l != end(); ++l)
|
||||
sum += l->length();
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
void normalize()
|
||||
{
|
||||
for(iterator l = begin(); l != end(); ++l)
|
||||
l->normalize();
|
||||
}
|
||||
|
||||
void desaturate()
|
||||
{
|
||||
for(iterator l = begin(); l != end(); ++l)
|
||||
l->desaturate();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// sample
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
struct sample
|
||||
{
|
||||
vector input, output;
|
||||
|
||||
sample(unsigned input_size = 0, unsigned output_size = 0):
|
||||
input(input_size), output(output_size) {}
|
||||
};
|
||||
|
||||
istream& operator>>(istream& is, sample& s)
|
||||
{
|
||||
return is >> s.input >> s.output;
|
||||
}
|
||||
|
||||
ostream& operator<<(ostream& os, const sample& s)
|
||||
{
|
||||
return os << s.input << " " << s.output;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// set
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class set: public std::vector<sample>
|
||||
{
|
||||
public:
|
||||
set(unsigned input_size = 0, unsigned output_size = 0,
|
||||
unsigned num_samples = 0):
|
||||
std::vector<sample>(num_samples, sample(input_size, output_size)) {}
|
||||
|
||||
set(istream& is)
|
||||
{
|
||||
is >> (*this);
|
||||
}
|
||||
};
|
||||
|
||||
ostream& operator<<(ostream& os, const set& s)
|
||||
{
|
||||
os << "<" << endl;
|
||||
for (unsigned i = 0; i < s.size(); ++i)
|
||||
os << s[i] << endl;
|
||||
return os << ">";
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// euclidean_distance
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
real euclidean_distance(const net& n1, const net& n2)
|
||||
{
|
||||
real sum = 0;
|
||||
|
||||
for(net::const_reverse_iterator l1 = n1.rbegin(), l2 = n2.rbegin();
|
||||
l1 != n1.rend() && l2 != n2.rend(); ++l1, ++l2)
|
||||
for(layer::const_iterator n1 = l1->begin(), n2 = l2->begin();
|
||||
n1 != l1->end() && n2 != l2->end(); ++n1, ++n2)
|
||||
{
|
||||
real b = n1->bias - n2->bias;
|
||||
vector w = n1->weight - n2->weight;
|
||||
sum += b * b + w * w;
|
||||
}
|
||||
/*
|
||||
#include <fstream>
|
||||
std::ofstream file("dist.stat", ios::app);
|
||||
file << sqrt(sum) << endl;
|
||||
*/
|
||||
return sqrt(sum);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
} // namespace mlp
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // mlp_h
|
||||
|
||||
// Local Variables:
|
||||
// mode:C++
|
||||
// End:
|
||||
140
eo/app/gprop/mse.h
Normal file
140
eo/app/gprop/mse.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// mse.h
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef mse_h
|
||||
#define mse_h
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <qp.h> // neuron layer net set
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace mse
|
||||
{
|
||||
//---------------------------------------------------------------------------
|
||||
// useful typedefs
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
using qp::real;
|
||||
using qp::vector;
|
||||
using qp::max_real;
|
||||
using qp::min_real;
|
||||
using qp::set;
|
||||
using qp::neuron;
|
||||
using qp::layer;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// error
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
real error(const mlp::net& net, const set& ts)
|
||||
{
|
||||
real error_ = 0.0;
|
||||
|
||||
for (set::const_iterator s = ts.begin(); s != ts.end(); ++s)
|
||||
{
|
||||
vector out = net(s->input);
|
||||
|
||||
for (unsigned i = 0; i < out.size(); ++i)
|
||||
{
|
||||
real diff = s->output[i] - out[i];
|
||||
error_ += diff * diff;
|
||||
}
|
||||
}
|
||||
|
||||
return error_ / ts.size();
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
// mse
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
class net: public qp::net
|
||||
{
|
||||
public:
|
||||
net(mlp::net& n): qp::net(n) {}
|
||||
|
||||
real error(const set& ts)
|
||||
{
|
||||
real error_ = 0;
|
||||
|
||||
for (set::const_iterator s = ts.begin(); s != ts.end(); ++s)
|
||||
{
|
||||
forward(s->input);
|
||||
error_ += backward(s->input, s->output);
|
||||
}
|
||||
error_ /= ts.size();
|
||||
|
||||
return error_;
|
||||
}
|
||||
|
||||
private:
|
||||
real backward(const vector& input, const vector& output)
|
||||
{
|
||||
reverse_iterator current_layer = rbegin();
|
||||
reverse_iterator backward_layer = current_layer + 1;
|
||||
real error_ = 0;
|
||||
|
||||
// output layer
|
||||
for (unsigned j = 0; j < current_layer->size(); ++j)
|
||||
{
|
||||
neuron& n = (*current_layer)[j];
|
||||
|
||||
real diff = output[j] - n.out;
|
||||
n.ndelta += n.delta = diff * n.out * (1.0 - n.out);
|
||||
|
||||
if (size() == 1) // monolayer
|
||||
n.dxo += n.delta * input;
|
||||
else // multilayer
|
||||
for (unsigned k = 0; k < n.dxo.size(); ++k)
|
||||
n.dxo[k] += n.delta * (*backward_layer)[k].out;
|
||||
|
||||
error_ += diff * diff;
|
||||
}
|
||||
|
||||
// hidden layers
|
||||
while (++current_layer != rend())
|
||||
{
|
||||
reverse_iterator forward_layer = current_layer - 1;
|
||||
reverse_iterator backward_layer = current_layer + 1;
|
||||
|
||||
for (unsigned j = 0; j < current_layer->size(); ++j)
|
||||
{
|
||||
|
||||
neuron& n = (*current_layer)[j];
|
||||
real sum = 0;
|
||||
|
||||
for (unsigned k = 0; k < forward_layer->size(); ++k)
|
||||
{
|
||||
neuron& nf = (*forward_layer)[k];
|
||||
sum += nf.delta * (nf.n->weight[j] + nf.dweight1[j]);
|
||||
}
|
||||
|
||||
n.delta = n.out * (1.0 - n.out) * sum;
|
||||
n.ndelta += n.delta;
|
||||
|
||||
|
||||
if (backward_layer == rend()) // first hidden layer
|
||||
n.dxo += n.delta * input;
|
||||
else // rest of hidden layers
|
||||
for (unsigned k = 0; k < n.dxo.size(); ++k)
|
||||
n.dxo[k] += n.delta * (*backward_layer)[k].out;
|
||||
}
|
||||
}
|
||||
|
||||
return error_;
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
} // namespace mse
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // mse_h
|
||||
|
||||
// Local Variables:
|
||||
// mode:C++
|
||||
// End:
|
||||
251
eo/app/gprop/qp.h
Normal file
251
eo/app/gprop/qp.h
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// qp.h
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef qp_h
|
||||
#define qp_h
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <iostream> // istream ostream
|
||||
#include <algorithm> // fill
|
||||
#include <vector> // vector
|
||||
#include <utils/rnd_generators.h> // uniform_generator
|
||||
#include <mlp.h> // neuron layer net
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace qp
|
||||
{
|
||||
//---------------------------------------------------------------------------
|
||||
// useful typedefs
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
using mlp::real;
|
||||
using mlp::vector;
|
||||
|
||||
using mlp::max_real;
|
||||
using mlp::min_real;
|
||||
|
||||
using mlp::set;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// useful constants
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
const real eta_default = 0.5;
|
||||
const real eta_floor = 0.0001;
|
||||
const real alpha_default = 0.9;
|
||||
const real lambda_default = 0.5;
|
||||
const real lambda0 = 0.1;
|
||||
const real backtrack_step = 0.5;
|
||||
const real me_floor = 0.0001;
|
||||
const real mw_floor = 0.0001;
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// neuron
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
struct neuron
|
||||
{
|
||||
mlp::neuron* n;
|
||||
real out, delta, ndelta, dbias1, dbias2;
|
||||
vector dweight1, dweight2, dxo;
|
||||
|
||||
neuron(mlp::neuron& _n):
|
||||
n(&_n), out(0), delta(0), ndelta(0), dbias1(0), dbias2(0),
|
||||
dweight1(n->weight.size(), 0),
|
||||
dweight2(n->weight.size(), 0),
|
||||
dxo(n->weight.size(), 0) {}
|
||||
|
||||
void reset()
|
||||
{
|
||||
// underlaying neuron
|
||||
n->reset();
|
||||
|
||||
// addons
|
||||
out = delta = ndelta = dbias1 = dbias2 = 0;
|
||||
fill(dweight1.begin(), dweight1.end(), 0);
|
||||
fill(dweight2.begin(), dweight2.end(), 0);
|
||||
fill(dxo.begin(), dxo.end(), 0);
|
||||
}
|
||||
|
||||
real operator()(const vector& input)
|
||||
{
|
||||
return out = mlp::sigmoid(n->bias + dbias1 +
|
||||
(n->weight + dweight1) * input);
|
||||
}
|
||||
};
|
||||
|
||||
ostream& operator<<(ostream& os, const neuron& n)
|
||||
{
|
||||
return os << *n.n << " " << n.out << " " << n.delta << " "
|
||||
<< n.ndelta << " " << n.dbias1 << " " << n.dbias2 << " "
|
||||
<< n.dweight1 << " " << n.dweight2 << " " << n.dxo;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// layer
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class layer: public std::vector<neuron>
|
||||
{
|
||||
public:
|
||||
layer(mlp::layer& l)//: std::vector<neuron>(l.begin(), l.end()) {}
|
||||
{
|
||||
for (mlp::layer::iterator n = l.begin(); n != l.end(); ++n)
|
||||
push_back(neuron(*n));
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
for(iterator n = begin(); n != end(); ++n)
|
||||
n->reset();
|
||||
}
|
||||
|
||||
vector operator()(const vector& input)
|
||||
{
|
||||
vector output(size());
|
||||
|
||||
for(unsigned i = 0; i < output.size(); ++i)
|
||||
output[i] = (*this)[i](input);
|
||||
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// net
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
class net: public std::vector<layer>
|
||||
{
|
||||
public:
|
||||
net(mlp::net& n) //: std::vector<layer>(n.begin(), n.end()) { reset(); }
|
||||
{
|
||||
for (mlp::net::iterator l = n.begin(); l != n.end(); ++l)
|
||||
push_back(*l);
|
||||
}
|
||||
|
||||
virtual ~net() {}
|
||||
|
||||
void reset()
|
||||
{
|
||||
for(iterator l = begin(); l != end(); ++l)
|
||||
l->reset();
|
||||
}
|
||||
|
||||
real train(const set& ts,
|
||||
unsigned epochs,
|
||||
real target_error,
|
||||
real tolerance,
|
||||
real eta = eta_default,
|
||||
real momentum = alpha_default,
|
||||
real lambda = lambda_default)
|
||||
{
|
||||
real error_ = max_real;
|
||||
|
||||
while (epochs-- && error_ > target_error)
|
||||
{
|
||||
real last_error = error_;
|
||||
|
||||
init_delta();
|
||||
|
||||
error_ = error(ts);
|
||||
|
||||
if (error_ < last_error + tolerance)
|
||||
{
|
||||
coeff_adapt(eta, momentum, lambda);
|
||||
weight_update(ts.size(), true, eta, momentum);
|
||||
}
|
||||
else
|
||||
{
|
||||
eta *= backtrack_step;
|
||||
eta = max(eta, eta_floor);
|
||||
momentum = eta * lambda;
|
||||
weight_update(ts.size(), false, eta, momentum);
|
||||
error_ = last_error;
|
||||
}
|
||||
}
|
||||
|
||||
return error_;
|
||||
}
|
||||
|
||||
virtual real error(const set& ts) = 0;
|
||||
|
||||
// protected:
|
||||
void forward(vector input)
|
||||
{
|
||||
for (iterator l = begin(); l != end(); ++l)
|
||||
{
|
||||
vector tmp = (*l)(input);
|
||||
input.swap(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
// private:
|
||||
void init_delta()
|
||||
{
|
||||
for (iterator l = begin(); l != end(); ++l)
|
||||
for (layer::iterator n = l->begin(); n != l->end(); ++n)
|
||||
fill(n->dxo.begin(), n->dxo.end(), n->ndelta = 0.0);
|
||||
}
|
||||
|
||||
void coeff_adapt(real& eta, real& momentum, real& lambda)
|
||||
{
|
||||
real me = 0, mw = 0, ew = 0;
|
||||
|
||||
for (iterator l = begin(); l != end(); ++l)
|
||||
for (layer::iterator n = l->begin(); n != l->end(); ++n)
|
||||
{
|
||||
me += n->dxo * n->dxo;
|
||||
mw += n->dweight1 * n->dweight1;
|
||||
ew += n->dxo * n->dweight1;
|
||||
}
|
||||
|
||||
me = max(static_cast<real>(sqrt(me)), me_floor);
|
||||
mw = max(static_cast<real>(sqrt(mw)), mw_floor);
|
||||
eta *= (1.0 + 0.5 * ew / ( me * mw));
|
||||
eta = max(eta, eta_floor);
|
||||
lambda = lambda0 * me / mw;
|
||||
momentum = eta * lambda;
|
||||
#ifdef DEBUG
|
||||
cout << me << " \t" << mw << " \t" << ew << " \t"
|
||||
<< eta << " \t" << momentum << " \t" << lambda << endl;
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
void weight_update(unsigned size, bool fire, real eta, real momentum)
|
||||
{
|
||||
for (iterator l = begin(); l != end(); ++l)
|
||||
for (layer::iterator n = l->begin(); n != l->end(); ++n)
|
||||
{
|
||||
n->ndelta /= size;
|
||||
n->dxo /= size;
|
||||
if (fire)
|
||||
{
|
||||
n->n->weight += n->dweight1;
|
||||
n->dweight2 = n->dweight1;
|
||||
n->n->bias += n->dbias1;
|
||||
n->dbias2 = n->dbias1;
|
||||
}
|
||||
n->dweight1 = eta * n->dxo + momentum * n->dweight2;
|
||||
n->dbias1 = eta * n->ndelta + momentum * n->dbias2;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
} // namespace qp
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // qp_h
|
||||
|
||||
// Local Variables:
|
||||
// mode:C++
|
||||
// End:
|
||||
213
eo/app/gprop/vecop.h
Normal file
213
eo/app/gprop/vecop.h
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// vecop.h
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef VECOP_H
|
||||
#define VECOP_H
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <iostream> // ostream istream
|
||||
#include <vector> // vector
|
||||
#include <functional> // plus minus multiplies divides
|
||||
#include <numeric> // inner_product
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// vector + vector
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class T> vector<T> operator+(const vector<T>& v1, const vector<T>& v2)
|
||||
{
|
||||
vector<T> tmp = v1;
|
||||
transform(tmp.begin(), tmp.end(), v2.begin(), tmp.begin(), plus<T>());
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<class T> vector<T> operator-(const vector<T>& v1, const vector<T>& v2)
|
||||
{
|
||||
vector<T> tmp = v1;
|
||||
transform(tmp.begin(), tmp.end(), v2.begin(), tmp.begin(), minus<T>());
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<class T> T operator*(const vector<T>& v1, const vector<T>& v2)
|
||||
{
|
||||
return inner_product(v1.begin(), v1.end(), v2.begin(), static_cast<T>(0));
|
||||
}
|
||||
|
||||
template<class T> T operator/(const vector<T>& v1, const vector<T>& v2)
|
||||
{
|
||||
return inner_product(v1.begin(), v1.end(), v2.begin(), static_cast<T>(0),
|
||||
plus<T>(), divides<T>());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// vector += vector
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class T> vector<T>& operator+=(vector<T>& v1, const vector<T>& v2)
|
||||
{
|
||||
transform(v1.begin(), v1.end(), v2.begin(), v1.begin(), plus<T>());
|
||||
return v1;
|
||||
}
|
||||
|
||||
template<class T> vector<T>& operator-=(vector<T>& v1, const vector<T>& v2)
|
||||
{
|
||||
transform(v1.begin(), v1.end(), v2.begin(), v1.begin(), minus<T>());
|
||||
return v1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// vector + number
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class A, class B> vector<A> operator+(const vector<A>& a, const B& b)
|
||||
{
|
||||
vector<A> tmp = a;
|
||||
transform(tmp.begin(), tmp.end(), tmp.begin(), bind2nd(plus<A>(), b));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<class A, class B> vector<A> operator-(const vector<A>& a, const B& b)
|
||||
{
|
||||
vector<A> tmp = a;
|
||||
transform(tmp.begin(), tmp.end(), tmp.begin(), bind2nd(minus<A>(), b));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<class A, class B> vector<A> operator*(const vector<A>& a, const B& b)
|
||||
{
|
||||
vector<A> tmp = a;
|
||||
transform(tmp.begin(), tmp.end(), tmp.begin(), bind2nd(multiplies<A>(), b));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<class A, class B> vector<A> operator/(const vector<A>& a, const B& b)
|
||||
{
|
||||
vector<A> tmp = a;
|
||||
transform(tmp.begin(), tmp.end(), tmp.begin(), bind2nd(divides<A>(), b));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// number + vector
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class A, class B> vector<A> operator+(const B& b, const vector<A>& a)
|
||||
{
|
||||
vector<A> tmp = a;
|
||||
transform(tmp.begin(), tmp.end(), tmp.begin(), bind2nd(plus<A>(), b));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<class A, class B> vector<A> operator-(const B& b, const vector<A>& a)
|
||||
{
|
||||
vector<A> tmp(a.size(), b);
|
||||
transform(tmp.begin(), tmp.end(), a.begin(), tmp.begin(), minus<A>());
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<class A, class B> vector<A> operator*(const B& b, const vector<A>& a)
|
||||
{
|
||||
vector<A> tmp = a;
|
||||
transform(tmp.begin(), tmp.end(), tmp.begin(), bind2nd(multiplies<A>(), b));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<class A, class B> vector<A> operator/(const B& b, const vector<A>& a)
|
||||
{
|
||||
vector<A> tmp(a.size(), b);
|
||||
transform(tmp.begin(), tmp.end(), a.begin(), tmp.begin(), divides<A>());
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// vector += number
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class A, class B> vector<A>& operator+=(vector<A>& a, const B& b)
|
||||
{
|
||||
transform(a.begin(), a.end(), a.begin(), bind2nd(plus<A>(), b));
|
||||
return a;
|
||||
}
|
||||
|
||||
template<class A, class B> vector<A>& operator-=(vector<A>& a, const B& b)
|
||||
{
|
||||
transform(a.begin(), a.end(), a.begin(), bind2nd(minus<A>(), b));
|
||||
return a;
|
||||
}
|
||||
|
||||
template<class A, class B> vector<A>& operator*=(vector<A>& a, const B& b)
|
||||
{
|
||||
transform(a.begin(), a.end(), a.begin(), bind2nd(multiplies<A>(), b));
|
||||
return a;
|
||||
}
|
||||
|
||||
template<class A, class B> vector<A>& operator/=(vector<A>& a, const B& b)
|
||||
{
|
||||
transform(a.begin(), a.end(), a.begin(), bind2nd(divides<A>(), b));
|
||||
return a;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// I/O
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class T> ostream& operator<<(ostream& os, const vector<T>& v)
|
||||
{
|
||||
os << '<';
|
||||
if (v.size())
|
||||
{
|
||||
copy(v.begin(), v.end() - 1, ostream_iterator<T>(os, " "));
|
||||
os << v.back();
|
||||
}
|
||||
return os << '>';
|
||||
}
|
||||
|
||||
template<class T> istream& operator>>(istream& is, vector<T>& v)
|
||||
{
|
||||
v.clear();
|
||||
|
||||
char c;
|
||||
is >> c;
|
||||
if (!is || c != '<')
|
||||
is.setstate(ios::failbit);
|
||||
else
|
||||
{
|
||||
T t;
|
||||
do {
|
||||
is >> c;
|
||||
if (is && c!= '>')
|
||||
{
|
||||
is.putback(c);
|
||||
is >> t;
|
||||
if (is)
|
||||
v.push_back(t);
|
||||
}
|
||||
} while (is && c != '>');
|
||||
}
|
||||
|
||||
return is;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// euclidean_distance
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template<class T> T euclidean_distance(const vector<T>& v1,
|
||||
const vector<T>& v2)
|
||||
{
|
||||
T sum = 0, tmp;
|
||||
|
||||
for (unsigned i = 0; i < v1.size(); ++i)
|
||||
{
|
||||
tmp = v1[i] - v2[i];
|
||||
sum += tmp * tmp;
|
||||
}
|
||||
|
||||
return sqrt(sum);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif VECOP_H
|
||||
Reference in a new issue