Newsletter #4: April/May 2001 Edition
Home Up Feedback Search

Products
Order
Downloads
Support
Articles & Tips
Recommended Links
About

 
 

 
 
RiverSoftAVG Newsletter #4
April/May 2001
 
Hello and welcome to the fourth edition of RiverSoftAVG's newsletter!  It is amazing how the year is flying by.  This latest newsletter may be a little late but it is the best one yet!  In this issue, we reveal exciting details about the database support that will be in the upcoming Inference Engine Component Suite (IECS) version 2.  Also, we have two tips for writing your expert systems, one from the coding side and one from the expert system side.  Finally, we thought you should know about a new free component to download (in case you haven't been to the web site lately)!
 
A reminder, this newsletter and all previous ones are available for download from the web site at http://www.riversoftavg.com/articles_&_tips.htm
 
Contents
 
 
Note: You received this newsletter because you are an owner of a RiverSoftAVG product.  If you received this newsletter by mistake or if for any reason you wish to not receive any future mailings from RiverSoftAVG, just reply to this message informing us so.  We apologize for any intrusion.
 
 
 
This Fall, the Inference Engine Component Suite (IECS) is going to receive a major upgrade, bringing it up to version 2.0.  While this will not be a free upgrade (pricing to be determined), we think that this upgrade will be well worth it.  This month, we will discuss one of the great new features coming in version 2.0, database support.  In later newsletters, we will have more about other great features to come.
 
One of the major new features for the IECS will be database support (for Delphi Pro and above users, of course).  The new database features of the IECS are incredibly integrated and transparent.  Basically, if you have used the Delphi database components before, you will know how to use these.  For version 2, we are making a data-aware inference engine descendant, TDBInferenceEngine, which is much more powerful than standard data-aware controls.  The TDBInferenceEngine component provides two powerful database features for your expert systems:
bulletit can act as a data-aware control (similar to TDBGrid) for multiple data sources
bulletit can act like a database, where every fact template can be a dataset, for other data-aware controls
Let's talk about the first feature.  The TDBInferenceEngine component accepts multiple datasources and multiple fields from each datasource.  Unlike traditional data-aware controls (TDBEdit, TDBMemo) which accept one dataset and usually only one field in the dataset, the TDBInferenceEngine component can read from and write to multiple datasources.  Each data source defines a different fact template in the inference engine, and each field of the data source can be mapped to a slot in the fact template.  At run-time, each record in the data source defines, or relates to, a fact.  As the user or program scrolls around the dataset, new facts are automatically asserted to and retracted from the inference engine.
 
For example, the BioLife table in the DBDEMOS database defines 8 fields: Species No, Category, Common_Name, Species Name, Length (cm), Length_In, Notes, and Graphic.  The TDBInferenceEngine component supports fields with primitive types: integer, float, etc (sorry, no blobs).  The IECS architecture automatically maps this table as a fact template in the expert system; each allowable field maps to one slot in the fact template (you can specify which ones).  Each record, as the dataset moves to it, is asserted onto the fact list of the inference engine.  By default, when the dataset leaves the record, the equivalent fact is retracted from the inference engine.  Note that retractions, again by default, will not delete records in the dataset (deleting records when retractions occur could be a disastrous side effect, for example, when you clear the inference engine).
 
