/* 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);
/* 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.