Task control

The control activity is transferred from task to task during the search for a solution of the problem. This transfer can be either simple (sequential - task 1 always follows task 2) or more complex when the exact form of the activity transfer depends on the current state of the solution (e.g. on the result of some test). Control transfer is performed in the ''background''. When a task becomes active, it is active till it returns this activity back to the task control mechanism (in the current state of the solution there is no need for the task to remain active - this stage is detected by the active task). Then the task control passes the activity to the next appropriate task.

Each task consists of a set of rules. While some task is active, only rules of this task and rules dedicated to the activity transfer to the next task can be fired. The rules of the task have higher priority than the activity transfer rules. This enables first to fire all relevant rules of the active task. The rules for the task control (the choice of the next task and the passing the activity to this task) can be fired only when there is no rule of the active task which is relevant in the current situation. Which fact is currently active is specified by a control token. This token is the fact of the following form

(job <name of the active task>)
which can be found in the database. To divide all rules into groups according to the tasks they belong to, every rule contains the test for the activity of its task at the beginning of its condition part. Thus a general form of rules belonging to a particular task is as follows
(defrule <rule name>
(job <name of a task the rule belongs to>)
...
=>
...
)
The transfer of the activity from one task to another can be implemented in two steps:
  1. remove the old control token from the database
  2. assert the new control token with the name of the next task into the database
An example of a simple sequential activity transfer is the transfer of the control token from the task initialize to the task evaluate:
(defrule end-initialize-1
(declare (salience -50))
?a <- (job initialize)
=>
(retract ?a)
(assert (job evaluate))
)
Similar schema is used to activate the task test for solution existence. The only difference is that this task is always activated as the first one. The rule belonging to this task has a very simple form
(defrule start-1
(declare (salience -50))
=>
(assert (job test-exist))
)
More complex activity transfer, based on the result of the previous task, consists of several rules. For instance to choose the next task after the task evaluate returns the control:
(defrule end-evaluate-1
(declare (salience -50))
?a <- (job evaluate)
=>
(retract ?a)
(assert (job test1))
)
(defrule end-test1-1
(declare (salience -50))
?a <- (job test1)
(not (object (is-a constraint) (cons-violation yes)))
=>
(retract ?a)
(assert (job optimize))
)
(defrule end-test1-2
(declare (salience -50))
?a <- (job test1)
(object (is-a constraint) (cons-violation yes))
=>
(retract ?a)
(assert (job change))
)
where first the simple transfer to the appropriate test is performed. The test always consists of several rules (the number of rules corresponds to the number of different output values of the test). These rules have to contain the appropriate form of the test in their condition parts (in the example above the presence of constraint violations is tested).

The test can be performed as the test of the current state of the solution. Another possibility is to test the result of the activity of the previous task. The previous task could assert its result into the database represented by one of the facts (result success) or (result failure). The next task should retract this information from the database. This is true for the control after the tasks test for solution existence, change, and relax. As an example, the part of the task control after the task change is finished

(defrule end-test2-2
(declare (salience -50))
?a <- (job test2)
?b <- (result failure)
=>
(retract ?a)
(retract ?b)
(assert (job relaxation))
)
Tasks success and failure are implemented as special tasks which are able to display the message about the success of the search of the solution and to provide the current state of this solution.