home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-06-24 | 29.1 KB | 624 lines | [TEXT/MACA] |
- ; (c) Copyright 1990 by University of Massachusetts. All rights reserved.
- ; This software was conceived, designed, and written by Dan Suthers
- ; while supported by the National Science Foundation under grant number
- ; MDR 8751362, and by a fellowship from Apple Computer, Inc., Cupertino,
- ; CA. Partial support was also received from the Office of Naval Research
- ; under a University Research Initiative Grant, contract N00014-86-K-0764.
- ; Mr. Suthers created this software under his own initiative while in an
- ; academic relationship with the University of Massachusetts. The above
- ; copyright notice was a condition placed by University lawyers on approval
- ; of distribution of this software by Apple Computer, and is not meant to
- ; imply that this software was created in an employment or "work for hire"
- ; relationship between the University and Mr. Suthers.
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; File: HNET.LISP
- ; Author: Dan Suthers
- ; Created: 20-May-88 23:05:48
- ; Modified: 22-Jun-90 02:26:22 (Dan Suthers)
- ; Language: LISP
- ; Package: HNET
- ;
- ; Description: Represents simple term hierarchies (directed acyclic graphs
- ; with labeled nodes). Efficient computation of queries such
- ; as what terms subsume are are subsumed by a given term, and
- ; what the relation between two terms is.
- ;
- ; (c) Copyright 1988, by Daniel D. Suthers
- ; Department of Computer and Information Science
- ; University of Massachusetts
- ; Amherst, Massachusetts 01003
- ;
- ; This software was conceived, designed, and written by Dan Suthers
- ; while supported by the National Science Foundation under grant number
- ; MDR 8751362, and by a fellowship from Apple Computer, Inc., Cupertino,
- ; CA. Partial support was also received from the Office of Naval Research
- ; under a University Research Initiative Grant, contract N00014-86-K-0764.
- ; I wish to acknowledge the generous support of Beverly Woolf, who obtained
- ; the above grants and encouraged me to pursue my own research interests in
- ; her lab. This work would not have been possible without the resources and
- ; stimulating environment of the Computer and Information Science department.
- ;
- ; Permission to use, modify, and distribute this software is granted subject
- ; to the following restrictions and understandings:
- ; 1. The file header, including this notice, shall be retained, and may be
- ; extended to include documentation of modifications to the software.
- ; 2. This material is for nonprofit educational and research purposes only.
- ; Users are requested, but not required, to inform Mr. Suthers of any
- ; noteworthy uses of this software.
- ; 3. Mr. Suthers and the University of Massachusetts make no warrantee or
- ; representation that the operation of this software will be error free,
- ; and are under no obligation to provide any services.
- ; 4. Any user of such software agrees to indemnify and hold harmless Mr.
- ; Suthers and the University of Massachusetts from all claims arising
- ; out of the use or misuse of this software, or arising out of any
- ; accident, injury, or damage whatsoever, and from all costs, counsel
- ; fees, and liabilities incurred in or about any such claim, action, or
- ; proceeding brought thereon.
- ; 5. All materials and reports developed as a consequence of the use of
- ; this software shall duly acknowledge such use, in accordance with
- ; the usual standards of acknowledging credit in academic research.
- ;
- ; Status: Usable.
- ;
- ; Tested: Hewlett Packard 9000 02-Nov-88 Dan Suthers
- ; Macintosh II Coral/Allegro 10-Jan-89 Dan Suthers
- ; Texas Instruments Explorer 02-Nov-88 Dan Suthers DO NOT COMPILE
- ; VAX/VMS 02-Nov-88 Dan Suthers
- ;
- ; Changes:
- ;
- ; 30-Jun-88 ADD-SUPERORDINATE now returns NIL if action failed due to
- ; circularity. This lets using programs know. DEFINE-TERM does not
- ; have to, since it calls UNDEFINE-TERM on existing terms first, and
- ; I modified the latter to undefine ALL references to the term (not
- ; just backlinks, as before).
- ; 02-Jul-88 "symbol" parameters changed to "sym", since TI was confused.
- ; 13-Jul-88 Updated for new SM version.
- ; 23-Jul-88 Added HNET-ROOTS and SUBORDINATE-LEAVES.
- ; 30-Jul-88 Added SUPERORDINATE-MAKES-CYCLE.
- ; 01-Nov-88 Documentation changes.
- ; 10-Jan-89 Changed to accept any object as a "term", not just symbols.
- ; (This lets me index DNET-TERMINALs into a HNET, allowing the
- ; expressions so indexed in a DNET to be organized hierarchically.)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;
- ; About HNET
- ;
- ; HNET represents directed acyclic graphs, and provides efficient computation
- ; of hierarchy relations, eg. finding the immediate or transitive predecessors
- ; and successors of a node in the graph, and determining what the subsumption
- ; relation is between any two nodes. Each node has an associated object, the
- ; TERM. A term's predecessors are called 'superordinates', and its successors
- ; are 'subordinates'. Obviously, an intended application of HNET is to encode
- ; and test subsumption relations in term hierarchies.
- ;
- ; Creating and Manipulating HNETs:
- ; Each HNET is an SM object. See CREATE-HNET, HNET, and HNET-INFO (which were
- ; defined by SM in the HNET package). Also, SM functions such as DESTROYS are
- ; applicable to HNET objects.
- ;
- ; Defining and Undefining Terms:
- ; See DEFINE-TERM, UNDEFINE-TERM, ADD-SUPERORDINATE, DELETE-SUPERORDINATE,
- ; DEFINED-TERMS, and UNDEFINED-TERMS.
- ;
- ; Information About a Term:
- ; See DEFINED-P, TERM-INFO, SUPERORDINATES, SUPERORDINATE*, SUBORDINATES, and
- ; SUBORDINATE*.
- ;
- ; Relation Between Terms:
- ; See SUBSUMPTION-RELATION.
- ;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;
- ; Design and Implementation:
- ;
- ; Speed of queries is optimized, at the expense of speed of defining and
- ; undefining terms where necessary. These are intended to be relatively
- ; static networks.
- ;
- ; Multiple HNETs: All user functions are parameterized by the name of the HNET.
- ; To map term names to structures, I use one hash table for each HNET. The
- ; term structures are not SM structures, since these are not objects which
- ; a user or programmer will need to edit directly, and we'd have to use
- ; generated names anyway. Superordinate and subordinate slots list objects
- ; and the corresponding structure is obtained by hashing into the term table.
- ;
- ; Deferred Linkages: We allow the user to define a term when its super-
- ; ordinates have not been defined, as long as pending definitions are
- ; completed before (that part of) the HNET is used. Pending linkages
- ; between term nodes in a given HNET are saved in the deferred-linkages
- ; slot. Any time a new term is defined, we attempt to complete these links,
- ; as the new term makes possible.
- ;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (in-package :HNET)
-
- (export '(
-
- ;; Manipulating HNETs (all these defined by SM)
- create-hnet
- hnet
- hnet-info
-
- ;; Defining and undefining the terms and their relations.
- add-superordinate
- define-term
- defined-terms
- delete-superordinate
- superordinate-makes-cycle
- undefine-term
- undefined-terms
-
- ;; Querying the network.
- defined-p
- hnet-roots
- term-info
- subsumption-relation
- subordinate-leaves
- subordinates
- subordinate*
- superordinates
- superordinate*
-
- ))
-
- (require :SM)
-
- (proclaim '(optimize (speed 2) (space 2)))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; DATA STRUCTURES
- ;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- ;;; We save these things as is, including the hash table.
-
- (sm:dst (HNET
- (:reusable nil)
- (:redefine nil)
- (:sort-instances t)
- (:comments "
- Hierarchical NETwork object. Represents a DAG of terms, for the purpose of
- computing subsumption relations: see the documetation for package HNET.
- HNETs saved to a file are empty when reloaded, due to the hash table in a
- :compute slot. Not reusable since there is a lot of space to reclaim in the
- hash table."))
-
- (TERM-TABLE (make-hash-table :test #'eq :size 23)
- :type hash-table
- :computed t
- :comments "
- A hash table associating symbols to CL TERM structures. Latter record the
- superordinates and subordinates of terms in an HNET.")
-
- (DEFERRED-LINKAGES (list :head)
- :type list
- :computed t
- :comments "
- A list of (<super> . <sub>) entries, where <super> was undefined at the time
- it was declared as a parent of <super>. This list needs to be checked every
- time a new term is defined, for pending linkages involving that term. :Head
- is for nconc style processing.")
-
- (INFO nil
- :type T
- :computed nil
- :comments "
- The user may associate arbitrary information with the HNET by storing it here.")
- )
-
- (defstruct (TERM (:constructor make-term (superordinates info-slot)))
- (superordinates nil :type list)
- (subordinates nil :type list)
- (info-slot nil :type T)
- )
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; MACROS (ADT OPERATIONS)
- ;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- ;;; Only used internally. Save space by not loading in compiled files.
- (eval-when (compile eval)
-
- (defmacro BACKLINK (obj super hnet-struct)
- ;; Backlink from parent, or push deferred linkage.
- `(let ((super-struct (gethash ,super (hnet-term-table ,hnet-struct))))
- (declare (type term super-struct) (optimize speed))
- (if super-struct
- (pushnew ,obj (term-subordinates super-struct))
- (nconc (hnet-deferred-linkages ,hnet-struct)
- (list (cons ,super ,obj))))))
-
- (defmacro UNBACKLINK (obj super hnet-struct)
- ;; Remove backpointers from the superordinate. If it does not exist,
- ;; (<super> . <obj>) is removed from deferred-linkages.
- `(let ((super-struct (gethash ,super (hnet-term-table ,hnet-struct))))
- (declare (type term super-struct) (optimize speed))
- (if super-struct
- (setf (term-subordinates super-struct)
- (delete ,obj (term-subordinates super-struct)))
- (setf (hnet-deferred-linkages ,hnet-struct)
- (delete (cons ,super ,obj)
- (hnet-deferred-linkages ,hnet-struct) :test #'equal)))))
-
- (defmacro PROCESS-DEFERRED-LINKAGES (new-term hnet-struct)
- ;; Called when <new-term> was just defined in the hnet.
- ;; Hnet-Deferred-linkages is of form (:head (<super> . <sub>) ...). If
- ;; <new-term> occurs as <super>, we need to backlink to <sub> and delete
- ;; the (<super> . <sub>) entry from the list. The :head lets us delete
- ;; without consing, by manipulating the cdr of a pointer into the list.
- `(do ((dl-ptr (hnet-deferred-linkages ,hnet-struct))
- (term-struct (gethash ,new-term (hnet-term-table ,hnet-struct))))
- ((null (cdr dl-ptr)))
- (declare (list dl-ptr) (type term term-struct) (optimize speed))
- (cond ((eq (caadr dl-ptr) ,new-term)
- ;; Deferred superordinate: backlink and delete entry. Use pushnew
- ;; since retries may get multiple entries on deferred-linkages.
- (pushnew (cdadr dl-ptr) (term-subordinates term-struct))
- (setf (cdr dl-ptr) (cddr dl-ptr)))
- (T (setf dl-ptr (cdr dl-ptr))))))
-
- (defmacro MAKES-CYCLE (term hnet-struct)
- ;; Returns T if a cycle is found, starting from <term> and searching up.
- ;; Need the <term> parameter because the heirarchy may not be connected.
- `(let ((*hnet-struct* ,hnet-struct))
- (declare (type hnet *hnet-struct*)
- (special *hnet-struct*)
- (optimize speed))
- (labels ((cycle-search (term active)
- (declare (list active) (special *hnet-struct*))
- (if (member term active) (throw :cycle-catch T))
- (push term active)
- ;; The <term> may not be defined in <hnet-struct> yet ...
- ;; if not, get its supers as preimage in deferred-linkages.
- (dolist (super (if (gethash term (hnet-term-table *hnet-struct*))
- (term-superordinates
- (gethash term (hnet-term-table *hnet-struct*)))
- (do ((ptr (cdr (hnet-deferred-linkages *hnet-struct*))
- (rest ptr))
- (preimage nil))
- ((null ptr) preimage)
- (declare (list ptr preimage))
- (if (eq (cdar ptr) term)
- (pushnew (caar ptr) preimage)))))
- (cycle-search super active))))
- (catch :cycle-catch (cycle-search ,term nil) nil))))
-
- ;;; For use on a completed hierarchy. This assumes there are NO cycles,
- ;;; and assumed there are no deferred-linkages. (Debugging: cycles show
- ;;; up as infinite regress or as two terms being mutually superordinate;
- ;;; deferred-linkages show up as "Error: NIL is not a structure".
-
- (defmacro OCCURS-ABOVE (super-candidate start-term hnet-struct)
- ;; Returns T iff <super-candidate> is a superordinate of <start-term> in
- ;; <hnet-struct>, including the case where they are equal. (No cycles!)
- `(let ((*super-candidate* ,super-candidate)
- (*term-table* (hnet-term-table ,hnet-struct)))
- (declare (hash-table *term-table*)
- (special *super-candidate* *term-table*)
- (optimize speed))
- (labels ((super-search (term)
- (declare (special *super-candidate* *term-table*))
- (if (eq term *super-candidate*) (throw :super-catch T))
- (dolist (super (term-superordinates (gethash term *term-table*)))
- (super-search super))))
- (catch :super-catch (super-search ,start-term) nil))))
-
- ) ; end of EVAL-WHEN
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;;
- ;;; EXPORTED
- ;;;
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (defun DEFINE-TERM (obj superordinates hnet &optional (info nil))
- "define-term <obj> <superordinates> <hnet> [Function]
- Adds <obj> as a term in <hnet>. If the superordinates do not exist, the
- inverse linking to their children will be deferred until they do exist.
- If the term already is defined, it is undefined first. Returns <obj>."
- (check-type superordinates list)
- (check-type hnet symbol)
- (assert (sm:gets 'hnet hnet) (hnet)
- "[HNET:DEFINE-TERM] HNET ~S is unknown." hnet)
- (let ((hnet-struct (sm:gets 'hnet hnet))
- (term-struct (make-term superordinates info)))
- (declare (type hnet hnet-struct) (type term term-struct))
- ;; If it already exists, undefine it while we know who it was linked to.
- (if (gethash obj (hnet-term-table hnet-struct))
- (undefine-term obj hnet))
- ;; Now it is safe to clobber old entry in the hash table.
- (setf (gethash obj (hnet-term-table hnet-struct)) term-struct)
- ;; Make any linkages the new definition may have enabled.
- (process-deferred-linkages obj hnet-struct)
- (dolist (super superordinates)
- (backlink obj super hnet-struct))
- ;; Due to undefine-term, cycles are not possible, so no check needed here.
- obj))
- (proclaim '(function define-term (t list symbol &optional t) t))
-
- (defun UNDEFINE-TERM (term hnet)
- "undefine-term <term> <hnet> [Function]
- Removes <term> from the <hnet>, removing all links in both directions.
- Returns <term>."
- (check-type hnet symbol)
- ;; These have to be done outside the following LET so the user has a
- ;; chance to change what LET binds. Less efficient this way though.
- (assert (sm:gets 'hnet hnet) (hnet)
- "[HNET:UNDEFINE-TERM] HNET ~S is unknown." hnet)
- (assert (defined-p term hnet) (term)
- "[HNET:UNDEFINE-TERM] Term ~S is not defined in ~S." term hnet)
- (let* ((hnet-struct (sm:gets 'hnet hnet))
- (term-struct (gethash term (hnet-term-table hnet-struct))))
- (declare (type hnet hnet-struct) (type term term-struct))
- ;; Remove references to it by its subordinates.
- (dolist (sub (term-subordinates term-struct))
- ;; This is the essence of (delete-superordinate sub term hnet):
- (setf (term-superordinates (gethash sub (hnet-term-table hnet-struct)))
- (delete term (term-superordinates
- (gethash sub (hnet-term-table hnet-struct)))))
- (unbacklink sub term hnet-struct))
- ;; Remove references to it by its superordinates.
- (dolist (super (term-superordinates term-struct))
- (unbacklink term super hnet-struct))
- ;; Take it out of the term table..
- (remhash term (hnet-term-table hnet-struct))
- term))
- (proclaim '(function undefine-term (T symbol) T))
-
- (defun DEFINED-P (obj hnet)
- "defined-p <obj> <hnet> [Function]
- Returns T iff <obj> is defined as a term in the <hnet>."
- (check-type hnet symbol)
- (assert (sm:gets 'hnet hnet) (hnet)
- "[HNET:DEFINED-P] HNET ~S is unknown." hnet)
- (if (gethash obj (hnet-term-table (the hnet (sm:gets 'hnet hnet)))) T NIL))
- (proclaim '(function defined-p (T symbol) T))
-
- (defun DEFINED-TERMS (hnet)
- "defined-terms <hnet> [Function]
- Returns a (freshly consed) list of all currently defined terms in <hnet>."
- (check-type hnet symbol)
- (assert (sm:gets 'hnet hnet) (hnet)
- "[HNET:DEFINED-TERMS] HNET ~S is unknown." hnet)
- (let ((defined-terms nil))
- (declare (list defined-terms)
- (optimize speed))
- (maphash #'(lambda (key entry)
- (declare (ignore entry))
- (push key defined-terms))
- (hnet-term-table (the hnet (sm:gets 'hnet hnet))))
- defined-terms))
- (proclaim '(function defined-terms (symbol) list))
-
- (defun UNDEFINED-TERMS (hnet)
- "undefined-terms <hnet> [Function]
- Returns a list of objects which have been given as the superordinate of
- existing terms in <hnet>, yet are not yet themselves defined as terms."
- (check-type hnet symbol)
- (assert (sm:gets 'hnet hnet) (hnet)
- "[HNET:UNDEFINED-TERMS] HNET ~S is unknown." hnet)
- (delete-duplicates
- (mapcar #'car (cdr (hnet-deferred-linkages (the hnet (sm:gets 'hnet hnet)))))))
- (proclaim '(function undefined-terms (symbol) list))
-
- (defun HNET-ROOTS (hnet)
- "hnet-roots <hnet> [Function]
- Returns a list of all terms in <hnet> which have no superordinates."
- (check-type hnet symbol)
- (assert (sm:gets 'hnet hnet) (hnet)
- "[HNET:HNET-ROOTS] HNET ~S is unknown." hnet)
- (let ((term-table (hnet-term-table (the hnet (sm:gets 'hnet hnet))))
- (roots nil))
- (declare (hash-table term-table) (list roots) (optimize speed))
- (maphash #'(lambda (key term-struct)
- (declare (type term term-struct))
- (if (null (term-superordinates term-struct))
- (push key roots)))
- term-table)
- roots))
- (proclaim '(function hnet-roots (symbol) list))
-
- (defun SUPERORDINATE-MAKES-CYCLE (term super hnet)
- "superordinate-makes-cycle <term> <super> <hnet> [Function]
- Returns T iff (add-superordinate <term> <super> <hnet> would result in
- an error due to creation of a cycle in the HNET."
- (check-type hnet symbol)
- (assert (sm:gets 'hnet hnet) (hnet)
- "[HNET:SUPERORDINATE-MAKES-CYCLE] HNET ~S is unknown." hnet)
- (assert (defined-p term hnet) (term)
- "[HNET:SUPERORDINATE-MAKES-CYCLE] Term ~S is not defined in ~S." term hnet)
- (let ((hnet-struct (sm:gets 'hnet hnet)))
- (declare (type hnet hnet-struct))
- ;; UGLY way to do it ... Go ahead and define it, test, and undefine.
- (pushnew super (term-superordinates
- (gethash term (hnet-term-table hnet-struct))))
- (backlink term super hnet-struct)
- (prog1
- (makes-cycle term hnet-struct)
- (delete-superordinate term super hnet))))
- (proclaim '(function superordinate-makes-cycle (T T symbol) symbol))
-
- (defun ADD-SUPERORDINATE (term super hnet)
- "add-superordinate <term> <super> <hnet> [Function]
- Installs <super> as a new superordinate of <term> in <hnet>, deferring
- linkage if <super> does not exist yet. Cerror if cycle created: if
- continued, the <super> will be undone. Returns T if the addition
- succeeded, and NIL if it did not."
- (check-type hnet symbol)
- ;; These have to be done outside the following LET so the user has a
- ;; chance to change what LET binds. Less efficient this way though.
- (assert (sm:gets 'hnet hnet) (hnet)
- "[HNET:ADD-SUPERORDINATE] HNET ~S is unknown." hnet)
- (assert (defined-p term hnet) (term)
- "[HNET:ADD-SUPERORDINATE] Term ~S is not defined in ~S." term hnet)
- (let ((hnet-struct (sm:gets 'hnet hnet)))
- (declare (type hnet hnet-struct))
- (pushnew super (term-superordinates
- (gethash term (hnet-term-table hnet-struct))))
- (backlink term super hnet-struct)
- (if (makes-cycle term hnet-struct)
- (progn
- (cerror "Will delete this new superordinate."
- "[HNET:ADD-SUPERORDINATE] ~S's new superordinate ~S creates a cycle in ~S."
- term super hnet)
- (delete-superordinate term super hnet)
- nil)
- t)))
- (proclaim '(function add-superordinate (T T symbol) symbol))
-
- (defun DELETE-SUPERORDINATE (term super hnet)
- "delete-superordinate <term> <super> <hnet> [Function]
- Removes <super> as a superordinate of <term> in <hnet>, removing all links,
- actual or deferred."
- (check-type hnet symbol)
- ;; These have to be done outside the following LET so the user has a
- ;; chance to change what LET binds. Less efficient this way though.
- (assert (sm:gets 'hnet hnet) (hnet)
- "[HNET:DELETE-SUPERORDINATE] HNET ~S is unknown." hnet)
- (assert (defined-p term hnet) (term)
- "[HNET:DELETE-SUPERORDINATE] Term ~S is not defined in ~S." term hnet)
- (let ((hnet-struct (sm:gets 'hnet hnet)))
- (declare (type hnet hnet-struct))
- (setf (term-superordinates (gethash term (hnet-term-table hnet-struct)))
- (delete super (term-superordinates
- (gethash term (hnet-term-table hnet-struct)))))
- (unbacklink term super hnet-struct)
- super))
- (proclaim '(function delete-superordinate (T T symbol) T))
-
- (defmacro TERM-INFO (obj hnet)
- "term-info <term> <hnet> [Macro]
- Setf-able access to the information associated with <term> in <hnet>."
- `(term-info-slot
- (the term
- (gethash ,obj
- (hnet-term-table (the hnet (sm:gets 'hnet ,hnet)))))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; The remainder of these must be fast, so we are lax on checking arguments,
- ;;; only doing so to the extent necessary to prevent a user error from making
- ;;; it to deeper code (eg. loops and macros).
-
- (defun SUPERORDINATES (term hnet)
- "superordinates <term> <hnet> [Function]
- Returns the IMMEDIATE superordinates of <term> in the <hnet>."
- (term-superordinates
- (the term
- (gethash term (hnet-term-table (the hnet (sm:gets 'hnet hnet)))))))
- (proclaim '(function superordinates (T symbol) list))
-
- (defun SUBORDINATES (term hnet)
- "subordinates <term> <hnet> [Function]
- Returns the IMMEDIATE subordinates of <term> in the <hnet>."
- (term-subordinates
- (the term
- (gethash term (hnet-term-table (the hnet (sm:gets 'hnet hnet)))))))
- (proclaim '(function subordinates (T symbol) list))
-
- (defun SUPERORDINATE* (term hnet)
- "superordinate* <term> <hnet> [Function]
- Returns ALL (transitive) superordinates of <term> in the <hnet>,
- including <term>. The returned list is in order of breadth-first
- search upwards starting with <term>."
- (let ((hnet-struct (the hnet (sm:gets 'hnet hnet))))
- (declare (type hnet hnet-struct) (optimize speed))
- ;; This one check makes sure everything is there before getting deep
- ;; into speed optimized code. (If hnet is bad, it will blow up now.)
- (assert (gethash term (hnet-term-table hnet-struct)) (term)
- "[HNET:SUPERORDINATE*] Term ~S is not in HNET ~S" term hnet)
- ;; Frontier is current terms to expand into supers. Once they are
- ;; expanded, they go onto the list of supers found (preserving order).
- (do ((frontier (list term))
- (new-frontier nil nil)
- (supers (list :head)))
- ((null frontier) (delete-duplicates (cdr supers)))
- (declare (list frontier new-frontier supers))
- (dolist (super frontier)
- (dolist (new-super (term-superordinates
- (the term
- (gethash super (hnet-term-table hnet-struct)))))
- (push new-super new-frontier)))
- (nconc supers frontier)
- (setf frontier new-frontier))))
- (proclaim '(function superordinate* (T symbol) list))
-
- (defun SUBORDINATE* (term hnet)
- "subordinate* <term> <hnet> [Function]
- Returns ALL (transitive) subordinates of <term> in the <hnet>,
- including <term>. The returned list is in order of breadth-first
- search downwards starting with <term>."
- (let ((hnet-struct (the hnet (sm:gets 'hnet hnet))))
- (declare (type hnet hnet-struct) (optimize speed))
- ;; This one check makes sure everything is there before getting deep
- ;; into speed optimized code. (If hnet is bad, it will blow up now.)
- (assert (gethash term (hnet-term-table hnet-struct)) (term)
- "[HNET:SUBORDINATE*] Term ~S is not in HNET ~S" term hnet)
- ;; Frontier is current terms to expand into subs. Once they are
- ;; expanded, they go onto the list of subs found (preserving order).
- (do ((frontier (list term))
- (new-frontier nil nil)
- (subs (list :head)))
- ((null frontier) (delete-duplicates (cdr subs)))
- (declare (list frontier new-frontier subs))
- (dolist (sub frontier)
- (dolist (new-sub (term-subordinates
- (the term
- (gethash sub (hnet-term-table hnet-struct)))))
- (push new-sub new-frontier)))
- (nconc subs frontier)
- (setf frontier new-frontier))))
- (proclaim '(function subordinate* (T symbol) list))
-
- (defun SUBORDINATE-LEAVES (term hnet)
- "subordinate-leaves <term> <hnet> [Function]
- Returns leaf terms which are subordinates of <term> in the <hnet>."
- (let ((hnet-struct (the hnet (sm:gets 'hnet hnet))))
- (declare (type hnet hnet-struct) (optimize speed))
- (assert (gethash term (hnet-term-table hnet-struct)) (term)
- "[HNET:SUBORDINATE-LEAVES] Term ~S is not in HNET ~S" term hnet)
- (do ((frontier (list term))
- (new-frontier nil nil)
- (leaves (list :head)))
- ((null frontier) (delete-duplicates (cdr leaves)))
- (declare (list frontier new-frontier leaves))
- (dolist (sub frontier)
- (let ((subordinates
- (term-subordinates
- (the term (gethash sub (hnet-term-table hnet-struct))))))
- (if (null subordinates)
- (nconc leaves (list sub))
- (dolist (new-sub subordinates)
- (push new-sub new-frontier)))))
- (setf frontier new-frontier))))
- (proclaim '(function subordinate-leaves (T symbol) list))
-
-
- (defun SUBSUMPTION-RELATION (term1 term2 hnet)
- "subsumption-relation <term1> <term2> <hnet> [Function]
- Determines the subsumption relation between two terms in <hnet>.
- Returns :SUBORDINATE if <term1> is a subordinate of <term2>,
- :SUPERORDINATE for the inverse case, and :INCOMPARABLE if neither
- subsumes the other. Heuristic guide: give <term1> the one you
- suspect is superordinate. The algorithm checks for this first."
- (let ((hnet-struct (the hnet (sm:gets 'hnet hnet))))
- (declare (type hnet hnet-struct) (optimize speed))
- ;; Safety check, to make optimizing speed safe.
- (assert (and (gethash term1 (hnet-term-table hnet-struct))
- (gethash term2 (hnet-term-table hnet-struct)))
- (term1 term2)
- "[HNET:SUBSUMPTION-RELATION] One or both terms are not in ~S" hnet)
- (cond ((occurs-above term1 term2 hnet-struct) :superordinate)
- ((occurs-above term2 term1 hnet-struct) :subordinate)
- (T :incomparable))))
- (proclaim '(function subsumption-relation (T T symbol) keyword))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (provide :HNET)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; EOF
-