Loom® 2.0 Release Notes

We are pleased to announce a final release of Loom® 2.0. This new version of Loom should prove to be significantly more robust than the beta 2.0 that has been available since last Fall. It includes a few new features which some users will find useful. This message describes
  1. the kinds of upgrades made to Loom,
  2. modifications that are not compatible with Loom 2.0b
  3. new features
  4. how to obtain the new release (it's not in the usual place).

Bug Fixes

We have significantly upgraded the tools we use to test Loom releases and patches. Our test suite now includes over 700 separate tests, and that number is growing rapidly. The test suite calls clear-kb to reset the kb between separate groups of tests, and that practice has uncovered several bugs in the retraction/revision code that are now history (in the past, clear-kb has been hard to fix because revision bugs are notoriously hard to reproduce). Other problems fixed include bugs in production rules, in the backtracker, in save-kb, and in default rules. Some of these fixes have found their way into the 2.0b patches, but some of them have not. If something has not worked for you in the past, we suggest trying it again on this new release.


The semantics of get-value and set-value has changed slightly: Previously, calls such as (get-value 'I 'R) and (set-value 'I 'R 'V) could be applied to both single-valued and multiple-valued relations R. Now, these two functions are intended to be used only for single valued relations. The motivation for this change is (i) that it makes asserting and retrieving a role pointing to a list much more straightforward, and (ii) it eliminates some coercion that made these routines overly clever. Before, when get-value returned a list, that value could represent a single role filler or a list of fillers, depending on whether or not the role was single- or multiple-valued. Now, get-value always returns a value representing a single role filler. The new semantics is slightly more forgiving than just described -- the new get-value permits retrieval from a multiple-valued role in the cases when the role contains zero or one filler. Two new functions, get-values and set-values have been introduced to accommodate multiple-valued roles. get-values returns a list of fillers, and set-values assigns from a list of fillers. These new functions also work with single-valued relations. The functions all-role-values, the-role-value, and some-role-value still exist, but we recommend not using them (they don't automatically advance the state of a knowledge base before retrieval). get-values makes all-role-values obsolete, and get-value makes the-role-value obsolete (and no one seemed to like some-role-value).

We have also modified the semantics for computing the roles of a Loom concept. This affects the generation of slots when CLOS classes are created from the definitions of Loom concepts. Because this is coupled with a new feature (a :roles declaration), the new semantics is described under the ENHANCEMENTS heading.

We have also made a small modification to the macro list-kb. Previously, the argument to the :partitions keyword was implicitly quoted -- now its not (and should never have been).

Note: Before making changes to get/set-value and role computations, we solicited opinions from the Loom user community, and the above-mentioned changes are compatible with the answers we received. In general, we try to avoid making incompatible upgrades to Loom, but we will make them when (i) we feel that the previous semantics represented a bad choice, and (ii) when no user claims to be inconvenienced by the change.


The facility for generating CLOS classes is now friendlier in several respects. It is no longer necessary to attach the :clos-class :characteristic to a concept -- Loom now automatically figures out when its necessary to create a CLOS class. For example, executing

   (defconcept A)
   (create 'Fred 'A :clos-instance-p t)

causes a CLOS class named A to be created in response to the attempt to create the instance Fred. Furthermore, Loom now supports automatic revision of CLOS classes -- when a Loom concept is redefined, the corresponding class (if such exists) gets redefined the next time it is instantiated. For example, if we now say

   (defrelation R)
   (defconcept A :is-primitive (at-least 1 R))
   (create 'Sue 'A :clos-instance-p t)

Loom will redefine the CLOS class A to include a slot named R.

Previously, Loom took its cue for generating the slots for a class based on the :domain constraints attached to roles. If a role relation R had domain A, then a slot was assigned to the class A (and inherited by its subclasses). This has been changed. There are two new ways to assign a slot to a class via the concept declaration. First, Loom now creates a slot corresponding to any relation that is restricted by a concept definition. In the above example, when we restricted the concept A with the clause (at-least 1 R), that caused Loom to generate a slot R for the class A. A :roles option provides a second means for generating slots on a class. For example, let us redefine A again:

   (defconcept A :roles (R S))
   (create 'Joe 'A :clos-instance-p t)

Now the class A has two slots, R and S. Oops, we forgot to define a relation named S! Not to worry. Loom automatically defines a multiple-valued binary relation corresponding to each member of :roles that is not already declared. These definitions can be overridden after the fact by subsequent defrelation definitions. This means that you can now use Loom without ever explicitly defining a relation, if that suits your fancy. However, you still need to call defrelation if you want to make a relation single-valued (I was glad to get an endorsement from Mark Burstein at BBN in making that decision).

The old role semantics can be enabled by setting the loom feature :domain-implies-role. However, while this setting causes Loom to infer roles based on domain information, it does not disable either of the two new role-inducing mechanisms. We expect that users may wish for a capability for disabling the inference of roles/slots based on restrictions. However, when we conducted a poll, no one asked for such a feature. Hence, we have decided to defer the introduction of such a disabling feature until such time as users ask for it. In any case, the :roles option now gives users much greater control over allocation of slots. (Note: In the laboratory version of Loom, roles are first-class objects, and the :roles option controls more than just the generation of CLOS slots. Thats why its called :roles rather than :slots).

Loom now provides two new query functions: GET-MATCHING-INSTANCES and QUERY. These were described in a message to Loom forum. A summary follows:

GET-MATCHING-INSTANCES conceptList roleFillerList

Returns a list of instances that belong to all concepts in conceptList and have all of the role fillers specified in roleFillerList. For example, the following will get all instances that are A's and B's and that have 4 and 5 as fillers for roles R and S:

	(get-matching-instances '(A B) '((R 4 5) (S 4) (S 5)))

QUERY variableList queryExpression

Provides a functional interface to RETRIEVE-style queries. The syntax is the same as retrieve, except that the arguments are evaluated. Also, any free variables in queryExpression must be declared special! Note that one should always use retrieve in preference to query, since retrieve will result in faster code. The following are equivalent:

     (let ((?v 3))
        (retrieve (?x ?y) (:and (C ?x) (R ?x ?y) (S ?x ?v))))

     (let ((?v 3))
	(declare (special ?v))
        (query '(?x ?y) '(:and (C ?x) (R ?x ?y) (S ?x ?v))))

Loom provides two more new defconcept options: :keys and :indices. The :indices option causes Loom to create a hash index(es) that accelerates retrieval based on the values of role fillers. The :keys option declares sets of roles that collectively define a key on a concept. The difference between keys and indices are that the set of values of roles in a key must be unique for each instance in the corresponding concept, and that the specification of keys without indices doesn't provide accelerated access. Roles referenced by the :keys and/or :indices options must be single-valued. The function get-matching-instances knows how to take advantage of role indices. For example

   (defconcept A :roles (R S T) :indices (R (S T)))
   (defrelation R :characteristics :single-valued)
   (defrelation S :characteristics :single-valued)
   (defrelation T :characteristics :single-valued)
   (tell (about Ann
                (create A)
                (R 3) (S 4) (T 5)))
   (get-matching-instances nil '((R 3)))
   (get-matching-instances nil '((S 4) (T 5)))

The concept A has two independent indices. One index is the value of the role R. The second index is a list of the values of the roles S and T. Here, Ann is retrieved by each of the above calls to get-matching-instances, using two different hash indices. The function query calls get-matching-instances to execute simple queries, such as the following:

   (query '?x '(R ?x 3))
   (query '?x '(and (A ?x) (R ?x 3)))

However, we have not yet had time to upgrade retrieve to use role indices. Hence, on the above queries, retrieve will not use the indices to accelerate the retrieval.

The :keys option allows one to specify sets of keys for instances of a concept. In this example

   (defconcept A :roles (R S) :keys ((R S)) :indices ((R S)))
   (defrelation R :characteristics :single-valued)
   (defrelation S :characteristics :single-valued)
   (tellm (about Jack
              (create A)
              (R 4) (S 3))
       (about Jill
              (create A)
              (R 4) (S 3))
       (about Mary
              (create A)
              (R 4)))

Loom emits a warning that Jack and Jill have duplicate values for the key (R S), and also warns that Mary is supposed to have filled in its value for the role S. Note: Checking for duplicate keys only happens if there is an index declared that matches the key being monitored.

Obtaining Loom Sources

Starting with this release of Loom, a new procedure for acquiring the sources goes into effect. Loom sources will no longer be available via anonymous ftp. Instead, a new account named loomftp has been established. This account will require a password for connection. The password will be distributed to all current license holders.

The loom files will be stored in a special directory accessible to the loomftp user, but not accessible from the anonymous ftp server. After ftp'ing into the loomftp account, the Loom files can be retrieved in the normal manner. We will distribute the sources in Unix tar format as well as Macintosh stuffed and binhex'd format. Remember to use binary mode to retrieve tar files!!


Unix %  ftp isi.edu
Name (your name here): loomftp
Password: _________
ftp> binary
ftp> get loom2.0.tar

For Macintosh users, the files are also available in binhex format as a self-extracting archive in the file Loom2.0.sea.hqx.

Loom is a registered trademark of the University of Southern California.
Information Sciences Institute ISI Intelligent Systems Division Loom Home Page