/************************************************************************************

   This file is part of SnnsCLib, a fork of the kernel and parts of the gui of 
   the Stuttgart Neural Network Simulator (SNNS), version 4.3.

   The file's original version is part of SNNS 4.3. It's source code can be found at

   http://www.ra.cs.uni-tuebingen.de/SNNS/

   SNNS 4.3 is under the license LGPL v2. We note that source code files of SNNS 4.3 
   state as version "4.2". Base of this fork is SNNS 4.3 with a reverse-applied 
   python patch (see http://developer.berlios.de/projects/snns-dev/).

   SnnsCLib was developed in 2010 by Christoph Bergmeir under supervision of 
   José M. Benítez, both affiliated to DiCITS Lab, Sci2s group, DECSAI, 
   University of Granada

   Changes done to the original code were performed with the objective to
   port it from C to C++ and to encapsulate all code in one class named SnnsCLib.

   Changes in header files mainly include:
   * removed all static keywords
   * moved initializations of variables to the constructor of SnnsCLib

   Changes in cpp code files mainly include:
   * changed file ending from .c to .cpp
   * removed all SNNS internal includes and only include SnnsCLib   
   * static variables within functions were turned into member variables of SnnsCLib
   * function declarations were changed to method declarations, i.e. "SnnsCLib::.."
     was added
   * calls to the function table are now "C++-style", using the "this"-pointer

   License of SnnsCLib:
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
 
   This library 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.  See the GNU
   Library General Public License for more details.
 
   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.

************************************************************************************/


/*****************************************************************************
  FILE           : $Source: /projects/higgs1/SNNS/CVS/SNNS/kernel/sources/cc_mac.h,v $
  SHORTNAME      : mac.h
  SNNS VERSION   : 4.2

  PURPOSE        : macros for cascade correlation and TACOMA
  NOTES          :

  AUTHOR         : Michael Schmalzl
  DATE           : 24.2.93

  CHANGED BY     : 
  RCS VERSION    : $Revision: 2.12 $
  LAST CHANGE    : $Date: 1998/02/25 15:25:59 $

    Copyright (c) 1990-1995  SNNS Group, IPVR, Univ. Stuttgart, FRG
    Copyright (c) 1996-1998  SNNS Group, WSI, Univ. Tuebingen, FRG

******************************************************************************/

#ifndef _CC_MAC_DEFINED_
#define _CC_MAC_DEFINED_

/* constants for all algorithms */

#define NO_INC_ALGORITHM 0

//This define causes a very strange compiler error on Solaris together with stlport4, so renamed, C. Bergmeir 06/05/2013
#define SNNSCLIB_CC 1
#define TACOMA 3

#define OFF 0
#define ON  1


#define FIELD_EMPTY -1

#define NO_OF_ACT_FUNCS 7

#define ASYM_SIGMOID 0
#define SYM_SIGMOID  1
#define TANH         2
#define THRESHOLD    3
#define SINUS        4
#define EXPONENTIAL  5
#define RANDOM       6  /* RANDOM has to be last Act_function !!! */

#define SIN_FAKTOR   0.1    
#define THRESHOLD_DERIV 1   /* not used anymore */

#define BACKPROP         0
#define BACKPROP_ONLINE  1
#define QUICKPROP        2
#define RPROP            3

#define SBC          0
#define AIC          1
#define CMSEP        2

#define CC_NO_MOD    0
#define CC_SDCC      1
#define CC_LFCC      2
#define CC_RLCC      3
#define CC_ECC       4
#define CC_GCC       5
#define CC_STAT      6

#define CONTINUE_LEARNING 1
#define STOP_LEARNING 0

#define CC_MAX_VALUE  0.1 
#define FLOAT_MAX 1E+37



     /* these are the standard parameter settings */

/* output parameter definitions */
#define  OUT_PATIENCE                  50 
#define  MAX_NO_OF_ERROR_UPDATE_CYCLES 200
#define  MIN_ERROR_CHANGE              0.01

/* special parameter definitions */
#define  SPECIAL_PATIENCE                   25 
#define  MAX_NO_OF_COVARIANCE_UPDATE_CYCLES 200
#define  MIN_COVARIANCE_CHANGE              0.04
#define  MAX_SPECIAL_UNIT_NO                8
#define  SPECIAL_FUNC_TYPE                  SYM_SIGMOID

