Mapping BNumbers to Quantifiers

The standard numerical format in SWAT is the BNumber, ranging from -1 to +1. This is a warped number, representing actual values in a bell curve. For example, let’s talk about an actor’s Good_Bad value. A BNumber value of 0.0 does not mean that the actor has no Good; it means that the actor has average Good_Bad. A value of 0.9 means that the actor has Good_Bad of such high value that very few people can match it. A value of 1.0 represents infinite Good_Bad. 

Currently BNumbers are mapped linearly to Quantifiers. Since there are only seven quantifier values (3 positive, 3 negative, one zero), the mapping uses the following formula:

quantifierIndex = (int)(3 * (value + 1));

This is how this mapping looks:

BellCurveQuantifierIndexes

This exposes the problem: the extreme values are rarely invoked. This suggests that I should convert the BNumber to a regular Number using my standard transform algorithm:

if (boundedNumber > 0.0f) {
   if (boundedNumber>Utils.MAXI_VALUE)
      boundedNumber = Utils.MAXI_VALUE;
   return (1.0f / (1.0f - boundedNumber)) -1.0f;
}
else
{
   if (boundedNumber<Utils.MINI_VALUE)
      boundedNumber = Utils.MINI_VALUE;
   return 1.0f - (1.0f / (1.0f + boundedNumber));
}

The problem with this approach is that it can return values approaching ±infinity. This would require a series of IF-statements to properly handle; if I’m going to use such a method, I might as well just specify it directly, like so:

if (value < -0.6)
   quantifierIndex = 0;

if ((value >= -0.6) & (value < -0.3))
   quantifierIndex = 1;

if ((value >= -0.3) & (value < -0.1))
   quantifierIndex = 2;

if ((value >= -0.1) & (value < +0.1))
   quantifierIndex = 3;

if ((value >= +0.1) & (value < +0.3))
   quantifierIndex = 4;

if ((value >= +0.3) & (value < +0.6))
   quantifierIndex = 5;

if (value >= +0.6)
   quantifierIndex = 6;

This yields a better bell curve:

Perhaps you’ll object that the areas underneath the curve are still not equal. That’s not quite the case; to demonstrate this, I prepared a graph of the actual function, and here’s what I got:

BNumber2Number

This came as quite a shock; I had not realized that the curve had such a blocky shape. However, on contemplation, I realize that in fact this shape is necessary. The reason comes from two simple certainties: first, the slope of the graph must be vertical at each end, and second, the slope must be zero at the center. The former is true because that is the only way to map the entire number line (from - to +) into the region -1 to +1. The latter is true because I require a continuous first derivative on the graph lest we get strange jumps in behavior around 0. 

However, this is not the only shape that meets my requirement; here’s another:

HalfCircle

However, after much screwing around with the math, I’ve decided that it really doesn’t matter that much; the important thing is to get a roughly equal distribution of values.