#define CONTROLLER 'c'
#define PLANT 'p'
#define US 0
#define YS 1
#define SP 2
#define IN 0
#define OUT 1

#define SWAP(a,b) {tamp=(a); (a)=(b); (b)=tamp;}
#define SQR(a) ((a)*(a))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
#define SIGN(a) ((a)<0?-1:1)

typedef double *dataPtr;
typedef int *dataPtrI;

/*======================table object =================================*/
typedef struct tableTag
        { 
            dataPtr *p;
            int n,m,extend;
        } table;
table *t_Init(table *_thisref,int _n,int _m);
    // crÈe un vecteur de rÈel
void  t_Terminate(table *thisref);
    // libËre de la pile un vecteur de rÈel
void t_extend(table *thisref);
void t_exactshape(table *thisref);

/*======================vector object =================================*/
typedef struct vectorTag
        { 
            dataPtr p;
            int n,extend;
        } vector;
vector *v_Init(vector *_thisref,int _n);
    // crÈe un vecteur de rÈel
void    v_Terminate(vector *thisref);
    // libËre de la pile un vecteur de rÈel
void v_extend(vector *thisref);
void v_exactshape(vector *thisref);

/*======================vectorI object==================================*/

typedef struct vectorITag
        { 
            dataPtrI p;
            int n,extend;
        } vectorI;
vectorI *vi_Init(vectorI *_thisref,int _n);
    // crÈe un vecteur d'entier
void     vi_Terminate(vectorI *thisref);
    // libËre de la pile un vecteur d'entier

/*======================general functions==============================*/

void error(char *s);
    // stoppe la imulation et affiche le message d'erreur donnÈ en
    // paramËtre
double sqr(double t);
    // = t*t
double GetDouble(const mxArray *mx,char *BaseName);
    // renvoie le nombre qui se trouve dans le champs "basename" de la
    // structure mx.
double GetDoublePlus(const mxArray *mx,char *BaseName, double defaultvalue);
    // renvoie le nombre qui se trouve dans le champs "basename" de la
    // structure mx. Si cette structure est absente, alors renvoie defaultvalue.
vector getVector(const mxArray *mx,char *subindex);
    // renvoie au pointeur vers les donnÈes de la matrice qui se trouve
    // dans le champs "basename" de la structure mx.

/*======================syst object====================================*/
typedef struct systTag
        {
            char type;
            vectorI ny,nu,nd;
            int nEntree;
			vectorI optimParams;
        } syst;
syst  *syst_Init(syst *_thisref,const mxArray *pmiso,
									vector nu, vector nd, vector ny, int nOut);
    // initialise un systËme quelconque.
    // tous les systËmes (fuzzy gaussian,fuzzy inversedist,lazy, ...) sont "dÈrivÈs" de
    // syst (=multiple input, single output).
    // lorsque vous voulez rajouter un nouveau type de prÈdicteur
    // vous modifiez lÈgËrement les "mÈthodes"(=fonctions) de syst
    // pour exÈcuter vos nouvelles routines (ajout d'un test sur 'type').
    // Le branchement se fait sur base de la variable 'type':
    //  -type='e' : erreur.
    //  -type='g' : fuzzy gaussian.
    //  -type='h' : fuzzy inversedist.
	//  -type='l' : lazy
void   syst_Terminate(syst *thisref);
    // libËre la mÈmoire
double syst_eval(syst *thisref,int nsyst,vector *in);
    // calcule la sortie du systËme 
double syst_jacobinput(syst *thisref,int nsyst,int k, vector *in);
    // calcule la dÈrivÈe du systËme par rapport ý l'entree k.
double syst_jacobparam(syst *thisref,int nsyst,int p,vector *entree_work);
    // calcule la dÈrivÈe du systËme par rapport ý son paramËtre p.
double syst_getParam(syst *thisref,int p);
    // retourne la valeur du paramËtre p.
void   syst_setParam(syst *thisref,int p,double a);
    // dÈfini la valeur du paramËtre p.

/*======================default mapping object=====!!==================*/
typedef struct defaultMapTag
        {
			// commun ý syst:
            char type;
            vectorI ny,nu,nd;
            int nEntree;
			vectorI optimParams;
			// propre a linear:
			mxArray *prhs[3];
        } defaultMap;