/* global parameter definitions */
#define  MAX_PIXEL_ERROR 0.2
#define  LEARNING_FUNC   QUICKPROP
#define  MODIFICATION    CC_NO_MOD
#define  ON_OFF   OFF
#define  CACHING_ONOFF ON


/* Constants for the  display-functions */

#define X_MIN_POS 2
#define Y_MIN_POS 3
#define MAX_POS   1000000
#define MIN_HIDDEN_LAYER_HEIGHT 5

#define Y_MAX_MODE1                      5
#define Y_MAX_MODE2                      8
#define Y_MAX_MODE3                     12
#define Y_MAX_MODE4                     20
#define Y_MAX_MODE5                     MAX_POS
#define X_MAX_DISPLAYABLE               30
#define DEFAULT_DISTANCE_BETWEEN_LAYERS  2
#define DISTANCE_TO_INOUT_LAYERS         3

/* Output-constants */    

#define LENGTH_HEADLINE                 80



/* Size of one block of the layerlist */

#define MINIMAL_LAYERLIST_SIZE 100

/* where the slopes are stored */

#define LN_CURRENT_SLOPE(LinkPtr)       LinkPtr->value_a
#define LN_PREVIOUS_SLOPE(LinkPtr)      LinkPtr->value_b
#define LN_LAST_WEIGHT_CHANGE(LinkPtr)  LinkPtr->value_c

#define BIAS_CURRENT_SLOPE(UnitPtr)      UnitPtr->value_a
#define BIAS_PREVIOUS_SLOPE(UnitPtr)     UnitPtr->value_b
#define BIAS_LAST_WEIGHT_CHANGE(UnitPtr) UnitPtr->value_c


/* Macros for all learn algorithms */

#define  NET_ERROR( param )      param[ 0 ]  /*    returns the net error   */

#define GET_UNIT_NO(UnitPtr) \
   ((int) ((UnitPtr) - unit_array))  

#define GET_UNIT_XPOS(UnitPtr) \
   (*UnitPtr).unit_pos.x

#define GET_UNIT_YPOS(UnitPtr) \
   (*UnitPtr).unit_pos.y

#define SET_UNIT_XPOS(UnitPtr,XPos) \
   (*UnitPtr).unit_pos.x = XPos 

#define SET_UNIT_YPOS(UnitPtr,YPos) \
   (*UnitPtr).unit_pos.y = YPos

/* error-macros */

#define ERROR_CHECK \
   if(KernelErrorCode!=KRERR_NO_ERROR) { \
     return(KernelErrorCode); \
   }  

#define ERROR_CHECK_WITH_MEMORY_DEALLOCATION \
   if((TempErrorCode=KernelErrorCode)!=KRERR_NO_ERROR) { \
     cc_freeStorage(StartPattern,EndPattern,0); \
     return(TempErrorCode); \
   } 

#define TAC_ERROR_CHECK_WITH_MEMORY_DEALLOCATION \
   if((TempErrorCode=KernelErrorCode)!=KRERR_NO_ERROR) { \
     tac_freeStorage(StartPattern,EndPattern); \
     return(TempErrorCode); \
   } 

#define UPS_ERROR_CHECK_WITH_MEMORY_DEALLOCATION \
   if((TempErrorCode=KernelErrorCode)!=KRERR_NO_ERROR) { \
     ups_freeStorage(StartPattern,EndPattern); \
     return(TempErrorCode); \
   } 

#define ERROR_CHECK_WRC \
   if(KernelErrorCode!=KRERR_NO_ERROR) { \
     return; \
   } 

#define CC_ERROR(ErrorCode) \
   return(ErrorCode)
 
/* memory allocation macros */

#define FREE_IF_USED(i) \
   if((i) != NULL){free(i); i=NULL; }

#define FREE_2DIMENSIONAL_ARRAY(Anker,NoOfRows,i) \
   if (Anker!=NULL){ \
      FREE_IF_USED(Anker[0]); \
      FREE_IF_USED(Anker); \
      Anker = NULL; \
   }

