/*****************************************************************************
  FILE           : $Source: /usr/local/bv/SNNS/SNNSv4.1/kernel/sources/RCS/cc_rcc.c,v $
  SHORTNAME      : 
  SNNS VERSION   : 4.1

  PURPOSE        : Common functions of CC and RCC
  NOTES          :

  AUTHOR         : Michael Schmalzl
  DATE           : 5.2.93

  CHANGED BY     : Michael Vogt, Guenter Mamier, Christian Wehrfritz
  IDENTIFICATION : $State: Exp $ $Locker:  $
  RCS VERSION    : $Revision: 2.7 $
  LAST CHANGE    : $Date: 1995/11/16 12:02:01 $

             Copyright (c) 1990-1995  SNNS Group, IPVR, Univ. Stuttgart, FRG

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

#include <stdio.h>
#include <math.h>
#include <time.h>  
#include <memory.h>
#ifndef WIN32
#include <malloc.h>
#endif
#include <values.h>

#include "kr_typ.h"	
#include "kr_const.h"	 
#include "kr_def.h"	 
#include "random.h"
#include "kr_mac.h"
#include "kernel.h"
#include "kr_ui.h"
#include "kr_newpattern.h"
#include "cc_mac.h"	
#include "cc_type.h"
#include "cc_rcc.ph"   

/*****************************************************************************
  FUNCTION : cc_freeStorage

  PURPOSE  : Frees all the storage allocated by CC or RCC.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/


krui_err cc_freeStorage(int dummy1, int dummy2, int flag)
{
 int p,s;
 struct Unit *unitPtr;
 struct Link *linkPtr;
 int start, end;

 start = old.StartPattern;
 end = old.EndPattern;

 cc_storageFree = 1;

 if(flag==1){
   (void) cc_deleteAllSpecialAndAllHiddenUnits();
   cc_end = 0;

   FOR_ALL_UNITS(unitPtr){
     if(UNIT_IN_USE(unitPtr) && IS_OUTPUT_UNIT(unitPtr)){
       unitPtr->value_a =  unitPtr->value_b = unitPtr->value_c = 0;
       FOR_ALL_LINKS(unitPtr,linkPtr){
         linkPtr->value_a =  linkPtr->value_b = linkPtr->value_c = 0;
       }
     }
   }
 }

 IF_PTR_IS_NOT_NULL(OutputUnitError) {
   FOR_ALL_PATTERNS(start,end,p) 
     IF_PTR_IS_NOT_NULL(OutputUnitError[p])
       free(OutputUnitError[p]);
   free(OutputUnitError);
   OutputUnitError = NULL;
 }

 IF_PTR_IS_NOT_NULL(SpecialUnitAct) {
   FOR_ALL_PATTERNS(start,end,p) 
     IF_PTR_IS_NOT_NULL(SpecialUnitAct[p])
       free(SpecialUnitAct[p]);
   free(SpecialUnitAct);
   SpecialUnitAct = NULL;
 }

 IF_PTR_IS_NOT_NULL(CorBetweenSpecialActAndOutError) {
     for(s=0;s<OldNoOfSpecialUnitStorage;s++){
       IF_PTR_IS_NOT_NULL(CorBetweenSpecialActAndOutError[s])
         free(CorBetweenSpecialActAndOutError[s]); 
     }
   free(CorBetweenSpecialActAndOutError);  
   CorBetweenSpecialActAndOutError = NULL;
 } 

 IF_PTR_IS_NOT_NULL(OutputUnitSumError) {
   free(OutputUnitSumError);
   OutputUnitSumError = NULL;
 }

 IF_PTR_IS_NOT_NULL(SpecialUnitSumAct) {
   free(SpecialUnitSumAct);
   SpecialUnitSumAct = NULL;
 }

 return(KRERR_NO_ERROR);
}

/*****************************************************************************
  FUNCTION : cc_allocateStorage

  PURPOSE  : Allocates all the storage needed by CC and RCC
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

krui_err cc_allocateStorage(int StartPattern, int  EndPattern, int NoOfSpecialUnits)
{
 int s,p;
 struct Unit *dummyPtr;
 int start, end;

 OldNoOfSpecialUnitStorage = NoOfSpecialUnits;
 cc_storageFree = 0;

 KernelErrorCode = kr_initSubPatternOrder(StartPattern,EndPattern);
 ERROR_CHECK;
 start = kr_AbsPosOfFirstSubPat(StartPattern);
 end   = kr_AbsPosOfFirstSubPat(EndPattern);
 end  += kr_NoOfSubPatPairs(EndPattern) - 1;

 OutputUnitSumError = (float *) calloc(NoOfOutputUnits,sizeof(float));
 if(OutputUnitSumError == NULL) {
   CC_ERROR(KRERR_CC_ERROR3);
 }
 SpecialUnitSumAct = (float *) calloc(NoOfSpecialUnits,sizeof(float));
 if(SpecialUnitSumAct == NULL) {
   CC_ERROR(KRERR_CC_ERROR3);
 }
 OutputUnitError = (float **)calloc(end-start+1,sizeof(float *));
 if(OutputUnitError == NULL) {
   CC_ERROR(KRERR_CC_ERROR3);
 }
 SpecialUnitAct = (float **)calloc(end-start+1,sizeof(float *));
 if(SpecialUnitAct == NULL) {
   CC_ERROR(KRERR_CC_ERROR3);
 }
 CorBetweenSpecialActAndOutError =  (float **)calloc(NoOfSpecialUnits,sizeof(float *));
 if(CorBetweenSpecialActAndOutError == NULL) {
   CC_ERROR(KRERR_CC_ERROR3);
 }


 FOR_ALL_PATTERNS(start,end,p) {
   OutputUnitError[p] = (float *)calloc(NoOfOutputUnits,sizeof(float));
   if(OutputUnitError[p] == NULL) {
     CC_ERROR(KRERR_CC_ERROR3);
   }
   SpecialUnitAct[p] = (float *)calloc(NoOfSpecialUnits,sizeof(float));
   if(SpecialUnitAct[p] == NULL) {
     CC_ERROR(KRERR_CC_ERROR3);
   }
 }

 FOR_ALL_SPECIAL_UNITS(dummyPtr,s) {
   CorBetweenSpecialActAndOutError[s] = (float *)calloc(NoOfOutputUnits,sizeof(float));   
   if(CorBetweenSpecialActAndOutError[s] == NULL) {
     CC_ERROR(KRERR_CC_ERROR3);
   }
 } 

 old.EndPattern       = end;
 old.StartPattern     = start;

 return(KRERR_NO_ERROR);
}

/*****************************************************************************
  FUNCTION : cc_deleteAllSpecialAndAllHiddenUnits

  PURPOSE  : Deletes all special units and all hidden units.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

krui_err cc_deleteAllSpecialAndAllHiddenUnits(void)
{
 struct Unit *UnitPtr;

 if(NoOfUnits != 0) {
   FOR_ALL_UNITS(UnitPtr){
     if((IS_HIDDEN_UNIT(UnitPtr) || IS_SPECIAL_UNIT(UnitPtr)) && UNIT_IN_USE(UnitPtr)) {
       KernelErrorCode = kr_removeUnit(UnitPtr); 
       ERROR_CHECK;
     }
   }
   kr_forceUnitGC();
   NoOfHiddenUnits = 0;
   NetModified = 1;
 }
 return(KRERR_NO_ERROR);
} 

/*****************************************************************************
  FUNCTION : rcc_manageResetArray

  PURPOSE  : Allocates the storage of the reset array in needed.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

void rcc_manageResetArray(int startPattern, int endPattern, int flag) 
{
 int p;
 int start, end;
 int pat, sub;
 int size;
 Patterns pat_ptr;

 if(reset!=NULL){
   free(reset);
 }
 reset = NULL;

 if(flag){
   reset = (int *) calloc(kr_TotalNoOfSubPatPairs(),sizeof(int));
   reset[0] = 1;
   KernelErrorCode = kr_initSubPatternOrder(startPattern,endPattern);
   if (KernelErrorCode != KRERR_NO_ERROR)
       return;
   start = kr_AbsPosOfFirstSubPat(startPattern+1);
   end   = kr_AbsPosOfFirstSubPat(endPattern-1);
   end  += kr_NoOfSubPatPairs(endPattern-1) - 1;
   for(p=start; p<=end;p++){
       kr_getSubPatternByNo(&pat,&sub,p);
       pat_ptr = kr_getSubPatData(pat,sub,OUTPUT,&size);
       if( *(pat_ptr + size - 1) > 0.0 ) {
	   reset[p+1] = 1; 
     }
   }
 }
}

/*****************************************************************************
  FUNCTION : rcc_manageLinkArray

  PURPOSE  : Allocates the storage of the link array if needed.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

void rcc_manageLinkArray(int newNoOfSpecialUnits, int flag)
{
 static int oldNoOfSpecialUnits=0;
 int i,noOfHiddenUnits=0;
 struct Unit *unit_ptr;

 for(i=0;i<oldNoOfSpecialUnits;i++){
   if(linkArray[i]!=NULL){
     free(linkArray[i]);
   }
 }
 if(linkArray!=NULL){
   free(linkArray);
 }

 oldNoOfSpecialUnits = 0;

 if(flag){
   FOR_ALL_UNITS(unit_ptr){
     if(IS_HIDDEN_UNIT(unit_ptr)){
       noOfHiddenUnits++;
     }
   }
   linkArray = (float **) calloc(newNoOfSpecialUnits,sizeof(float *));

   for(i=0;i<newNoOfSpecialUnits;i++){
     linkArray[i] = (float *) calloc(newNoOfSpecialUnits+noOfHiddenUnits+2,sizeof(float));
   }
   
   oldNoOfSpecialUnits = newNoOfSpecialUnits;
 }
}
 

/*****************************************************************************
  FUNCTION : cc_initErrorArrays

  PURPOSE  : 
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

void cc_initErrorArrays(void)
{
 int o;
 struct Unit *outputUnitPtr;

  FOR_ALL_OUTPUT_UNITS(outputUnitPtr,o) {
    OutputUnitSumError[o] = 0.0;
  }
}

/*****************************************************************************
  FUNCTION : cc_initActivationArrays

  PURPOSE  : 
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

void cc_initActivationArrays(void)
{
 int s,o;
 struct Unit *outputUnitPtr,*specialUnitPtr;

  FOR_ALL_SPECIAL_UNITS(specialUnitPtr,s) {
    SpecialUnitSumAct[s] = 0.0;
  }

 FOR_ALL_SPECIAL_UNITS(specialUnitPtr,s) {
   FOR_ALL_OUTPUT_UNITS(outputUnitPtr,o) {
    CorBetweenSpecialActAndOutError[s][o] = 0.0;
  }
 } 
}


/*****************************************************************************
  FUNCTION : cc_generateRandomNo

  PURPOSE  : Generates a random number in the interval [-maxValue,+maxValue]
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

FlintType cc_generateRandomNo(float maxValue)
{
 return (FlintType)(drand48()*2.0*maxValue-maxValue);  
}

/*****************************************************************************
  FUNCTION : cc_compareActFunctions

  PURPOSE  : Tests wether the selected activation functions are consistent. 
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/


void cc_compareActFunctions(int actFunc, int flag)
{
 int found_h=0,found_o=0;
 struct Unit *unit_ptr,*hiddenUnitPtr,*outputUnitPtr;
 char name_o[30],name_h[30];

 if((actFunc != RANDOM) && cc_printOnOff){
   FOR_ALL_UNITS(unit_ptr){
     if(IS_HIDDEN_UNIT(unit_ptr) && found_h != 1){
       hiddenUnitPtr = unit_ptr;
       strcpy(name_h,krui_getUnitActFuncName(GET_UNIT_NO(hiddenUnitPtr)));
       found_h = 1;
     }
     if(IS_OUTPUT_UNIT(unit_ptr) && found_o != 1){
       outputUnitPtr = unit_ptr;
       strcpy(name_o,krui_getUnitActFuncName(GET_UNIT_NO(outputUnitPtr)));
       found_o = 1;
     }
     if(found_h && found_o){
       break;
     }
   }
   if(flag == CC){
     if(found_o && strcmp(cc_actFuncArray[actFunc],name_o)){
       printf("!!! Warning: Output units and special units have different act. functions !!!\n");
     }
   }
   else {
     if(found_o && strcmp(rcc_actFuncArray[actFunc],name_o)){
       printf("!!! Warning: Output units and special units have different act. functions !!! \n");
     }
   }
   if(flag == CC){
     if(found_h && strcmp(cc_actFuncArray[actFunc],name_h)){
       printf("!!! Warning: Hidden units and special units have different act. functions !!!\n");
     }
   }
   else {
     if(found_h && strcmp(rcc_actFuncArray[actFunc],name_h)){
       printf("!!! Warning: Hidden units and special units have different act. functions !!! \n");
     }
   }

   if(found_h && (outputUnitPtr->act_func != hiddenUnitPtr->act_func)){
     printf("!!! Warning:  Output units and hidden units have different act. functions !!! \n");
   }
 }
}

/*****************************************************************************
  FUNCTION : cc_changeActFuncOfSpecialUnit

  PURPOSE  : Changes the activation function of the special units.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

krui_err cc_changeActFuncOfSpecialUnits(int type, int LearnFunc)
{
 int s,selector;
 struct Unit *specialUnitPtr;

 FOR_ALL_SPECIAL_UNITS(specialUnitPtr,s) {
   if(type==RANDOM){
     selector = s % (NO_OF_ACT_FUNCS - 1);
   }
   else {
     selector = type;
   }
   if(LearnFunc == CC){
     KernelErrorCode = krui_setUnitActFunc(GET_UNIT_NO(specialUnitPtr),cc_actFuncArray[selector]);
     ERROR_CHECK;  
   }
   else {
     KernelErrorCode = krui_setUnitActFunc(GET_UNIT_NO(specialUnitPtr),cc_actFuncArray[selector]);
     ERROR_CHECK;  
   }
 }
 return(KRERR_NO_ERROR);
}

/*****************************************************************************
  FUNCTION : cc_calculateNetParameters

  PURPOSE  : Calculates the position of the current input, hidden and output
             layer.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

krui_err cc_calculateNetParameters(int *maxYPosOfHiddenUnit, int *xPosOfLastInsertedHiddenUnit,
                                   int *yPosOfLastInsertedHiddenUnit, int *outXMax)
{         
 struct Unit *unitPtr;
 int x,y;
 int inputXMin=0,inputXMax=0,hiddenXMin=0,hiddenXMax=0,outputXMin=0,outputXMax=0;
 int inputYMin=0,inputYMax=0,hiddenYMin=0,hiddenYMax=0,outputYMin=0,outputYMax=0;
 int xInputOffset=0,xHiddenOffset=0,xOutputOffset=0;
 int yInputOffset=0,yHiddenOffset=0,yOutputOffset=0;

 NoOfInputUnits  = 0;
 NoOfHiddenUnits = 0;
 NoOfOutputUnits = 0;
  
 FOR_ALL_UNITS(unitPtr){
   if(IS_INPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)){
     x = GET_UNIT_XPOS(unitPtr);
     y = GET_UNIT_YPOS(unitPtr);
     NoOfInputUnits++;
     if((y >= inputYMax) || (inputYMax==0)){
       inputYMax = y;
     }
     if((y <= inputYMin) || (inputYMin==0)){
       inputYMin = y;
     }
     if((x >= inputXMax) || (inputXMax==0)){
       inputXMax = x;
     }
     if((x <= inputXMin) || (inputXMin==0)){
       inputXMin = x;
     }
   }
   else if(IS_HIDDEN_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)){
     x = GET_UNIT_XPOS(unitPtr);
     y = GET_UNIT_YPOS(unitPtr);
     NoOfHiddenUnits++;
     if((y >= hiddenYMax) || (hiddenYMax==0)){
       hiddenYMax = y;
     }
     if((y <= hiddenYMin) || (hiddenYMin==0)){
       hiddenYMin = y;
     }
     if((x >= hiddenXMax) || (hiddenXMax==0)){
       hiddenXMax = x;
     }
     if((x <= hiddenXMin) || (hiddenXMin==0)){
       hiddenXMin = x;
     }
   }
   else if(IS_OUTPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)){
     x = GET_UNIT_XPOS(unitPtr);
     y = GET_UNIT_YPOS(unitPtr);
     NoOfOutputUnits++;
     if((y >= outputYMax) || (outputYMax==0)){
       outputYMax = y;
     }
     if((y <= outputYMin) || (outputYMin==0)){
       outputYMin = y;
     }
     if((x >= outputXMax) || (outputXMax==0)){
       outputXMax = x;
     }
     if((x <= outputXMin) || (outputXMin==0)){
       outputXMin = x;
     }
   }
 }

 if(NoOfHiddenUnits==0){
   hiddenXMax = hiddenXMin = X_MIN_POS + (inputXMax-inputXMin) + 3;
   hiddenYMax = hiddenYMin = Y_MIN_POS;
   *outXMax = X_MIN_POS + (inputXMax-inputXMin) + (hiddenXMax-hiddenXMin) + 6;
   *xPosOfLastInsertedHiddenUnit = X_MIN_POS + (inputXMax - inputXMin) + 3;
 }
 else {
   *xPosOfLastInsertedHiddenUnit = X_MIN_POS + (inputXMax - inputXMin) + (hiddenXMax - hiddenXMin) + 3;
   *outXMax = X_MIN_POS + (inputXMax-inputXMin) + (hiddenXMax-hiddenXMin) + (outputXMax-outputXMin) + 6;
 }
 *yPosOfLastInsertedHiddenUnit = Y_MIN_POS-1;
 if(NoOfHiddenUnits==0) {
   *maxYPosOfHiddenUnit = Y_MIN_POS + HIDDEN_LAYER_HEIGHT - 1;
 }
 else {
   if(hiddenYMax - hiddenYMin + 1 >= MIN_HIDDEN_LAYER_HEIGHT) {
     *maxYPosOfHiddenUnit = Y_MIN_POS + (hiddenYMax-hiddenYMin);
   }
   else {
     *maxYPosOfHiddenUnit = Y_MIN_POS + HIDDEN_LAYER_HEIGHT - 1;
   }
 }

 xInputOffset = X_MIN_POS - inputXMin;
 yInputOffset = Y_MIN_POS - inputYMin;

 xHiddenOffset = X_MIN_POS + (inputXMax-inputXMin) - hiddenXMin + 3;
 yHiddenOffset = Y_MIN_POS - hiddenYMin;

 xOutputOffset = X_MIN_POS + (inputXMax-inputXMin) + (hiddenXMax-hiddenXMin) - outputXMin + 6;
 yOutputOffset = Y_MIN_POS - outputYMin;   

 FOR_ALL_UNITS(unitPtr){
   if(IS_INPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr) ) {
     SET_UNIT_XPOS(unitPtr,GET_UNIT_XPOS(unitPtr)+xInputOffset);
     SET_UNIT_YPOS(unitPtr,GET_UNIT_YPOS(unitPtr)+yInputOffset);
   }
   if(IS_HIDDEN_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)) {
     SET_UNIT_XPOS(unitPtr,GET_UNIT_XPOS(unitPtr)+xHiddenOffset);
     SET_UNIT_YPOS(unitPtr,GET_UNIT_YPOS(unitPtr)+yHiddenOffset);
   }
   if(IS_OUTPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr) ) {
     SET_UNIT_XPOS(unitPtr,GET_UNIT_XPOS(unitPtr)+xOutputOffset);
     SET_UNIT_YPOS(unitPtr,GET_UNIT_YPOS(unitPtr)+yOutputOffset);
   }
 }

 if(NoOfHiddenUnits!=0) {
   FOR_ALL_UNITS(unitPtr){
     if(IS_HIDDEN_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)) {
       x = GET_UNIT_XPOS(unitPtr);
       y = GET_UNIT_YPOS(unitPtr);
       if(x == *xPosOfLastInsertedHiddenUnit){
         if(y >= *yPosOfLastInsertedHiddenUnit){
           *yPosOfLastInsertedHiddenUnit = y;
         }
       }
     }
   }
 }
 return(KRERR_NO_ERROR);
}

  
/*****************************************************************************
  FUNCTION : cc_initOutputUnits

  PURPOSE  : Initializes the links of the output units.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

void cc_initOutputUnits(void)
{
 struct Unit *outputUnitPtr, *newHiddenUnitPtr;
 struct Link *linkPtr;
 int o;

 FOR_ALL_OUTPUT_UNITS(outputUnitPtr,o){
   outputUnitPtr->value_a =  outputUnitPtr->value_b = outputUnitPtr->value_c = 0;
   FOR_ALL_LINKS(outputUnitPtr,linkPtr){
     linkPtr->value_a =  linkPtr->value_b = linkPtr->value_c = 0;
   }
 }
 /* backfitting */
 if(LastInsertedHiddenUnit && cc_backfittingOnOff) {
   newHiddenUnitPtr=kr_getUnitPtr(LastInsertedHiddenUnit);
   newHiddenUnitPtr->value_a =  newHiddenUnitPtr->value_b
     = newHiddenUnitPtr->value_c = 0;
   FOR_ALL_LINKS(newHiddenUnitPtr,linkPtr){
     linkPtr->value_a =  linkPtr->value_b = linkPtr->value_c = 0;
   }
 }
}


