Loom® 2.1 Release Notes

This document describes the new features that were added to Loom® 2.0 for the 2.1 release. The three major changes were the addition of temporal concepts and relations; the introduction of a new type of instance; and the debut of negated assertions in the ABox. There were also some more minor changes in the way knowledge bases work caused by the introduction of "contexts." The changes are discussed in the following sections:

  1. Upper-Structure-KB Changed
  2. "Lite" Instances Added
  3. Context Mechanism
  4. Negated Assertions and Definitions
  5. Time Support in Loom 2.1
  6. CLOS Instances Support


Upper-Structure-KB Renamed

The standard knowledge base has comes with a context (see below) named BUILT-IN-THEORY. There is no knowledge base object associated with this context. For compatibility, the extended prefix "UPPER-STRUCTURE-KB^" will be interpreted correctly. This will only affect those users who refer to the knowledge base directly by name.

"Lite" Instances Added

Loom 2.1 now has a new type of instance that joins the existing Loom instances and CLOS instances: "Lite" instances. Lite instances differ from Loom instances in not being classified. They are also smaller in size and should operate much faster than Loom instances. The tradeoff is that they are strictly less powerful in inference than Loom instances. This should mainly affect the behavior of defaults and incoherence detection.

With the introduction of lite instances, Loom now has the capability of asserting features on instances that are not classified.

CHANGE IN BEHAVIOR: Lite instances are now the default instance created by Loom. This default can be modified by using the "creation-policy" function documented in the section on the context mechanism. This change in default also affects the create function:

CREATE   identifier concept &key :context :creation-policy
                                 :add-suffix-p                [Function]
Create a new instance of concept and assign it the identifier identifier. The type of instance created is determined by the creation policy of the indicated or current context, unless overridden explictly by the keyword creation-policy. If the policy :clos-instance is indicated but no appropriate CLOS class exists, a :classified-instance or :lite-instance will be created, and a warning issued. If add-suffix-p, then add a suffix if necessary to assure that the identifier is unique.

The keyword arguments :clos-instance-p and :suffix-p are now obsolete. They will continue to be recognized for a while to insure backward compatibility.

CREATION-POLICY   &optional policy		              [Function]
Set the creation policy of the current context to policy. Legal values are :classified-instance, :lite-instance, or :clos-instance. If policy is null, return the creation policy of the current context.

Compatibility Note: The default type of instance created is now :lite-instance rather than :classified-instance. If your application relies on having classified (i.e., Loom instances) and you use the create function you will need to add the :creation-policy keyword with the value :classified-instances. Alternately, one could evaluate the function creation-policy with the argument :classified-instance to set the default type of creation for a particular context.

Note: Loom instances have been renamed "classified instances."

Negated Assertions and Definitions