defaultMap* defaultMap_Init(defaultMap *_thisref, const mxArray *pmiso,vector nu, vector nd, 
                    vector ny, int nOut);
void defaultMap_Terminate(defaultMap *thisref);
double defaultMap_eval(defaultMap* thisref,int nsyst,vector *in);
double defaultMap_jacobinput(defaultMap *thisref,int nsyst,int k,vector *in);

/*======================linear object=====!!===========================*/
typedef struct linearTag
        {
			// commun ý syst:
            char type;
            vectorI ny,nu,nd;
            int nEntree;
			vectorI optimParams;
			// propre a linear:
			vector linears;
        } linear;
linear* linear_Init(linear *_thisref, const mxArray *pmiso,vector nu, vector nd, 
                    vector ny, int nOut);
void linear_Terminate(linear *thisref);
double linear_eval(linear* thisref,int nsyst,vector *in);
double linear_jacobinput(linear *thisref,int nsyst,int k,vector *in);

/*======================lookup object=====!!===========================*/
typedef struct lookupTag
        {
			// commun ý syst:
            char type;
            vectorI ny,nu,nd;
            int nEntree;
			vectorI optimParams;
			// propre a lookup:
			mxArray *Y_IN,*Y_OUT,*output_array[1],*input_array[2];
			vectorI dims,Ddims,valLow,valHigh;
			table scales,Dscales,Dlup;
			vector lup,levels;
			double **idxs;
        } lookup;

lookup *lookup_Init(lookup *_thisref, const mxArray *pmiso,
								vector nu, vector nd,vector ny, int nOut);
void lookup_Terminate(lookup *thisref);
double lookup_eval(lookup* thisref,vector *in);
double lookup_jacobinput(lookup *thisref,int k,vector *in);

/*======================lazy object=======!!===========================*/
typedef struct lazyTag
        {
			// commun ý syst:
            char type;
            vectorI ny,nu,nd;
            int nEntree;
			vectorI optimParams;
			// propre a lazy:
			vector Wvec,Y,t_hat,W,t,tB,a,BestDist;
			vectorI BestIndx;
			table X,C,Z,v;
			int idm,idM;
			double LAMBDA;
        } lazy;
lazy* lazy_Init(lazy *_thisref, const mxArray *pmiso,vector nu, vector nd, 
                    vector ny, int nOut);
void lazy_Terminate(lazy *thisref);
double lazy_eval(lazy* thisref,vector *in);
double lazy_jacobinput(lazy *thisref,int k,vector *in);

/*======================gaussian object================================*/

typedef struct gaussianTag
        {
            // commun ý syst:
            char type;
            vectorI ny,nu,nd;
            int nEntree;
			vectorI optimParams;    
            // propre ý gaussian:
			int nRules,subParams;
            vector Centers,Variances,Linears;
            double sumMemb;
            vector xMinC,y,memb;
        } gaussian;
gaussian *gaus_Init(gaussian *_thisref,const mxArray *pmiso,vector nu,
                   vector nd, vector ny,int nOut);
    // gaussian est "hÈritÈ" de syst pour des ensemble gaussien.
void   gaus_Terminate(gaussian *thisref);
double gaus_eval(gaussian *thisref,vector *in);
double gaus_jacobinput(gaussian *thisref,int k, vector *in);
double gaus_jacobparam(gaussian *thisref,int p,vector *entree_work);
double gaus_getParam(gaussian *thisref,int p);
void   gaus_setParam(gaussian *thisref,int p,double a);
int    gaus_numParams(gaussian *thisref);

double gaus_workParam(gaussian *thisref,int toDo,int p,vector *entre_work,double set);
void   gaus_setCenter(gaussian *thisref,int rule, int entree,double d);
void   gaus_setVariance(gaussian *thisref,int rule, int i, int j,double d);
void   gaus_setLinear(gaussian *thisref,int rule, int entree,double d);
double gaus_getCenter(gaussian *thisref,int rule, int entree);
double gaus_getVariance(gaussian *thisref,int rule, int i, int j);
double gaus_getLinear(gaussian *thisref,int rule, int entree);
double gaus_jacoblinear(gaussian *thisref,int k,int l,vector *in);
double gaus_jacobvariance(gaussian *thisref,int k,int l, int m, vector *in);
double gaus_jacobcenter(gaussian *thisref,int k, int l, vector *in);
double gaus_MembershipFnct(gaussian *thisref,double d, int i);

