scales.h

/* This is the header file for the Scales module.  It is also included by the
   Cases, Adjuster and Odometer modules. */

/* external functions */

extern void
Zero_Weight(
      weight_type *weight_pointer);

extern void
Write_Weights_Table(
      file weights_stream,
      area *area_pointer);

extern void
Weight_Attributes(
      file weights_stream,
      file log_stream,
      case_law_specification case_law,
      boolean inputable_latex);

scales.c

/* This is the implementation file for the Scales module. */

#include <stdio.h>
#include <stdlib.h>
#include "shyster.h"
#include "cases.h"
#include "scales.h"

static void
error_exit(
      file stream,
      const string message)
{
   Write_Error_Message_And_Exit(stream, "Scales", message);
}

static void
warning(
      file stream,
      const string message)
{
   Write_Warning_Message(stream, "Scales", message, Top_Level);
}

extern void
Zero_Weight(
      weight_type *weight_pointer)

/* Sets the weight pointed to by weight_pointer to zero. */

{
   weight_pointer->infinite = FALSE;
   weight_pointer->finite = 0.0;
}

static boolean
calculate_mean_and_centroids(
      file log_stream,
      result *result_head,
      attribute *attribute_pointer)

/* Calculates the mean (and, for each result, centroid element) for the
   attribute pointed to by attribute_pointer.  Returns TRUE, iff the
   attribute has known values. */

{
   result *result_pointer;
   kase *case_pointer;
   matrix_element *matrix_pointer;
   centroid_element *centroid_pointer;
   floating_point sum,
      temp;
   cardinal count,
      total_count = 0;

   attribute_pointer->mean = 0.0;
   matrix_pointer = attribute_pointer->matrix_head;

   /* for every result ... */

   for (result_pointer = result_head; result_pointer != NULL;
         result_pointer = result_pointer->next) {

      sum = 0.0;
      count = 0;

      /* sum the attribute values for this attribute for each case with this
         result */

      for (case_pointer = result_pointer->case_head;
            (case_pointer != NULL) && (matrix_pointer != NULL);
            case_pointer = case_pointer->next) {
         if (Attribute_Value(matrix_pointer->attribute_value, &temp)) {
            sum += temp;
            count++;
         }
         matrix_pointer = matrix_pointer->attribute_next;
      }

      if (result_pointer->centroid_head == NULL) {

         /* allocate memory for this centroid element (the first in the list) */

         if ((result_pointer->centroid_head =
                     (centroid_element *) malloc(sizeof(centroid_element))) == NULL)
            error_exit(log_stream, "malloc failed during centroid building");
         centroid_pointer = result_pointer->centroid_head;

      } else {

         /* go to the end of the centroid */

         for (centroid_pointer = result_pointer->centroid_head;
               centroid_pointer->next != NULL;
               centroid_pointer = centroid_pointer->next);

         /* allocate memory for this centroid element */

         if ((centroid_pointer->next =
                     (centroid_element *) malloc(sizeof(centroid_element))) == NULL)
            error_exit(log_stream, "malloc failed during centroid building");
         centroid_pointer = centroid_pointer->next;
      }

      if (!(centroid_pointer->unknown = count == 0))
         centroid_pointer->value = sum / (floating_point) count;
      centroid_pointer->next = NULL;

      attribute_pointer->mean += sum;
      total_count += count;
   }
   if (total_count == 0)

      /* the attribute has no known values */

      return FALSE;

   else {

      attribute_pointer->mean = attribute_pointer->mean / (floating_point) total_count;
      return TRUE;
   }
}

static void
calculate_weights(
      file log_stream,
      area *area_pointer)

/* Calculates the weight of each attribute in the area pointed to by
   area_pointer.  (The weight is the inverse of the variance of the attribute
   values.) */

{
   attribute *attribute_pointer;
   cardinal count;
   floating_point variance;
   char message[Max_Error_Message_Length];

   count = 1;

   /* for every attribute ... */

   for (attribute_pointer = area_pointer->attribute_head; attribute_pointer != NULL;
         attribute_pointer = attribute_pointer->next) {

      variance = 0.0;
      Zero_Weight(&attribute_pointer->weight);

      if (!calculate_mean_and_centroids(log_stream, area_pointer->result_head,
                  attribute_pointer)) {

         /* the attribute has no known values */

         sprintf(message, "A%u in %s area has no weight", count,
               area_pointer->identifier);
         warning(log_stream, message);

      } else {

         /* the attribute has known values, so determine its weight */

         variance = attribute_pointer->mean -
               (attribute_pointer->mean * attribute_pointer->mean);

         if (attribute_pointer->weight.infinite = Is_Zero(variance)) {
            sprintf(message,
                  "A%u in %s area has infinite weight", count,
                  area_pointer->identifier);
            warning(log_stream, message);
            area_pointer->infinite_weight = TRUE;
         } else
            attribute_pointer->weight.finite = 1 / variance;
      }
      count++;
   }
}

