nnfw/src/liboutputfunctions.cpp

00001 /********************************************************************************
00002  *  Neural Network Framework.                                                   *
00003  *  Copyright (C) 2005-2009 Gianluca Massera <emmegian@yahoo.it>                *
00004  *                                                                              *
00005  *  This program is free software; you can redistribute it and/or modify        *
00006  *  it under the terms of the GNU General Public License as published by        *
00007  *  the Free Software Foundation; either version 2 of the License, or           *
00008  *  (at your option) any later version.                                         *
00009  *                                                                              *
00010  *  This program is distributed in the hope that it will be useful,             *
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of              *
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
00013  *  GNU General Public License for more details.                                *
00014  *                                                                              *
00015  *  You should have received a copy of the GNU General Public License           *
00016  *  along with this program; if not, write to the Free Software                 *
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  *
00018  ********************************************************************************/
00019 
00020 #include "liboutputfunctions.h"
00021 #include "cluster.h"
00022 #include <QStringList>
00023 #include <QRegExp>
00024 #include <cmath>
00025 
00026 namespace farsa {
00027 
00028 IdentityFunction::IdentityFunction()
00029     : OutputFunction() {
00030 }
00031 
00032 void IdentityFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00033     outputs.copyValues( inputs );
00034 }
00035 
00036 bool IdentityFunction::derivate( const DoubleVector&, const DoubleVector&, DoubleVector& derivates ) const {
00037     derivates.setAll( 1.0 );
00038     return true;
00039 }
00040 
00041 void IdentityFunction::configure(ConfigurationParameters& params, QString prefix)
00042 {
00043     ((void)params);
00044     ((void)prefix);
00045     // Nothing to configure
00046 }
00047 
00048 void IdentityFunction::save(ConfigurationParameters& params, QString prefix)
00049 {
00050     // Just telling our type to ConfigurationParameters
00051     params.startObjectParameters(prefix, "IdentityFunction", this);
00052 }
00053 
00054 ScaleFunction::ScaleFunction( double rate )
00055     : OutputFunction() {
00056     this->rate = rate;
00057 }
00058 
00059 void ScaleFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00060     mul( outputs, rate, inputs );
00061 }
00062 
00063 bool ScaleFunction::derivate( const DoubleVector&, const DoubleVector&, DoubleVector& derivates ) const {
00064     derivates.setAll( rate );
00065     return true;
00066 }
00067 
00068 void ScaleFunction::configure(ConfigurationParameters& params, QString prefix)
00069 {
00070     rate = 1.0;
00071     QString str = params.getValue(prefix + "rate");
00072     if (!str.isEmpty()) {
00073         bool ok;
00074         rate = str.toDouble(&ok);
00075         if (!ok) {
00076             rate = 1.0;
00077         }
00078     }
00079 }
00080 
00081 void ScaleFunction::save(ConfigurationParameters& params, QString prefix)
00082 {
00083     params.startObjectParameters(prefix, "ScaleFunction", this);
00084     params.createParameter(prefix, "rate", QString::number(rate));
00085 }
00086 
00087 GainFunction::GainFunction( double gain )
00088     : OutputFunction() {
00089     gainv = gain;
00090 }
00091 
00092 void GainFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00093     outputs.copyValues( inputs );
00094     outputs += gainv;
00095 }
00096 
00097 bool GainFunction::derivate( const DoubleVector&, const DoubleVector&, DoubleVector& derivates ) const {
00098     derivates.setAll( 1.0 );
00099     return true;
00100 }
00101 
00102 void GainFunction::configure(ConfigurationParameters& params, QString prefix)
00103 {
00104     gainv = 1.0;
00105     QString str = params.getValue(prefix + "gain");
00106     if (!str.isEmpty()) {
00107         bool ok;
00108         gainv = str.toDouble(&ok);
00109         if (!ok) {
00110             gainv = 1.0;
00111         }
00112     }
00113 }
00114 
00115 void GainFunction::save(ConfigurationParameters& params, QString prefix)
00116 {
00117     params.startObjectParameters(prefix, "GainFunction", this);
00118     params.createParameter(prefix, "gain", QString::number(gainv));
00119 }
00120 
00121 SigmoidFunction::SigmoidFunction( double l ) : OutputFunction() {
00122     lambda = l;
00123 }
00124 
00125 void SigmoidFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00126     // ____________1_________________
00127     //   exp( -lamba*inputs ) + 1
00128     inv( exp( mul( outputs, -lambda, inputs ) ) += 1.0 );
00129 }
00130 
00131 bool SigmoidFunction::derivate( const DoubleVector&, const DoubleVector& outputs, DoubleVector& derivates ) const {
00132     // derivates <- lambda * out * (1.0-out)
00133     subtract( derivates, 1.0, outputs );
00134     derivates *= outputs;
00135     derivates *= lambda;
00136     return true;
00137 }
00138 
00139 void SigmoidFunction::configure(ConfigurationParameters& params, QString prefix)
00140 {
00141     lambda = 1.0;
00142     QString str = params.getValue(prefix + "lambda");
00143     if (!str.isEmpty()) {
00144         bool ok;
00145         lambda = str.toDouble(&ok);
00146         if (!ok) {
00147             lambda = 1.0;
00148         }
00149     }
00150 }
00151 
00152 void SigmoidFunction::save(ConfigurationParameters& params, QString prefix)
00153 {
00154     params.startObjectParameters(prefix, "SigmoidFunction", this);
00155     params.createParameter(prefix, "lambda", QString::number(lambda));
00156 }
00157 
00158 FakeSigmoidFunction::FakeSigmoidFunction( double l )
00159     : OutputFunction() {
00160     lambda = l;
00161 }
00162 
00163 void FakeSigmoidFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00164     unsigned int size = inputs.size();
00165     double x;
00166     double x0 = 6. + 2./3.;
00167     double zero = 0.5;
00168     for ( unsigned int i = 0; i<size; i++ ) {
00169         x = inputs[i];
00170         x *= lambda;
00171         x -= (.5 - zero) / (.075 + zero);
00172         if ( x <= -x0 ) {
00173             outputs[i] = 0.0;
00174         } else {
00175             if ( x < x0 ) {
00176                 outputs[i] = .5 + .575 * x / ( 1.0 + fabs(x) );
00177             } else {
00178                 outputs[i] = 1.0;
00179             }
00180         }
00181     }
00182 }
00183 
00184 bool FakeSigmoidFunction::derivate( const DoubleVector&, const DoubleVector& outputs, DoubleVector& derivates ) const {
00185     // derivates <- lambda * out * (1.0-out)
00186     subtract( derivates, 1.0, outputs );
00187     derivates *= outputs;
00188     derivates *= lambda;
00189     return true;
00190 }
00191 
00192 void FakeSigmoidFunction::configure(ConfigurationParameters& params, QString prefix)
00193 {
00194     lambda = 1.0;
00195     QString str = params.getValue(prefix + "lambda");
00196     if (!str.isEmpty()) {
00197         bool ok;
00198         lambda = str.toDouble(&ok);
00199         if (!ok) {
00200             lambda = 1.0;
00201         }
00202     }
00203 }
00204 
00205 void FakeSigmoidFunction::save(ConfigurationParameters& params, QString prefix)
00206 {
00207     params.startObjectParameters(prefix, "FakeSigmoidFunction", this);
00208     params.createParameter(prefix, "lambda", QString::number(lambda));
00209 }
00210 
00211 ScaledSigmoidFunction::ScaledSigmoidFunction( double l, double min, double max )
00212     : OutputFunction() {
00213     lambda = l;
00214     this->min = min;
00215     this->max = max;
00216 }
00217 
00218 void ScaledSigmoidFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00219     //--- compute the sigmoid
00220     // ____________1_________________
00221     //   exp( -lamba*inputs ) + 1
00222     inv( exp( mul( outputs, -lambda, inputs ) ) += 1.0 );
00223     //--- and scale it
00224     outputs *= max-min;
00225     outputs += min;
00226 }
00227 
00228 bool ScaledSigmoidFunction::derivate( const DoubleVector&, const DoubleVector& outputs, DoubleVector& derivates ) const {
00229     // derivates <- lambda * out * (1.0-out)
00230     subtract( derivates, 1.0, outputs );
00231     derivates *= outputs;
00232     derivates *= lambda;
00233     return true;
00234 }
00235 
00236 void ScaledSigmoidFunction::configure(ConfigurationParameters& params, QString prefix)
00237 {
00238     lambda = 1.0;
00239     QString str = params.getValue(prefix + "lambda");
00240     if (!str.isEmpty()) {
00241         bool ok;
00242         lambda = str.toDouble(&ok);
00243         if (!ok) {
00244             lambda = 1.0;
00245         }
00246     }
00247 
00248     min = -1.0;
00249     str = params.getValue(prefix + "min");
00250     if (!str.isEmpty()) {
00251         bool ok;
00252         min = str.toDouble(&ok);
00253         if (!ok) {
00254             min = -1.0;
00255         }
00256     }
00257 
00258     max = 1.0;
00259     str = params.getValue(prefix + "max");
00260     if (!str.isEmpty()) {
00261         bool ok;
00262         max = str.toDouble(&ok);
00263         if (!ok) {
00264             max = 1.0;
00265         }
00266     }
00267 }
00268 
00269 void ScaledSigmoidFunction::save(ConfigurationParameters& params, QString prefix)
00270 {
00271     params.startObjectParameters(prefix, "ScaledSigmoidFunction", this);
00272     params.createParameter(prefix, "lambda", QString::number(lambda));
00273     params.createParameter(prefix, "min", QString::number(min));
00274     params.createParameter(prefix, "max", QString::number(max));
00275 }
00276 
00277 RampFunction::RampFunction()
00278     : OutputFunction() {
00279     min_x = 0.0;
00280     max_x = 0.0;
00281     min_y = 0.0;
00282     max_y = 0.0;
00283 }
00284 
00285 RampFunction::RampFunction( double minX, double maxX, double minY, double maxY )
00286     : OutputFunction() {
00287     min_x = minX;
00288     max_x = maxX;
00289     min_y = minY;
00290     max_y = maxY;
00291 }
00292 
00293 void RampFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00294     unsigned int size = inputs.size();
00295     double m = ( max_y-min_y )/( max_x-min_x );
00296     double q = min_y - m*min_x;
00297     for ( unsigned int i = 0; i<size; i++ ) {
00298         double ret = m*(inputs[i]) + q;
00299         if (ret < min_y) {
00300             outputs[i] = min_y;
00301         } else if (ret > max_y) {
00302             outputs[i] = max_y;
00303         } else {
00304             outputs[i] = ret;
00305         }
00306     }
00307 }
00308 
00309 bool RampFunction::derivate( const DoubleVector& inputs, const DoubleVector&, DoubleVector& derivates ) const {
00310     for( unsigned int i=0; i<inputs.size(); i++ ) {
00311         if ( inputs[i] >= min_x && inputs[i] <= max_x ) {
00312             derivates[i] = ( max_y-min_y )/( max_x-min_x );
00313         } else {
00314             double y;
00315             y = 1.0/( 1.0 + std::exp( -inputs[i] ) );
00316             derivates[i] = y * ( 1.0 - y );
00317         }
00318     }
00319     return true;
00320 }
00321 
00322 void RampFunction::configure(ConfigurationParameters& params, QString prefix)
00323 {
00324     min_x = 0.0;
00325     QString str = params.getValue(prefix + "minX");
00326     if (!str.isEmpty()) {
00327         bool ok;
00328         min_x = str.toDouble(&ok);
00329         if (!ok) {
00330             min_x = 0.0;
00331         }
00332     }
00333 
00334     max_x = 0.0;
00335     str = params.getValue(prefix + "maxX");
00336     if (!str.isEmpty()) {
00337         bool ok;
00338         max_x = str.toDouble(&ok);
00339         if (!ok) {
00340             max_x = 0.0;
00341         }
00342     }
00343 
00344     min_y = 0.0;
00345     str = params.getValue(prefix + "minY");
00346     if (!str.isEmpty()) {
00347         bool ok;
00348         min_y = str.toDouble(&ok);
00349         if (!ok) {
00350             min_y = 0.0;
00351         }
00352     }
00353 
00354     max_y = 0.0;
00355     str = params.getValue(prefix + "maxY");
00356     if (!str.isEmpty()) {
00357         bool ok;
00358         max_y = str.toDouble(&ok);
00359         if (!ok) {
00360             max_y = 0.0;
00361         }
00362     }
00363 }
00364 
00365 void RampFunction::save(ConfigurationParameters& params, QString prefix)
00366 {
00367     params.startObjectParameters(prefix, "RampFunction", this);
00368     params.createParameter(prefix, "minX", QString::number(min_x));
00369     params.createParameter(prefix, "maxX", QString::number(max_x));
00370     params.createParameter(prefix, "minY", QString::number(min_y));
00371     params.createParameter(prefix, "maxY", QString::number(max_y));
00372 }
00373 
00374 LinearFunction::LinearFunction()
00375     : OutputFunction() {
00376     m = 0.0;
00377     b = 0.0;
00378 }
00379 
00380 LinearFunction::LinearFunction( double m, double b )
00381     : OutputFunction() {
00382     this->m = m;
00383     this->b = b;
00384 }
00385 
00386 void LinearFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00387     mul( outputs, m, inputs ) += b;
00388 }
00389 
00390 bool LinearFunction::derivate( const DoubleVector& , const DoubleVector&, DoubleVector& derivates ) const {
00391     derivates.setAll( m );
00392     return true;
00393 }
00394 
00395 void LinearFunction::configure(ConfigurationParameters& params, QString prefix)
00396 {
00397     m = 0.0;
00398     QString str = params.getValue(prefix + "m");
00399     if (!str.isEmpty()) {
00400         bool ok;
00401         m = str.toDouble(&ok);
00402         if (!ok) {
00403             m = 0.0;
00404         }
00405     }
00406 
00407     b = 0.0;
00408     str = params.getValue(prefix + "b");
00409     if (!str.isEmpty()) {
00410         bool ok;
00411         b = str.toDouble(&ok);
00412         if (!ok) {
00413             b = 0.0;
00414         }
00415     }
00416 }
00417 
00418 void LinearFunction::save(ConfigurationParameters& params, QString prefix)
00419 {
00420     params.startObjectParameters(prefix, "LinearFunction", this);
00421     params.createParameter(prefix, "m", QString::number(m));
00422     params.createParameter(prefix, "b", QString::number(b));
00423 }
00424 
00425 StepFunction::StepFunction( double min, double max, double threshold )
00426     : OutputFunction() {
00427     this->min = min;
00428     this->max = max;
00429     this->threshold = threshold;
00430 }
00431 
00432 void StepFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00433     unsigned int size = inputs.size();
00434     for ( unsigned int i = 0; i<size; i++ ) {
00435         ( inputs[i] > threshold ) ? outputs[i] = max : outputs[i] = min;
00436     }
00437 }
00438 
00439 bool StepFunction::derivate( const DoubleVector& inputs, const DoubleVector&, DoubleVector& derivates ) const {
00440     //--- return the same as if it is a sigmoid with lambda = 1
00441     for( unsigned int i=0; i<inputs.size(); i++ ) {
00442         double y;
00443         y = 1.0/( 1.0 + std::exp( -inputs[i] ) );
00444         derivates[i] = y * ( 1.0 - y );
00445     }
00446     return true;
00447 }
00448 
00449 void StepFunction::configure(ConfigurationParameters& params, QString prefix)
00450 {
00451     min = 0.0;
00452     QString str = params.getValue(prefix + "min");
00453     if (!str.isEmpty()) {
00454         bool ok;
00455         min = str.toDouble(&ok);
00456         if (!ok) {
00457             min = 0.0;
00458         }
00459     }
00460 
00461     max = 1.0;
00462     str = params.getValue(prefix + "max");
00463     if (!str.isEmpty()) {
00464         bool ok;
00465         max = str.toDouble(&ok);
00466         if (!ok) {
00467             max = 1.0;
00468         }
00469     }
00470 
00471     threshold = 0.0;
00472     str = params.getValue(prefix + "threshold");
00473     if (!str.isEmpty()) {
00474         bool ok;
00475         threshold = str.toDouble(&ok);
00476         if (!ok) {
00477             threshold = 0.0;
00478         }
00479     }
00480 }
00481 
00482 void StepFunction::save(ConfigurationParameters& params, QString prefix)
00483 {
00484     params.startObjectParameters(prefix, "StepFunction", this);
00485     params.createParameter(prefix, "min", QString::number(min));
00486     params.createParameter(prefix, "max", QString::number(max));
00487     params.createParameter(prefix, "threshold", QString::number(threshold));
00488 }
00489 
00490 LeakyIntegratorFunction::LeakyIntegratorFunction()
00491     : OutputFunction(), delta(), outprev()
00492 {
00493 }
00494 
00495 LeakyIntegratorFunction::LeakyIntegratorFunction( const DoubleVector& d )
00496     : OutputFunction(), delta(d.size()), outprev(d.size()) {
00497     delta.copyValues( d );
00498     outprev.zeroing();
00499 }
00500 
00501 void LeakyIntegratorFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00502     //--- y <- delta*y(t-1) + (1.0-delta)*inputs
00503     //---  its equivalent to
00504     //--- y <- delta*( y(t-1) - inputs ) + inputs
00505     outputs = subtract( outputs, outprev, inputs );
00506     outputs *= delta;
00507     outputs += inputs;
00508     outprev.copyValues( outputs );
00509 }
00510 
00511 void LeakyIntegratorFunction::zeroingStatus() {
00512     outprev.zeroing();
00513 }
00514 
00515 void LeakyIntegratorFunction::clusterSetted() {
00516     if ( clusterv->numNeurons() != delta.size() ) {
00517         delta.resize( clusterv->numNeurons() );
00518         outprev.resize( clusterv->numNeurons() );
00519     }
00520 }
00521 
00522 void LeakyIntegratorFunction::configure(ConfigurationParameters& params, QString prefix)
00523 {
00524     // Delta is a vector, that is a list of space-separated values
00525     QString str = params.getValue(prefix + "delta");
00526     if (!str.isEmpty()) {
00527         QStringList list = str.split(QRegExp("\\s+"), QString::SkipEmptyParts);
00528         delta.resize(list.size());
00529         for( int i = 0; i < list.size(); i++) {
00530             bool ok;
00531             delta[i] = list[i].toDouble(&ok);
00532             if (!ok) {
00533                 delta[i] = 0.0;
00534             }
00535         }
00536     }
00537 
00538     // Also reloading outprev (resizing it to match delta length)
00539     str = params.getValue(prefix + "outprev");
00540     if (!str.isEmpty()) {
00541         QStringList list = str.split(QRegExp("\\s+"), QString::SkipEmptyParts);
00542         outprev.resize(list.size());
00543         for( int i = 0; i < list.size(); i++) {
00544             bool ok;
00545             outprev[i] = list[i].toDouble(&ok);
00546             if (!ok) {
00547                 outprev[i] = 0.0;
00548             }
00549         }
00550     }
00551     outprev.resize(delta.size());
00552 }
00553 
00554 void LeakyIntegratorFunction::save(ConfigurationParameters& params, QString prefix)
00555 {
00556     params.startObjectParameters(prefix, "LeakyIntegratorFunction", this);
00557 
00558     // First creating a string list, then transforming to a single string
00559     QStringList list;
00560     for (unsigned int i = 0; i < delta.size(); i++) {
00561         list.push_back(QString::number(delta[i]));
00562     }
00563     params.createParameter(prefix, "delta", list.join(" "));
00564 
00565     // Saving in the same way also outprev
00566     list.clear();
00567     for (unsigned int i = 0; i < delta.size(); i++) {
00568         list.push_back(QString::number(outprev[i]));
00569     }
00570     params.createParameter(prefix, "outprev", list.join(" "));
00571 }
00572 
00573 LogLikeFunction::LogLikeFunction( double A, double B )
00574     : OutputFunction() {
00575     this->A = A;
00576     this->B = B;
00577 }
00578 
00579 void LogLikeFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00580     //--- y <- x / ( 1+A*x+b )
00581     outputs = inv( mul( outputs, A, inputs ) += (1.0+B) );
00582     outputs *= inputs;
00583 }
00584 
00585 void LogLikeFunction::configure(ConfigurationParameters& params, QString prefix)
00586 {
00587     A = 1.0;
00588     QString str = params.getValue(prefix + "A");
00589     if (!str.isEmpty()) {
00590         bool ok;
00591         A = str.toDouble(&ok);
00592         if (!ok) {
00593             A = 1.0;
00594         }
00595     }
00596 
00597     B = 5.0;
00598     str = params.getValue(prefix + "B");
00599     if (!str.isEmpty()) {
00600         bool ok;
00601         B = str.toDouble(&ok);
00602         if (!ok) {
00603             B = 5.0;
00604         }
00605     }
00606 }
00607 
00608 void LogLikeFunction::save(ConfigurationParameters& params, QString prefix)
00609 {
00610     params.startObjectParameters(prefix, "LogLikeFunction", this);
00611     params.createParameter(prefix, "A", QString::number(A));
00612     params.createParameter(prefix, "B", QString::number(B));
00613 }
00614 
00615 CompositeFunction::CompositeFunction()
00616     : OutputFunction(), first(), second(), mid() {
00617 }
00618 
00619 CompositeFunction::CompositeFunction( OutputFunction *f, OutputFunction *g )
00620     : OutputFunction(), first(f), second(g), mid() {
00621 }
00622 
00623 CompositeFunction::~CompositeFunction() {
00624     // auto_ptr will release memory for us
00625 }
00626 
00627 void CompositeFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00628     first->apply( inputs, mid );
00629     second->apply( mid, outputs );
00630 }
00631 
00632 bool CompositeFunction::setFirstFunction( OutputFunction *f ) {
00633     first.reset(f);
00634     first->setCluster( clusterv );
00635     return true;
00636 }
00637 
00638 OutputFunction* CompositeFunction::getFirstFunction() {
00639     return first.get();
00640 }
00641 
00642 bool CompositeFunction::setSecondFunction( OutputFunction *g ) {
00643     second.reset(g);
00644     second->setCluster( clusterv );
00645     return true;
00646 }
00647 
00648 OutputFunction* CompositeFunction::getSecondFunction() {
00649     return second.get();
00650 }
00651 
00652 void CompositeFunction::clusterSetted() {
00653     mid.resize( clusterv->numNeurons() );
00654     first->setCluster( clusterv );
00655     second->setCluster( clusterv );
00656 }
00657 
00658 void CompositeFunction::configure(ConfigurationParameters& params, QString prefix)
00659 {
00660     // We don't need configured component functions here (and they will be
00661     // configured after exiting from this function)
00662     first.reset(params.getObjectFromParameter<OutputFunction>(prefix + "first", false, false));
00663     second.reset(params.getObjectFromParameter<OutputFunction>(prefix + "second", false, false));
00664 
00665     // We don't need to reload a reference to the cluster as he calls our setCluster
00666     // function after our creation
00667 }
00668 
00669 void CompositeFunction::save(ConfigurationParameters& params, QString prefix)
00670 {
00671     params.startObjectParameters(prefix, "CompositeFunction", this);
00672     params.createParameter(prefix, "first", first.get());
00673     params.createParameter(prefix, "second", second.get());
00674 
00675     // We don't need to save the reference to the cluster as he calls our setCluster
00676     // function after our creation
00677 }
00678 
00679 LinearComboFunction::LinearComboFunction()
00680     : OutputFunction(), first(), second(), mid()
00681 {
00682     this->w1 = 0.0;
00683     this->w2 = 0.0;
00684 }
00685 
00686 LinearComboFunction::LinearComboFunction( double w1, OutputFunction *f, double w2, OutputFunction *g )
00687     : OutputFunction(), first(f), second(g), mid() {
00688     this->w1 = w1;
00689     this->w2 = w2;
00690 }
00691 
00692 LinearComboFunction::~LinearComboFunction() {
00693     // auto_ptr will release memory for us
00694 }
00695 
00696 void LinearComboFunction::apply( DoubleVector& inputs, DoubleVector& outputs ) {
00697     first->apply( inputs, mid );
00698     mid *= w1;
00699     second->apply( inputs, outputs );
00700     outputs *= w2;
00701     outputs += mid;
00702 }
00703 
00704 bool LinearComboFunction::setFirstFunction( OutputFunction *f ) {
00705     first.reset(f);
00706     first->setCluster( clusterv );
00707     return true;
00708 }
00709 
00710 OutputFunction* LinearComboFunction::getFirstFunction() {
00711     return first.get();
00712 }
00713 
00714 bool LinearComboFunction::setFirstWeight( double v ) {
00715     w1 = v;
00716     return true;
00717 }
00718 
00719 double LinearComboFunction::getFirstWeight() {
00720     return w1;
00721 }
00722 
00723 bool LinearComboFunction::setSecondFunction( OutputFunction *g ) {
00724     second.reset(g);
00725     second->setCluster( clusterv );
00726     return true;
00727 }
00728 
00729 OutputFunction* LinearComboFunction::getSecondFunction() {
00730     return second.get();
00731 }
00732 
00733 bool LinearComboFunction::setSecondWeight( double v ) {
00734     w2 = v;
00735     return true;
00736 }
00737 
00738 double LinearComboFunction::getSecondWeight() {
00739     return w2;
00740 }
00741 
00742 void LinearComboFunction::clusterSetted() {
00743     mid.resize( clusterv->numNeurons() );
00744     first->setCluster( clusterv );
00745     second->setCluster( clusterv );
00746 }
00747 
00748 void LinearComboFunction::configure(ConfigurationParameters& params, QString prefix)
00749 {
00750     // We don't need configured component functions here (and they will be
00751     // configured after exiting from this function)
00752     first.reset(params.getObjectFromParameter<OutputFunction>(prefix + "first", false, false));
00753 
00754     w1 = 0.0;
00755     QString str = params.getValue(prefix + "w1");
00756     if (!str.isEmpty()) {
00757         bool ok;
00758         w1 = str.toDouble(&ok);
00759         if (!ok) {
00760             w1 = 0.0;
00761         }
00762     }
00763 
00764     second.reset(params.getObjectFromParameter<OutputFunction>(prefix + "second", false, false));
00765 
00766     w2 = 0.0;
00767     str = params.getValue(prefix + "w2");
00768     if (!str.isEmpty()) {
00769         bool ok;
00770         w2 = str.toDouble(&ok);
00771         if (!ok) {
00772             w2 = 0.0;
00773         }
00774     }
00775 
00776     // We don't need to reload a reference to the cluster as he calls our setCluster
00777     // function after our creation
00778 }
00779 
00780 void LinearComboFunction::save(ConfigurationParameters& params, QString prefix)
00781 {
00782     params.startObjectParameters(prefix, "LinearComboFunction", this);
00783     params.createParameter(prefix, "first", first.get());
00784     params.createParameter(prefix, "w1", QString::number(w1));
00785     params.createParameter(prefix, "second", second.get());
00786     params.createParameter(prefix, "w2", QString::number(w2));
00787 
00788     // We don't need to save the reference to the cluster as he calls our setCluster
00789     // function after our creation
00790 }
00791 
00792 }