/*****************************************************************************
  FUNCTION : cc_calculateCorrelation

  PURPOSE  : Calculates the correlation of the pool of candidate units and 
             returns the high score.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

float cc_calculateCorrelation(int StartPattern, int EndPattern, int counter)
{
 int s,o,n;
 float highScore=0.0,bestSpecialUnitScore,scoreBuffer;
 struct Unit *SpecialUnitPtr,*OutputUnitPtr;
 int start, end;

 KernelErrorCode = kr_initSubPatternOrder(StartPattern,EndPattern);
 ERROR_CHECK;
 start = kr_AbsPosOfFirstSubPat(StartPattern+1);
 end   = kr_AbsPosOfFirstSubPat(EndPattern-1);
 end  += kr_NoOfSubPatPairs(EndPattern-1) - 1;

 n = end - start + 1;

 bestSpecialUnitPtr = NULL;
 bestSpecialUnitScore = 0.0;
 if(cc_printOnOff) {
   printf("Cycle %d ",counter);
 } 
 

 FOR_ALL_SPECIAL_UNITS(SpecialUnitPtr,s) {
   FOR_ALL_OUTPUT_UNITS(OutputUnitPtr,o) {
     scoreBuffer =  (CorBetweenSpecialActAndOutError[s][o] - 
                    (OutputUnitSumError[o]/n  * SpecialUnitSumAct[s])) / SumSqError;
     highScore += fabs(scoreBuffer);
     CorBetweenSpecialActAndOutError[s][o] = SIGN(scoreBuffer);
   }
   if(highScore > bestSpecialUnitScore) {
     bestSpecialUnitScore = highScore;
     bestSpecialUnitPtr = SpecialUnitPtr;
   }
   if(cc_printOnOff) {
     printf("S[%d]: %.4f ",s,highScore);
   }
   highScore = 0.0;
 }
 if(cc_printOnOff) {
   printf("\n");
 } 

 return(bestSpecialUnitScore);
}

/*****************************************************************************
  FUNCTION : cc_initInputUnitsWithPattern

  PURPOSE  : Initialize the input layer with pattern PatternNo.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

void cc_initInputUnitsWithPattern(int SubPatternNo)
{
  register struct Unit   *unit_ptr;
  register Patterns  in_pat;
  register int dummy;
  int pat, sub;
  

  kr_getSubPatternByNo(&pat,&sub,SubPatternNo);
  in_pat = kr_getSubPatData(pat,sub,INPUT,NULL);

  FOR_ALL_INPUT_UNITS(unit_ptr,dummy){
    if(unit_ptr->out_func == OUT_IDENTITY) {
      unit_ptr->Out.output = unit_ptr->act = *in_pat++;
    }
    else {
      unit_ptr->Out.output = (*unit_ptr->out_func) (unit_ptr->act = *in_pat++);
    }
  }
}



/*****************************************************************************
  FUNCTION : cc_setHiddenUnit

  PURPOSE  : Positions the hidden layer.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

krui_err cc_setHiddenUnit(struct Unit *hiddenUnitPtr, int maxYPosOfHiddenUnit,
                          int *xPosOfLastInsertedHiddenUnit, int *yPosOfLastInsertedHiddenUnit)

{
 struct Unit *outputUnitPtr,*specialUnitPtr;
 int dummy;

 if(*yPosOfLastInsertedHiddenUnit<maxYPosOfHiddenUnit){
   SET_UNIT_XPOS(hiddenUnitPtr,*xPosOfLastInsertedHiddenUnit);
   SET_UNIT_YPOS(hiddenUnitPtr,++*yPosOfLastInsertedHiddenUnit);
 }
 else {
   SET_UNIT_XPOS(hiddenUnitPtr,++*xPosOfLastInsertedHiddenUnit);
   SET_UNIT_YPOS(hiddenUnitPtr,*yPosOfLastInsertedHiddenUnit=Y_MIN_POS);
   FOR_ALL_OUTPUT_UNITS(outputUnitPtr,dummy) {
     SET_UNIT_XPOS(outputUnitPtr,GET_UNIT_XPOS(outputUnitPtr)+1);
   }
   FOR_ALL_SPECIAL_UNITS(specialUnitPtr,dummy) {
     SET_UNIT_XPOS(specialUnitPtr,GET_UNIT_XPOS(specialUnitPtr)+1);
   }
 }
 return(KRERR_NO_ERROR);
}

/*****************************************************************************
  FUNCTION : cc_setPointers

  PURPOSE  : Calculates the beginning of the input, hidden, output and special
             units in the topo_ptr_array. 
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/


krui_err cc_setPointers(void)
{
 FirstInputUnitPtr   = (struct Unit **)(&topo_ptr_array[1]);
 if(*(FirstInputUnitPtr-1)!=NULL) CC_ERROR(KRERR_CC_ERROR1);
 FirstHiddenUnitPtr  = FirstInputUnitPtr  + NoOfInputUnits  + 1;
 if(*(FirstHiddenUnitPtr-1)!=NULL) CC_ERROR(KRERR_CC_ERROR1);
 FirstOutputUnitPtr  = FirstHiddenUnitPtr + NoOfHiddenUnits + 1;
 if(*(FirstOutputUnitPtr-1)!=NULL) CC_ERROR(KRERR_CC_ERROR1);
 FirstSpecialUnitPtr = FirstOutputUnitPtr + NoOfOutputUnits + 1;    
 if(*(FirstSpecialUnitPtr-1)!=NULL) CC_ERROR(KRERR_CC_ERROR1);
 return(KRERR_NO_ERROR);
}

/*****************************************************************************
  FUNCTION : cc_initSpecialUnitLinks

  PURPOSE  : Sets all the links of the special units to zero.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/


krui_err cc_initSpecialUnitLinks(void)
{
 int s;
 struct Unit *SpecialUnitPtr;
 struct Link *LinkPtr;

 FOR_ALL_SPECIAL_UNITS(SpecialUnitPtr,s) {
   SpecialUnitPtr->bias = 0.0;
   BIAS_CURRENT_SLOPE(SpecialUnitPtr) = 0.0; 
   BIAS_PREVIOUS_SLOPE(SpecialUnitPtr) = 0.0; 
   BIAS_LAST_WEIGHT_CHANGE(SpecialUnitPtr) = 0.0;
   FOR_ALL_LINKS(SpecialUnitPtr,LinkPtr) {
     LinkPtr->weight = cc_generateRandomNo(CC_MAX_VALUE);
     LN_CURRENT_SLOPE(LinkPtr) = 0.0;
     LN_PREVIOUS_SLOPE(LinkPtr) = 0.0;
     LN_LAST_WEIGHT_CHANGE(LinkPtr) = 0.0;
   }
 }
 return(KRERR_NO_ERROR);
}

/*****************************************************************************
  FUNCTION : cc_updatePosOfSpecialUnits

  PURPOSE  : Updates the position of the special units.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

void cc_updatePosOfSpecialUnits(void)
{
 int x,outputXMax=0,s;
 struct Unit *unitPtr,*specialUnitPtr;
 
 if(cc_cascade) {
   FOR_ALL_UNITS(unitPtr) {
     if(IS_OUTPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)){
       x = GET_UNIT_XPOS(unitPtr);
       if((x >= outputXMax) || (outputXMax==0)){
         outputXMax = x;
       }
     }
   }

   FOR_ALL_SPECIAL_UNITS(specialUnitPtr,s){
     if(specialUnitPtr != NULL) { /* this can happen if there is an error before the function "cc_setPointers" */
       SET_UNIT_XPOS(specialUnitPtr,outputXMax+3);
     }
   }
   cc_cascade = 0;
 }
}