static void
calculate_result_weights(
      file log_stream,
      area *area_pointer)

/* Calculates the result weight for each attribute in the area pointed to by
   area_pointer.  (The result weight is the inverse of the variance of the
   attribute values for that result.) */

{
   attribute *attribute_pointer;
   result *result_pointer;
   centroid_element *centroid_pointer;
   cardinal count;
   floating_point variance;
   weight_list_element *weights_pointer;
   boolean zero_result_weight = FALSE;
   char message[Max_Error_Message_Length];

   /* for every attribute ... */

   for (attribute_pointer = area_pointer->attribute_head; attribute_pointer != NULL;
         attribute_pointer = attribute_pointer->next)

      /* for every result ... */

      for (result_pointer = area_pointer->result_head; result_pointer != NULL;
            result_pointer = result_pointer->next) {

         /* find, in the centroid for this result, the mean for this
            attribute */

         centroid_pointer = result_pointer->centroid_head;
         for (count = 1; count < attribute_pointer->number; count++)
            centroid_pointer = centroid_pointer->next;

         if (attribute_pointer->weights_head == NULL) {

            /* allocate memory for this result weight (the first in the list) */

            if ((attribute_pointer->weights_head =
                        (weight_list_element *) malloc(sizeof(weight_list_element))) ==
                  NULL)
               error_exit(log_stream, "malloc failed during weights building");
            weights_pointer = attribute_pointer->weights_head;

         } else {

            /* allocate memory for this result weight */

            if ((weights_pointer->next =
                        (weight_list_element *) malloc(sizeof(weight_list_element))) ==
                  NULL)
               error_exit(log_stream, "malloc failed during weights building");
            weights_pointer = weights_pointer->next;
         }

         Zero_Weight(&weights_pointer->weight);

         if (centroid_pointer->unknown &&
               (attribute_pointer->weight.infinite ||
                     !Is_Zero(attribute_pointer->weight.finite)))

            /* the result weight is zero, but the weight for the whole
               attribute is not zero, so ensure a warning is issued later (if
               the weight for the whole attribute is zero, a warning has
               already been issued) */

            zero_result_weight = TRUE;

         else if (attribute_pointer->weight.infinite)

            /* this attribute has infinite weight, so make this result weight
               infinite too */

            weights_pointer->weight.infinite = TRUE;

         else {

            /* the attribute has known values, so determine the result weight */

            variance = centroid_pointer->value -
                  (centroid_pointer->value * centroid_pointer->value);

            if (!(weights_pointer->weight.infinite = Is_Zero(variance)))
               weights_pointer->weight.finite = 1 / variance;
         }
         weights_pointer->next = NULL;
      }
   if (zero_result_weight) {
      sprintf(message,
            "one or more attributes in %s area has a zero result weight",
            area_pointer->identifier);
      warning(log_stream, message);
   }
}

extern void
Write_Weights_Table(
      file weights_stream,
      area *area_pointer)

/* Writes a table of weights for the area pointed to by area_pointer. */