Now let's go through the steps so you can see how really easy it truly is:
bulletThe first thing we do is drop down our TTable and TDataSource components. 
bulletWe then set the TDataSource to point to the TTable.  The TTable DatabaseName property is set to DBDEMOS, TableName property to biolife.db, and, finally, we make Active equal to True.  None of this should be new to database component users.  That finishes setting up the database side.
bulletNext, we drop a TDBInferenceEngine component on the form.  The TDBInferenceEngine component descends from TInferenceEngine and surfaces a new property, DataSources.  DataSources is a TCollection property and uses the standard Collection editor.  From this editor, we can add, delete, and edit individual data source connections.
bulletNext, we add a connection in the DataSources collection.  Adding a connection creates a TDBIEDataConnection item, which has 6 properties: AutoRetractRecord, DataSource, ReadOnly, RetractRecordsEnabled, Slots, and TemplateName.  The TDBIEDataConnection class is responsible for managing the datasource and the mapping between the datasource's records and their equivalent facts in the inference engine.  The DataSource and ReadOnly property should be familiar to anyone who has worked with Delphi's database components, they perform the same function here.  The AutoRetractRecords property and RetractRecordsEnabled property control how the TDBInferenceEngine manages the facts associated with records.  If AutoRetractRecords is TRUE (the default), only the current record in the dataset is instantiated on the fact list.  As the current record changes, the old fact/record gets retracted and the new fact/record gets asserted.  If it is FALSE, old records are left on the fact list until the expert system retracts them.  The RetractRecordsEnabled property (FALSE by default) enables the "retract-record" function of the inference engine, which retracts a fact from the fact list AND deletes the associated record.  Finally, the TemplateName and Slots properties define the mapping between the dataset and the fact template.  Each Slot Item contains a FieldName, the equivalent SlotName, and the Visible property (should the field be in the fact template).  So, connecting our data source creates the following fact template automatically (note that invalid characters in field names, such as spaces, are automatically deleted when creating slot names):
(deftemplate Table1 "Dataset facts"
    (slot SpeciesNo (type INTEGER FLOAT) (default "90020") )
    (slot Category (type ATOM STRING) (default "Triggerfish") )
    (slot Common_Name (type ATOM STRING) (default "Clown Triggerfish") )
    (slot SpeciesName (type ATOM STRING) (default "Ballistoides conspicillum") )
    (slot Length_In (type INTEGER FLOAT) (default "19.6850393700787") )
    (slot Lengthcm (type INTEGER FLOAT) (default "50") )
)
bulletWe are done!  Now, you have an automatic connection between the table and the inference engine.  As you move around the dataset, facts get automatically asserted and retracted, rules activated, etc.  For example, if you moved to the "shark" record, the fact list could look like this:
f-0 (Initial-Fact)
f-1 (Table1 (SpeciesNo 90110) (Category "Shark") (Common_Name "Swell Shark") (SpeciesName "Cephaloscyllium ventriosum") (Length_In 40.1574803149606) (Lengthcm 102))
For a total of 2 facts.
 
bulletTo make an application that reads one database record at a time, executes an expert system to reason about that record, and then reads the next record, etc., becomes trivial:
     Table1.First;
     while not Table1.Eof do
     begin
          DBInferenceEngine1.Run;
          Table1.Next;
     end;
bulletTo make an application that quickly asserts all the records of a dataset into an expert system is also very easy.  Set the AutoRetractRecords property to FALSE and write the following code:
     Table1.First;
     while not Table1.Eof do
          Table1.Next;
 
Now, what does it mean "it can act like a database, where every fact template can be a dataset, for other data-aware controls?"  The TDBInferenceEngine component can also make the connection the other way.  The inference engine acts as a virtual database.  Using a special TIEDataSet component, you can connect to the TDBInferenceEngine component.  From there, a TDataSource component can link to the dataset, and data-aware controls can link to the data source.  But what does this feature mean to you?  Well, now you can use standard Delphi data-aware controls, such as TDBGrid, to edit, assert, and retract facts from the engine.  Your user (or you) need not know any CLIPS!  As a bonus, by making the IE data-aware and act like a database at the same time, you can chain IEs together.  IE1->TIEDataset->TDataSource->IE2!
 
The database support is rounded out in the IECS by supplying functions so that you can work with these new features from within your expert system.  For example, an 'assert-record' function is now available that will not only assert your fact into the inference engine, but if the fact template is mapped to a dataset, will also post a record.
 
This is only a quick explanation of the new database features in the IECS.  Hopefully, it has whetted your appetite for version 2.0.  In the coming months, we will discuss other features of this major upgrade.
 
 
 
Many times, you may want to write an expert system where only certain rules should be considered at certain time.  For example, you may want to write rules that only fire during some initialization phase, other rules to fire when an expert system is "reasoning", and finally, some rules at the end to clean up.  What you are looking for is some way to control the flow of execution in the expert system, to partition your rule set.
 
To partition your rule sets is very easy.  You define a special phase, or flow-of-control, fact type, which is used as a pattern on the left-hand-side of your rules to control their activations.  For example, say you wanted to have three periods in your expert system: init, reason, and cleanup.  To write rules that would only execute in the reason period, you would include the (phase reason) fact in your rule:
 
(deftemplate citizen (slot name) (slot status))
(defrule MyRule
    (phase reason)
    (citizen (name ?name) (status good))
    =>
    (printout t ?name " is a good citizen"))

 
