/***************************************************************************
 *   Copyright (C) 2005 by Robot Group Leipzig                             *
 *    martius@informatik.uni-leipzig.de                                    *
 *    fhesse@informatik.uni-leipzig.de                                     *
 *    der@informatik.uni-leipzig.de                                        *
 *                                                                         *
 *   ANY COMMERCIAL USE FORBIDDEN!                                         *
 *   LICENSE:                                                              *
 *   This work is licensed under the Creative Commons                      *
 *   Attribution-NonCommercial-ShareAlike 2.5 License. To view a copy of   *
 *   this license, visit http://creativecommons.org/licenses/by-nc-sa/2.5/ *
 *   or send a letter to Creative Commons, 543 Howard Street, 5th Floor,   *
 *   San Francisco, California, 94105, USA.                                *
 *                                                                         *
 *   This program 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.                  *
 *                                                                         *
 *   $Log: ffnncontroller.h,v $
 *   Revision 1.5  2008/05/30 11:58:27  martius
 *   use cmath instead of math.h
 *
 *   Revision 1.4  2008/04/17 14:54:44  martius
 *   randomGen added, which is a random generator with long period and an
 *    internal state. Each Agent has an instance and passed it to the controller
 *    and the wiring. This is good for
 *   a) repeatability on agent basis,
 *   b) parallel execution as done in ode_robots
 *
 *   Revision 1.3  2007/06/14 13:57:08  martius
 *   initial waiting time (no control before that)
 *
 *   Revision 1.2  2007/06/08 15:46:54  martius
 *   support different static networks (e.g. satellite nets)
 *
 *   Revision 1.1  2006/11/29 16:21:35  martius
 *   controller that uses a fixed feed forward neural network with some history
 *
 *
 ***************************************************************************/
#ifndef __FFNNCONTROLLER_H
#define __FFNNCONTROLLER_H

#include "abstractcontroller.h" 
#include <assert.h>
#include <cmath>

#include <selforg/matrix.h>
#include <selforg/multilayerffnn.h>

/**
 * class for robot controller that uses the georg's matrixlib for 
 *  direct robnot control with a given neural feedforward network
 */
class FFNNController : public AbstractController {

public:
  /** networkfilename is the file to load the network from, 
      and history is the number of time steps the network gets input from (in sense of dimension of input) 
      \param input_only_x if true then the input vector is \f[ (x_{t},x_{t-1},...,x_{t-history})^T \f]
      if false then also the y values are used: \f[ (x_{t}, y_{t-1}, x_{t-1},y_{t-2},...,x_{t-history})^T \f]
  */
  FFNNController(const std::string& networkfilename, int history, bool input_only_x, unsigned int init_wait=0);
  
  virtual void init(int sensornumber, int motornumber, RandGen* randGen = 0);

  virtual ~FFNNController();

  /// returns the number of sensors the controller was initialised with or 0 if not initialised
  virtual int getSensorNumber() const { return number_sensors; }
  /// returns the mumber of motors the controller was initialised with or 0 if not initialised
  virtual int getMotorNumber() const  { return number_motors; }

  virtual void step(const sensor* , int number_sensors, motor* , int number_motors);
  virtual void stepNoLearning(const sensor* , int number_sensors, 
			      motor* , int number_motors);

  /**** STOREABLE ****/
  /** stores the controller values to a given file (binary).  */
  virtual bool store(FILE* f) const;
  /** loads the controller values from a given file (binary). */
  virtual bool restore(FILE* f);  

  // inspectable interface
  virtual std::list<iparamkey> getInternalParamNames()const  { return std::list<iparamkey>(); }
  virtual std::list<iparamval> getInternalParams() const { return std::list<iparamval>(); }

  // configureable interface
  virtual paramval getParam(const paramkey& key) const;
  virtual bool setParam(const paramkey& key, paramval val);
  virtual paramlist getParamList() const ;

protected:
  void putInBuffer(matrix::Matrix* buffer, const matrix::Matrix& vec, int delay = 0);

  matrix::Matrix calculateSmoothValues(const matrix::Matrix* buffer, int number_steps_for_averaging_) const;

  virtual matrix::Matrix assembleNetworkInputXY(matrix::Matrix* xbuffer, matrix::Matrix* ybuffer) const;

  virtual matrix::Matrix assembleNetworkInputX(matrix::Matrix* xbuffer, matrix::Matrix* ybuffer) const;

  virtual matrix::Matrix assembleNetworkOutput(const matrix::Matrix& output) const;


protected:
  unsigned short number_motors;
  unsigned short number_sensors;
  unsigned short history;
  unsigned short buffersize;
  bool input_only_x;
  unsigned short s4avg;
  unsigned int t;
  unsigned int init_wait;
  
  matrix::Matrix* x_buffer;
  matrix::Matrix* y_buffer;
  matrix::Matrix x_smooth;

  MultiLayerFFNN* net; 
  bool initialised;

};

#endif