/*****************************************************************************
  FUNCTION : cc_deleteAllSpecialUnits

  PURPOSE  : Deletes all special units.
  NOTES    :

  UPDATE   : 5.2.93
******************************************************************************/

krui_err cc_deleteAllSpecialUnits(void)
{
 struct Unit *UnitPtr;

 if(NoOfUnits != 0) {
   FOR_ALL_UNITS(UnitPtr){
     if(IS_SPECIAL_UNIT(UnitPtr) && UNIT_IN_USE(UnitPtr)){
       KernelErrorCode = kr_removeUnit(UnitPtr); 
       ERROR_CHECK;
     }
   }
   kr_forceUnitGC();
   NetModified = 1;
 }
 return(KRERR_NO_ERROR);
}



/* Begin of print functions, only needed for debugging. */

/*****************************************************************************
  FUNCTION : cc_printTopoPtrArray

  PURPOSE  : Prints the topo_ptr_array.
  NOTES    : Only needed for debugging.

  UPDATE   : 5.2.93
******************************************************************************/

void cc_printTopoPtrArray(void)
{
 int i;
 printf("topo_ptr_array\n\n"); 
  if( topo_ptr_array != NULL) {
    for(i=0;i<NoOfUnits+5;i++) {
      printf("topo_ptr_array[%d]: %d adr: %d \n",i,(int)topo_ptr_array[i],(int)&topo_ptr_array[i]);
    }
  }
}

