
// $ Revision: 1.2 $ 
//
// ICclasses.C 
//
// This file is part from the Mex-Files 'simulate' and 'ICctrl'.
//
// To build 'ICctrl' under LINUX systems, type:
//    mex -O ICmain.c ICclasses.c -o ICctrl.mexlx
// To build 'simulate' under LINUX systems, type:
//    mex -O simulation_error.c ICclasses.c -o simulate.mexlx
//
// Copyright (c) 1984-1998 by Frank Vanden Berghen.
// All Rights Reserved.

#include "mex.h"

#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)

#define T_EXTEND 100
#define V_EXTEND 100

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

/*======================cache object ===================================*/
typedef struct cacheTag
	    {
            vector in,out;
        } cache;
cache *ca_Init(cache *_thisref,int nIn,int nOut);
void ca_Terminate(cache *thisref);
int ca_test(cache *thisref,double *in, double *out);
void ca_update(cache *thisref,double *in, double *out);

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

void error(char *s);
    // stoppe la imulation et affiche le message d'erreur donné en
    // paramètre

void *MyMalloc(unsigned int n);
void *MyRealloc(void *t,unsigned int n);
void MyFree(void *t);

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 un pointeur vers les données de la matrice qui se trouve
    // dans le champs "basename" de la structure mx.
vector getVectorPlus(const mxArray *mx,char *subindex);
    // voir getVector
    // si le champ n'existe pas alors le pointeur renvoyé est NULL.
vector getVectorTest(const mxArray *mx,char *subindex,int _c,int _l);
    // voir getVector
    // si _c!=0 alors la matrice doit avoir _c colonnes
    // idem pour _l
/*======================syst object====================================*/
typedef struct systTag
        {
            char type;
            vectorI ny,nu,nd;
            int nEntree,nSortie;
            vectorI optimParams;
        } syst;
syst  *syst_Init(syst *_thisref,const mxArray *pmiso,
                                    vector nu, vector nd, vector ny);
    // 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,nSortie;
            vectorI optimParams;
            // propre a linear:
            mxArray *prhs[3];
            cache *CA;
        } defaultMap;
defaultMap* defaultMap_Init(defaultMap *_thisref, const mxArray *pmiso,vector nu, vector nd, 
                    vector ny);
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,nSortie;
            vectorI optimParams;
            // propre a linear:
            vector linears;
        } linear;
linear* linear_Init(linear *_thisref, const mxArray *pmiso,vector nu, vector nd, 
                    vector ny);
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,nSortie;
            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);
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,nSortie;
            vectorI optimParams;
            // propre a lazy:            
            vector Wvec,Y,t_hat,W,t,a,BestDist,BestError;
            vectorI BestIndx;
            table X,C,Z,v,BestPred;
            int idm,idM,cmb;
            double LAMBDA;
            cache CA;
        } lazy;
lazy* lazy_Init(lazy *_thisref, const mxArray *pmiso,vector nu, vector nd, 
                    vector ny);
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,nSortie;
	    vectorI optimParams;
            // propre à gaussian:
            vector optimParamsOrig;
            int nRules;
            vector Centers,Variances,Linears;
            double sumMemb;
            vector xMinC,y,memb;
            cache CA;
        } gaussian;
gaussian *gaus_Init(gaussian *_thisref,const mxArray *pmiso,vector nu,
                   vector nd, vector ny);
    // 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,nSortie;
            vectorI optimParams;
            // commun à gaussian
            vector optimParamsOrig;
            int nRules;
            vector Centers,Variances,Linears;
            double sumMemb;
            vector xMinC,y,memb;
            cache CA;
            // 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);
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);
    // 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.

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

typedef struct DerivMatrixTag
        {
            vector v;
            int setPoints,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(...);
