The Department of Computer Science & Engineering
SNePS main page

SNePS 2.7 Release Notes

The following is a list of changes in SNePS version 2.7. Only changes that are visible to the SNePS user are listed.
SNePS 2.7 also includes some additional improvements.

Note: If the installer chooses to make either the Java-SNePS API or the JUNG/JIMI version of show available, the installation must have Franz's Allegro CL or else one of the prepackaged SNePS executables must be used.

  1. The speed of computing the union of node sets has been improved.
  2. The intext command runs the load function documented below.
  3. Previously, one could not have a node named with a string the Lisp reader could not handle, such as "#", and node-to-lisp-object did not handle nodes with names like "5 pounds". Both these problems are now fixed. A node's name can now be any Lisp number, string, or symbol, and node-to-lisp-object is able to handle it.
  4. Previously, *infertrace* and *plantrace* defaulted to t, so that tracing was done unless turned off. Now, the default values are nil, so that tracing is not done unless turned on.

  1. The SNePSLOG parser has been completely rewritten, improved, and made more robust.
    Error messages should be more understandable.

    The SNePSLOG syntax is now:

        Note: _(_ and  _)_ are the object language characters between the _ marks.
       input            ::= wffNameCommand | snepslogCommand | wffCommand
       wffNameCommand   ::= wffName terminalPunctuation
       wffCommand       ::= wff terminalPunctuation ; wff must not be a single symbol
       wff              ::= infixedTerm | entailment | prefixedTerm
       infixedTerm      ::= prefixedTerm [( and | or | <=> ) prefixedTerm]+
       entailment       ::= termSet (=> | v=> | &=> | <Lisp integer> =>) termSet
       pTermSet         ::= termSet ; but taken to denote all terms that match
       termSet          ::= prefixedTerm | { termSequence }
       termSequence     ::= prefixedTerm [, prefixedTerm]*
       prefixedTerm     ::= negatedTerm | andorTerm | allTerm | nexistsTerm |
                            threshTerm | atomicTerm
       negatedTerm      ::= ~ atomicTerm
       andorTerm        ::= andor (i, j) termSet ; i, j integers, 0 <= i <= j
       threshTerm       ::= thresh (i [, j]) termSet ; i, j integers, 0 <= i <= j
       allTerm          ::= all _(_ symbolSequence _)_ _(_ wff _)_   ; but wff cannot be an atomic symbol
       nexistsTerm      ::= nexists nexistsParameters
                            _(_ symbolSequence _)_ 
                            _(_ termSet : termSet _)_
       nexistsParameters ::= _(_ i, j, k _)_ | _(_ _, j, _ _)_ | _(_ i, _, k _)_
       atomicTerm       ::= wffName | qvar | SNePSLOGsymbol |
                            withsome/allTerm | ; in mode 3 only
                            (qvar | SNePSLOGsymbol) _(_ termSetSequence _)_ |
                            _(_ wff _)_
       withsome/allTerm ::= (withsome | withall) _(_ symbolSequence, termSet, termSet [, termSet]  _)_
       termSetSequence  ::= termSet [, termSet]*
       symbolSequence ::= SNePSLOGsymbol [, SNePSLOGsymbol]*
       wffName          ::= wff <Lisp integer, i> ; Assuming that mi is a SNePS node
       qvar             ::= ? SNePSLOGsymbol
       SNePSLOGsymbol   ::= (wff <Lisp integer>) | <Lisp atom>
       terminalPunctuation ::= . | ! | ? | ??
       snepslogCommand ::= %-command |
                           ^-command |
                           a-command |
                           c-command |
                           d-command |
                           e-command |
                           l-command |
                           n-command |
                           p-command |
                           r-command |
                           s-command |
                           t-command |
       %-command ::= % <SNePSUL command>
       ^-command ::= ^^ | ^ <Lisp form>
       a-command ::= activate wff [.] |
                     activate! wff [terminalPunctuation] |
                     add-to-context SNePSLOGsymbol termSet [.]|
                     ask wff [terminalPunctuation] |
                     askifnot wff [terminalPunctuation] |
                     askwh wff [terminalPunctuation] |
                     askwhnot wff [terminalPunctuation]
       c-command ::= clear-infer [.] |
                     clearkb [.]
       d-command ::= define-frame SNePSLOGsymbol <Lisp list> [<Lisp string>] [.] |
                     define-path SNePSRelation SNePSPath [.] |
                     describe-terms [pTermSet] [.] |
                     describe-context [SNePSLOGsymbol] [.] |
                     demo [<file path> | ? | i] [t | b | bv | a | av | n] [.]
       e-command ::= expert [.]
       l-command ::= lisp [.] |
                     list-contexts [.] |
                     list-terms [pTermSet] [.] |
                     list-wffs [.] |
                     list-asserted-wffs [SNePSLOGsymbol] [.] |
                     load <file path>
       n-command ::= normal [.]
       p-command ::= perform atomicTerm
       r-command ::= remove-from-context SNePSLOGsymbol pTermSet
       s-command ::= set-context SNePSLOGsymbol [pTermSet]
                 ::= set-default-context SNePSLOGsymbol 
                 ::= set-mode-1
                 ::= set-mode-2
                 ::= set-mode-3 [t | nil]
                 ::= show [pTermSet] [.]
       t-command ::= trace [SNePSLOGsymbol]* [.]
          Specially recognized symbols: inference, acting, translation, parsing
       u-command ::= undefine-path SNePSRelation [.]
                 ::= unlabeled [.]
                 ::= untrace [SNePSLOGsymbol]* [.]
          Specially recognized symbols: inference, acting, translation, parsing
  2. The SNePSLOG load command runs the load function discussed below.
  3. Normal output from SNePSLOG now shows the wff number (wffi) before each top-level wff listed. The old, unlabeled, output is obtained by giving SNePSLOG the unlabeled command. Output produced after the expert command shows both the wff number and the support, as previously.
  4. Previously, inference tracing and acting tracing was on unless turned off. Now, inference tracing and acting tracing is off unless turned on.
  5. Previously, snepslog:tell took a sequence of zero or more strings, passed each to the SNePSLOG interpreter, printed what SNePSLOG would print, and returned nil. Now snepslog:tell takes a single string, passes it to the SNePSLOG interpreter, prints nothing, and returns whatever would be returned by the string as a SNePSLOG command. For example,
    cl-user(10): (snepslog:tell "Isa(Fido,dog).")
    cl-user(11): (snepslog:tell "Isa(Fluffy,cat).")
  6. Previously snepslog:askwh and snepslog:askwhnot would return a simple list of terms, even if the query had more than one free variable. Now, snepslog:askwh and snepslog:askwhnot return a list of substitutions (assoc lists), even if the query has only one free variable. For example,
    cl-user(12): (snepslog:askwh "Isa(?x,?y)")
    (((snepslog::y . cat) (snepslog::x . Fluffy))
     ((snepslog::y . dog) (snepslog::x . Fido)))
  7. A Java-SNePS API has been added to give Java programs access to SNePS via the tell-ask interface. Use of the API requires Franz's Allegro CL or one of the prepackaged SNePS executables. To use SNePS from a Javaprogram: include the locations of the files JavaSnepsAPI.jar and jlinker.jar in the Java classpath; and import into the Java program edu.buffalo.JavaSnepsAPI, edu.buffalo.Substitution, and java.util.ArrayList. The Java program must create an object of the JavaSnepsAPI class, which can use the Java versions of the tell and ask functions. There are two constructors of the JavaSnepsAPI instance. One requires a port to connect to and the String filepath specifying the location of the java_sneps_config.config file (default location is in the JavaSnepsAPI subdirectory, but ask the individual who installed SNePS for specifics). This method doesn't require you to manually start SNePS, and will do so for you automatically provided a correct configuration file. The second method only requires that you specify the port to run the JavaSnepsAPI over, but requires that you manually start the sneps system and invoke the java-sneps connection funtion as follows: (snepslog:init-java-sneps-connection <port> <java-classpath>). Note: <port> should be the same port as passed to the JavaSnepsAPI constructor, and <java-classpath> the string representing the classpath needed to run the JavaSnepsAPI program.
  8. Previously, in add-to-context context termSet, only the wffs in termSet that had already been introduced to the KB as hypotheses were added as hypotheses of context. Now, all the wffs in termSet are asserted into the context.
  9. Previously inference and acting tracing were on by default. Now, they are off by default.
  10. An optional <Lisp string> has been added to define-frame. This string should give the intended semantics of the function whose frame is being defined, and it must contain a substring of the form [relation], for every non-null relation in the frame. The string will be used by describe-terms to construct a gloss of the term.

  1. Due to the use of active connection graphs, SNePS could always handle rules of the form
    all(x,y,z)({ancestor(x,y), ancestor(y,z)} &=> ancestor(x,z))
    without getting into infinite recursive loops. However, infinite recursive loops would still occur if backchaining through rules of the form
    all(x)(Duck(motherOf(x)) => Duck(x))
    or when forward-chaining through rules of the form
    all(x)(number(x) => number(s(x))).
    Now those two kinds of infinite recursive loops are also avoided by use of the depth bounds *depthcutoffback* and *depthcutoffforward*, respectively. They work by limiting the nesting depth of functional terms when backchaining or forward-chaining. The default value of each of them is 10, but they can be reset by the user. If either is set to nil it means "no limit" in that direction.
  2. A procecural attachment facility has been added. Normally, if the system backchains into a proposition-valued function node, it will use inference to determine what instances of the (negation of the) node may be asserted. If, however, the node has an arc labelled attachedfunction to a node that has been attached to a function, the system will determine what instances of the (negation of the) node may be asserted by evaluating the attached function. For instance, backchaining into the node

    (p1 (attachedfunction Sum) (add1 3) (add2 4) (sum v1))
    could result in a computation to determine that the node
    (m1 (attachedfunction Sum) (add1 3) (add2 4) (sum 7))
    should be asserted.

    To use the procedural attachment facility, the user must do three things:

    1. if using SNePSLOG, define the frames for the predicates to which functions will be attached,
      if using SNePSUL, define the relations to be used as function arguments;
    2. define the attached function;
    3. attach the function to a SNePS predicate node.
    These steps are more fully explained below.
    1. For an example of (1) using the above example, the SNePSLOG user would do:
      define-frame Sum(attachedfunction add1 add2 sum)
      and the SNePSUL user would do:
      (define add1 add2 sum)
      The relation, attachedfunction is defined by the SNePS system.
    2. Attached functions must be defined by
      (define-attachedfunction fun ( <lambda variables> ) &body)
      1. fun will be the name of the attached function.
      2. each lambda variable must either be a relation used for the arguments of the predicate node, or such a relation enclosed in a pair of parentheses. If the lambda variable is an atomic relation name, it will be bound to the (modified) set of nodes that that relation points to. If it is a relation enclosed in parentheses, the relation symbol will be bound to one element of the (modified) set of nodes that that relation points to (presumably, there will only be one). The way that the nodes will be modified is
        1. if the node is a variable, it will be left alone;
        2. if the node's name looks like a Lisp number, the number will be provided;
        3. otherwise, a Lisp symbol whose name is the same string as the node's name will be provided.
        In the body of the attached function, the three Lisp predicates numberp, symbolp, and sneps:isvar.n may be used to distinguish the three types of argument.
      3. the attached function must return a list, each of whose members is a list of two members:
        1. Either: 'snip:pos to indicate that the instance of the proposition is to be asserted;
          or 'snip:neg to indicate that the negation of the instance of the proposition is to be asserted;
        2. A substitution of the form ( ... (var term) ...) to indicate the appropriate instance of the proposition, where each var is a variable-node argument, and term is a Lisp object to be converted into a node giving the instance.
        If the attached function returns nil, that indicates that neither any instance of the proposition nor any instance of its negation is to be asserted.
      A simple attached-function definition for the above example is:
      (define-attachedfunction sumfn ((add1) (add2) (sum))
         ;; If all three are numbers, check that it is correct.
         ((and (numberp add1) (numberp add2) (numberp sum))
          (if (cl:= (cl:+ add1 add2) sum)
      	`((snip:pos nil))
            `((snip:neg nil))))
         ;; If add1 and add2 are numbers, and sum is a variable, compute the sum.
         ((and (numberp add1) (numberp add2) (sneps:isvar.n sum))
          `((snip:pos ( (,sum . ,(cl:+ add1 add2))) )))
         ;; Else, don't give an answer
         (t nil)))
    3. The user must attach functions to SNePS predicates using
      (attach-function node fun node fun ...)
      For example
      (attach-function Sum sumfn)
      After which, the SNePSLOG user can ask questions such as
      and Sum(4,6,?x)?
      and the SNePSUL user can ask questions such as


      1. Previously clear-infer deactivated act nodes. That is no longer done.
      2. The message printed when the proposition of an achieve act has already been achieved has been placed under the control of plantrace.
      3. The message printed when there is no plan found for an act has been improved and placed under the control of plantrace.
      4. The guarded acts in snif and sniterate can now take sets of conditions and sets of acts. snif and each loop of sniterate still performs one act one of whose guards holds.
      5. A warning is issued if SNeRE is asked to perform an act which is not represented as a node with an action arc emanating from it.
      6. The mental acts adopt and unadopt are now available for adopting and unadopting policies, and should be used for those purposes instead of believe and disbelieve.
      7. Any of the variables in the lambda list of define-primaction may be enclosed in parentheses, in which case the variable will be bound to a member of the appropriate nodeset. This avoids many uses of sneps:choose.ns to pick a member from the nodeset. Also the primitive-action function is now compiled for faster behavior.

      Program Interface
      1. The function (load file :format format) is available. It reads and executes all the SNePSUL (if format is :sneps or :snepsul) or SNePSLOG commands (if format is :snepslog (default)) on file without printing anything. Any asserting specified by the file is postponed until the file is completely loaded, then the asserted terms are checked for consistency by SNeBR. The load function may be called from Lisp programs outside the SNePS or SNePSLOG loop. The symbol load is external in the sneps package, and accessible in the snepslog package. The SNePSUL version of this function is now used by the SNePSUL command intext.

      XGinseng and show
      XGinseng has been eliminated because it was implemented in Garnet, which has not been maintained, and was difficult to use. SNePS networks may now be displayed by show using either: dot; or a graphical representation implemented in Java that requires JUNG and JIMI. Whichever method the installer chooses to use, the sneps_config.lisp file (in the SNePS home directory) should be configured appropriately. See the config file for details. If the installer installs both versions of show, the user can dynamically pick the version to be used by setting the global variable cl-user:*use-gui-show* to t for the JUNG/JIMI version, or to nil for the dot version.

      Last modified: Thu Sep 20 14:41:12 EDT 2007
      Stuart C. Shapiro <>

      (deduce attachedfunction Sum add1 3 add2 4 sum 7)
      and (deduce attachedfunction Sum add1 3 add2 4 sum $x)