Loom 2.1 extends the language for both definitions and assertions by allowing explicit negation. The negation operator "not" may now be used in the definitions of concepts and binary relations. One is now allowed to write definitions like:

	(defconcept A)
	(defconcept B :is (not A))

	(defconcept Status :is (:one-of 'OK 'Damaged 'Wrecked 'Sliced
				    'Diced 'Pulverized 'Obliterated)) 
        (defrelation status)
	(defconcept Unit)
        (defconcept Hurting-Unit :is (:and Unit
	                                (not (:filled-by status 'OK)))) 

Assertions of the form

	(tell (not (B i)))
	(tell (not (status u4 'sliced)))

are also permitted now.

Context Mechanism

Knowledge bases have been modified extensively, although most of the modifications should be hidden from most users. All KBs now have a context associated with them. The context has a named generated by taking the root name of the KB and adding the suffix -THEORY to it.

The major change in behavior is that the extensions of concepts are now context-sensitive. This means that sibling KBs will no longer share all instances. The second major change is that functions which used to take a KB as a keyword argument now take contexts instead! A list of affected function appears further below.

User Note: Unless a context is created as a side effect of creating a knowledge base, there is no way to save its contents to a file. That is, the only function that saves information to a file is still the save-kb function. The context mechanism will be further developed in Loom 3.0.

New Function Documentation

The following new functions have been added to the Loom programmer's interface to support contexts. The existing functions change-kb, in-kb, save-kb, etc. continue to function as before.

CC   &optional contextName		                         [Macro]
Change context, or if contextName is null, return the current context.

CHANGE-CONTEXT   contextOrName		                      [Function]
Replace the top of the context stack with the context contextOrName and reset the current context. Return the new current context.

CONTEXT-STACK   		                              [Function]
Return the current context stack. The context stack is manipulated by pushing and popping contexts or by executing change-context.

CREATION-POLICY   &optional policy		              [Function]
Set the creation policy of the current context to policy. Legal values are :classified-instance, :lite-instance, or :clos-instance. If policy is null, return the creation policy of the current context.

CURRENT-CONTEXT   		                              [Function]
Return the current context.

DEFCONTEXT   contextName typeOfContext parentContexts            [Macro]
             &key :creation-policy :monotonic-p		
Create a new context called contextName of type typeOfContext that inherits the contexts parentContexts. Legal types are :theory, :workspace, :island, and :world. creation-policy indicates the meta-class for instances created in this context -- this establishes the inference policy for the context. Legal policies are :classified-instance, :lite-instance, and :clos-instance. The default policy creates CLOS instances for workspaces and LITE instances for theories.

DEFINE-CONTEXT   name typeOfContext parentContexts            [Function]
                 &key :creation-policy :monotonic-p
Create a new context called contextName of type typeOfContext that inherits the contexts parentContexts. Legal types are :theory, :workspace, :island, and :world. creation-policy indicates the meta-class for instances created in context -- this establishes the inference policy for the context. Legal policies are :classified-instance, :lite-instance, and :clos-instance. The default policy creates CLOS instances for workspaces and LITE instances for theories.

DESTROY-CONTEXT   contextOrName		                      [Function]
Destroy the context context and all contexts below it.

EXPORT-NAMES-IN-CONTEXT   contextOrName		              [Function]
Place names of all objects belonging to contextOrName on package export list(s).

FIND-CONTEXT   contextOrName &key :error-p	 	      [Function]
Return the context whose name matches contextOrName. If error-p, then generate an error if there is no such context. Note: get-context is slightly faster, but can't handle strings and eliminates type checking.

GET-CONTEXT   contextOrName		                      [Function]
Return the context whose name matches contextOrName. Assumes that a non-symbol is a legal context.

IN-CONTEXT   contextName                                         [Macro]
Replace the top of the context stack with the context contextName and reset the current context. Unlike change-context, in-context evaluates at compile and load time.

It can only appear at top-level in a Lisp program.

PUSH-CONTEXT   contextOrName	                              [Function]
Push the context contextOrName onto the context stack, and make it the current context. Return the new current context.

POP-CONTEXT   		                                      [Function]
Pop the current context from the context stack, and make the new top-most context on the stack the current context. Return the new current context.

LIST-CONTEXT   &rest arguments		                         [Macro]
Return a list of objects in the specified partitions of the context named context. The :partitions keyword indicates what partitions are to be retrieved, while the optional parameter context indicates what context to use. Setting the keyword :sort-p to t causes the result to be sorted. Setting :sort-p to :sort-each-partition causes individual partitions to be sorted.

LIST-CONTEXTS                                                 [Function]
Return a list of all contexts defined in Loom.

WITHIN-CONTEXT   contextOrName  &body body	                 [Macro]
Execute body with context temporarily set to contextOrName. This wrapper performs a push-context before executing body and a pop-context afterwards.

Changed Argument Documentation

The following functions and macros used to take :kb as a keyword argument. They no longer accept this argument. Instead they take :context as an argument:

ADD-TYPE      instanceOrId conceptOrName &key context no-error-p
ADD-VALUE     instanceOrId roleOrName fillerOrId &key context no-error-p
ASK           query &key context generators 3-valued-p
COPY-INSTANCE instance &key identifier copy-into context add-suffix-p
CREATE        identifier concept &key context creation-policy
CREATEM       identifier concept &key context creation-policy
FASK          query &key context generators 3-valued-p
FC            conceptName &key context
FI            instanceSymbol &key context
FIND-ALL      term &key context
FIND-CONCEPT  conceptOrName &key no-warning-p ignore-package-p context
FIND-INSTANCE instanceOrSymbol &key no-warning-p context ignore-package-p
FIND-RELATION relationOrName &key no-warning-p ignore-package-p context
FIND-THE      term &key context
FP            productionName &key context
FR            relationName &key context
FRETRIEVE     outputVariables query &key context generators
GET-CONCEPT   conceptOrName &key context no-error-p
GET-INSTANCE  self &key context error-p
GET-INVERSE-VALUES instanceOrId roleOrName &key context no-error-p
GET-RELATION       relationOrName &key context arity no-error-p
GET-VALUE          instanceOrId roleOrName &key context no-error-p
GET-VALUES         instanceOrId roleOrName &key context no-error-p
LIST-MONITORS      &key context
LIST-PRODUCTIONS   &key context
REMOVE-TYPE   instanceOrId conceptOrName &key context no-error-p
REMOVE-VALUE  instanceOrId roleOrName fillerOrId &key context no-error-p
RETRIEVE      outputVariables query &key context generators
SET-VALUE     instanceOrId roleOrName fillerOrId &key context no-error-p
SET-VALUES    instanceOrId roleOrName fillersOrIds &key context no-error-p

The following function used to take :destroy-kbs-p as a keyword argument. It no longer accepts that argument. Instead it takes :destroy-contexts-p.

INITIALIZE-NETWORK &key destroy-contexts-p

Time Support in Loom 2.1

Support for temporal concepts and relations has been added to Loom in release 2.1. The temporal extensions allow one to make factual assertions about role fillers that hold only over specified intervals, rather than being universally true. It is also possible to define temporal concepts, where instances satisfy a concept only over some period of time.

The following extensions have been made to the Loom language to support time:

:Temporal Characteristic

A new characteristic, ":temporal" has been added. In order to be allowed to assert temporal information about a concept or binary relation, this characteristic must appear in its definition (or in the definition of a super-concept). If a concept or relation is defined to be temporal, only temporal assertions may be made with respect to that concept or relation. The temporal characteristic is inherited by sub-concepts. Example:

	(defrelation R)                               ; non-temporal
	(defrelation TR :characteristics :temporal)   ; temporal

	(defconcept TC :characteristics :temporal)    ; temporal
	(defconcept TC2 :is-primitive TC)             ; temporal also

The temporal characteristic implies the :backward-chaining and :closed-world charateristics as well. At this time only concepts and binary relations are supported by the time manager. We will only consider supporting N-ary relations if user demand justifies the effort.

Temporal attributes can be used in the definition of concepts as well:

      (defconcept Woman)
      (defrelation Husband :characteristics :temporal)
      (defconcept Married-Woman :is (:and Woman (:exactly 1 Husband))
                           :characteristics :temporal)

(n.B. Loom can infer that the concept Married-Woman must be temporal)

Most Loom reasoning works with these extended definitions. The exception is the generation of beginning and ending times of intervals for concepts that use value restrictions. This is discussed in more detail in the section on Queries.

Model of Time and Assertions

Loom's model of time uses fixed time points. That means that all times must be specified exactly and thereby linked to an underlying time line. The time line is internally represented by the (positive and negative) integers. For logical purposes Loom does not impose any interpretation of the scale of the time line.

Date conversion and parsing utilities for Loom do, however, use the format of CommonLisp universal time. This is the number of seconds since January 1, 1900. It is always a positive number.

Limit Semantics

Assertions about the validity of facts are made using a point-based syntax (described in more detail below). Based on these assertions, an interval model of facts holding over time is constructed. Membership in concepts and the fluents of role fillers are interval values.

For any assertion in Loom that holds over a time interval T, that assertion is also true over any sub-interval of T. In Allen's terminology that means that temporal concepts and relations are properties. In Shoham's terminology it means that they are liquid.

The value of a filler or the membership of an instance in a concept can be queried at particular points in time. The value returned is determined by evaluating the time using limit semantics. This semantics are designed so that we can give unambiguous and well founded answers at the endpoints of intervals.

For example, consider the statement (A Fred) holding from time 1 to 5. It is clear that (A Fred) holds at time 3. What answer is appropriate at time 1? The answer Loom will return is based on which of the query forms (detailed below) is used. (A Fred) holds in the limit as the time approaches 1 from the future end of the time line. (A Fred) does not hold in the limit as time approaches 1 from the past end of the time line. Each of these questions can be asked in Loom. In addition, if no direction is specified, (A Fred) will hold only if it holds in the limit from both directions. That is, (A Fred) does not hold at 1 or 5, but does at 2, 3 and 4.

Persistance Assumptions

Loom implements persistence of values from times when they are specified to hold until they are explicitly retracted or clipped. Clipping is done only for single-valued relations. Persistence can run both forward or backward in time. The direction of persistence is specified when a temporal assertion is made.

Specifying Times

All times in Loom must be exactly specified. Internally time is represented as integers. Input and output conversion routines are provided based on the CommonLisp universal time format. This format has a resolution of seconds. Note that it is only necessary to adopt this convention for interpreting times in Loom if you wish to use the string or KRSL style of time specification. The following time formats are accepted:


Positive and negative integers may always be specified as times. Although the time line is infinite, no assertions may be made at infinity. All times must be finite. (Values can persist to infinity, though).


Loom has a parser that converts date and time strings into CommonLisp universal time format. It is a slightly modified version of the date parser released to the publich domain by the CMU CommonLisp project. It is a fairly flexible parser. Examples of dates that can be parsed are

	"August 25, 1993"            "11/11/75"

and times that can be parsed are

     "10:30"     "22:30"      "10:30am"       "10:30 pm"    "Noon"

and, of course, combined date and time strings. Unspecified values will default to today for dates and to zero for times.

Localization Note: Only American style dates are parsed (sorry), but if the Europeans are interested, the date parsing mechanism is sufficiently flexible that other formats can be easily added. This is also true of the output function.

KRSL Lists

Times may also be specified in KRSL list format:

	(:year 1993 :month 8 :day 25 :hour 10 :minute 30)

Times specified in this format will be converted to CommonLisp universal time with a granularity of seconds. As an extension to the KRSL standard, the keyword :second can also be used in Loom. Unspecified values will default to today for dates and to zero for times.

The Loom parser is able to parse any combination of these three forms on input. Output is (by default) in string format. For output in KRSL or integer format, see the section "Environment Control" below.


The following temporal operators have been added to the Loom assertion and query language :holds-after, :holds-before, :holds-at, :begins-at and :ends-at.

The syntax for making temporal assertions is:

     (<TemporalOperator> <TimeSpec> <SimpleTemporalClause>*)

<TemporalOperator>  ::=  :holds-after | :holds-before  | :holds-at |
                         :begins-at | :ends-at
<TimeSpec>          ::=  <Integer> | <TimeString> | <KRSL-List>
<SimpleTemporalClause>  ::=  (<Concept> <Instance>)  |
                             (<Relation> <Instance> <Filler>)


     (tell (:holds-after 10 (TC Fred) (TR Fred 5) (TR Fred 8)))
     (tell (:about Sue (:holds-before "1/1/86" TC (TR 6) (TR 9))))

Simple temporal assertions may not contain connectives such as :and or :or. Multiple clauses are permitted as syntactic sugar. The meaning of

	(:holds-after 10  (TC Fred) (TR Fred 5) (TR Fred 8))

is the same as the combination:

       (:and (:holds-after 10  (TC Fred))
             (:holds-after 10  (TR Fred 5))
             (:holds-after 10  (TR Fred 8)))

Note that this syntax is legal inside an :about clause, in which case concept and relation syntax changes analogously with regular Loom conventions.

:holds-after (:holds-before) This operator means that an assertion is true in the limit after (or before) the time specified. The assertion will persist forward (backward) in time. This form can result in a clip of another temporal assertion only in the case of single valued relations. In particular, NO statement is made about the value of the assertion before (after) the time point in question.

Aside from the clipping of single-valued roles, the only assertions that will terminate persistence are :begins-at and :ends-at. For example, the following assertions will have (TR Fred 3) over the entire time line!

   (tell (:holds-after  0 (TR Fred 3))
         (:holds-before 10 (TR Fred 3))) 

This is because :holds-after says nothing about the value of TR before time 0. The persistence from the :holds-before at time 10 continues into the past and passes time 0.

:holds-at This temporal assertion is the equivalent of combining a :holds-after and a :holds-before at the same time. It is provided as a convenience.

:begins-at (:ends-at) These operators make a stronger statement than the :holds-after (:holds-before) operators. They assert that the statement is true in the limit after (before) the specified time point. They also assert that the statement is not true before (after) the specified time point. This negative assertion is used by Loom for persistence clipping and error detection. The negative assertion is not directly represented in the knowledge base but is derived from the closed world characteristics of Loom's temporal concepts and relations.

The following asserts that TR of Fred has the value 3 only from time 0 to time 10:

   (tell (:begins-at  0 (TR Fred 3))
         (:ends-at   10 (TR Fred 3))) 

Note that because of the closed world nature of Loom's temporal representation, a single assertion of a :begins-at and a :holds-after create the same time line. The assertions differ in their interaction with the persistence of assertions at other times. Whereas a :begins-at will stop the backwards persistence of a fact, :holds-after will not.

Note that the following (one-way) implications are true:

     :begins-at    -->    :holds-after
     :ends-at      -->    :holds-before
     :holds-at     -->    :holds-after
     :holds-at     -->    :holds-before

as well as the following equivalence:

     :holds-before & :holds-after  <-->  :holds-at

Single Valued Relations & Incoherence

Single valued relations will clip. This can occur in one of two ways: (1) If a new value is asserted at the same time as a previously asserted value, the new value will replace the previous value. (2) If a new value is asserted it will clip the persistence of an existing value. Example:

   (defrelation SR :characteristics (:single-valued :temporal))

   (tell (:holds-after  0 (SR Fred 3))
         (:holds-after 10 (SR Fred 4)))

The assertion of (SR Fred 4) at time 10 clips the forward persistence of (SR Fred 3). SR has the value of 3 from time 0 to time 10 and 4 thereafter.

Temporal Incoherence

It is possible to have conflicting persistences with single-valued roles, as in the following example:

   (tell (:holds-after   0 (SR Fred 3))
         (:holds-before 10 (SR Fred 4)))

We have 3 persisting forward from time 0 and 4 persisting backward from time 10. This is an incoherent state from which no well justified action can be taken. Loom stores both values of SR for the interval 0 to 10, but only one (determined at random) will be accessible via the query mechanism. The instance will belong to the concept Temporal-Incoherent during the interval 0 to 10. This is currently the only form of incoherence that we detect in the temporal representation.


The regular Loom query mechanism (retrieve, ask, query) can be used to make temporal queries. Temporal queries use the same operators as assertions.

The syntax for asking temporal queries is:

     (<TemporalOperator> <TimeSpec> <LoomClause>)

<TemporalOperator>  ::=  :holds-after | :holds-before  | :holds-at |
                         :begins-at | :ends-at
<TimeSpec>          ::=  <Integer> | <TimeString> | <KRSL-List>

This syntax differs from that of assertions in two ways: (1) Only one clause is allowed in the body of the temporal operator. (2) The clause can be more complex. In particular, it can include conjunction and disjunction. (But see the semantic caveat about conjunctions below).

The meaning of the operators in queries is the same as in assertions:

:holds-after (:holds-before) The operator is satisfied if the LoomClause holds in the limit as time approaches from the future (past) end of the time line. The value of the LoomClause in the limit from the other direction is irrelvant.

:holds-at The clause must hold in the limit from both directions of the time line.

:begins-at (:ends-at) The LoomClause must hold in the limit as time approaches from the future (past) end of the time line. In addition, the LoomClause must not hold -- either by assertion with :begins-at (:ends-at) or through the closed world assumption from a :holds-after (:holds-before) -- in the limit as time approaches from the past (future) end of the time line.

Following the assertion of

         (tell (:begins-at 0 (TC Fred))   (:end-at 10 (TC Fred)))

The following query returns the values shown in the table for different combinations of operator and time:

            	 (ask (?op ?t (TC Fred)))

|  ?op          | ?t=      0               5             10     |
| :holds-at     |         nil              T            nil     |
| :holds-before |         nil              T             T      |
| :holds-after  |          T               T            nil     |
| :begins-at    |          T              nil           nil     |
| :ends-at      |         nil             nil            T      |

Temporal Generators

In addition to retrieving the values of roles at particular times, Loom can also use :begins-at and :ends-at as temporal generators. These are the only two operators that can serve as generators since they are the only ones with well defined time point values. Using the previous example, :begins-at would generate only 0 whereas :holds-at (using discrete time) would have to generate 1, 2, 3, 4, 5, 6, 7, 8 and 9.

To use one of these operators as a generator, the time argument is replaced by a variable:

     (retrieve ?t (:begins-at ?t (TC Fred)))     ==> (0)
     (ask (:exists ?t (:ends-at ?t (TC Fred))))  ==>  T

Concepts that are defined using value restrictions (such as (:some R TC)) where TC is a temporal concept are allowed as temporal generators in queries. Because the search space for potential transition points involves looking not only at one instance, but also at the temporal transitions of the role fillers, these queries are slower.

Queries and Conjunctions

It is important to realize that conjunctions do not distribute across the temporal operators. The following two forms are NOT identical in a query:

       (:begins-at T (:and A B C))          (:and (:begins-at T A)
                                                  (:begins-at T B)
                                                  (:begins-at T C)

The left form is satisfied by any T at which the conjunction becomes true. This can be satisfied by all three of A, B and C becoming true at time T. It can also be satisfied if B and C were already true and A became true at T, etc. The right form is satisfied only if all three of A, B and C become true at the same time (T). Ignorance of this distinction can lead to particularly subtle misunderstandings in the case where T is a variable.

Environment Control

As noted above, there are three different forms for the input of time points: integers, strings or KRSL style lists. The output from the Loom print functions and save-kb functions can also be formatted in one of those styles. The style chosen is determined by the value of the global variable

*format-time-style* Legal values of the variable are :string, :krsl or nil. The default value is :string. If :string is chosen, then times will be formatted as a standard string such as "2/22/58 18:35:03". Particular details of the formatting are controlled by additional variables described below. If :krsl is chosen, then all printed times will be formatted as a list: (:YEAR 58 :MONTH 2 :DAY 22 :HOUR 18 :MINUTE 35 :SECOND 03). Note that this format extends the KRSL draft standard by adding :second as a field. If the value of this variable is NIL, then the time will appear as an integer. For the example time, this would be the CommonLisp universal time value 1834886103 (for the US West Coast).

All negative time values will be printed as integers regardless of the setting of this variable (i.e., formatting doesn't work for negative time values--dates before 1900). Years will be printed as two or four digit numbers in compatibly with the CommonLisp standard's convention.

The additional control variables are:

*format-time-smallest-unit* Legal values of this variable are :second, :minute, :hour, :day, :month, and :year. The default value is :second. This controls the smallest unit printed when :string or :krsl formatting is selected. It has no effect on the printing of integer values. If complete KRSL compliance is desired, the user should specify :minute as the smallest time unit displayed. This would change the previous examples to "2/22/58 18:35" and (:YEAR 58 :MONTH 2 :DAY 22 :HOUR 18 :MINUTE 35).

*format-time-include-date-p* Controls whether the date is included in the output. The default value is T. This controls operates only when :string or :krsl formatting is selected. It has no effect on the printing of integer values. The default (T) value results in printing as in the examples above. If the value is NIL, then only the time part will be printed: "18:35:03" and (:HOUR 18 :MINUTE 35 :SECOND 03).

*format-time-long-date-p* Controls whether the date is printed in a long form or in an abbreviated form. The default value is NIL, resulting in an abbreviated date. This variable only affects output in :string format. It has no effect on :krsl or integer values. If the value is nil, then dates will format as "2/22/58". If the value where T then the example's date would print as "February 22, 1958".

CLOS Instances Support

If you want to roll your own instances, the following mixins have been defined that allow access to the new features added to Loom 2.1:
Allows you to make temporal assertions about the instances. Including this mixin (directly or by inheritance) is the only way that you can use temporal concepts and assertions. Instance-With-Everything and lite instances include this mixin.
Allows you to make negated assertions about instances. This permits asserting that the instance does not have a particular role filler, or is not a member of a particular concept.
Has been extended to include the new features. In fact, Lite instances are just instances with everything. This can be added as a mixin to other CLOS classes to provide the same functionality as Loom's Lite instances along with other application-specific behavior that derives from the implementor's own classes.

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