#define FREE_2DIMENSIONAL_ARRAY_WITH_PRINT(Anker,NoOfRows,i) \
   if (Anker!=NULL){ \
     FREE_IF_USED(Anker[0]);  \
      Anker = NULL; \
   }

#define FREE_2ND_ARRAY(Anker,NoOfRows,UnderType,i) \
   if (Anker!=NULL){ \
      FREE_IF_USED(Anker[0].UnderType); \
   }

#define CALLOC_ERRORCHECK(Anker,Anzahl,Datentyp) \
 if( (Anker = (Datentyp *) calloc(Anzahl,sizeof(Datentyp))) == NULL){ \
      CC_ERROR(KernelErrorCode=KRERR_CC_ERROR3); \
 }

#define CALLOC_2DIMENSIONAL_ARRAY(Anker,NoOfRows,NoOfCols,DatenTyp,i) \
  { \
     CALLOC_ERRORCHECK(Anker,NoOfRows,DatenTyp*); \
     CALLOC_ERRORCHECK(Anker[0],(NoOfRows)*(NoOfCols),DatenTyp); \
     for(i=1;i<NoOfRows;i++) \
     { \
        Anker[i]=Anker[i-1]+NoOfCols; \
     } \
  } \

#define CALLOC_2ND_ARRAY(Anker,NoOfRows,UnderType,NoOfCols,DataType,i) \
  { \
     CALLOC_ERRORCHECK(Anker[0].UnderType,(NoOfRows)*(NoOfCols),DataType); \
     for(i=1;i<(NoOfRows);i++) \
     { \
        Anker[i].UnderType=Anker[i-1].UnderType+(NoOfCols); \
     } \
  }
  


/* propagation macros */

#define CALCULATE_ACTIVATION_AND_OUTPUT(UnitPtr,value,p) \
 { \
    UnitPtr->Out.output = ((UnitPtr->out_func == OUT_IDENTITY) ? \
                          (UnitPtr->act = value) : \
                          (this->*UnitPtr->out_func) (UnitPtr->act = value)); \
 }

#define CALCULATE_INPUTUNIT_ACTIVATION_AND_OUTPUT(UnitPtr,value) \
    UnitPtr->Out.output = ((UnitPtr->out_func == OUT_IDENTITY) ? \
                          (UnitPtr->act = value) : \
                          (this->*UnitPtr->out_func) (UnitPtr->act = value)); \

#define PROPAGATE_THROUGH_INPUT_LAYER(inputUnitPtr,dummy,pattern) \
    FOR_ALL_INPUT_UNITS(inputUnitPtr,dummy){ \
        CALCULATE_INPUTUNIT_ACTIVATION_AND_OUTPUT(inputUnitPtr,*pattern++); \
    }

#define PROPAGATE_THROUGH_HIDDEN_LAYER(hiddenUnitPtr,dummy,pattern) \
    FOR_ALL_HIDDEN_UNITS(hiddenUnitPtr,dummy) { \
        CALCULATE_ACTIVATION_AND_OUTPUT(hiddenUnitPtr, \
                  (this->*hiddenUnitPtr->act_func)(hiddenUnitPtr),pattern); \
    }

#define PROPAGATE_THROUGH_OUTPUT_LAYER(outputUnitPtr,dummy,pattern) \
    FOR_ALL_OUTPUT_UNITS(outputUnitPtr,dummy) { \
        CALCULATE_ACTIVATION_AND_OUTPUT(outputUnitPtr, \
                  (this->*outputUnitPtr->act_func)(outputUnitPtr),pattern); \
    }
#define PROPAGATE_THROUGH_SPECIAL_LAYER(specialUnitPtr,dummy,pattern) \
	FOR_ALL_SPECIAL_UNITS(specialUnitPtr,dummy) { \
            CALCULATE_ACTIVATION_AND_OUTPUT(specialUnitPtr, \
                      (this->*specialUnitPtr->act_func) (specialUnitPtr),pattern); \
    }

/* modification macros */

#define UNITS_IN_SAME_GROUP(spec,outpt) \
    ((cc_modification!=CC_GCC)|| \
    ((spec%CCS_NO_OF_GROUPS)==ccs_GroupList[outpt]))