To implement your flow of control automatically, e.g., to change phases, you need a fact set (or deffacts in CLIPS terminology) and a "phase change" rule.  The fact set specifies the phase fact and enumerates all the phases using some "next-phase" facts.  The phase change rule is a rule with a really low priority so that it only fires if no other rule can fire.  If the phase change rule fires, it automatically advances the phase to the next phase in the enumeration.

For example,
; *************************
; Fact Sets

(deffacts phase-factset ""
    (phase init)
    (next-phase init reason)
    (next-phase reason cleanup)
)

(defrule phase-change
    "Change phases if no other rules can fire"
    (declare (salience -10))
    ?p <- (phase ?phase)
    (next-phase ?phase ?next-phase)
    =>
    (retract ?p)
    (assert (phase ?next-phase)))
 
 
 
Often in expert systems, you will find yourself writing rules which have variables.  Variables match facts against a certain pattern and then work with that specific fact's information in the right hand side of the rule.  For example,
 
(defrule MyRule
    (phase reason)
    (citizen (name ?name) (status good))
    =>
    (printout t ?name " is a good citizen"))
 
?name is a variable.  When the inference engine finds a citizen fact that matches to "status equals good", this rule will be activated.  Using the ?name variable, you can access the fact's name slot value on the right-hand-side of the rule, such as with the printout function above.
 
Well, that is all well and good when you are writing rules in CLIPS, but how do you access variables from within a rule's OnFire event, using a TRule component at design-time?  When the OnFire event is called, your event handler gets two parameters: Sender (which is the rule) and Context.  It turns out Context is the key to getting rules from your code.  The TIEContext object is how the inference engine library defines scope within an expert system.  Just like in Object Pascal, where you can have global variables which can be hidden by local variables within a function or method, so too does the inference engine have global and local variables.  The scoping is controlled through TIEContext objects.  There is a global context (GlobalContext property) for the inference engine.  Every rule firing also gets a local context which will contains the variables defined only for that rule (such as the ?name variable above). 
 
You use the Variable property of the TIEContext class to access variables.  The Variable property accepts the name of variable (without the question mark) and returns its value (IIEValue interface).
 
So, to write the above rule as a design-time rule, we would use the following steps:
bulletFirst, drop a TRule component onto the form and set its Engine property to the inference engine.
bulletDouble-click on the TRule component.  This brings up the rule editor.  In the rule editor, we will define the conditions that activate this rule (we could also define actions too but since we want to speed up the rule, let's ignore that for now)
bulletDefine the IF, or LHS, portion of the rule like above (this assumes you have already defined the fact template).  Leave the THEN portion blank.  Click Ok.
bulletNow, go to the event tab of the property inspector and double-click on the OnFire event.  Delphi will open the code editor, write the event signature, and place you at the correct place to start writing your code.
bulletWrite the following code:
procedure TMainForm.Rule1Fire(Sender: TObject; Context: TIEContext);
begin
     InferenceEngine1.PrintOut( Context.Variable['name'].AsString + ' is a good citizen.' );
end;
bulletVoila!  You are done.  This rule, when it fires, will correctly pull the ?name variable out of the context and print it all out. 
 
 
In January, we made available for download from our web site a free Flocking component.  Last month, we extended the flocking components to implement group formations!  These new components move your little boids into squares, wedges, etc like they are on a parade ground! :)  If you haven't already downloaded it, you should get it as it really is an amazing display of emergent behavior.  The demo comes with source and executable for testing the flocking code. It demonstrates how to implement formations using flocking behavior. The formation flocking code is based on the four rules of flocking: separation, alignment, cohesion, and avoidance.  The Formation Flocking code however modifies the standard cohesion and separation rules to provide formations.  The cohesion rule now moves the boid towards its position in the formation rather than toward the flock's center point.  The separation rule has been modified so that it doesn't interfere when the boid is in its place in formation. In addition, the separation strength has been turned way down to avoid the boids from pushing away from each other in the formation. 

You can find the Formation Flocking component at http://www.riversoftavg.com/formation_flocking.htm
 
 
 
Send mail to webmasterNO@SPAMRiverSoftAVG.com with questions or comments about this web site.
Copyright 2002-2010 RiverSoftAVG
Last modified: September 20, 2010