{
   result *result_pointer;
   attribute *attribute_pointer;
   centroid_element *centroid_pointer;
   cardinal centroid_count;
   weight_list_element *weights_pointer;

   Indent(weights_stream, 1);
   fprintf(weights_stream, "\\begin{small}\n");
   Indent(weights_stream, 2);
   fprintf(weights_stream,
         "\\begin{tabular}{|c|*{%u}{c@{\\hspace{%s}}c@{\\hspace{%s}}r|}}"
         "\\hline\n", area_pointer->number_of_results + 1,
         Column_Separation, Column_Separation);
   Indent(weights_stream, 3);
   fprintf(weights_stream, "&");

   /* write the column headings */

   for (result_pointer = area_pointer->result_head; result_pointer != NULL;
         result_pointer = result_pointer->next)
      fprintf(weights_stream, "\\multicolumn{3}{c|}{%s %s}&",
            Identifier_Font, result_pointer->identifier);
   fprintf(weights_stream, "&&\\\\\n");
   Indent(weights_stream, 3);
   fprintf(weights_stream, "\\smash{\\raisebox{%s}{\\it Attr.}}&",
         Raise_Height);
   for (result_pointer = area_pointer->result_head; result_pointer != NULL;
         result_pointer = result_pointer->next)
      fprintf(weights_stream,
            "$\\mu$&$\\sigma^2$&\\multicolumn{1}{c|}{$w$}&");
   fprintf(weights_stream,
         "\\smash{\\raisebox{%s}{$\\mu$}}&"
         "\\smash{\\raisebox{%s}{$\\sigma^2$}}&"
         "\\multicolumn{1}{c|}{\\smash{\\raisebox{%s}{$w$}}}"
         "\\\\\\hline\\hline", Raise_Height, Raise_Height, Raise_Height);

   /* for every attribute ... */

   for (attribute_pointer = area_pointer->attribute_head; attribute_pointer != NULL;
         attribute_pointer = attribute_pointer->next) {

      weights_pointer = attribute_pointer->weights_head;
      fprintf(weights_stream, "\n");
      Indent(weights_stream, 3);
      fprintf(weights_stream, "$A_{%u}$&", attribute_pointer->number);

      /* for every result ... */

      for (result_pointer = area_pointer->result_head; result_pointer != NULL;
            result_pointer = result_pointer->next) {

         /* find, in the centroid for this result, the mean for this
            attribute */

         centroid_pointer = result_pointer->centroid_head;
         for (centroid_count = 1; centroid_count < attribute_pointer->number;
               centroid_count++)
            centroid_pointer = centroid_pointer->next;

         /* write the mean and the variance for this result and attribute */

         if (centroid_pointer->unknown)
            fprintf(weights_stream, "\\footnotesize?&\\footnotesize?&");
         else {
            Write_Floating_Point(weights_stream, centroid_pointer->value, Empty_String);
            fprintf(weights_stream, "&");
            Write_Floating_Point(weights_stream, centroid_pointer->value -
                  (centroid_pointer->value * centroid_pointer->value), Empty_String);
            fprintf(weights_stream, "&");
         }

         /* write the result weight for this attribute */

         if (weights_pointer->weight.infinite)
            fprintf(weights_stream, "\\multicolumn{1}{c|}{$\\infty$}");
         else if (Is_Zero(weights_pointer->weight.finite))
            fprintf(weights_stream, "\\multicolumn{1}{c|}{--}");
         else
            Write_Floating_Point(weights_stream, weights_pointer->weight.finite,
                  Empty_String);
         fprintf(weights_stream, "&");

         weights_pointer = weights_pointer->next;
      }

      /* write the mean and the variance for this attribute */

      Write_Floating_Point(weights_stream, attribute_pointer->mean, Empty_String);
      fprintf(weights_stream, "&");
      Write_Floating_Point(weights_stream, attribute_pointer->mean -
            (attribute_pointer->mean * attribute_pointer->mean), Empty_String);
      fprintf(weights_stream, "&");

      /* write the weight for this attribute */

      if (attribute_pointer->weight.infinite)
         fprintf(weights_stream, "\\multicolumn{1}{c|}{$\\infty$}");
      else if (Is_Zero(attribute_pointer->weight.finite))
         fprintf(weights_stream, "\\multicolumn{1}{c|}{--}");
      else
         Write_Floating_Point(weights_stream, attribute_pointer->weight.finite,
               Empty_String);
      fprintf(weights_stream, "\\\\");
   }
   fprintf(weights_stream, "\\hline\n");
   Indent(weights_stream, 2);
   fprintf(weights_stream, "\\end{tabular}\n");
   Indent(weights_stream, 1);
   fprintf(weights_stream, "\\end{small}\n\n");
}

extern void
Weight_Attributes(
      file weights_stream,
      file log_stream,
      case_law_specification case_law,
      boolean inputable_latex)

/* Calculates the weights for each area in the specification case_law, and
   writes a table of weights for each area to weights_stream (if it is not
   NULL).  Writes LaTeX code that can be included in another LaTeX document
   (i.e. not stand-alone code), if inputable_latex is TRUE. */

{
   area *area_pointer;

   if (weights_stream != NULL) {
      fprintf(weights_stream, "%% Weights file\n\n");
      Write_LaTeX_Header(weights_stream, inputable_latex);
   }

   /* for every area ... */

   for (area_pointer = case_law.area_head; area_pointer != NULL;
         area_pointer = area_pointer->next) {

      if (weights_stream != NULL)
         fprintf(weights_stream, "%s{%s area}\n\n", Heading,
               area_pointer->identifier);

      area_pointer->infinite_weight = FALSE;
      calculate_weights(log_stream, area_pointer);
      calculate_result_weights(log_stream, area_pointer);

      if (weights_stream != NULL)
         Write_Weights_Table(weights_stream, area_pointer);
   }
   if (weights_stream != NULL)
      Write_LaTeX_Trailer(weights_stream, inputable_latex);
}

Other SHYSTER modules: Shyster, Statutes, Cases, Tokenizer, Parser, Dumper, Checker, Adjuster, Consultant, Odometer and Reporter.