#define NO_OF_GROUPS ((cc_modification!=CC_GCC) ? 1 : CCS_NO_OF_GROUPS)


/* misc macros */

#define IF_PTR_IS_NOT_NULL(ptr) if(ptr!=NULL)

#define FOR_ALL_INPUT_UNITS(UnitPtr,i) \
   for(UnitPtr= *FirstInputUnitPtr,i=0;UnitPtr!=NULL;UnitPtr=FirstInputUnitPtr[++i])

#define FOR_ALL_HIDDEN_UNITS(UnitPtr,h) \
   for(UnitPtr= *FirstHiddenUnitPtr,h=0;UnitPtr!=NULL;UnitPtr=FirstHiddenUnitPtr[++h])

#define FOR_ALL_OUTPUT_UNITS(UnitPtr,o) \
   for(UnitPtr= *FirstOutputUnitPtr,o=0;UnitPtr!=NULL;UnitPtr=FirstOutputUnitPtr[++o])

#define FOR_ALL_SPECIAL_UNITS(UnitPtr,s) \
   for(UnitPtr= *FirstSpecialUnitPtr,s=0;UnitPtr!=NULL;UnitPtr=FirstSpecialUnitPtr[++s])
          
#define FOR_ALL_PATTERNS(StartPattern,EndPattern,p) \
   for(p=StartPattern;p<=EndPattern;p++)

#define SIGN(n) (((n) > 0) ? (1) : (-1))

#define GET_RECURRENT_LINK(unit_ptr,link_ptr) \
   (link_ptr) = (struct Link *) (unit_ptr)->sites 

#define FOR_ALL_NOT_RECURRENT_LINKS( unit_ptr, link_ptr ) \
for ((link_ptr) = ((struct Link *) (unit_ptr)->sites)->next; (link_ptr) != NULL; \
     (link_ptr) = (link_ptr)->next)

#define MAX(a,b) (((a)>(b))?(a):(b))

#define MIN(a,b) (((a)<(b))?(a):(b))

#define NO_OF_NET_UNITS \
   (NoOfInputUnits+NoOfOutputUnits+NoOfHiddenUnits)

#define NO_OF_INOUT_UNITS \
   (NoOfInputUnits+NoOfOutputUnits)

#define REL_HIDDEN_NO(a) \
   ((a)-NoOfInputUnits-NoOfOutputUnits)


#define DISTANCE_BETWEEN_LAYERS(a) \
   (((a)==0)||((a)==NoOfLayers)) ? DISTANCE_TO_INOUT_LAYERS : cc_LayerDistance


#define CC_LAYER_NO(Ptr) ((Ptr->lln >= 0) ? Ptr->lln : ((-1) - Ptr->lln))

#define CC_SET_LAYER_NO(Ptr,LayerNo) \
   if (Ptr->lln >= 0) \
      Ptr->lln = LayerNo; \
   else \
      Ptr->lln = (-1) - LayerNo;

#define FIRST_ROW_NEXT_LAYER(i) \
   ((i>0) ? \
   (ListOfLayers[i].xPosFirstRow + \
   (((ListOfLayers[i].NoOfUnitsInLayer)-1) / cc_display_mode) + \
   (DISTANCE_BETWEEN_LAYERS(i))) : \
   ListOfLayers[i].xPosFirstRow)

#define PRINTF  if (cc_printOnOff) printf 

#define SIGN_OF_THE_CORRELATION CorBetweenSpecialActAndOutError

#define OUTPUT_UNIT_SUM_ERROR   MeanOutputUnitError
/* Aus Performance-Gruenden wird Variable 2-mal benutzt. 
*/
/* */

/* Parameters for Cascade-Correlation */