/*======================hyperbolic object===============================*/

typedef struct hyperbolicTag
        {
            // commun ý syst&gaussian
            char type;
            vectorI ny,nu,nd;
            int nEntree;
            vectorI optimParams;
            // commun ý gaussian
			int nRules,subParams;
            vector Centers,Variances,Linears;
            double sumMemb;
            vector xMinC,y,memb;
    
            // propre ý hyperbolic
            double m;
            vector jacobTmp;
        } hyperbolic;
    // hyperbolic est "hÈritÈ" de gaussian pour des ensemble inversedist.
hyperbolic *hyp_Init(hyperbolic *_thisref,const mxArray *pmiso, vector nu,
                          vector nd, vector ny, int nOut);
void   hyp_Terminate(hyperbolic *thisref);
double hyp_jacobinput(hyperbolic *thisref,int k, vector *in);    
double hyp_jacobvariance(hyperbolic *thisref,int k,int l, int m, vector *in);
double hyp_jacobcenter(hyperbolic *thisref,int k, int l, vector *in);
double hyp_MembershipFnct(hyperbolic *thisref,double d,int i);

/*============================mimo object===============================*/

typedef struct mimoTag
        {
            int nIn,nOut,nMapping,numTParams;
			char type;			// type='c': controller // 'p': prÈdicteur
            vector minmax;
			vectorI links,indiceParams;
            syst *((*head)[1]);  // declaration d'un pointeur vers un tableau
                                 // de pointeur pointant vers des objets "syst"
        } mimo;
mimo *mimo_Init2(mimo *_thisref,const mxArray *tmp3,char _type);
mimo *mimo_Init (mimo *_thisref,const mxArray *p,char *BaseName,char type);
    // ensemble de syst formant un mimo.(multiple input, multiple output)
void  mimo_Terminate(mimo* thisref);
syst *mimo_get(mimo *thisref,int indice);
    //obtention de la sortie 'indice' de type syst du mimo.
double mimo_eval(mimo *thisref,int nsyst,vector *in);
double mimo_jacobinput(mimo *thisref,int nsyst,int k, vector *in);
    // retourne la dÈrivÈe du IËme systËme du mimo thisref
    // par rapport a son entree k.
double mimo_jacobparam(mimo *thisref,int i,int p,vector *entree_work);
    // retourne la dÈrivÈe du IËme systËme du mimo thisref
    // par rapport au paramËtre p. P estun indice dÈfini sur l'ensemble
    // de tous les paramËtres de tous les systËmes de thisref.
double mimo_getParam(mimo *thisref,int p);
void mimo_setParam(mimo *thisref,int p,double a);
int mimo_numParams(mimo *thisref,int nsyst);
    // retourne la nombre de paramËtres du systËme nsyst.

/*============================StateMatrix object=========================*/

typedef struct StateMatrixTag
        {
            vector v;
            int xsize,max_time,setPoints,horizon;
			double sampTime;
			time_T CTime;
        } StateMatrix;
StateMatrix *st_Init(StateMatrix *_thisref,const mxArray *mx,int *setPoints,int _horizon);
    // le vecteur d'Ètat.
    // il est en partie (t<0) initialisÈ avec les valeurs des time steps 
    // prÈcÈdents. L'autre partie (0<t<horizon) est calculÈe dans 
    // la simulation de la boucle fermÈe.
    // sa structure est:
    //            | U | Consignes | Y |  V |
    //  ------------------------------------
    //  t=-1      |   |           |   |    |
    //  t=0       |   |           |   |    |
    //  t=1       | ? |      ?    | ? |  ? |
    //    ...     |   |           |   |    |
    //  t=horizon |   |           |   |    |
    //  ------------------------------------
    //
