/*****************************************************************************
  FILE           : kr_newpattern.c
  SHORTNAME      : newpattern
  SNNS VERSION   : 3.2

  PURPOSE        : handling of new pattern files;
  NOTES          :

  AUTHOR         : Michael Vogt
  DATE           : 10.9.93

  CHANGED BY     : 
  IDENTIFICATION : @(#)kr_newpattern.c	1.6 4/21/94
  SCCS VERSION   : 1.6
  LAST CHANGE    : 4/21/94

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

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

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>

#include "kr_typ.h"
#include "glob_typ.h"
#include "kr_mac.h"

#ifndef rand
#include "random.h"      /*  Randomize Library Function Prototypes  */
#endif

#include "kernel.h"
#include "kr_const.h"
#include "kr_pat_scan.h"
#include "kr_pat_parse.h"
#include "kr_newpattern.ph"

/*****************************************************************************
 FUNCTIONS WHICH ARE CALLED BY THE KERNEL USER INTERFACE TO PERFORM
 THE KERNEL INTERFACE OF THE NEW PATTERN MANAGEMENT
******************************************************************************/

/*****************************************************************************
  FUNCTION : kr_npui_setCurrPatSet

  PURPOSE  : determines the number of the current pattern set (in
             kernel terminology) numbering starts with 0
  RETURNS  : kernel error code
  NOTES    :

  UPDATE   : 
******************************************************************************/
krui_err kr_npui_setCurrPatSet(int number)
{
    if (number<0 || number>=npui_number_pat_sets)
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    npui_curr_pat_set = number;
    npui_curr_pattern = 1;
    npui_train_defined = FALSE;
    npui_show_defined = FALSE;
    np_abs_count_valid = FALSE;
    np_sub_pat_sizes_valid = FALSE;

    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_npui_deletePatSet

  PURPOSE  : deletes the specified pattern set from memory and
             undefines the current pattern set, pattern, training
	     scheme and display scheme
  RETURNS  : kernel error code
  NOTES    :

  UPDATE   : 
******************************************************************************/
krui_err kr_npui_deletePatSet(int number)
{
    int i;
    int pat_set;

    if (number<0 || number>=npui_number_pat_sets)
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    pat_set = npui_pat_sets[number];

    for (i=number; i<npui_number_pat_sets-1; i++)
	npui_pat_sets[i] = npui_pat_sets[i+1];
    npui_number_pat_sets--;
    npui_curr_pat_set = -1;
    npui_curr_pattern = -1;
    npui_train_defined = FALSE;
    npui_show_defined = FALSE;
    np_abs_count_valid = FALSE;
    np_sub_pat_sizes_valid = FALSE;

    return kr_np_DeletePatternSet(pat_set);
}

/*****************************************************************************
  FUNCTION : kr_npui_GetPatInfo

  PURPOSE  : retrieves all available information concerning the
             current pattern set and the current pattern which both
	     must be defined. The given parameter fields are filled
	     with the information.
  RETURNS  : kernel error code
  NOTES    :

  UPDATE   : 
******************************************************************************/
krui_err kr_npui_GetPatInfo(pattern_set_info *set_info, 
                            pattern_descriptor *pat_info)
{
    pattern_descriptor *int_pat_info;
    krui_err err_code;

    if (npui_curr_pat_set == -1)
	return KRERR_NP_NO_CURRENT_PATTERN_SET;

    if (npui_curr_pattern == -1)
	return KRERR_NP_NO_CURRENT_PATTERN;

    err_code = kr_np_GetInfo(npui_pat_sets[npui_curr_pat_set],
			     set_info);
    if (err_code != KRERR_NO_ERROR)
	return err_code;

    err_code = kr_np_GetDescriptor(npui_pat_sets[npui_curr_pat_set],
				   npui_curr_pattern-1,
				   &int_pat_info);
    if (err_code != KRERR_NO_ERROR)
	return err_code;

    *pat_info = *int_pat_info;

    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_npui_DefShowSubPat

  PURPOSE  : Define the display scheme:
             Size and position of a sub pattern for the current
             pattern in the current pattern set is defined. <insize>
	     is a pointer to an array of integer values which define
	     the dimensional sizes of the input sub pattern. <inpos>
	     is a pointer to an array of integer values which defines
	     the offset (position) of this sub pattern inside the
	     pattern. <outsize> and <outpos> are used to define the
	     respective output sub pattern 
  RETURNS  : kernel error code
  NOTES    :

  UPDATE   : 
******************************************************************************/
krui_err kr_npui_DefShowSubPat(int *insize, int *outsize, 
                               int *inpos, int *outpos)
{
    krui_err err_code;
    pattern_descriptor *pattern;
    int i;

    npui_show_defined = FALSE;

    if (npui_curr_pat_set == -1)
	return KRERR_NP_NO_CURRENT_PATTERN_SET;

    if (npui_curr_pattern == -1)
	return KRERR_NP_NO_CURRENT_PATTERN;

    err_code = kr_np_GetDescriptor(npui_pat_sets[npui_curr_pat_set],
				   npui_curr_pattern-1,
				   &pattern);

    if (err_code != KRERR_NO_ERROR)
	return err_code;

    for (i=0; i<pattern->input_dim; i++)
    {
	if ((pattern->input_dim_sizes)[i] < insize[i] + inpos[i] - 1)
	    err_code = KRERR_NP_DIMENSION;
    }
    for (i=0; i<pattern->output_dim; i++)
    {
	if ((pattern->output_dim_sizes)[i] < outsize[i] + outpos[i] - 1)
	    err_code = KRERR_NP_DIMENSION;
    }

    if (err_code != KRERR_NO_ERROR)
	return err_code;

    memcpy(npui_insize, insize, MAX_NO_OF_VAR_DIM * sizeof(int));
    memcpy(npui_outsize, outsize, MAX_NO_OF_VAR_DIM * sizeof(int));
    memcpy(npui_inpos, inpos, MAX_NO_OF_VAR_DIM * sizeof(int));
    memcpy(npui_outpos, outpos, MAX_NO_OF_VAR_DIM * sizeof(int));
    for (i=0; i<MAX_NO_OF_VAR_DIM; i++)
    {
	npui_inpos[i]--;
	npui_outpos[i]--;
    }

    npui_show_defined = TRUE;

    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_npui_DefTrainSubPat

  PURPOSE  : Define the training scheme:
             Size and step size of sub pattern for the current pattern
             in the current pattern set is defined for training and
	     testing. <insize> is a pointer to an array of integer
	     values which define the dimensional sizes of the input sub
	     pattern. <instep> is a pointer to an array of integer
	     values which defines the step size which is used to move
	     the sub pattern over the pattern.
             <outsize> and <outpos> are used to define the respective
	     output sub pattern. 
             <max_n_pos> (if not NULL) returns the number of valid
	     input sub pattern positions for the current pattern and
	     the given training scheme.

  RETURNS  : kernel error code
  NOTES    :

  UPDATE   : 
******************************************************************************/
krui_err kr_npui_DefTrainSubPat(int *insize, int *outsize, 
                                int *instep, int *outstep, int *max_n_pos)
{
    krui_err err_code;
    int n;
    pattern_descriptor *p;

    npui_train_defined = FALSE;
    np_abs_count_valid = FALSE;
    np_sub_pat_sizes_valid = FALSE;

    if (npui_curr_pat_set == -1)
	return KRERR_NP_NO_CURRENT_PATTERN_SET;

    if (npui_curr_pattern == -1)
	return KRERR_NP_NO_CURRENT_PATTERN;

    memcpy(npui_insize, insize, MAX_NO_OF_VAR_DIM * sizeof(int));
    memcpy(npui_outsize, outsize, MAX_NO_OF_VAR_DIM * sizeof(int));
    memcpy(npui_instep, instep, MAX_NO_OF_VAR_DIM * sizeof(int));
    memcpy(npui_outstep, outstep, MAX_NO_OF_VAR_DIM * sizeof(int));

    err_code = 
	kr_np_DefineSubPatternOrdering(npui_pat_sets[npui_curr_pat_set],
				       TRUE, npui_insize, npui_instep);
    if (err_code != KRERR_NO_ERROR)
	return err_code;

    err_code = 
	kr_np_DefineSubPatternOrdering(npui_pat_sets[npui_curr_pat_set],
				       FALSE, npui_outsize,
				       npui_outstep);
    if (err_code != KRERR_NO_ERROR)
	return err_code;

    npui_train_defined = TRUE;

    if (max_n_pos != (int *) NULL)
    {
	err_code = kr_np_GetDescriptor(npui_pat_sets[npui_curr_pat_set],
				       npui_curr_pattern-1, &p);
	if (err_code != KRERR_NO_ERROR)
	    return err_code;

	if (!kr_np_gen_sub_pos(p->input_dim, &n, p->input_dim_sizes, 
			       npui_insize, npui_instep, (int *) NULL, 
			       TRUE))
	    return KRERR_NP_DIMENSION;
	*max_n_pos = n;
    }

    return KRERR_NO_ERROR;
}


/*****************************************************************************
  FUNCTION : kr_npui_AlignSubPat

  PURPOSE  : Align the position of a sub pattern:
             Using the current training scheme and the current pattern
	     of the current pattern set, the given position of an
	     input sub pattern <inpos> and the given position of the
	     corresponding output sub pattern <outpos> is aligned to fit
	     the currently defined training scheme.
	     E.g. if the training scheme defines a step width of 5 for
	     a specific dimension, only the positions 0, 5, 10, 15 ...
	     are valid positions for a sub pattern.
	     The position of each dimension is aligned independently
	     from all other dimensions by moving to the next valid
	     position which is lower or equal to the given position.
             <no> (if not NULL) returns the number of the sub pattern
	     which corresponds to the new aligned position which is
	     returned in place (<inpos> <outpos>).

  RETURNS  : kernel error code
  NOTES    :

  UPDATE   : 
******************************************************************************/
krui_err kr_npui_AlignSubPat(int *inpos, int *outpos, int *no)
{
    krui_err err_code;
    pattern_descriptor *p;
    int pos;
    int i;

    if (npui_curr_pat_set == -1)
	return KRERR_NP_NO_CURRENT_PATTERN_SET;

    if (npui_curr_pattern == -1)
	return KRERR_NP_NO_CURRENT_PATTERN;

    if (npui_train_defined == FALSE)
	return KRERR_NP_NO_TRAIN_SCHEME;

    err_code = kr_np_GetDescriptor(npui_pat_sets[npui_curr_pat_set],
				   npui_curr_pattern-1, &p);
    if (err_code != KRERR_NO_ERROR)
	return err_code;

    /* enumeration starts with 0, not with 1 */
    for (i=0; i< p->input_dim; i++)
	inpos[i] -= 1;

    /* align the position of the input sub pattern */
    if (!kr_np_align_sub_pos(p->input_dim, &pos, 
			     p->input_dim_sizes, npui_insize, 
			     npui_instep, inpos))
    {
	for (i=0; i< p->input_dim; i++)
	    inpos[i] = 1;
	return KRERR_NP_DIMENSION;
    }

    /* now enumeration starts with 1 again */
    for (i=0; i< p->input_dim; i++)
	inpos[i] += 1;

    /* find the output sub pattern which is related to the aligned */
    /* input sub pattern */
    if (!kr_np_gen_sub_pos(p->output_dim, &pos, 
			   p->output_dim_sizes, npui_outsize, 
			   npui_outstep, outpos, FALSE))
    {
	for (i=0; i< p->output_dim; i++)
	    outpos[i] = 1;
	return KRERR_NP_DIMENSION;
    }

    /* now enumeration starts with 1 again */
    for (i=0; i< p->output_dim; i++)
	outpos[i] += 1;

    /* return the absolute position */
    *no = pos+1;

    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_npui_allocNewPatternSet

  PURPOSE : Allocate an (additional) empty pattern set: A new pattern
  set is allocated if the maximum number of loaded pattern sets
  (NO_OF_PAT_SETS) is not exceeded. The corresponding pattern set
  handle is returned in <set_no>.  The new allocated pattern set
  becomes the current set.  There is no current pattern defined.
  Training scheme and display scheme both become undefined.

  NOTES    : 

  RETURNS  : 
  UPDATE   : 
******************************************************************************/
krui_err kr_npui_allocNewPatternSet(int *set_no)
{
    int pat_set;
    krui_err err_code;

    if (npui_number_pat_sets >= NO_OF_PAT_SETS)
	return KRERR_NP_NO_MORE_ENTRIES;

    /* allocate pattern set with zero pattern */
    err_code = kr_np_AllocatePatternSet(&pat_set, 0);
    if (err_code == KRERR_NO_ERROR)
    {
	npui_curr_pat_set = npui_number_pat_sets;
	npui_number_pat_sets++;
	npui_curr_pattern = -1;
	npui_pat_sets[npui_curr_pat_set] = pat_set;
	*set_no = npui_curr_pat_set;
	npui_train_defined = FALSE;
	npui_show_defined = FALSE;
	np_abs_count_valid = FALSE;
	np_sub_pat_sizes_valid = FALSE;
    }

    return err_code;
}

/*****************************************************************************
  FUNCTION : kr_npui_loadNewPatterns

  PURPOSE  : Load an (additional) pattern file:
             The file with name <filename> is loaded into memory if
	     existent and if the maximum number of loaded pattern sets
	     (NO_OF_PAT_SETS) is not exceeded. The corresponding
	     pattern set handle is returned in <set_no>.

	     The new loaded pattern set becomes the current set. The
	     first pattern inside this set becomes the current
	     pattern. Training scheme and display scheme both become
	     undefined.

  RETURNS  : kernel error code
  NOTES    :

  UPDATE   : 
******************************************************************************/
krui_err kr_npui_loadNewPatterns(char *filename, int *set_no)
{
    FILE *infile;
    int pat_set;
    int read_from_pipe = 0;
    char *buf;
    krui_err err_code;

    if (npui_number_pat_sets >= NO_OF_PAT_SETS)
	return KRERR_NP_NO_MORE_ENTRIES;

    if (access(filename, F_OK) != 0)
	return KRERR_FILE_OPEN;
    if (strcmp(&filename[strlen(filename)-2], ".Z") == 0)
    {
	buf = (char *) malloc(strlen(filename)+strlen("zcat ")+1);
	if (buf == (char *) NULL)
	    return KRERR_INSUFFICIENT_MEM;
	sprintf(buf, "zcat %s", filename);
	infile = popen(buf,"r");
	read_from_pipe = 1;
    }
    else
	infile = fopen(filename, "r");
    if (infile == (FILE *) NULL)
	return KRERR_FILE_OPEN;

    err_code = kr_np_LoadPatternFile(infile, &pat_set);
    if (err_code == KRERR_NO_ERROR)
    {
	npui_curr_pat_set = npui_number_pat_sets;
	npui_number_pat_sets++;
	npui_curr_pattern = 1;
	npui_pat_sets[npui_curr_pat_set] = pat_set;
	*set_no = npui_curr_pat_set;
	npui_train_defined = FALSE;
	npui_show_defined = FALSE;
	np_abs_count_valid = FALSE;
	np_sub_pat_sizes_valid = FALSE;
    }

    if (read_from_pipe)
    {
	pclose(infile);
	free(buf);
    }
    else
	fclose(infile);

    return err_code;
}

/*****************************************************************************
  FUNCTION : kr_npui_saveNewPatterns

  PURPOSE  : The given pattern set <set_no> is written to file
             <filename> in new style format. No side effects.

  RETURNS  : kernel error code
  NOTES    :

  UPDATE   : 
******************************************************************************/
krui_err kr_npui_saveNewPatterns(char *filename, int set_no)
{
    FILE *outfile;
    krui_err err_code;

    if (set_no<0 || set_no>=npui_number_pat_sets)
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    outfile = fopen(filename, "w");
    if (outfile == (FILE *) NULL)
	return KRERR_FILE_OPEN;

    err_code = kr_np_SavePatternFile(outfile, npui_pat_sets[set_no]);

    fclose(outfile);

    return err_code;
}

/*****************************************************************************
  FUNCTION : kr_npui_GetShapeOfSubPat

  PURPOSE  : Get the shape of a sub pattern which is specified by a
             number:
             After kr_npui_DefTrainSubPat has been called for the
	     current pattern set and a current pattern is defined,
	     this function retrieves the <n_pos>th valid sub pattern
	     pair which matches the defined training scheme. Size and
	     position of the sub pattern pair is returned in <insize>
	     <inpos> <outsize> and <outpos> which are all pointer to
	     integer arrays.

  RETURNS  : kernel error code
  NOTES    :

  UPDATE   : 
******************************************************************************/
krui_err kr_npui_GetShapeOfSubPat(int *insize, int *outsize, 
                                int *inpos, int *outpos, int n_pos)
{
    int sp[MAX_NO_OF_VAR_DIM];
    pattern_descriptor *p;
    krui_err err_code;
    int n;
    int i;

    if (npui_curr_pat_set == -1)
	return KRERR_NP_NO_CURRENT_PATTERN_SET;

    if (npui_curr_pattern == -1)
	return KRERR_NP_NO_CURRENT_PATTERN;

    if (!npui_train_defined)
	return KRERR_NP_NO_TRAIN_SCHEME;

    err_code = kr_np_GetDescriptor(npui_pat_sets[npui_curr_pat_set],
				   npui_curr_pattern-1, &p);
    if (err_code != KRERR_NO_ERROR)
	return err_code;

    n = n_pos-1;
    if (!kr_np_gen_sub_pos(p->input_dim, &n, p->input_dim_sizes, 
			   npui_insize, npui_instep, sp, FALSE))
	return KRERR_NP_NO_SUCH_PATTERN;
    
    memcpy((char *) inpos, (char *) sp, p->input_dim * sizeof(int));
    for (i=0; i<p->input_dim; i++)
	inpos[i]++;

    if (!kr_np_gen_sub_pos(p->output_dim, &n, p->output_dim_sizes, 
			   npui_outsize, npui_outstep, sp, FALSE))
	return KRERR_NP_NO_SUCH_PATTERN;

    memcpy((char *) outpos, (char *) sp, p->output_dim *sizeof(int));
    for (i=0; i<p->output_dim; i++)
	outpos[i]++;

    memcpy((char *) insize, (char *) npui_insize, p->input_dim *sizeof(int));
    memcpy((char *) outsize, (char *) npui_outsize, p->input_dim *sizeof(int));

    return KRERR_NO_ERROR;
}

/*****************************************************************************
 FUNCTIONS WHICH ARE CALLED BY OTHER KERNEL FUNCTIONS LIKE TRAINING
 AND INITIALIZATION FUNCTIONS:
******************************************************************************/

/*****************************************************************************
  FUNCTION : kr_np_pattern

  PURPOSE  : multiple pattern handling functions depending on mode and mode1
  RETURNS  : result, depending on operation or kernel error code
  NOTES    : KernelErrorCode is set to the valid kernel error code

  UPDATE   : 
******************************************************************************/
int  kr_np_pattern(int mode ,int mode1 ,int pattern_no)
{
    int return_code;
    int new_pattern;
    pattern_set_info info;

    return_code = (int) (KernelErrorCode = KRERR_NO_ERROR);

    if (npui_curr_pat_set == -1)
    {
	KernelErrorCode = KRERR_NP_NO_CURRENT_PATTERN_SET;
	return (int) KernelErrorCode;
    }

    /* for some modes, test current pattern definition */ 
    switch (mode)
    {
      case  PATTERN_GET:	/*  returns the current pattern  */
      case  PATTERN_DELETE:	/*  delete the current pattern pair  */
      case  PATTERN_MODIFY:	/*  modify the current pattern pair  */
      case  PATTERN_SHOW:	/*  show pattern  */
	if (npui_curr_pattern == -1 && mode != PATTERN_SET)
	{
	    KernelErrorCode = KRERR_NP_NO_CURRENT_PATTERN;
	    return (int) KernelErrorCode;
	}
      default:
	break;
    }

    switch (mode)
    {
      case  PATTERN_SET:	/*  set the current pattern  */
	if (pattern_no < 1 || pattern_no >
	np_info[npui_pat_sets[npui_curr_pat_set]].number_of_pattern)
	{
	    return_code = (int) (KernelErrorCode = KRERR_PATTERN_NO);
	    npui_curr_pattern = -1;
	}
	else
	    npui_curr_pattern = pattern_no;
	break;

      case  PATTERN_GET:	/*  returns the current pattern  */
	return_code = npui_curr_pattern;
	break;

      case  PATTERN_DELETE:	/*  delete the current pattern pair  */
	return_code = kr_np_DeletePattern(npui_pat_sets[npui_curr_pat_set],
					  npui_curr_pattern-1);
	npui_curr_pattern = -1;
	break;

      case  PATTERN_MODIFY:	/*  modify the current pattern pair  */
	return_code = (int) (KernelErrorCode = kr_np_modifyPattern());
	break;

      case  PATTERN_SHOW:	/*  show pattern  */
	return_code = (int) (KernelErrorCode = kr_np_showPatternSTD(mode1));
	break;

      case  PATTERN_NEW:	/*  new pattern  */
	/* before creating a new pattern, first ensure that new pattern */
	/* fits into existing set */
	return_code = kr_np_GetInfo(npui_pat_sets[npui_curr_pat_set], &info);
	if (return_code != KRERR_NO_ERROR)
	    break;
	(void) kr_IOCheck();
	if (NoOfInputUnits == 0)
	{
	    return_code = KernelErrorCode = KRERR_NO_INPUT_UNITS;
	    break;
	}

	if (info.number_of_pattern > 0)
	{
	    if (info.in_number_of_dims != 0 || 
		info.out_number_of_dims != 0 ||
		info.in_fixsize != NoOfInputUnits || 
		 info.out_fixsize != NoOfOutputUnits)
	    {
		/* creation of variable sized patterns is not possible */
		/* also the new pattern must be of equal size compared to */
		/* existing pattern */
		return_code = KRERR_NP_INCOMPATIBLE_NEW;
		break;
	    }
	}

	return_code = KernelErrorCode =
	    kr_np_AddPattern(npui_pat_sets[npui_curr_pat_set], &new_pattern);
	if (return_code != KRERR_NO_ERROR)
	    break;

	npui_curr_pattern = new_pattern + 1;
	return_code = (int) (KernelErrorCode = kr_np_modifyPattern());
	if (return_code != KRERR_NO_ERROR)
	{
	    (void) kr_np_DeletePattern(npui_pat_sets[npui_curr_pat_set],
				       npui_curr_pattern-1);
	    npui_curr_pattern = -1;
	}
	break;

      case  PATTERN_DELETE_ALL:	/*  delete all pattern  */
	break;

      case  PATTERN_SHUFFLE_ON:	/*  shuffle pattern  */
	npui_shuffle_pattern = TRUE;
	break;

      case  PATTERN_SHUFFLE_OFF: /*  shuffle pattern off */
	npui_shuffle_pattern = FALSE;
	break;

      case  PATTERN_SET_NUMBER:
	break;

      case  PATTERN_GET_NUMBER:
	return_code = 
	    np_info[npui_pat_sets[npui_curr_pat_set]].number_of_pattern;
	break;
	
      case  PATTERN_SUB_SHUFFLE_ON:
	npui_shuffle_sub_pattern = TRUE;
	break;

      case  PATTERN_SUB_SHUFFLE_OFF:
	npui_shuffle_sub_pattern = FALSE;
	break;

      case GET_SHUFFLE_FLAG:
	return_code = npui_shuffle_pattern;
	break;

      case GET_SUB_SHUFFLE_FLAG:
	return_code = npui_shuffle_sub_pattern;
	break;

      default:
	KernelErrorCode = KRERR_PARAMETERS;
    }

    return return_code;
}

/*****************************************************************************
  FUNCTION : kr_initSubPatternOrder

  PURPOSE  : The sub pattern ordering for the current pattern set is
             reset for the next training or initialization run. During
	     this run all sub patterns from pattern <start> up to
	     pattern <end> are generated according to current shuffle
	     flags for patterns and sub patterns.  
             kr_getSubPatByOrder is to be called to get the next sub
	     pattern number during the run (see below) 

  RETURNS  : kernel error code
  NOTES    :

  UPDATE   : 
******************************************************************************/
krui_err kr_initSubPatternOrder(int start, int end)
{
    int pat_set;
    int n_sub;

    if (!npui_train_defined)
	return KRERR_NP_NO_TRAIN_SCHEME;

    pat_set = npui_pat_sets[npui_curr_pat_set];
    if (!kr_np_allocate_pat_train_entries(np_info[pat_set].number_of_pattern))
	return KRERR_INSUFFICIENT_MEM;

    if (npui_shuffle_pattern && npui_shuffle_sub_pattern)
    {
	np_random_train_number = kr_TotalNoOfSubPatPairs();
	np_next_train_random = 0;

	return KRERR_NO_ERROR;
    }

    kr_np_order_pat_entries(start, end);
    np_next_train_pat = 0;

    np_current_pattern = 
	&(np_pat_sets[pat_set][np_pat_train_order[0]]);
    
    kr_np_gen_sub_pos(np_current_pattern -> input_dim, &n_sub,
		      np_current_pattern -> input_dim_sizes, np_t_insize, 
		      np_t_instep, NULL, TRUE);

    if (!kr_np_allocate_sub_pat_train_entries(n_sub))
	return KRERR_INSUFFICIENT_MEM;

    kr_np_order_sub_pat_entries(0, n_sub-1);
    np_next_train_sub_pat = 0;

    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_getSubPatternByOrder

  PURPOSE : According to the last call to kr_initSubPatternOrder, the
  last call to this function and the shuffle flags, the next position
  of pattern and sub pattern is determined. This numbers are returned
  in <pattern> and <sub> (beginning with 0). 

  RETURNS : If there are no more sub pattern avaliable the return
  value is FALSE, otherwise TRUE.
  NOTES    :

  UPDATE   : 
******************************************************************************/
bool kr_getSubPatternByOrder(int *pattern, int *sub)
{
    int n_sub;

    if (npui_shuffle_pattern && npui_shuffle_sub_pattern)
    {
	if (np_next_train_random == -1)
	    return FALSE;

	if (++np_next_train_random >= np_random_train_number)
	    np_next_train_random = -1;

	return (kr_getSubPatternByNo(pattern, sub, 
				     lrand48() % np_random_train_number));
    }

    if (np_next_train_pat == -1)
	return FALSE;

    *pattern = np_pat_train_order[np_next_train_pat];
    *sub = np_sub_pat_train_order[np_next_train_sub_pat];

    np_next_train_sub_pat++;
    if (np_next_train_sub_pat >= np_sub_pat_train_number)
    {
	np_next_train_pat++;
	if (np_next_train_pat >= np_pat_train_number)
	{
	    np_next_train_pat = -1;
	    return TRUE;
	}

	np_current_pattern = 
	    &(np_pat_sets[npui_pat_sets[npui_curr_pat_set]]
	                 [np_pat_train_order[np_next_train_pat]]);
    
	kr_np_gen_sub_pos(np_current_pattern -> input_dim, &n_sub,
			  np_current_pattern -> input_dim_sizes, np_t_insize, 
			  np_t_instep, NULL, TRUE);

	if (!kr_np_allocate_sub_pat_train_entries(n_sub))
	{
	    KernelErrorCode = KRERR_INSUFFICIENT_MEM;
	    return FALSE;
	}

	kr_np_order_sub_pat_entries(0, n_sub-1);
	np_next_train_sub_pat = 0;
    }

    return TRUE;
}

/*****************************************************************************
  FUNCTION : kr_getSubPatternByNo

  PURPOSE : According to the current pattern set, the position of the
  <n>th sub pattern is determined and returned in <pattern> (the
  pattern which includes the subpattern) and <sub> (the sub pattern
  inside the pattern) (beginning with 0).  
  This function does not effect the ordering of the function
  kr_getSubPatByOrder. <n> ranges from 0 to kr_TotalNoOfSubPatPairs()-1.

  RETURNS : If the sub pattern is available, TRUE is returned,
  otherwise FALSE.

  NOTES    :

  UPDATE   : 
******************************************************************************/
bool kr_getSubPatternByNo(int *pattern, int *sub, int n)
{
    register int ts;
    register int tp;
    register int low, high, mid;

    ts = kr_TotalNoOfSubPatPairs();
    if (n<0 || n>=ts)
	return FALSE;

    tp = np_info[npui_pat_sets[npui_curr_pat_set]].number_of_pattern;

    if (tp == 1)
	/* only one pattern present, sub pattern must be here */
	high = 0;
    else
    {
	/* more than one pattern present.... */
	/* first try to find the right position by a direct jump */
	high = (n*tp)/ts;

	if (np_abs_count[high] <= n || (high != 0 && np_abs_count[high-1] > n))
	{
	    /* direct jump was not sucessfull, now perform binary search */
	    low = 0;
	    high = tp-1;
	    while (low < high)
	    {
		mid = (high+low)/2;
		if (np_abs_count[mid] > n)
		    high = mid;
		else
		    low = mid+1;
	    }
	}
    }

    /* now high gives the index of the pattern where the sub pattern is in */
    *pattern = high;

    /* calculate the position of the sub pattern inside the found pattern */
    if (high != 0)
	*sub = n - np_abs_count[high-1];
    else
	*sub = n;

    return TRUE;
}

/*****************************************************************************
  FUNCTION : kr_TotalNoOfSubPatPairs

  PURPOSE : This function returns the total number of available sub
  patterns for the current pattern set or 0 if no pattern set is
  defined.  The result is the sum of the numbers of subpattern for all
  patterns in the current set.

  RETURNS  : number of sub pattern or 0
  NOTES    :

  UPDATE   : 
******************************************************************************/
int kr_TotalNoOfSubPatPairs(void)
{
    int n;
    int i;
    int sum;
    int n_sub;
    pattern_descriptor *pat;

    if (np_abs_count_valid)
	return np_abs_count_No;

    if (npui_curr_pat_set == -1)
	return 0;

    n = np_info[npui_pat_sets[npui_curr_pat_set]].number_of_pattern;

    if (n > np_abs_count_size)
    {
	if (np_abs_count != (int *) NULL)
	    free(np_abs_count);
	np_abs_count_size = 0;
	np_abs_count = (int *) malloc(n * sizeof(int));
	if (np_abs_count == (int *) NULL && n != 0)
	    return 0;
	np_abs_count_size = n;
    }

    pat = np_pat_sets[npui_pat_sets[npui_curr_pat_set]];
    sum = 0;
    for (i=0; i<n; i++)
    {
	kr_np_gen_sub_pos(pat -> input_dim, &n_sub, 
			  pat -> input_dim_sizes, np_t_insize,
			  np_t_instep, NULL, TRUE);
	sum += n_sub;
	np_abs_count[i] = sum;
	pat++;
    }
    np_abs_count_No = sum;
    np_abs_count_valid = TRUE;

    return np_abs_count_No;
}

/*****************************************************************************
  FUNCTION : kr_NoOfSubPatPairs

  PURPOSE  : This function returns the number of available sub patterns
  for the pattern <pattern> of the current pattern set or 0 if this
  pattern is not defined.

  RETURNS  : 
  NOTES    :

  UPDATE   : 
******************************************************************************/
int kr_NoOfSubPatPairs(int pattern)
{
    register int ps;

    if (!np_abs_count_valid)
    {
	if (kr_TotalNoOfSubPatPairs() == 0)
	    return 0;
    }

    if (pattern<0 || 
	pattern > np_info[npui_pat_sets[npui_curr_pat_set]].number_of_pattern)
	return 0;

    ps = np_abs_count[pattern];

    if (pattern == 0)
	return ps;
    else
	return (ps - np_abs_count[pattern-1]);
}

/*****************************************************************************
  FUNCTION : kr_AbsPosOfFirstSubPat

  PURPOSE  : This function returns the absolute position of the first
  sub pattern of pattern <pattern> in the current pattern set. This
  position is defined as the Sum of kr_NoOfSubPatPairs(i) where i runs
  from 0 to <pattern>-1.  The absolute position of the first sub
  pattern of pattern 0 is 0.  The returned value may be used as
  argument for the function kr_getSubPatternByNo.

  RETURNS  : 
  NOTES    :

  UPDATE   : 
******************************************************************************/
int kr_AbsPosOfFirstSubPat(int pattern)
{
    if (!np_abs_count_valid)
    {
	if (kr_TotalNoOfSubPatPairs() == 0)
	    return 0;
    }

    if (pattern <= 0 || 
	pattern > np_info[npui_pat_sets[npui_curr_pat_set]].number_of_pattern)
	return 0;

    return np_abs_count[pattern-1];
}

/*****************************************************************************
  FUNCTION : kr_TotalNoOfPattern

  PURPOSE : This function returns the total number of available
  patterns for the current pattern set or 0 if no pattern set is
  defined.  

  RETURNS  : number of pattern or 0
  NOTES    :

  UPDATE   : 
******************************************************************************/
int kr_TotalNoOfPattern(void)
{
    if (npui_curr_pat_set == -1)
	return 0;

    return np_info[npui_pat_sets[npui_curr_pat_set]].number_of_pattern;
}

/*****************************************************************************
  FUNCTION : kr_getSubPatData

  PURPOSE : For the current pattern set and the specified sub pattern
  size, the data array of the <sub_no>th sub pattern of the <pat_no>th
  pattern is returned. io_type spcifies whether the input (INPUT) or
  output (OUTPUT) data is requested. If <size> is != NULL the size of
  the data array is returned is this parameter.  

  RETURNS : The function returns a pointer to the data array (type
  Patterns) or NULL if an error occured.
  NOTES    : KernelErrorCode is set if an error occured

  UPDATE   : 
******************************************************************************/
Patterns kr_getSubPatData(int pat_no, int sub_no, int io_type, int *size)
{
    int set;
    pattern_descriptor *pat;
    int subpos[MAX_NO_OF_VAR_DIM];
    float *data;
    krui_err err;
    static float dummy_data = 0.0;

#ifdef DEBUG_PATTERN
    fprintf(stderr, "pattern %d sub %d\n", pat_no, sub_no);
#endif

    set = npui_pat_sets[npui_curr_pat_set];
    pat = np_pat_sets[set];
    
    if (pat_no >= np_info[set].number_of_pattern)
	return (Patterns) NULL;

    pat += pat_no;
    np_current_pattern = pat;
    switch (io_type)
    {
      case INPUT:
	if (!kr_np_gen_sub_pos(pat->input_dim, &sub_no, pat->input_dim_sizes,
			       np_t_insize, np_t_instep, subpos, FALSE))
	{
	    KernelErrorCode = KRERR_NP_NO_SUCH_PATTERN;
	    return (Patterns) NULL;
	}
	if ((err = kr_np_GetSubPat(TRUE, subpos, np_t_insize, &data, size))
	    != KRERR_NO_ERROR)
	{
	    KernelErrorCode = err;
	    return (Patterns) NULL;
	}
	return (Patterns) data;
	break;
      case OUTPUT:
	if (!kr_np_gen_sub_pos(pat->output_dim, &sub_no, pat->output_dim_sizes,
			       np_t_outsize, np_t_outstep, subpos, FALSE))
	{
	    KernelErrorCode = KRERR_NP_NO_SUCH_PATTERN;
	    return (Patterns) NULL;
	}
	if ((err = kr_np_GetSubPat(FALSE, subpos, np_t_outsize, &data, size))
	    != KRERR_NO_ERROR)
	{
	    KernelErrorCode = err;
	    return (Patterns) NULL;
	}

	/* kr_np_GetSubPat reports no error if a zero length output sub */
	/* pattern is requested. Instead a NULL pointer is returned but */
	/* must be exchanged by a dummy non NULL pointer because this */
	/* function reports errors by NULL pointers */
	if (data == 0)
	    return (Patterns) &dummy_data;

	return (Patterns) data;
	break;
      default:
	KernelErrorCode = KRERR_PARAMETERS;
	return (Patterns) NULL;
    }
}

/*****************************************************************************
  FUNCTION : kr_SizeOfInputSubPat

  PURPOSE  : For the current pattern set and the specified sub pattern size, 
  the size of the input part of the first sub pattern of the first pattern is 
  returned. Negative return values indicate KernelErrorCode. Size 0 is a valid 
  return value since the pattern may contain no data.
  RETURNS  : negative Kernel Error Codes or positive valid value
  NOTES    :

  UPDATE   : 
******************************************************************************/
int kr_SizeOfInputSubPat(void)
{
    krui_err err;

    if (np_sub_pat_sizes_valid)
	return np_sub_pat_input_size;

    err = kr_np_GetSubPatSizes(&np_sub_pat_input_size, 
			       &np_sub_pat_output_size);

    if (err == KRERR_NO_ERROR)
    {
	np_sub_pat_sizes_valid = TRUE;
	return np_sub_pat_input_size;
    }

    return err;
}

/*****************************************************************************
  FUNCTION : kr_SizeOfOutputSubPat

  PURPOSE  : For the current pattern set and the specified sub pattern size, 
  the size of the output part of the first sub pattern of the first pattern is 
  returned. Negative return values indicate KernelErrorCode. Size 0 is a valid 
  return value since the pattern may contain no data.
  RETURNS  : negative Kernel Error Codes or positive valid value
  NOTES    :

  UPDATE   : 
******************************************************************************/
int kr_SizeOfOutputSubPat(void)
{
    krui_err err;

    if (np_sub_pat_sizes_valid)
	return np_sub_pat_output_size;
    
    err = kr_np_GetSubPatSizes(&np_sub_pat_input_size, 
			       &np_sub_pat_output_size);

    if (err == KRERR_NO_ERROR)
    {
	np_sub_pat_sizes_valid = TRUE;
	return np_sub_pat_output_size;
    }

    return err;
}

/*****************************************************************************
 FUNCTIONS WHICH ARE CALLED BY THE PATTERN PARSER OR FROM INSIDE THIS
 MODULE. DON'T USE THESE FUNCTIONS FOR OTHER PURPOSES !!!!!
******************************************************************************/

/*****************************************************************************
  FUNCTION : kr_np_AllocatePatternSet

  PURPOSE  : looks for a free slot in pattern set array and allocates <number>
             of free pattern descriptors

  RETURNS  : kernel error code
  NOTES    : don't call this function. This function is only to be
             called by the parser or by functions inside this module

  UPDATE   : 
******************************************************************************/
krui_err kr_np_AllocatePatternSet(int *pat_set, int number)
{
    krui_err err_code;
    int i;
    int set = -1;

    if (np_used_pat_set_entries == 0)
    {
	/* never patterns allocated */
	err_code = kr_np_InitPattern();
	if (err_code != KRERR_NO_ERROR)
	    return err_code;
    }

    /* check for free pattern set entry */
    for (i=0; i<np_used_pat_set_entries; i++)
    {
	if (!np_pat_set_used[i])
	{
	    set = i;
	    break;
	}
    }
    if (set == -1)
    {
	/* no more free entries */
	return KRERR_NP_NO_MORE_ENTRIES;
    }

    /* allocate array of pattern descriptors */
    np_pat_sets[set] = 
	(pattern_descriptor *) malloc(number * sizeof(pattern_descriptor));
    if (np_pat_sets[set] == (pattern_descriptor *) NULL && number != 0)
	return KRERR_INSUFFICIENT_MEM;

    /* initialize part of the pattern descriptors */
    for (i=0; i<number; i++)
    {
	np_pat_sets[set][i].input_fixsize = 0;
	np_pat_sets[set][i].output_fixsize = 0;
	np_pat_sets[set][i].input_pattern = (float *) NULL;
	np_pat_sets[set][i].output_pattern = (float *) NULL;
	np_pat_sets[set][i].input_info = (char *) NULL;
	np_pat_sets[set][i].output_info = (char *) NULL;
    }

    /* store number of allocated descriptors */
    np_info[set].number_of_pattern = number;
    np_info_valid[set] = FALSE; /* only number_of_pattern is valid */

    /* sucessfull return */
    np_pat_set_used[set] = TRUE;
    *pat_set = set;
    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_np_AllocatePattern

  PURPOSE  : uses the information provided in given pattern descriptor to
             allocate memory for pattern data

  RETURNS  : kernel error code
  NOTES    : don't call this function. This function is only to be
             called by the parser or by functions inside this module

  UPDATE   : 
******************************************************************************/
krui_err kr_np_AllocatePattern(pattern_descriptor *pattern,
			       bool input)
{
    int i;
    int size;

    if (np_used_pat_set_entries == 0)
	return KRERR_NO_PATTERNS;

    if (input)
    {
	size = pattern -> input_fixsize;
	for (i=0; i<pattern -> input_dim; i++)
	    size *= (pattern -> input_dim_sizes)[i];
	pattern -> input_info = (char *) NULL;
	pattern -> input_pattern = (float *) malloc(size * sizeof(float));
	if (pattern -> input_pattern == (float *) NULL && size != 0)
	    return KRERR_INSUFFICIENT_MEM;
	else
	    return KRERR_NO_ERROR;
    }
    else
    {
	size = pattern -> output_fixsize;
	for (i=0; i<pattern -> output_dim; i++)
	    size *= (pattern -> output_dim_sizes)[i];
	pattern -> output_info = (char *) NULL;
	pattern -> output_pattern = (float *) malloc(size * sizeof(float));
	if (pattern -> output_pattern == (float *) NULL && size != 0)
	    return KRERR_INSUFFICIENT_MEM;
	else
	    return KRERR_NO_ERROR;
    }
}

/*****************************************************************************
  FUNCTION : kr_np_GetDescriptor

  PURPOSE  : determine a pointer to a specified pattern descriptor
             and make this pattern to be the current pattern

  RETURNS  : kernel error code
  NOTES    : don't call this function. This function is only to be
             called by the parser or by functions inside this module

  UPDATE   : 
******************************************************************************/
krui_err kr_np_GetDescriptor(int pat_set, int number, 
			     pattern_descriptor **pattern)
{
    if (np_used_pat_set_entries == 0)
	return KRERR_NO_PATTERNS;

    if (pat_set < 0 || pat_set >= np_used_pat_set_entries ||
	!np_pat_set_used[pat_set])
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    if (number >= np_info[pat_set].number_of_pattern)
	return KRERR_PATTERN_NO;

    *pattern = np_current_pattern = &(np_pat_sets[pat_set][number]);

    return KRERR_NO_ERROR;
}

/*****************************************************************************
 INTERNAL FUNCTIONS OF THIS MODULE. IMPOSSIBLE TO CALL THESE FUNCTIONS
 FROM OUTSIDE THE MODULE (IF NOBODY CHANGES THE STATIC DECLARATION) !!!!!!!
******************************************************************************/

/*****************************************************************************
  FUNCTION : kr_np_InitPattern

  PURPOSE  : initialization of pattern descriptor array
  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_InitPattern(void)
{
    int i;

    np_pat_sets = (pattern_descriptor **) malloc(NO_OF_PAT_SETS *
						 sizeof(pattern_descriptor *));
    np_pat_set_used = (bool *) malloc(NO_OF_PAT_SETS * sizeof(bool));
    np_info = (pattern_set_info *) malloc(NO_OF_PAT_SETS *
				     sizeof(pattern_set_info));

    np_info_valid = (bool *) malloc(NO_OF_PAT_SETS * sizeof(bool));

    if (np_pat_sets == (pattern_descriptor **) NULL ||
	np_info == (pattern_set_info *) NULL ||
	np_info_valid == (bool *) NULL)
    {
	return KRERR_INSUFFICIENT_MEM;
    }
    else
    {
	np_used_pat_set_entries = NO_OF_PAT_SETS;
	for (i=0; i<NO_OF_PAT_SETS; i++)
	{
	    np_pat_sets[i] = (pattern_descriptor *) NULL;
	    np_pat_set_used[i] = FALSE;
	    np_info_valid[i] = FALSE;
	}

	return KRERR_NO_ERROR;
    }
}


/*****************************************************************************
  FUNCTION : kr_np_ReallocatePatternSet

  PURPOSE  : reallocates the pattern set <pat_set> to contain <new_number> 
             of pattern entries.

  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_ReallocatePatternSet(int pat_set, int new_number)
{
    pattern_descriptor *new_mem;

    /* check whether patterns are allocated */
    if (np_used_pat_set_entries == 0)
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    /* check whether the pattern set is present */
    if (!np_pat_set_used[pat_set])
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    /* reallocate array of pattern descriptors */
    if (np_pat_sets[pat_set] != (pattern_descriptor *) NULL)
    {
	new_mem = (pattern_descriptor *) 
	    realloc(np_pat_sets[pat_set],
		    new_number * sizeof(pattern_descriptor));
    }
    else
    {
	new_mem = (pattern_descriptor *) 
	    malloc(new_number * sizeof(pattern_descriptor));
    }

    if (new_mem == (pattern_descriptor *) NULL && new_number != 0)
	return KRERR_INSUFFICIENT_MEM;

    np_pat_sets[pat_set] = new_mem;

    /* store number of allocated descriptors */
    np_info[pat_set].number_of_pattern = new_number;
    np_info_valid[pat_set] = FALSE; /* only number_of_pattern is valid */

    /* sucessfull return */
    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_np_DeletePatternSet

  PURPOSE  : delete a pattern set and free all memory
  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_DeletePatternSet(int pat_set)
{
    int i;
    pattern_descriptor *p;

    /* check for valid number of pattern set */
    if (np_used_pat_set_entries == 0)
	return KRERR_NO_PATTERNS;

    if (pat_set<0 || pat_set>=np_used_pat_set_entries)
	return KRERR_NP_NO_SUCH_PATTERN_SET;
	
    p = np_pat_sets[pat_set];
    if (!np_pat_set_used[pat_set])
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    /* free all pattern */
    for (i=0; i<np_info[pat_set].number_of_pattern; i++)
    {
	if (p -> input_pattern != (float *) NULL)
	    free(p -> input_pattern);
	if (p -> input_info != (char *) NULL)
	    free(p -> input_info);
	if (p -> output_pattern != (float *) NULL)
	    free(p -> output_pattern);
	if (p -> output_info != (char *) NULL)
	    free(p -> output_info);
	p++;
    }

    /* free the pattern descriptors */ 
    if (np_pat_sets[pat_set] != (pattern_descriptor *) NULL)
	free(np_pat_sets[pat_set]);
    np_pat_sets[pat_set] = (pattern_descriptor *) NULL;
    np_pat_set_used[pat_set] = FALSE;

    np_info[pat_set].number_of_pattern = 0;
    np_info_valid[pat_set] = FALSE;
    np_current_pattern = (pattern_descriptor *) NULL;

    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_np_DeletePattern

  PURPOSE  : delete a specific pattern form a pattern set
  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_DeletePattern(int pat_set, int pattern)
{
    pattern_descriptor *p;
    int i;

    /* check for valid number of pattern set */
    if (np_used_pat_set_entries == 0)
	return KRERR_NO_PATTERNS;

    if (pat_set<0 || pat_set>=np_used_pat_set_entries)
	return KRERR_NP_NO_SUCH_PATTERN_SET;
	
    p = np_pat_sets[pat_set];
    if (!np_pat_set_used[pat_set])
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    if (pattern < 0 || pattern >= np_info[pat_set].number_of_pattern)
	return KRERR_NP_NO_SUCH_PATTERN;

    /* free memory for the specified pattern */
    p += pattern;
    if (p -> input_pattern != (float *) NULL)
	free(p -> input_pattern);
    if (p -> input_info != (char *) NULL)
	free(p -> input_info);
    if (p -> output_pattern != (float *) NULL)
	free(p -> output_pattern);
    if (p -> output_info != (char *) NULL)
	free(p -> output_info);

    /* move tail of array one position to fill up the empty entry */
    for (i=pattern+1; i<np_info[pat_set].number_of_pattern; i++)
    {
	(void) memcpy((char *) p, (char *) (p+1), sizeof(pattern_descriptor));
	p++;
    }

    /* last entry of the array is no longer active */
    return kr_np_ReallocatePatternSet(pat_set, 
				   np_info[pat_set].number_of_pattern-1);
}

/*****************************************************************************
  FUNCTION : kr_np_AddPattern

  PURPOSE  : Add an empty pattern descriptor to the specified pattern set. 
             The position of the pattern inside the set is returned 
             in <pattern>.
  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_AddPattern(int pat_set, int *pattern)
{
    krui_err err;
    pattern_descriptor *p;
    int number;

    /* check for valid number of pattern set */
    if (np_used_pat_set_entries == 0)
	return KRERR_NO_PATTERNS;

    if (pat_set<0 || pat_set>=np_used_pat_set_entries)
	return KRERR_NP_NO_SUCH_PATTERN_SET;
	
    p = np_pat_sets[pat_set];
    if (!np_pat_set_used[pat_set])
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    number = np_info[pat_set].number_of_pattern + 1;
    err = kr_np_ReallocatePatternSet(pat_set, number);

    if (err != KRERR_NO_ERROR)
	return err;

    p = np_pat_sets[pat_set];
    p += (number-1);

    /* initialize part of the new pattern descriptors */
    {
	p -> input_fixsize = 0;
	p -> output_fixsize = 0;
	p -> input_dim = 0;
	p -> output_dim = 0;
	p -> input_pattern = (float *) NULL;
	p -> output_pattern = (float *) NULL;
    }

    *pattern = (number-1);
    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_np_LoadPatternFile

  PURPOSE  : loads new or old pattern file from pat_file. The number of the 
             associated pattern set is returned in pat_set.
  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_LoadPatternFile(FILE *pat_file, int *pat_set)
{
    int i;
    bool free;
    krui_err err_code;
    int pattern_set;

    /* be sure to have a place where to put the patterns */
    if (np_used_pat_set_entries == 0)
    {
	/* never patterns allocated */
	err_code = kr_np_InitPattern();
	if (err_code != KRERR_NO_ERROR)
	    return err_code;
    }
    else
    {
	free = FALSE;

	/* check for free entry before starting parser */
	for (i=0; i<np_used_pat_set_entries; i++)
	{
	    if (!np_pat_set_used[i])
	    {
		free = TRUE;
		break;
	    }
	}

	if (!free)
	    return KRERR_NP_NO_MORE_ENTRIES;	    
    }

    /* reset the scanner and the parser */
    scanner_init_scanner(pat_file);

    /* parse pattern file and check for errors */
    if (parse_pattern_file(&pattern_set) != 0)
    {
	(void) kr_np_DeletePatternSet(pattern_set);
	return KRERR_FILE_FORMAT;
    }
    else
    {
	*pat_set = pattern_set;
	return KRERR_NO_ERROR;
    }
}

/*****************************************************************************
  FUNCTION : kr_np_SavePatternFile

  PURPOSE  : save the pattern set pat_set to out_file
  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_SavePatternFile(FILE *out_file, int pat_set)
{
    pattern_set_info info;
    krui_err err_code;
    int i, j, n;
    float *in_pat, *out_pat;
    time_t clock;
    
    if (np_used_pat_set_entries == 0)
	return KRERR_NO_PATTERNS;

    if (pat_set<0 || pat_set>=np_used_pat_set_entries)
	return KRERR_NP_NO_SUCH_PATTERN_SET;
	
    if (!np_pat_set_used[pat_set])
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    err_code = kr_np_GetInfo(pat_set, &info);
    if (err_code != KRERR_NO_ERROR)
	return err_code;

    if (info.number_of_pattern == 0)
	return KRERR_NO_PATTERNS;

    fprintf(out_file, "SNNS pattern definition file V%d.%d\n",
	    CURRENT_VERSION_V, CURRENT_VERSION_R);
    clock = time((time_t *) NULL);
    fprintf(out_file, "generated at %s\n\n", (char *) ctime(&clock));
    fprintf(out_file, "No. of patterns : %d\n", info.number_of_pattern);
    fprintf(out_file, "No. of input units : %d\n", info.in_fixsize);
    if (info.out_fixsize != 0)
	fprintf(out_file, "No. of output units : %d\n", info.out_fixsize);
    if (info.in_number_of_dims != 0)
    {
	fprintf(out_file, "No. of variable input dimensions : %d\n", 
		info.in_number_of_dims);
	fprintf(out_file, "Maximum input dimensions : [ ");
	for (i=0; i<info.in_number_of_dims; i++)
	{
	    fprintf(out_file, "%d ", info.in_max_dim_sizes[i]);
	}
	fprintf(out_file, "]\n");
    }
    if (info.out_fixsize != 0 && info.out_number_of_dims != 0)
    {
	fprintf(out_file, "No. of variable output dimensions : %d\n", 
		info.out_number_of_dims);
	fprintf(out_file, "Maximum output dimensions : [ ");
	for (i=0; i<info.out_number_of_dims; i++)
	{
	    fprintf(out_file, "%d ", info.out_max_dim_sizes[i]);
	}
	fprintf(out_file, "]\n");
    }
    fprintf(out_file, "\n");

    for (j=0; j<info.number_of_pattern; j++)
    {
	if (np_pat_sets[pat_set][j].input_fixsize > 0)
	{
	    fprintf(out_file, "# Input pattern %d:\n", j+1);
	    n = info.in_fixsize;
	    if (info.in_number_of_dims != 0)
	    {
		fprintf(out_file, "[ ");
		for (i=0; i<np_pat_sets[pat_set][j].input_dim; i++)
		{
		    fprintf(out_file, "%d ", 
			    np_pat_sets[pat_set][j].input_dim_sizes[i]);
		    n *= np_pat_sets[pat_set][j].input_dim_sizes[i];
		}
		fprintf(out_file, "]\n");
	    }
	    in_pat = np_pat_sets[pat_set][j].input_pattern;
	    for (i=0; i<n; i++)
	    {
		fprintf(out_file, "%g ", *in_pat++);
		if (i == n - 1 || i%10 == 9)
		    fprintf(out_file, "\n");
	    }
	}

	if (np_pat_sets[pat_set][j].output_fixsize > 0)
	{
	    fprintf(out_file, "# Output pattern %d:\n", j+1);
	    n = info.out_fixsize;
	    if (info.out_number_of_dims != 0)
	    {
		fprintf(out_file, "[ ");
		for (i=0; i<np_pat_sets[pat_set][j].output_dim; i++)
		{
		    fprintf(out_file, "%d ", 
			    np_pat_sets[pat_set][j].output_dim_sizes[i]);
		    n *= np_pat_sets[pat_set][j].output_dim_sizes[i];
		}
		fprintf(out_file, "]\n");
	    }
	    out_pat = np_pat_sets[pat_set][j].output_pattern;
	    for (i=0; i<n; i++)
	    {
		fprintf(out_file, "%g ", *out_pat++);
		if (i == n - 1 || i%10 == 9)
		    fprintf(out_file, "\n");
	    }
	}
    }

    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_np_GetInfo

  PURPOSE  : get some information about the specified pattern set
  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_GetInfo(int pat_set, pattern_set_info *info)
{
    int i, j;
    pattern_descriptor *p;
    

    if (np_used_pat_set_entries == 0)
	return KRERR_NO_PATTERNS;

    if (pat_set < 0 || pat_set >= np_used_pat_set_entries ||
	!np_pat_set_used[pat_set])
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    if (np_info_valid[pat_set])
    {
	*info = np_info[pat_set];
	return KRERR_NO_ERROR;
    }

    p = np_pat_sets[pat_set];
    info -> number_of_pattern = np_info[pat_set].number_of_pattern;
    info -> fixed_fixsizes = TRUE;

    if (info -> number_of_pattern > 0 && p != (pattern_descriptor *) NULL)
    {
	info -> output_present = p-> output_fixsize != 0;
	info -> in_fixsize = p -> input_fixsize;
	info -> out_fixsize = p-> output_fixsize;
	info -> in_number_of_dims = p->input_dim;
	info -> out_number_of_dims = p->output_dim;

	for (j=0; j < p->input_dim; j++)
	{
	    (info -> in_max_dim_sizes)[j] = (info -> in_min_dim_sizes)[j] =
		(p -> input_dim_sizes)[j];
	}
	for (j=0; j < p->output_dim; j++)
	{
	    (info -> out_max_dim_sizes)[j] = (info -> out_min_dim_sizes)[j] =
		(p -> output_dim_sizes)[j];
	}
    }
    
    for (i=0; i<info -> number_of_pattern; i++)
    {
	if (p -> input_fixsize != info -> in_fixsize)
	{
	    info -> fixed_fixsizes = FALSE;
	    info -> in_fixsize = -1;
	}
	if (p -> output_fixsize != info -> out_fixsize)
	{
	    info -> fixed_fixsizes = FALSE;
	    info -> out_fixsize = -1;
	}

	for (j=0; j < p->input_dim; j++)
	{
	    if ((p -> input_dim_sizes)[j] > (info -> in_max_dim_sizes)[j])
		(info -> in_max_dim_sizes)[j] = p -> input_dim_sizes[j];
	    if ((p -> input_dim_sizes)[j] < (info -> in_min_dim_sizes)[j])
		(info -> in_min_dim_sizes)[j] = p -> input_dim_sizes[j];
	}
	for (j=0; j < p->output_dim; j++)
	{
	    if ((p -> output_dim_sizes)[j] > (info -> out_max_dim_sizes)[j])
		(info -> out_max_dim_sizes)[j] = p -> output_dim_sizes[j];
	    if ((p -> output_dim_sizes)[j] < (info -> out_min_dim_sizes)[j])
		(info -> out_min_dim_sizes)[j] = p -> output_dim_sizes[j];
	}
	
	p++;
    }

    np_info[pat_set] = *info;
    np_info_valid[pat_set] = TRUE;

    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_np_GetSubPatSizes

  PURPOSE  : Depending on the current pattern set and the sub pattern 
  training scheme, which must be defined, the size of the first input sub 
  pattern and the size of the first output sub pattern is computed.
  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_GetSubPatSizes(int *input_size, int *output_size)
{
    int pat_set;
    pattern_descriptor *pattern;
    int i;

    if (!npui_train_defined)
	return KRERR_NP_NO_TRAIN_SCHEME;

    pat_set = npui_pat_sets[npui_curr_pat_set];
    pattern = &(np_pat_sets[pat_set][0]);

    *input_size = pattern -> input_fixsize;
    for (i=0; i<pattern -> input_dim; i++)
    {
	*input_size *= np_t_insize[i];
    }

    *output_size = pattern -> output_fixsize;
    for (i=0; i<pattern -> output_dim; i++)
    {
	*output_size *= np_t_outsize[i];
    }

    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_np_GetSubPat

  PURPOSE  : copy a sub pattern into another area 

A sub pattern is cut out of the current pattern at position
<pos_coord> with size <size_coord>. According to <input> the input
part or the output part of the current pattern is used. A pointer to
an array of float which contains the cut part is returned in <data>.
<pos_coord> is an array of int which defines the position of the sub
pattern inside the variable sized dimensions of the pattern.
<size_coord> is an array of int which defines the size of the sub
pattern in each dimensional direction. Both arrays must contain
<input_dim> (or <output_dim>) entries (see pattern descriptor).

Example: pattern with input_fixsize 2, input_dim 2, input_dim_sizes [4 5]
(hint: the values of the pattern represent the position)

{
0.00, 0.01, 0.10, 0.11, 0.20, 0.21, 0.30, 0.31, 0.40, 0.41,
1.00, 1.01, 1.10, 1.11, 1.20, 1.21, 1.30, 1.31, 1.40, 1.41,
2.00, 2.01, 2.10, 2.11, 2.20, 2.21, 2.30, 2.31, 2.40, 2.41,
3.00, 3.01, 3.10, 3.11, 3.20, 3.21, 3.30, 3.31, 3.40, 3.41,
}

the sub pattern with <pos_coord> [1 2], <size_coord> [3 2] looks like
this:

{
1.20, 1.21, 1.30, 1.31,
2.20, 2.21, 2.30, 2.31,
3.20, 3.21, 3.30, 3.31,
}

The parameter entries returns the number of entries in the data field.

  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_GetSubPat(bool input, int *pos_coord, int *size_coord,
				float **data, int *entries)
{
    int u_dim;                   /* copy of all necessary variables from */
    int u_size;                  /* pattern descriptor, depending on */
    int *u_dim_sizes;            /* <input> */
    float *u_pattern;
    int npu_subpatsize;
    float *npu_subpat;

    int f_size;                  /* size of copy area */
    int i;
    int c[MAX_NO_OF_VAR_DIM];    /* counter for the dimensions */
    int copy_size;               /* size of copy block for each memcpy */
    float *cf;                   /* pointer into pattern (copy source) */
    float *cdest;                /* copy destination */
    bool stop;                   /* TRUE if all done */
    int offset;                  /* offset in multidimensional array */

    /* check for valid pattern */
    if (np_used_pat_set_entries == 0)
	return KRERR_NO_PATTERNS;

    if (np_current_pattern == (pattern_descriptor *) NULL)
	return KRERR_NP_NO_CURRENT_PATTERN;

    /* make a copy of all pattern info to work with */
    if (input)
    {
	u_dim = np_current_pattern -> input_dim;
	u_size = np_current_pattern -> input_fixsize;
	u_dim_sizes = np_current_pattern -> input_dim_sizes;
	u_pattern = np_current_pattern -> input_pattern;
	npu_subpatsize = np_i_subpatsize;
	npu_subpat = np_i_subpat;
    }
    else
    {
	u_dim = np_current_pattern -> output_dim;
	u_size = np_current_pattern -> output_fixsize;
	u_dim_sizes = np_current_pattern -> output_dim_sizes;
	u_pattern = np_current_pattern -> output_pattern;
	npu_subpatsize = np_o_subpatsize;
	npu_subpat = np_o_subpat;
    }

    /* check whether this pattern exists */
    if (u_size == 0)
    {
	if (input)
	    return KRERR_NP_NO_SUCH_PATTERN;
	else
	{
	    /* this may be a network without output neurons, so don't */
	    /* produce an error but set the data pointer to NULL */

	    *data = (float *) NULL;
	    if (entries != (int *) NULL)
		*entries = 0;
	    return KRERR_NO_ERROR;
	}
    }

    /* calculate size of the sub pattern and check dimensions */
    f_size = u_size;
    for (i=0; i<u_dim; i++)
    {
	f_size *= size_coord[i];
	if (pos_coord[i] + size_coord[i] > u_dim_sizes[i])
	    return KRERR_NP_DIMENSION;
	c[i] = 0;
    }

    /* allocate space for sub pattern if necessary */
    if (f_size > npu_subpatsize)
    {
	if (npu_subpat != (float *) NULL)
	    free(npu_subpat);
	npu_subpat = (float *) malloc(f_size * sizeof(float));
	if (npu_subpat == (float *) NULL && f_size != 0)
	{
	    return KRERR_INSUFFICIENT_MEM;
	}
	npu_subpatsize = f_size;

	/* copy back new address and size */
	if (input)
	{
	    np_i_subpatsize = npu_subpatsize;
	    np_i_subpat = npu_subpat;
	}
	else
	{
	    np_o_subpatsize = npu_subpatsize;
	    np_o_subpat = npu_subpat;
	}
    }


    /* calculate size of one copy block. this includes the size of the */
    /* dimension with highest index (least significant dimension) */
    copy_size = u_size;
    if (u_dim>0)
	copy_size *= size_coord[u_dim-1];

    /* copy the sub pattern */
    cdest = npu_subpat;
    do
    {
	/* calculate offset in source pattern */
	offset = 0;
	for (i=0; i<u_dim; i++)
	{
	    offset *= u_dim_sizes[i];
	    offset += pos_coord[i] + c[i];
	}
	offset *= u_size;
	cf = u_pattern + offset;

	/* copy part of the pattern. this inlcudes the least significant */
	/* dimension */
	(void) memcpy((char *) cdest, (char *) cf, copy_size * sizeof(float));
	cdest += copy_size;

	/* count the dimensions and check whether we have to go on. */
	/* the least significant dimension is omitted, because it is already */
	/* copied */
	stop = TRUE;
	for (i=u_dim-2; i>=0; i--)
	{
	    c[i]++;
	    if (c[i] == size_coord[i])
		c[i] = 0;
	    else
	    {
		stop = FALSE;
		break;
	    }
	}
    } while (!stop);

    /* all done, return results */
    *data = npu_subpat;
    if (entries != (int *) NULL)
	*entries = f_size;
    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_np_SetSubPat

  PURPOSE  : copy another area into a sub pattern

A sub pattern is cut out of the current pattern at position
<pos_coord> with size <size_coord>. According to <input> the input
part or the output part of the current pattern is used. 
<pos_coord> is an array of int which defines the position of the sub
pattern inside the variable sized dimensions of the pattern.
<size_coord> is an array of int which defines the size of the sub
pattern in each dimensional direction. Both arrays must contain
<input_dim> (or <output_dim>) entries (see pattern descriptor).

Example: pattern with input_fixsize 2, input_dim 2, input_dim_sizes [4 5]
(hint: the values of the pattern represent the position)

{
0.00, 0.01, 0.10, 0.11, 0.20, 0.21, 0.30, 0.31, 0.40, 0.41,
1.00, 1.01, 1.10, 1.11, 1.20, 1.21, 1.30, 1.31, 1.40, 1.41,
2.00, 2.01, 2.10, 2.11, 2.20, 2.21, 2.30, 2.31, 2.40, 2.41,
3.00, 3.01, 3.10, 3.11, 3.20, 3.21, 3.30, 3.31, 3.40, 3.41,
}

the sub pattern with <pos_coord> [1 2], <size_coord> [3 2] looks like
this:

{
1.20, 1.21, 1.30, 1.31,
2.20, 2.21, 2.30, 2.31,
3.20, 3.21, 3.30, 3.31,
}

The parameter entries returns the number of entries in the data field.

  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_SetSubPat(bool input, int *pos_coord, int *size_coord,
				float *data, int entries)
{
    int u_dim;                   /* copy of all necessary variables from */
    int u_size;                  /* pattern descriptor, depending on */
    int *u_dim_sizes;            /* <input> */
    float *u_pattern;

    int f_size;                  /* size of copy area */
    int i;
    int c[MAX_NO_OF_VAR_DIM];    /* counter for the dimensions */
    int copy_size;               /* size of copy block for each memcpy */
    float *cf;                   /* pointer into pattern (copy destination) */
    float *csource;              /* copy source */
    bool stop;                   /* TRUE if all done */
    int offset;                  /* offset in multidimensional array */

    /* check for valid pattern */
    if (np_used_pat_set_entries == 0)
	return KRERR_NO_PATTERNS;

    if (np_current_pattern == (pattern_descriptor *) NULL)
	return KRERR_NP_NO_CURRENT_PATTERN;

    /* make a copy of all pattern info to work with */
    if (input)
    {
	u_dim = np_current_pattern -> input_dim;
	u_size = np_current_pattern -> input_fixsize;
	u_dim_sizes = np_current_pattern -> input_dim_sizes;
	u_pattern = np_current_pattern -> input_pattern;
    }
    else
    {
	u_dim = np_current_pattern -> output_dim;
	u_size = np_current_pattern -> output_fixsize;
	u_dim_sizes = np_current_pattern -> output_dim_sizes;
	u_pattern = np_current_pattern -> output_pattern;
    }

    /* check whether this pattern exists or whether all is done */
    if (u_size == 0)
    {
	if (entries == 0)
	    return KRERR_NO_ERROR;
	else
	    return KRERR_NP_NO_SUCH_PATTERN;
    }

    /* calculate size of the sub pattern and check dimensions */
    f_size = u_size;
    for (i=0; i<u_dim; i++)
    {
	f_size *= size_coord[i];
	if (pos_coord[i] + size_coord[i] > u_dim_sizes[i])
	    return KRERR_NP_DIMENSION;
	c[i] = 0;
    }

    /* check whether calculated space fits the delievered data block */
    if (f_size != entries)
	return KRERR_NP_DOES_NOT_FIT;

    /* calculate size of one copy block. this includes the size of the */
    /* dimension with highest index (least significant dimension) */
    copy_size = u_size;
    if (u_dim>0)
	copy_size *= size_coord[u_dim-1];

    /* copy the sub pattern */
    csource = data;
    do
    {
	/* calculate offset in destination pattern */
	offset = 0;
	for (i=0; i<u_dim; i++)
	{
	    offset *= u_dim_sizes[i];
	    offset += pos_coord[i] + c[i];
	}
	offset *= u_size;
	cf = u_pattern + offset;

	/* copy part of the pattern. this inlcudes the least significant */
	/* dimension */
	(void) memcpy((char *) cf, (char *)csource, copy_size * sizeof(float));
	csource += copy_size;

	/* count the dimensions and check whether we have to go on. */
	/* the least significant dimension is omitted, because it is already */
	/* copied */
	stop = TRUE;
	for (i=u_dim-2; i>=0; i--)
	{
	    c[i]++;
	    if (c[i] == size_coord[i])
		c[i] = 0;
	    else
	    {
		stop = FALSE;
		break;
	    }
	}
    } while (!stop);

    /* all done, return results */
    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_np_align_sub_pos

  PURPOSE  : For a given pattern dimension size <psize> of <dim>
             dimensions and a given sub pattern size <ssize> the position
	     <spos> of the sub pattern is alligned to a valid position
	     and the ordering number of this sub pattern is returned
	     in <n>. The shift pattern given in <sstep> is used to
	     find valid allignment positions

  RETURNS  : TRUE if succesfull, FALSE if inconsistent parameters

             <n> starts with 0 and ends with <number of possible
	     positions> - 1
	     <spos> gives the new aligned position

  NOTES    : internal function

  UPDATE   : 
******************************************************************************/
static bool kr_np_align_sub_pos(int dim, int *n, int *psize, int *ssize, 
				int *sstep, int *spos)
{
    int ns[MAX_NO_OF_VAR_DIM];
    register int i;
    register int ts = 0;

    for (i=0; i<dim; i++)
    {
	/* calculate how much steps could be made in each dimension */
	ns[i] = (psize[i] - ssize[i] + sstep[i]) / sstep[i];
	if (ns[i] == 0)
	    return FALSE;

	/* align the position of this dimension */
	spos[i] -= spos[i] % sstep[i];
	if (spos[i]+ssize[i] >= psize[i]+1)
	    spos[i] = 0;

	/* add the position of this dimension to the absolute position */
	ts *= ns[i];
	ts += spos[i]/sstep[i];
    }

    *n = ts;
    return TRUE;
}

/*****************************************************************************
  FUNCTION : kr_np_gen_sub_pos

  PURPOSE  : For a given pattern dimension size <psize> of <dim>
             dimensions and a given sub pattern size <ssize> the position
	     <spos> of the <n>th sub pattern is calculated. The shift
	     pattern given in <sstep> is used to move sub pattern over
	     the pattern.

	     If <count> is TRUE, only the number of possible positions
	     is determined and returned in <n> if at least 1 valid
	     position exists. <spos> is of no effect and may be NULL.

  RETURNS  : TRUE if the <n>th subpattern exists or if <count> is TRUE
             and at least 1 valid position exists, FALSE if <n> < 0.
	     If <n> is higher than the available number of subpattern, a 
	     wraparound occurs.

             <n> starts with 0 and ends with <number of possible
	     positions> - 1 or returns number of possible positions.

  NOTES    : internal function

  UPDATE   : 
******************************************************************************/
static bool kr_np_gen_sub_pos(int dim, int *n, int *psize, int *ssize, 
			      int *sstep, int *spos, bool count)
{
    int ns[MAX_NO_OF_VAR_DIM];
    int i;
    int ts;
    int nn;

    nn = *n;

    /* calculate how much steps could be made in each dimension */
    /* and the total number of positions ts (define the bases of a */
    /* multi base numerative system and determine the highest */
    /* representable number) */
    ts = 1;
    for (i=dim-1; i>=0; i--)
    {
	ns[i] = (psize[i] - ssize[i] + sstep[i]) / sstep[i];
	if (ns[i] == 0)
	    return FALSE;
	ts *= ns[i];
    }

    /* check whether this is all what we want to do now */
    if (count)
    {
	*n = ts;
	return TRUE;
    }
	
    /* check range of requested step position */ 
    if (nn<0)
	return FALSE;

    /* if requested position is higher than available positions, perform */
    /* wraparaound (this is usefull/necessary for pattern without subpattern */
    nn = nn%ts;

    /* calculate step position of the <n>th sub pattern (like counting */
    /* in a multi base numerative system) */
    for (i=dim-1; i>=0; i--)
    {
	spos[i] = (nn % ns[i]) * sstep[i];
	nn /= ns[i];
    }
    
    return TRUE;
}

/*****************************************************************************
  FUNCTION : kr_np_allocate_pat_train_entries

  PURPOSE  : allocate or reallocate an array which will later include
             the sorted or shuffled pattern order (during training)
  RETURNS  : FALSE if malloc fails
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static bool kr_np_allocate_pat_train_entries(int n)
{
    if (n > np_pat_train_size)
    {
	if (np_pat_train_order != (int *) NULL)
	    free(np_pat_train_order);
	np_pat_train_size = 0;
	np_pat_train_order = (int *) malloc(n * sizeof(int));
	if (np_pat_train_order == (int *) NULL && n != 0)
	    return FALSE;
	np_pat_train_size = n;
	np_pat_train_valid = FALSE;
    }
    return TRUE;
}

/*****************************************************************************
  FUNCTION : kr_np_allocate_sub_pat_train_entries

  PURPOSE  : allocate or reallocate an array which will later include
             the sorted or shuffled order of the sub pattern of the
	     current pattern
  RETURNS  : FALSE if malloc fails
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static bool kr_np_allocate_sub_pat_train_entries(int n)
{
    if (n > np_sub_pat_train_size)
    {
	if (np_sub_pat_train_order != (int *) NULL)
	    free(np_sub_pat_train_order);
	np_sub_pat_train_size = 0;
	np_sub_pat_train_order = (int *) malloc(n * sizeof(int));
	if (np_sub_pat_train_order == (int *) NULL && n != 0)
	    return FALSE;
	np_sub_pat_train_size = n;
	np_sub_pat_train_valid = FALSE;
    }
    return TRUE;
}

/*****************************************************************************
  FUNCTION : kr_np_order_pat_entries

  PURPOSE  : Fills the allocated array for the pattern ordering with
             increasing numbers if patterns are sorted or with a
	     random permutation if patterns are shuffled.
	     <start> and <end> define the first and last pattern
	     number to be used
  RETURNS  : nothing
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static void kr_np_order_pat_entries(int start, int end)
{
    static bool shuffle;
    static int c_start;
    static int c_end;

    register int i;
    register int *fp;
    register int h;
    register int s;
    register int n;

    if (!np_pat_train_valid || c_start != start || c_end != end 
	|| shuffle != npui_shuffle_pattern)
    {
	fp = np_pat_train_order;
	for (i=start; i<=end; i++)
	    *fp++ = i;
	np_pat_train_valid = TRUE;
	np_pat_train_number = end - start + 1;
	c_start = start;
	c_end = end;
	shuffle = npui_shuffle_pattern;
    }

    if (shuffle)
    {
	n = np_pat_train_number;
	fp = np_pat_train_order;
	for (i=0; i<n; i++)
	{
	    s = lrand48() % (n-i);
	    h = *fp;
	    *fp++ = np_pat_train_order[s+i];
	    np_pat_train_order[s+i] = h;
	}
    }
}

/*****************************************************************************
  FUNCTION : kr_np_order_sub_pat_entries

  PURPOSE  : Fills the allocated array for the sub pattern ordering with
             increasing numbers if sub patterns are sorted or with a
	     random permutation if sub patterns are shuffled.
	     <start> and <end> define the first and last sub pattern
	     number to be used
  RETURNS  : nothing
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static void kr_np_order_sub_pat_entries(int start, int end)
{
    static bool shuffle;
    static int c_start;
    static int c_end;

    register int i;
    register int *fp;
    register int h;
    register int s;
    register int n;

    if (!np_sub_pat_train_valid || c_start != start || c_end != end 
	|| shuffle != npui_shuffle_sub_pattern)
    {
	fp = np_sub_pat_train_order;
	for (i=start; i<=end; i++)
	    *fp++ = i;
	np_sub_pat_train_valid = TRUE;
	np_sub_pat_train_number = end - start + 1;
	c_start = start;
	c_end = end;
	shuffle = npui_shuffle_sub_pattern;
    }

    if (shuffle)
    {
	n = np_sub_pat_train_number;
	fp = np_sub_pat_train_order;
	for (i=0; i<n; i++)
	{
	    s = lrand48() % (n-i);
	    h = *fp;
	    *fp++ = np_sub_pat_train_order[s+i];
	    np_sub_pat_train_order[s+i] = h;
	}
    }
}

/*****************************************************************************
  FUNCTION : kr_np_DefineSubPatternOrdering

  PURPOSE : definition of generation of sub pattern during training

  The shape and ordering of sub patterns for training and display is
  defined.  <pat_set> specifies the pattern set to use. The flag
  <input> determines whether input or output sub patterns are to be
  defined. The array size_coord spezifies the shape of the sub pattern
  like in kr_np_GetSubPat. The array incr_coord specifies how sub
  patterns are generated from the whole pattern by shifting the shape
  over this pattern. Each value in this array gives an incremental
  offset for one dimensional direction. The start position is at [0 0
  0 ...]. New positions are generated by adding the rightmost value of
  incr_coord to the old position. If an overflow in this dimension
  occurs, this coordinate is reset to 0 and the next position to the
  left is incremented (and so on ...). After all sub patterns of one
  pattern are generated the next pattern is used.  Depending on
  npui_shuffle_pattern and npui_shuffle_sub_pattern shuffling is
  activated.

  RETURNS  : kernel error code
  NOTES    : internal use only

  UPDATE   : 
******************************************************************************/
static krui_err kr_np_DefineSubPatternOrdering(int pat_set, bool input, 
					       int *size_coord, 
					       int *incr_coord)
{
    krui_err err_code;
    pattern_descriptor *p;

    if (np_used_pat_set_entries == 0)
	return KRERR_NO_PATTERNS;

    if (pat_set < 0 || pat_set >= np_used_pat_set_entries ||
	!np_pat_set_used[pat_set])
	return KRERR_NP_NO_SUCH_PATTERN_SET;

    err_code = kr_np_GetDescriptor(pat_set, 0, &p);
    if (err_code != KRERR_NO_ERROR)
	return err_code;

    if (input)
    {
	memcpy((char *) np_t_insize, (char *) size_coord, 
	       p->input_dim * sizeof(int));
	memcpy((char *) np_t_instep, (char *) incr_coord, 
	       p->input_dim * sizeof(int));
    }
    else
    {
	memcpy((char *) np_t_outsize, (char *) size_coord, 
	       p->input_dim * sizeof(int));
	memcpy((char *) np_t_outstep, (char *) incr_coord, 
	       p->input_dim * sizeof(int));
    }

    np_pat_train_valid = FALSE;
    np_sub_pat_train_valid = FALSE;

    return KRERR_NO_ERROR;
}

/*****************************************************************************
  FUNCTION : kr_np_showPatternSTD

  PURPOSE  :  According to the mode kr_np_showPatternSTD stores the current
              Pattern/sub Pattern into the units activation (and/or output) 
	      values.
              The modes are:
              - OUTPUT_NOTHING
              store input pattern into input units activations
              - OUTPUT_ACT
              store input pattern into input units activations and
              store output pattern into output units activations
              - OUTPUT_OUT
              store input pattern into input units activations,
              store output pattern into output units activations and
              update output units output
  RETURNS  :  kernel error code
  NOTES    :  See include file glob_typ.h for mode constants.
              internal use only
  UPDATE   : 
******************************************************************************/
static krui_err kr_np_showPatternSTD(int mode)
{
    register struct Unit *unit_ptr;
    float *in_pat, *out_pat;
    pattern_descriptor *pattern;
    int in_pat_size, out_pat_size;

    /* make the pattern to become the current pattern */ 
    if ((KernelErrorCode = 
	 kr_np_GetDescriptor(npui_pat_sets[npui_curr_pat_set],
			     npui_curr_pattern-1, &pattern)) 
	!= KRERR_NO_ERROR)
	return KernelErrorCode;
  
    /*  calc. startaddress of patterns  */
    if ((KernelErrorCode = 
	 kr_np_GetSubPat(TRUE, npui_inpos, npui_insize, &in_pat, 
			 &in_pat_size)) 
	!= KRERR_NO_ERROR)
	return KernelErrorCode;

    if ((KernelErrorCode = 
	 kr_np_GetSubPat(FALSE, npui_outpos, npui_outsize, &out_pat, 
			 &out_pat_size)) 
	!= KRERR_NO_ERROR)
	return KernelErrorCode;

    /* calculate the units, ignore error code concerning old pattern format */
    (void) kr_IOCheck();
    KernelErrorCode = KRERR_NO_ERROR;

    /* check whether pattern fits the network, do not complain about */
    /* missing output pattern */
    if (NoOfInputUnits != in_pat_size ||
	(NoOfOutputUnits != out_pat_size && out_pat_size != 0))
	return KernelErrorCode = KRERR_NP_DOES_NOT_FIT;

    switch (mode)
    {
      case  OUTPUT_NOTHING:
	FOR_ALL_UNITS( unit_ptr )
	    if ( IS_INPUT_UNIT( unit_ptr ) && UNIT_IN_USE( unit_ptr ))
		if (in_pat_size--)
		    unit_ptr->act = *in_pat++;
	break;

      case  OUTPUT_ACT:
	FOR_ALL_UNITS( unit_ptr )
	    if UNIT_IN_USE( unit_ptr )
	    {
		if IS_INPUT_UNIT( unit_ptr )
		    unit_ptr->act = *in_pat++;
		if (IS_OUTPUT_UNIT( unit_ptr ) && out_pat_size != 0)
		    unit_ptr->act = *out_pat++;
	    }
	break;

      case  OUTPUT_OUT:
	FOR_ALL_UNITS( unit_ptr )
	    if UNIT_IN_USE( unit_ptr )
	    {
		if IS_INPUT_UNIT( unit_ptr )
		    unit_ptr->act = *in_pat++;
		if (IS_OUTPUT_UNIT( unit_ptr ) && out_pat_size != 0)
		{
		    unit_ptr->act = *out_pat++;
		    if (unit_ptr->out_func == NULL)
			/*  Identity Function   */
			unit_ptr->Out.output = unit_ptr->act;
		    else
			unit_ptr->Out.output = 
			    (*unit_ptr->out_func) (unit_ptr->act);
		}
	    }
	break;
    
      default:
	KernelErrorCode = KRERR_PARAMETERS;
    }

    return( KernelErrorCode );
}

/*****************************************************************************
  FUNCTION : kr_np_modifyPattern

  PURPOSE  : The current activation of the input and output units is used to
             modify the current sub pattern.

  RETURNS  : kernel error code
  NOTES    : internal use only
  UPDATE   : 
******************************************************************************/
static krui_err kr_np_modifyPattern(void)
{
    register struct Unit *unit_ptr;
    float *in_pat, *out_pat;
    float *ip, *op;
    pattern_descriptor *pattern;

    /* make the pattern to become the current pattern */ 
    if ((KernelErrorCode = 
	 kr_np_GetDescriptor(npui_pat_sets[npui_curr_pat_set],
			     npui_curr_pattern-1, &pattern)) 
	!= KRERR_NO_ERROR)
	return KernelErrorCode;
  
    /* calculate the units, ignore error code concerning old pattern format */
    (void) kr_IOCheck();
    KernelErrorCode = KRERR_NO_ERROR;

    /* allocate memory to hold the sub pattern */
    in_pat = (float *) malloc(NoOfInputUnits * sizeof(float));
    out_pat = (float *) malloc(NoOfOutputUnits * sizeof(float));
    if ((in_pat == (float *) NULL && NoOfInputUnits != 0) 
	|| (out_pat == (float *) NULL && NoOfOutputUnits != 0))
	return KRERR_INSUFFICIENT_MEM;

    /* copy unit activations into sub pattern area */
    ip = in_pat;
    op = out_pat;

    FOR_ALL_UNITS(unit_ptr)
        if (UNIT_IN_USE(unit_ptr))
	{
	    if (IS_INPUT_UNIT(unit_ptr))
		*ip++ = unit_ptr->act;
	    if (IS_OUTPUT_UNIT(unit_ptr))
		*op++ =  unit_ptr->act;
        }

    KernelErrorCode = KRERR_NO_ERROR;

    /* test whether pattern already contains data. */
    /* allocate space if necessary (for new allocated patterns) */
    if (pattern -> input_fixsize == 0)
    {
	pattern -> input_fixsize = NoOfInputUnits;
	pattern -> output_fixsize = NoOfOutputUnits;
	pattern -> input_dim = 0;
	pattern -> output_dim = 0;
	KernelErrorCode = kr_np_AllocatePattern(pattern, TRUE);
	if (KernelErrorCode == KRERR_NO_ERROR)
	    KernelErrorCode = kr_np_AllocatePattern(pattern, FALSE);
    }

    /* modify the copied sub pattern */
    if (KernelErrorCode == KRERR_NO_ERROR)
    {
	KernelErrorCode = kr_np_SetSubPat(TRUE, npui_inpos, npui_insize,
					  in_pat, NoOfInputUnits);
    }

    if (KernelErrorCode == KRERR_NO_ERROR)
    {
	KernelErrorCode = kr_np_SetSubPat(FALSE, npui_outpos, npui_outsize,
					  out_pat, NoOfOutputUnits);
    }

    /* free the memory */
    if (in_pat != (float *) NULL)
	free(in_pat);
    if (out_pat != (float *) NULL)
	free(out_pat);

    return KernelErrorCode;
}

/*****************************************************************************
END OF FILE
******************************************************************************/