#define PARAM1                          ParameterInArray[0]
#define PARAM2                          ParameterInArray[1]
#define PARAM3                          ParameterInArray[2]
#define PARAM4                          ParameterInArray[3]
#define PARAM5                          ParameterInArray[4]
#define PARAM6                          0.0001
#define MAX_PIXEL_ERR                   ParameterInArray[6]
#define LEARNING_FUNCTION               (int)ParameterInArray[7]
#define CC_PRINT_ONOFF                  (int)ParameterInArray[8]
#define MIN_COVAR_CHANGE                ParameterInArray[9]
#define SPEC_PATIENCE                   ParameterInArray[10]
#define MAX_NO_OF_COVAR_UPDATE_CYCLES   ParameterInArray[11] 
#define MAX_SPECIAL_UNIT_NUMBER         ParameterInArray[12] 
#define SPECIAL_FUNCTION_TYPE           (int)ParameterInArray[13] 
#define MINIMAL_ERROR_CHANGE            ParameterInArray[14]
#define OUT_PATIEN                      ParameterInArray[15] 
#define MAX_NO_ERROR_UPDATE_CYCLES      ParameterInArray[16]
#define CC_PRUNE_ONOFF                  (int)ParameterInArray[17]
#define CC_BACKFITTING_ONOFF            (int)ParameterInArray[18]
#define BACKFITT_PATIENCE               ParameterInArray[19]
#define PRUNE_FUNC                      (int)ParameterInArray[20]
#define MODIFICATION_NO                 (int)ParameterInArray[21]
#define CC_PARAMETER1                   ParameterInArray[22]
#define CC_PARAMETER2                   ParameterInArray[23]
#define CC_PARAMETER3                   ParameterInArray[24]
#define CC_PARAMETER4                   ParameterInArray[25]
#define CC_PARAMETER5                   ParameterInArray[26]
#define CC_FASTMODE                     ParameterInArray[27]

/* Parameters for the modifications of CC */


#define CCM_HEIGHT                      cc_Parameter[0]
#define CCM_DIFF_HEIGHT                 cc_Parameter[1]
#define CCM_DAEMPFUNG                   cc_Parameter[2]

#define CCR_NO_OF_LINKS                 (int)cc_Parameter[0]

#define CCC_M                           cc_Parameter[0]

#define CCO_FAKTOR                      cc_Parameter[0]

#define CCS_NO_OF_GROUPS                (int)cc_Parameter[0]

#define CCB_LAMBDA                      cc_Parameter[0]

#define SGN(x) (((x)==0.0)?0.0:(((x)<0.0)?-1.0:1.0))


/* And now .... the TACOMA macros... */


#define TAC_ALPHA(d,max) (0.1 * ((max-d)/(max)))


#define TAC_KOHONEN  ((int)cc_Parameter[0])
   /* how much runs to determine the best special units ? */
#define TAC_XI_RI_ETA  (cc_Parameter[1])
     /* step-width learning of xi and ri */
#define TAC_THRESHOLD cc_Parameter[2]
   /* All special units with g over this threshold were built in */
#define TAC_LAMBDA    cc_Parameter[3]
   /* A connection ist built in, iff the correlation is better than lambda */
#define TAC_BETA      cc_Parameter[4]
   /* To determine the initial radius of a link.*/
#define TAC_ETA       0.7


#define TAC_XIRI_ONLINE TRUE


#define TAC_EXP(x) \
	( (x>88.72) ? MAXFLOAT : ((x<-88.0) ? 0.0 : exp(x)) )

#define XI_OF_LINK(LinkPtr) \
	(LinkPtr->value_b)

#define RI_OF_LINK(LinkPtr) \
	(LinkPtr->value_a)
 
/* if you change  XI_OF_LINK and/or RI_OF_LINK, then take a look at the loading
   routines at krio_readConnectionDefs (kr_io.c) */


#define SUMMED_DISTANCES Ri

#define TAC_MAX_VALUE 1.0

/* Macros for Upstart */


#define UPS_MAX_VALUE 1.0

#define UPS_BEST_WEIGHT(LinkPtr) LinkPtr->value_c

#define UPS_MODIFIKATION_ON  (cc_Parameter[0] > 0.0)

#define UPS_ETA (cc_Parameter[1])

#define UPS_NEW_MODE (cc_Parameter[1]>0.0)

#define UPS_TEST (cc_Parameter[2]>0.0)

#define UPS_NOT_CALCULATED 0

#define UPS_GREAT_VALUE 10000

#define UPS_DAUGHTER_LINK(LinkPtr) LinkPtr->value_a

#endif
