Fuzzy Logic library

The fuzzy logic library, defined in Objects.ocd/Libraries.ocd/FuzzyLogic.ocd provides functionality for declaring and evaluating fuzzy logic rules and actions that can be used to deduce an action to be executed from some observations. For example, the fish uses fuzzy logic to navigate in a Clonk landscape while avoiding predators and heading towards food. To make the fuzzy logic functions available in a script, you need to include the library.

Creating a new fuzzy logic instance

The first step when working with the fuzzy logic library is to create a new instance and save it. All interface functions will be called on that instance later.
var fuzzy_logic = FuzzyLogic->Init();

Set definitions

fuzzy_logic->AddSet(string set_name, string textual_value, array [[int first_value, int assignment], [int second_value, int assignment], [int third_value, int assignment]]);
First you have to define on which sets (imagine them like categories) your logic should work. One set could e.g. be temperature and the values in the set could be {low, medium, high}.
You also have to specify what numerical values describe the textual values in the set best. For example, we could say that a temperature between -20 and 0 is clearly low and then slowly becomes less low until 20. The definition would look like this:
fuzzy_logic->AddSet("temperature", "low", [[-20, 1], [0, 1], [20, 0]]);
The assignment parameter specifies how strongly the value belongs to the set (0 or 1). Values that lie between the given three are interpolated.
Similarly, we can also add definitions for medium and high.
fuzzy_logic->AddSet("temperature", "medium", [[0, 0], [20, 1], [40, 0]]);
fuzzy_logic->AddSet("temperature", "high",   [[10, 0], [40, 1], [100, 1]]);
In a similar way, you also have to add sets for your actions (as opposed to your observations, like the temperature above). To continue our example, we will create an automatic heater control that turns the heater higher when it's cold. Let's say the heater's power can go from 0 to 100. Then we could define the following set:
fuzzy_logic->AddSet("heater", "full_power", [[80, 0], [100, 1], [100, 1]]);
fuzzy_logic->AddSet("heater", "a_little",   [[10, 0], [30, 1],  [40, 0]]);
fuzzy_logic->AddSet("heater", "off",        [[0, 1],  [0, 1],   [10, 0]]);

Rule definition

fuzzy_logic->AddRule(string/array condition, string result);
Now that we have defined our sets, we can also define rules that are based on those sets. A rule consists of one (or more) condition in the form of "<set_name>=<textual_value>" (e.g. "temperature=high") and exactly one resulting action in the same format (e.g. "heater=off"). There can be multiple different rules defined and the end result will take into account every definition. For our example above, we could define the rules as follows:
fuzzy_logic->AddRule("temperature=low",    "heater=full_power");
fuzzy_logic->AddRule("temperature=medium", "heater=a_little");
fuzzy_logic->AddRule("temperature=high",   "heater=off");

Rule operators

fuzzy_logic->And(condition1, condition2);
fuzzy_logic->Or(condition1, condition2);
fuzzy_logic->Not(condition);
A simple example like above would obviously be boring. We can also combine different conditions into one rule. Imagine we would also have defined the set window with the textual value of open. Then we could adjust our rules as follows:
fuzzy_logic->AddRule(fuzzy_logic->And("temperature=medium", fuzzy_logic->Not("window=open")), "heater=a_little");

Setting Values

fuzzy_logic->Fuzzify(string set, int value);
After we have defined all sets and rules, we need to provide values for our sets. The function Fuzzify calculates how much a value fits to the different textual values of a set (e.g. how much the value 15 belongs to the textual temperature value low). The Fuzzify function can be called an arbitrary amount of times before the next Execute.
local fuzzy_logic;
private func Construction()
{
	fuzzy_logic = FuzzyLogic->Init();
	// Define sets and rules here...
	// ...
	
	// Update temperature every second.
	AddTimer("UpdateTemperature", 30);
}

private func UpdateTemperature()
{
	fuzzy_logic->Fuzzify("temperature", GetTemperature());
}

Getting actions

proplist fuzzy_logic->Execute();
After having set all necessary values, the resulting actions according to the rules are calculated when calling Execute. The return value is a proplist with all the sets that occur in the rule definitions as results. The values of the sets are the calculated values from set definitions.
// Called regularly!
private func ExecuteActions()
{
	// Calculate the resulting actions from our fuzzified values.
	var actions = fuzzy_logic->Execute();
	// The properties in 'actions' are the numerical values here.
	Log("Turning the heater to %d%%!", actions["heater"]);
}
Zapper, 2015-09