void   st_Terminate(StateMatrix *thisref);
    // libËre la mÈmoire pour la "statematrix".
void   st_CreateEntree(StateMatrix *thisref, mimo* pmimo, int nsyst,int k, vector *result);
    // crÈe l'entrÈe pour le temps k pour le systËme flou f.
    // f est un systËme flou appartenant au controlleur ou au
    // prÈdicteur. forwhat dÈfini l'appartenance de f:
    // forwhat= CONTROLLER ou PLANT.
double st_Get(StateMatrix *thisref,int k, int i, int kind, int forWhat);
    // retourne une valeur de la statematrix.
    // cette valeur est prise ý l'instant k.
    // c'est la iËme composante du vecteur qui est:
    // 'kind'=IN ou OUT de forwhat= CONTROLLER ou PLANT.
void   st_Set(StateMatrix *thisref,int k, int i, int kind, double value);
    // voir ci-dessus.
void   st_InitFromMatlab(StateMatrix *thisref,const double *x,const double *Y,time_T _t);
    // rÈcupËre les valeurs de la statematrix des temps prÈcÈdents
void   st_UpdateMatlab(StateMatrix *thisref,double *x);
    // sauve la matrice pour les 'time steps" suivants.

/*============================filter object=========================*/

typedef struct filterTag
        {
            vector num,den,savePred,saveF;
            int memory,initial;
			StateMatrix *X;
        } filterT;
filterT *fil_Init(filterT *_thisref,const mxArray *mx, StateMatrix *_X);
void fil_initFromMatlab(filterT *thisref,const double *uc);
void fil_Terminate(filterT *thisref);

/*============================DerivMatrix object=========================*/

typedef struct DerivMatrixTag
        {
            vector v;
            int setPoints,horizon,shift;
        } DerivMatrix;
DerivMatrix *der_Init(DerivMatrix *_thisref,int spd, int _horizon,int numTParams);
    // matrice dans laquelle sont sauvÈe les dÈrivÈes du contrÙler (dui/pd)
    // et du prÈdicteur (dyi/dp).
void   der_Terminate(DerivMatrix *thisref);
    // libËre la mËmoire allouÈe
double der_Get(DerivMatrix *thisref,int p, int time, int indice, int kind, int forWhat);
    // retourne une valeur de la derivmatrix.
    // cette valeur est prise ý l'instant k.
    // c'est la iËme composante de la dÈrivÈe du vecteur qui est:
    // 'kind'=IN ou OUT de forwhat= CONTROLLER ou PLANT.
double der_Get2(DerivMatrix *thisref,int p, int time, int indice, int kind);
    // retourne une valeur de la derivmatrix.
    // cette valeur est prise ý l'instant k.
    // c'est la iËme composante de la dÈrivÈe du vecteur qui est:
    // 'kind'=US ou YS.
void   der_Set(DerivMatrix *thisref,int p, int time, int indice, int kind, double d);
    // voir der_get(...);

/*================================Debug object=========================*/

typedef struct debugClassTag
        {
            int dbug,toDo;
            double sampTime;
            StateMatrix *X;
            DerivMatrix *deriv;            
            vector u,y,t,li,sp,memb,etha,d,x;
            int li_largeur, memb_largeur;
        } debugClass;
debugClass *db_Init(debugClass *_thisref,int toDo,const mxArray *mx,StateMatrix *_X,DerivMatrix *_D);
    // objet utilisÈ pour le mode dÈbug.
    // cet objet sauve ý chaque "time step" les valeurs apparaÓssant
    // dans la variable globale "debug" ý l'arrÍt du contrÙleur.
void db_Terminate(debugClass *thisref);
void db_saveALL(debugClass *thisref);
void db_saveALLagain(debugClass *thisref);
void db_saveEtha(debugClass *thisref,double etha);
void db_sendToMatlab0(double d,mxArray *base,const char *name);
void db_sendToMatlab2(int l,vector *v,int n,mxArray *base,const char *name);
void db_sendToMatlab3(int l,vector *v,int n,int m,mxArray *base,const char *name);
void db_sendToMatlab4(int l,vector *v,int n,int m,int o,mxArray *base,const char *name);