|
(defpackage :radiplex (:export :match :clear-session :add-parent :get-parents :form-q-potential :add-qnode :clear-parent-cache :*last-radiplex-layer* :radiplex-get :get-previous-layer :add-to-layer :get-grandparents :set-all-parents :all-matches :all-bindings :contains :inputs :outputs :current-session :clear-session :qexprp :get-parent-closures) (:use :common-lisp :theoretica :english :util :db)) (in-package :radiplex) ;;;; Implementation of Ontological Topology (otopology) (defparameter *session* (make-instance 'session)) (defparameter *input-session* (make-instance 'session)) (defparameter *output-session* (make-instance 'session)) (defun current-session () *session*) (defun inputs () *input-session*) (defun outputs () *output-session*) (defun clear-session () (setf *session* (make-instance 'session))) #| what do we need for a general match? - we are looking from the context pool what is active * what is immediate should be in the session already - see what exactly matches, and what instantiates based on what is active - cross-bindings are active relative to each other * directionality? |# (defgeneric all-matches (obj &optional ctx) (:documentation "Find what general object(s) matches the obj passed in.")) ; in general, either they are in a context or have been activated, correct? ; variables: e.g. q1:noun is different from q2:noun, but both match noun (defmethod all-matches ((qnod qnode) &optional (ctx *session*)) (all-matches (q qnod) ctx)) (defmethod all-matches ((id integer) &optional (ctx *session*)) (all-matches (get-one id) ctx)) ; serendipitously, this may solve the question of when to use general forms ; to solve specific cases: if their satisfaction is active in the current ; context, they are matched against, it looks like... (defmethod all-matches ((nod node) &optional (ctx *session*)) (unless (gethash (hashid nod) (proper ctx)) (return-from all-matches '())) (let* ((qmatched (unless (qnodep nod) (gethash (hashid nod) (q-cache ctx)))) (matched (push (hashid nod) qmatched))) (let ((parents (get-parents (hashid nod) nil))) (dolist (parent parents) (let ((one (get-one parent))) (when (connectionp one) ;; there doesn't need to be a match in the other direction, no? (when (eq (prev one) (hashid nod)) (let ((match-curr (all-matches (get-one (curr one)) ctx))) (when (member (hashid *form*) match-curr) (setf matched (nconc matched (all-matches (get-one (subs one)) ctx)))))))))) (remove-duplicates matched))) ; shall we put Q-formation here? ; in all-matches for closures and connections, do we need also to check as in for ; node, if they satisfy or are satisfied, increasing their matches? ; get all satisfied closures(?) of a closure to match (defmethod all-matches ((clo closure) &optional (ctx *session*)) (unless (gethash (hashid clo) (proper ctx)) (return-from all-matches '())) (let ((hash-all (list (all-matches (get-one (root clo)) ctx))) (matches '())) (dolist (out (outs clo)) (push (all-matches (get-one out) ctx) hash-all)) (dolist (fwd (forwards clo)) (push (all-matches (get-one fwd) ctx) hash-all)) (setf hash-all (reverse hash-all)) ;; all permutations of each out and fwd in list (apply #'maperm #'(lambda (&rest args) (let ((exists (get-one (apply #'make-hash args)))) (when exists (push (hashid exists) matches)))) hash-all) (remove-duplicates matches))) ; removed satisfied check in ctx ; see permutations.lisp (defun maperm (fn &rest lists) (cond ((endp lists) nil) ((endp (rest lists)) (mapc fn (first lists))) (t (mapc #'(lambda (x) (apply #'maperm #'(lambda (&rest args) (apply fn x args)) (rest lists))) (first lists)))) (reduce #'* (mapcar #'length lists))) ; get all satisfied connections(?) of a connection to match (defmethod all-matches ((conn connection) &optional (ctx *session*)) (unless (gethash (hashid conn) (proper ctx)) (return-from all-matches '())) (let ((prev-one (get-one (prev conn))) (curr-one (get-one (curr conn))) (subs-one (get-one (subs conn))) (q-list '())) (let ((prevs (if prev-one (all-matches prev-one ctx) q-list)) (currs (if curr-one (all-matches curr-one ctx) q-list)) (subss (if subs-one (all-matches subs-one ctx) q-list)) (matches '())) (dolist (prev-id prevs) (dolist (curr-id currs) (dolist (subs-id subss) (let ((exists (get-one (make-hash prev-id curr-id subs-id)))) (when exists (push (hashid exists) matches)))))) matches))) ; removed satisfied check in ctx (defmethod all-bindings (nod &optional (ctx *session*) (bound-now (make-hash-table))) (let ((bound '()) (parents (get-parents (hashid nod) nil))) (setf (gethash (hashid nod) bound-now) nod) (dolist (parent parents) (let ((one (get-one parent))) (when (connectionp one) (if (eq (subs one) (hashid nod)) (when (not (gethash (prev one) bound-now)) (let* ((match-curr (all-matches (get-one (curr one)) ctx)) (is-bind (member (hashid *bind*) match-curr))) (when is-bind (let ((bound-prev (all-bindings (get-one (prev one)) ctx bound-now))) (setf bound (nconc bound bound-prev)))))) (when (eq (prev one) (hashid nod)) (let* ((match-curr (all-matches (get-one (curr one)) ctx)) (is-bind (member (hashid *bind*) match-curr))) (when is-bind (let ((bound-subs (all-bindings (get-one (subs one)) ctx bound-now))) (setf bound (nconc bound bound-subs)))))))))) (remove-duplicates bound))) (defmacro setc (which) `(lambda (conn val) (setf (apply ,which (list conn)) val))) ; this is for matching against Qs passed in... (defun form-q-potential (prev-id curr-id subs-id ctx exists) (let ((relevant '()) (prev-now (get-one prev-id)) (curr-now (get-one curr-id)) (subs-now (get-one subs-id))) (flet ((get-relevant (lst match fn) (dolist (el lst) (when (eq match (apply fn (list (get-one el)))) (push (get-one el) relevant))) relevant)) (let ((prev-parents (get-relevant (get-parents prev-id ctx) prev-id #'prev)) (curr-parents (get-relevant (get-parents curr-id ctx) curr-id #'curr)) (subs-parents (get-relevant (get-parents subs-id ctx) subs-id #'subs))) (flet ((get-which-intersect () (cond ((qnodep prev-now) (values prev-now (setc #'prev) (intersection curr-parents subs-parents))) ((qnodep curr-now) (values curr-now (setc #'curr) (intersection prev-parents subs-parents))) ((qnodep subs-now) (values subs-now (setc #'subs) (intersection curr-parents prev-parents)))))) (multiple-value-bind (qn which tween) (get-which-intersect) (when tween (let ((qdata (mapcar which tween)) (qconn (make-instance 'connection :hashid (get-next-id) :prev prev-id :curr curr-id :subs subs-id))) (when ctx (setf (gethash (hashid qconn) (proper ctx)) qconn) (apply which (list qconn (hashid qn))) (add-one-simple (get-syn-hash qconn) qconn) ;; when a q exists already, exclude the previous elements (when exists (dolist (q exists) (let ((qval (gethash q (q-cache ctx)))) (setf qdata (set-difference qdata qval))))) ;; update q-cache (setf (gethash (hashid qn) (q-cache ctx)) qdata) ;; update reverse-q-cache (dolist (qd qdata) (let ((rev (gethash qd (reverse-q-cache ctx)))) (unless (member (hashid qn) rev) (push (hashid qn) rev) (setf (gethash qd (reverse-q-cache ctx)) rev))))) (add-one qconn))))))))) (defgeneric contains (nod obj) (:documentation "Whether nod is contained in obj.")) (defmethod contains (nod1 (nod2 node)) (eq nod1 nod2)) (defmethod contains (nod (conn connection)) (or (contains nod (prev conn)) (contains nod (curr conn)) (contains nod (subs conn)))) (defmethod contains (nod (clo closure)) (dolist (id (outs clo)) (when (contains nod id) (return-from contains nod))) (dolist (id (forwards clo)) (when (contains nod id) (return-from contains nod)))) (defmethod contains (nod (id integer)) (contains nod (get-one id))) (defun qexprp (obj) ; use q-pool (contains *q* obj)) ;(defun add-void (id1 id2) ; (setf (gethash id1 *void-table*) id2) ; (setf (gethash id2 *void-table*) id1)) ;(defun is-void (id1 id2) ; (equal (gethash id1 *void-table*) id2)) (defun get-normalized-id (id) (hashid (get-one id))) (defun add-qnode (nod &optional (ctx *session*)) (let* ((q (hashid nod)) (qval (q nod)) (existing (reverse (gethash qval (q-cache ctx))))) (unless (member q existing) (setf (gethash qval (q-cache ctx)) (reverse (push q existing)))))) (defparameter *parent-cache* (make-hash-table :test 'equal) "For an ID of a node, all parents that include the node, in a list.") (defun clear-parent-cache () (clrhash *parent-cache*)) #| policy on parents in context? - get-parents checks context |# (defun add-parent (id parent-id &optional (ctx *session*)) (let ((parent-list (get-parents id nil))) (unless (member parent-id parent-list) (setf parent-list (push parent-id parent-list)) (setf (gethash id *parent-cache*) parent-list)))) ; ctx nil (defun get-parents (id &optional (ctx *session*)) ;(when (or (null ctx) (gethash id (satisfied ctx))) (let ((parents-raw (gethash id *parent-cache*)) (parents '())) (dolist (parent parents-raw) (when (or (null ctx) (gethash parent (proper ctx))) (push parent parents))) parents));) (defun get-grandparents (id &optional (ctx *session*)) (let ((parents (get-parents id)) (grandparents '())) (dolist (parent parents) (setf grandparents (union grandparents (get-parents parent ctx)))) grandparents)) (defun get-parent-closures (id &optional (ctx *session*)) (let ((parents (get-parents id ctx)) (closures '())) (dolist (parent parents) (let ((one (get-one parent))) (if (closurep one) (push one closures) (let ((grandparents (get-parents parent ctx))) (dolist (grandparent grandparents) (let ((grand (get-one grandparent))) (when (closurep grand) (push grand closures)))))))) (remove-duplicates closures))) (defgeneric set-all-parents (obj) (:documentation "For all subelements of an object, add it as a parent of subelement(s).")) (defmethod set-all-parents ((clo closure)) (dolist (fwd (forwards clo)) (add-parent fwd (hashid clo)) (set-all-parents (get-one fwd))) (dolist (out (outs clo)) (add-parent out (hashid clo)) (set-all-parents (get-one out)))) (defmethod set-all-parents ((conn connection)) (add-parent (prev conn) (hashid conn)) (add-parent (curr conn) (hashid conn)) (add-parent (subs conn) (hashid conn))) (defun get-intersecting-parents (id1 id2) (let ((parents1 (get-parents id1)) (parents2 (get-parents id2))) (intersection parents1 parents2))) |