Using a Control Shell |
A control shell is one of the three major components of a blackboard system (along with KSs and the blackboard). The control shell directs the problem-solving process by managing how KSs respond to contributions that are placed on the blackboard by an executing KS and to other events that may be triggered by the application or received from external sources. In this exercise we will use a control shell called the “Agenda Shell.”
GBBopen's Agenda Shell is a generalization of the priority-based scheduling approach that was used in the original Hearsay-II blackboard architecture. The Agenda Shell manages KS definitions, and it initiates and terminates KS activities by:
The Agenda Shell is highly customizable and extensible, and it can be used as the foundation for implementing advanced control mechanisms. We will use only the most basic Agenda Shell capabilities in this Tutorial.
The tutorial-example.lisp
(in-package :gbbopen-user) (define-unit-class location () (x y) (:dimensional-values (x :point x) (y :point y)) (:initial-space-instances (known-world))) (defmethod print-instance-slots ((location location) stream) (call-next-method) (when (and (slot-boundp location 'x) (slot-boundp location 'y)) (format stream " (~s ~s)" (x-of location) (y-of location))))
Start up a fresh Common Lisp session and load the
:agenda-shell-user
:agenda-shell-user
cl-user> :agenda-shell-user
;; Loading <install-dir>/startup.lisp
...
;; Loading <install-dir>/<platform-dir>/gbbopen/
;; control-shells/agenda-shell-user.fasl
gbbopen-user>
This loads everything that we've been loading with the
:gbbopen-user
:gbbopen-user
:gbbopen-user
Now, start the Agenda Shell:
gbbopen-user> (start-control-shell) ;; Control shell 1 started ;; No executable KSAs remain, exiting control shell ;; Control shell 1 exited: 2 cycles completed ;; Run time: 0 seconds ;; Elapsed time: 0 seconds :quiescence gbbopen-user>
What just happened? The Agenda Shell began executing and looked for something
to do. However, we have not yet defined any knowledge sources (KSs), so the
Agenda Shell indicates that it did not find any executable KSAs in its initial
KS-execution cycle. This situation is called quiescence and, by
default, the Agenda Shell signals that quiescence has occurred and then
continues for an additional KS-execution cycle in case any executable KSAs
resulted from the quiescence signal. Again, no executable KSAs were found in
cycle 2, so the Agenda Shell exits due to :quiescence
.
Note that the Agenda Shell requires that the idle-loop process has been started on CMUCL and that multiprocessing has been started on LispWorks. (An error message will instruct you on what to do if this is not the case.)
So let's define a KS!
Edit your tutorial-example.lisp
tutorial-example.lisp
(define-unit-class location () (x y) (:dimensional-values (x :point x) (y :point y)) (:initial-space-instances (known-world))) (defmethod print-instance-slots ((location location) stream) (call-next-method) (when (and (slot-boundp location 'x) (slot-boundp location 'y)) (format stream " (~s ~s)" (x-of location) (y-of location)))) ;;; ==================================================================== ;;; Startup KS (defun startup-ks-function (ksa) (declare (ignore ksa)) ;; Create an initial location unit instance at (0,0): (make-instance 'location :x 0 :y 0)) (define-ks startup-ks :trigger-events ((control-shell-started-event)) :execution-function 'startup-ks-function)
The function startup-ks-function
ksa
unit instance that represents the activation of the KS. For the
present, we will ignore the ksa
argument. Our simple
startup-ks-function
location
known-world
The startup-ks
:trigger-events
control-shell-started-event
control-shell-started-event
:execution-function
Compile and load the entire tutorial-example.lisp
C-c C-k
C-c
C-b
The Agenda Shell creates a ks
unit instance for each KS that we
define:
gbbopen-user> (map-instances-of-class #'print 'ks) #<ks startup-ks> nil gbbopen-user>Note that the name of the
ks
unit instance is the name of the KS.
known-world
Before we can run our KS, we must make the known-world
gbbopen-user> (make-space-instance '(known-world) :dimensions '((x :ordered) (y :ordered)))) #<standard-space-instance (known-world)> gbbopen-user>
Start the Agenda Shell again:
gbbopen-user> (start-control-shell) ;; Control shell 1 started ;; No executable KSAs remain, exiting control shell ;; Control shell 1 exited: 3 cycles completed ;; Run time: 0 seconds ;; Elapsed time: 0 seconds :quiescence gbbopen-user>
Did it work? Let's describe the blackboard repository:
gbbopen-user> :dsbb Space Instance Contents -------------- -------- known-world 1 instances (1 location) Unit Class Instances ---------- --------- control-shell 1 * ks 1 + ksa-queue 2 + location 1 ordered-ksa-queue 1 + standard-space-instance 1 --------- 7 instances gbbopen-user>The initial
location
Note that some other unit instances have been created by the control shell.
There is one ks
unit instance, our startup-ks
ksa-queue
ordered-ksa-queue
ordered-ksa-queue
ksa-queue
The ks
, ksa-queue
ordered-ksa-queue
+
). This indicates
that these unit classes have been defined to be retained, meaning
that their instances are not deleted by our call to
*
).
Let's verify this behavior by calling
gbbopen-user> (delete-blackboard-repository) t gbbopen-user> :dsbb There are no space instances in the blackboard repository. Unit Class Instances ---------- --------- control-shell 1 * ks 1 + ksa-queue 2 + ordered-ksa-queue 1 + gbbopen-user>
With all but the retained unit instances deleted from the blackboard repository, let's rerun the control shell. However, this time we will ask GBBopen to display more of what the control shell is doing. First, enable display of all control-shell and instance-creation events by evaluating:
gbbopen-user> (enable-event-printing '(control-shell-event :plus-subevents)) nil gbbopen-user> (enable-event-printing 'instance-created-event) nil gbbopen-user>or the shorthand equivalent:
gbbopen-user> (enable-event-printing '(control-shell-event +)) nil gbbopen-user> (enable-event-printing 'instance-created-event) nil gbbopen-user>
We will cover events, event printing, and event functions in greater detail in a later exercise.
Start the Agenda Shell once again:
gbbopen-user> (start-control-shell) ;; Control shell 1 started => Control-shell-started-event => Control-shell-cycle-event :cycle 1 => Instance-created-event :instance #<ksa 1 startup-ks 1> => Ksa-activated-event :instance #<ksa 1 startup-ks 1> :cycle 1 => Ksa-executing-event :instance #<ksa 1 startup-ks 1> :cycle 1 => Instance-created-event :instance #<location 1 (0 0)> => Control-shell-cycle-event :cycle 2 => Quiescence-event => Control-shell-cycle-event :cycle 3 ;; No executable KSAs remain, exiting control shell ;; Control shell 1 exited: 3 cycles completed ;; Run time: 0 seconds ;; Elapsed time: 0 seconds :quiescence gbbopen-user>
Let's rerun the control shell once again, but this time we will enable control-shell stepping. Again, delete the blackboard repository:
gbbopen-user> (delete-blackboard-repository) t gbbopen-user>and disable the event printing that we enabled in the last step:
gbbopen-user> (disable-event-printing) nil gbbopen-user>
Now start the Agenda Shell, this time with stepping enabled:
gbbopen-user> (start-control-shell :stepping 't) ;; Control shell 1 started >> CS Step (cycle 1): About to process event #<control-shell-started-event>... [? entered] Stepping commands (follow with <Return>): d Disable this kind of stepping (:process-event) e Enable another kind of stepping f Evaluate a form h or ? Help (this text) q Quit (disable all stepping and continue) s Show enabled stepping kinds x Exit control shell = Describe the object of interest (bound to ==) + Enable all stepping - Disable all stepping <Space> Continue (resume processing) >> CS Step (cycle 1): About to process event #<control-shell-started-event>... [<Return> entered] >> CS Step (cycle 1): About to activate KS startup-ks on control-shell-started-event... [<Return> entered] >> CS Step (cycle 1): About to execute KSA #<ksa 1 startup-ks 1>... [<Return> entered] << KSA 1 returned: (#<location 1 (0 0)>) >> CS Step (cycle 2): About to signal quiescence... [<Return> entered] >> CS Step (cycle 3): About to signal quiescence... [<Return> entered] ;; No executable KSAs remain, exiting control shell ;; Control shell 1 exited: 3 cycles completed ;; Run time: 0 seconds ;; Elapsed time: 1 minute, 6 seconds :quiescence gbbopen-user>
The GBBopen Project
Using a Control Shell |