/*****************************************************************************
  FUNCTION : cc_printUnitArray

  PURPOSE  : Prints the unit_array.
  NOTES    : Only needed for debugging.

  UPDATE   : 5.2.93
******************************************************************************/

void cc_printUnitArray(void)
{
 struct Unit *UnitPtr;

 printf("unit_array\n\n");

 FOR_ALL_UNITS(UnitPtr) {
   if(IS_INPUT_UNIT(UnitPtr)) {
     printf("adr(UnitPtr): %d %s x: %d y: %d\n",(int)UnitPtr,"INPUT",
            UnitPtr->unit_pos.x,UnitPtr->unit_pos.y);
   }
   else if(IS_HIDDEN_UNIT(UnitPtr)) {
     printf("adr(UnitPtr): %d %s x: %d y: %d\n",(int)UnitPtr,"HIDDEN",
            UnitPtr->unit_pos.x,UnitPtr->unit_pos.y);
   }
   else if(IS_OUTPUT_UNIT(UnitPtr)) {
     printf("adr(UnitPtr): %d %s x: %d y: %d\n",(int)UnitPtr,"OUTPUT",
            UnitPtr->unit_pos.x,UnitPtr->unit_pos.y);
   }
   else if(IS_SPECIAL_UNIT(UnitPtr)) {
     printf("adr(UnitPtr): %d %s x: %d y: %d\n",(int)UnitPtr,"SPECIAL",
            UnitPtr->unit_pos.x,UnitPtr->unit_pos.y);
   }
   else if(!UNIT_IN_USE(UnitPtr)) {
     printf("adr(UnitPtr): %d %s\n",(int)UnitPtr,"UNIT_NOT_IN_USE");
   }
   else {
     printf("adr(UnitPtr): %d %s\n",(int)UnitPtr,"FEHLER");
   }
 }
}


