/*---------------------------------------------------------------------------*/
void PrintNormMatch(FILE *File,
                    int NumParams,
                    PROTOTYPE *Proto,
                    FEATURE Feature) {
/*
 **	Parameters:
 **		File		open text file to dump match debug info to
 **		NumParams	# of parameters in proto and feature
 **		Proto[]		array of prototype parameters
 **		Feature[]	array of feature parameters
 **	Globals: none
 **	Operation: This routine dumps out detailed normalization match info.
 **	Return: none
 **	Exceptions: none
 **	History: Wed Jan  2 09:49:35 1991, DSJ, Created.
 */
  int i;
  FLOAT32 ParamMatch;
  FLOAT32 TotalMatch;

  for (i = 0, TotalMatch = 0.0; i < NumParams; i++) {
    ParamMatch = ((ParamOf (Feature, i) - Mean (Proto, i)) /
      StandardDeviation (Proto, i));

    fprintf (File, " %6.1f", ParamMatch);

    if (i == CharNormY || i == CharNormRx)
      TotalMatch += ParamMatch * ParamMatch;
  }
  fprintf (File, " --> %6.1f (%4.2f)\n",
    TotalMatch, NormEvidenceOf (TotalMatch));

}                                /* PrintNormMatch */
FLOAT32 Classify::ComputeNormMatch(CLASS_ID ClassId, FEATURE Feature,
                                   BOOL8 DebugMatch) {
/*
 **	Parameters:
 **		ClassId		id of class to match against
 **		Feature		character normalization feature
 **		DebugMatch	controls dump of debug info
 **	Globals:
 **		NormProtos	character normalization prototypes
 **	Operation: This routine compares Features against each character
 **		normalization proto for ClassId and returns the match
 **		rating of the best match.
 **	Return: Best match rating for Feature against protos of ClassId.
 **	Exceptions: none
 **	History: Wed Dec 19 16:56:12 1990, DSJ, Created.
 */
  LIST Protos;
  FLOAT32 BestMatch;
  FLOAT32 Match;
  FLOAT32 Delta;
  PROTOTYPE *Proto;
  int ProtoId;

  /* handle requests for classification as noise */
  if (ClassId == NO_CLASS) {
    /* kludge - clean up constants and make into control knobs later */
    Match = (Feature->Params[CharNormLength] *
      Feature->Params[CharNormLength] * 500.0 +
      Feature->Params[CharNormRx] *
      Feature->Params[CharNormRx] * 8000.0 +
      Feature->Params[CharNormRy] *
      Feature->Params[CharNormRy] * 8000.0);
    return (1.0 - NormEvidenceOf (Match));
  }

  BestMatch = MAX_FLOAT32;
  Protos = NormProtos->Protos[ClassId];

  if (DebugMatch) {
    cprintf ("\nFeature = ");
    WriteFeature(stdout, Feature);
  }

  ProtoId = 0;
  iterate(Protos) {
    Proto = (PROTOTYPE *) first_node (Protos);
    Delta = Feature->Params[CharNormY] - Proto->Mean[CharNormY];
    Match = Delta * Delta * Proto->Weight.Elliptical[CharNormY];
    Delta = Feature->Params[CharNormRx] - Proto->Mean[CharNormRx];
    Match += Delta * Delta * Proto->Weight.Elliptical[CharNormRx];

    if (Match < BestMatch)
      BestMatch = Match;

    if (DebugMatch) {
      cprintf ("Proto %1d = ", ProtoId);
      WriteNFloats (stdout, NormProtos->NumParams, Proto->Mean);
      cprintf ("      var = ");
      WriteNFloats (stdout, NormProtos->NumParams,
        Proto->Variance.Elliptical);
      cprintf ("    match = ");
      PrintNormMatch (stdout, NormProtos->NumParams, Proto, Feature);
    }
    ProtoId++;
  }
  return (1.0 - NormEvidenceOf (BestMatch));
}                                /* ComputeNormMatch */