/* -*-	Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
 * Copyright (c) 2006 National ICT Australia Ltd
 * All rights reserved.
 * Author:  E. LOCHIN,
 * 
 * Permission to use and copy this software in source and binary forms
 * is hereby granted, provided that the above copyright notice, this
 * paragraph and the following disclaimer are retained in any copies
 * of any part of this software and that the University of La Reunion is
 * acknowledged in all documentation pertaining to any such copy
 * or derivative work. The name of the University of La Reunion may not
 * be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL 
 * THE UNIVERSITY OF LA REUNION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER  
 * DEALINGS IN THE SOFTWARE.
 */

#ifndef ns_kred_h
#define ns_kred_h

#include "red.h"

class REDQueue;

enum Steps {Init1, Init2, Step1, Step2};
Steps steps;

class KREDQueue : public REDQueue {
 public:	
	 KREDQueue();
	
	 #define MAX_double      +HUGE_VAL
	 #define PI            (2*asin(1))
	 #define sqr(x)        ((x)*(x))

	 #define ROWS          25
	 #define COLS          25

	 #define N             2
	 #define C             (ROWS * COLS)
	 #define M             1

	 typedef struct {                     /* A LAYER OF A NET:                     */
        	int           Units;         /* - number of units in this layer       */
        	double*         Output;        /* - output of ith unit                  */
        	double**        Weight;        /* - connection weights to ith unit      */
        	double*         StepSize;      /* - size of search steps of ith unit    */
        	double*         dScoreMean;    /* - mean score delta of ith unit        */
	 } LAYER;

	 typedef struct {                     /* A NET:                                */
        	LAYER*        InputLayer;    /* - input layer                         */
        	LAYER*        KohonenLayer;  /* - Kohonen layer                       */
        	LAYER*        OutputLayer;   /* - output layer                        */
        	int           Winner;        /* - last winner in Kohonen layer        */
        	double          Alpha;         /* - learning rate for Kohonen layer     */
        	double          Alpha_;        /* - learning rate for output layer      */
        	double          Alpha__;       /* - learning rate for step sizes        */
        	double          Gamma;         /* - smoothing factor for score deltas   */
        	double          Sigma;         /* - parameter for width of neighborhood */	
	 } NET;
	 
	 NET Net;

  	 int  n,t,first,rwdone;
  	 double wOld, wNew, ScoreOld, ScoreNew, dScore, dScoreMean, StepSize;
  	 double Input[N];
  	 double Output[M];
  	 double Target[M];
	 FILE *fp;
	 double start_time;

 protected:
	double TrainSteps_;
	double lambda_low_;
	double lambda_high_;
	int curqlen_method_;
	int tdebug_;
	void updateMaxKohonen(NET* Net, double new_ave, double old_ave, double now);
	void updateMaxP(double new_ave, double now);
	void updateMaxPFeng(double new_ave);
	void InitKRED(double new_ave);
	double estimator(int nqueued, int m, double ave, double q_w);
	void enque(Packet* pkt);
	void openfile(void);
		
	void InitializeRandoms(void);
	double RandomEqualdouble(double Low, double High);
	double RandomNormaldouble(double Mu, double Sigma);
	void InitializeApplication(NET* Net);
	void GenerateNetwork(NET* Net);
	void RandomWeights(NET* Net);
	void SetInput(NET* Net, double* Input);
	void GetOutput(NET* Net, double* Output);
	void PropagateToKohonen(NET* Net);
	void PropagateToOutput(NET* Net);
	void PropagateNet(NET* Net);
	double Neighborhood(NET* Net, int i);
	void TrainKohonen(NET* Net, double* Input);
	void TrainOutput(NET* Net, double* Output);
	void TrainUnits(NET* Net, double* Input, double* Output);
	void ReadNet(NET* Net);
	void WriteNet(NET* Net);
	void TrainNet(NET* Net);
	void UseNet(NET* Net);
	
};
#endif