/*****************************************************************************
  FUNCTION : cc_printUnit

  PURPOSE  : Prints information of a single Unit.
  NOTES    : Only for debugging.

  UPDATE   : 5.2.93
******************************************************************************/

void cc_printUnit(struct Unit *unit_ptr)
{
 if(IS_INPUT_UNIT(unit_ptr)) {
   printf("adr(unit_ptr): %d %s x: %d y: %d\n",(int)unit_ptr,"INPUT",
   unit_ptr->unit_pos.x,unit_ptr->unit_pos.y);
 }
 else if(IS_HIDDEN_UNIT(unit_ptr)) {
   printf("adr(unit_ptr): %d %s x: %d y: %d\n",(int)unit_ptr,"HIDDEN",
   unit_ptr->unit_pos.x,unit_ptr->unit_pos.y);
 }
 else if(IS_OUTPUT_UNIT(unit_ptr)) {
   printf("adr(unit_ptr): %d %s x: %d y: %d\n",(int)unit_ptr,"OUTPUT",
   unit_ptr->unit_pos.x,unit_ptr->unit_pos.y);
 }
 else if(IS_SPECIAL_UNIT(unit_ptr)) {
   printf("adr(unit_ptr): %d %s x: %d y: %d\n",(int)unit_ptr,"SPECIAL",
   unit_ptr->unit_pos.x,unit_ptr->unit_pos.y);
 }
 else if(!UNIT_IN_USE(unit_ptr)) {
   printf("adr(unit_ptr): %d %s\n",(int)unit_ptr,"UNIT_NOT_IN_USE");
 } 
}

/*****************************************************************************
  FUNCTION : cc_printAllLinks

  PURPOSE  : Prints all the links of unit *unitPtr.
  NOTES    : Only for debugging.

  UPDATE   : 5.2.93
******************************************************************************/

void cc_printAllLinks(struct Unit *unitPtr)
{
 struct Link *linkPtr;

 if(unitPtr != NULL) {
   FOR_ALL_LINKS(unitPtr,linkPtr){
     if(linkPtr->to != NULL){
       printf("%d <-- %d %f\n",GET_UNIT_NO(unitPtr),GET_UNIT_NO(linkPtr->to),linkPtr->weight);
     }
     else {
       printf("%d <-- ZERO \n",GET_UNIT_NO(unitPtr));
     }
   }
 }
 else {
   printf("Unit has value zero\n");
 }
 printf("\n");
}
 

/* Print-Funktionen-End */


