/*
# proc: kl_premult - does necessary premultiplication ahead of the KL_transform
# proc:              call. Gives efficiency.
# proc: kl_transform - calculate the KL transform of 32x32 binary images
# proc:
*/

#include <stdio.h>
#include <stdlib.h>

#define ES2 	1024

/* performs the KL transform of binary 32 x 32 mis images  	*/
/* from +1,-1 binary images a mean vector is subtracted 	*/
/* the result is projected onto an eigenvector set  		*/
/* the code is a little more cryptic than would be the case for */
/* for grey level images since large efficiency gains are 	*/
/* available for binary data 					*/

/* speed is data dependent - faster for fewer true ink pixels 	*/
/* and faster for processing many mis files since some 		*/
/* pre processing is done to the eigenvector and mean 		*/

/* The KL transform is v = \Psi^{T} (u - \mu) 			*/
/*                       = \Psi^{T} u  - \Psi^{T} \mu 		*/
/* the second product is all float point stuff 			*/
/* the first is the binary add or subtract dot product bit 	*/




/* Projects the 1 byte per pixel two level image "data" onto the KL 	*/
/* basis "evts" then subtracts the KL transform of the "mean" image  	*/
/* does this for nPats images onto a subspace basis of dimension nInps 	*/
/* the feature dimensionality should not change between calls 		*/

kl_premult(nInps, mean, evts, klmu, sume)
float   *mean, *evts, **klmu, **sume;
int     nInps;
{
float *kptr, *eptr, *mptr, *sptr;
int    j, k;

   /* do some preliminary work ahead of time and only do it once */
   /* ------------------------------------------------------------ 	*/
   /* premulptiply the mean vector by the eigenvector basis 		*/
   if (((*klmu) = (float *)calloc(nInps, sizeof(float))) == NULL)
      syserr("kl_transform", "calloc", "space for transformed mean");
    for ( j = 0, kptr = (*klmu), eptr = evts ; j < nInps ; j++, kptr++ )
      for ( k = 0, mptr = mean ; k <  ES2 ; k++ )
         *kptr += *mptr++  *  *eptr++;
   /* ------------------------------------------------------------ 	*/
   /* ------------------------------------------------------------ 	*/
   if (((*sume) = (float *)calloc(nInps, sizeof(float))) == NULL)
      syserr("kl_transform", "calloc", "space for transformed mean");
    for ( j = 0, sptr = (*sume), eptr = evts ; j < nInps ; j++, sptr++ )
      for ( k = 0 ; k <  ES2 ; k++ )
         *sptr -= *eptr++;
   /* ------------------------------------------------------------ 	*/
   /* ------------------------------------------------------------ 	*/
   for ( j = 0, eptr = evts ; j < nInps ; j++, kptr++ )
      for ( k = 0 ; k <  ES2 ; k++ )
         *eptr++ *= 2.0;
   /* ------------------------------------------------------------ 	*/
}

kl_transform(data, nPats, nInps, evts, klmu, sume, klts)
float   *evts, **klts, *klmu, *sume;
char    *data;
int     nPats, nInps;
{
float *kptr, *eptr, *mptr, *sptr;
int    n, j, k;
char  *base, *bptr;

   /* --------------------------------------------------------------- 	*/
   /* allocate and initialize space for the KL transform result 	*/
   if ((*klts = (float *)malloc(nPats * nInps * sizeof(float))) == NULL)
      syserr("kl_transform", "malloc", "space for KL transforms");

   for ( n = 0, kptr = *klts ; n < nPats ; n++ )
      for ( j = 0, sptr = sume ; j < nInps ; j++ )
         *kptr++ = *sptr++;
   /* --------------------------------------------------------------- 	*/


   /* --------------------------------------------------------------- */
   /* all the time goes in this loop. Quite quick though 		 */
   for (n = 0, base = data, kptr = *klts ; n < nPats ; n++, base += ES2)
      for ( j = 0, eptr = evts ; j < nInps ; j++, kptr++ )
         for ( k = 0, bptr = base ; k <   ES2 ; k++, eptr++ )
            if (*bptr++)
               *kptr += *eptr;
   /* --------------------------------------------------------------- */


   /* --------------------------------------------------------------- */
   /* finally subtract the transformed mean from all the projections  */
   for ( n = 0, kptr = *klts ; n < nPats ; n++ )
      for ( j = 0, mptr = klmu ; j < nInps ; j++ )
         *kptr++ -= *mptr++;
   /* --------------------------------------------------------------- */
}
