;;; -*- Mode: Lisp; Package: Prolog; Base: 10. ; Options: ((World Eager)) -*- ;;; (C) Copyright 1983,1984,1985, Uppsala University ;;This implements bags and sets as seperate parallel processes (defflavor hurried (process value status inferiors constructor) (prolog-flavor) :initable-instance-variables :gettable-instance-variables :settable-instance-variables) (defun create-prolog-process (name function &rest arguments) (bind (locf #'coroutine-closure-function) #'prolog-process-internal) (with-trail (allocate-a-trail) (let* ((process (make-instance-in-area-and-initialize *prolog-work-area* 'si:process ':name name ':stack-group (allocate-a-coroutine function (first arguments) (copylist (rest1 arguments) *prolog-work-area*)) ':priority -1 ;;lower than the Lisp listener ;;(sub1 (funcall current-process ':priority)) ))) (send process ':pre-enable)))) si: (defmethod (process :pre-enable) () (without-interrupts (setq whostate "Hurrying") (set-process-wait self #'true ())) self) (defun prolog-process-internal #.*variables-shared-between-top-level-stack-groups* (establish-condition-handlers (catch-error-restart ((sys:abort error) "Terminate and free process ~A." (send current-process ':name)) (with-trail *trail-array* (lexpr-funcall function continuation arglist)))) (send current-process ':kill)) (defmethod (hurried :add-inferior) (inferior) (push inferior inferiors)) (defsubst wait-for-hurried-value (hurried-value) (process-wait "Eager value" #'not-hurried hurried-value)) (defun not-hurried (hurried-value) (neq (send hurried-value ':status) ':running)) (defmethod (hurried :ordinary-term) () (selectq status (:finished value) (:running (wait-for-hurried-value self) (send self ':ordinary-term)) (:stopped (cond ((variable-boundp value) value) (t (values self t)))))) (defun hurried-query-user-help (query-io &rest ignore) (format query-io "~%Type /"y/" to wait for the computation to finish, Type /"n/" to continue, Type /"p/" to wait for the hurried computation and any embedded ones. Or type /"f/" to flush the process running the computation.")) (defmethod (hurried :query-user) () (selectq status ((:finished :stopped) 'yes) (otherwise (let ((reply (fquery '(:choices (((yes "Yes") #/y) ((no "No") #/n) ((proceed "Proceed") #/p) ((flush "Flush Process") #/f)) :help-function hurried-query-user-help) "~%There is a unfinished computation, should I wait for it? " ))) (selectq reply ((yes proceed) (wait-for-hurried-value self) reply) (flush (send process ':flush) 'no) (no reply)))))) (defmethod (hurried :kill-process) () ;;have to be careful here that it doesn't change in the middle of this (without-interrupts (without-interrupts ; #+SYMBOLICS (progn (si:process-disable process) (si:process-all-processes process nil)) ; #-symbolics ; (send process ':kill) (setq status ':stopped) (mapc #'(lambda (inferior) (send inferior ':kill-process)) inferiors)))) (defmethod (hurried :unify) (other) (selectq status (:finished (unify value other)) (:running (wait-for-hurried-value self) (send self ':unify other)))) (defvar *hurried-value* ()) (defun next-eager-bag-element () (send *hurried-value* ':new-answer)) (defun next-eager-set-element () (send *hurried-value* ':new-unique-answer)) (defmethod (hurried :new-answer) () (setq value (prolog-cons (invoke constructor) (setq *hurried-value* (make-instance-in-area *prolog-work-area* 'hurried ':status ':running ':inferiors inferiors ':constructor constructor ':process process)))) (setq status ':finished) nil) (defvar *set-so-far*) (defmethod (hurried :new-unique-answer) () (let ((new-element (invoke constructor))) (cond ((not (mem 'identical-p new-element *set-so-far*)) (push new-element *set-so-far*) (setq value (prolog-cons new-element (setq *hurried-value* (make-instance-in-area *prolog-work-area* 'hurried ':status ':running ':inferiors inferiors ':constructor constructor ':process process)))) (setq status ':finished))) nil)) (defun make-eager-collection (predications-code constructor) (let* ((collection (make-instance-in-area *prolog-work-area* 'hurried ':status ':running ':constructor constructor ':inferiors nil)) (creator *hurried-value*) ;;(*hurried-value* collection) ;;(*set-so-far* ()) (process (create-prolog-process "Eager Collection" #'eager-collection-top-level ;;(closure '(*hurried-value* *set-so-far*) ;; #'eager-collection-top-level) predications-code collection ()))) (send collection ':set-process process) (remind collection ':kill-process) (cond (creator (send creator ':add-inferior collection))) (process-enable process) collection)) (defun eager-collection-top-level (predications-code *hurried-value* *set-so-far*) (invoke predications-code) (without-interrupts (send *hurried-value* ':set-value nil) (send *hurried-value* ':set-status ':finished)) nil) (define-predicate wait (:options (:argument-list (+sixtieths-of-a-second)) (:documentation "the process running this predicate waits +SIXTIETHS-OF-A-SECOND.")) ((wait ?sixtieths-of-a-second) (lisp-command (process-sleep '?sixtieths-of-a-second) :dont-invoke))) (define-predicate await (:options (:argument-list (+predication)) (:documentation "the process running this predicate waits until PREDICATION is true.")) ((await ?predication) (lisp-command (process-wait "Await" 'await-1 '?predication *trail-array* *prolog-work-area* *vector*) :dont-invoke))) (defun await-1 (predication *trail-array* *prolog-work-area* *vector*) (with-trail *trail-array* (funcall (current-entrypoint 'can-prove) (continuation (true)) predication))) (define-predicate eager-bag-of (:options (:compile-method :intrinsic compile-lazy-or-eager-collection) (:deterministic :always) (:argument-list (bag term &rest +predications)) (:documentation "Unifies BAG with instantiations of TERM in proofs of +PREDICATIONS. The BAG is computed in a seperate parallel process")) ((eager-bag-of ?bag ?term . ?predications) (eager-bag-of ?bag ?term (and . ?predications)))) (define-predicate eager-set-of (:options (:compile-method :intrinsic compile-lazy-or-eager-collection) (:deterministic :always) (:argument-list (set term &rest +predications)) (:documentation "Unifies SET with unique instantiations of TERM in proofs of +PREDICATIONS. The SET is computed in a seperate parallel process.")) ((eager-set-of ?set ?term . ?predications) (eager-set-of ?set ?term (and . ?predications)))) (define-predicate faster (:options (:argument-list (x y)) (:documentation "if X is a hurried value that is still running and Y is not then this fails, if X is not hurried this succeeds, if both are hurried then it waits for one to complete.")) ((faster ?x ?y) (lisp-predicate (faster-value '?x '?y) :dont-invoke))) (deffun faster-value (x y) (cond ((or (not (typep x 'hurried)) (neq (send x ':status) ':running)) t) ((or (not (typep y 'hurried)) (neq (send y ':status) ':running)) nil) (t (process-wait "Race" #'not-both-running x y) (faster-value x y)))) (defun not-both-running (x y) (or (neq (send x ':status) ':running) (neq (send y ':status) ':running))) (define-predicate collect ((collect ?collection ?term ?predication :lazy) (lazy-bag-of ?collection ?term ?predication)) ((collect ?collection ?term ?predication :sequential) (bag-of ?collection ?term ?predication)) ((collect ?collection ?term ?predication :eager) (eager-bag-of ?collection ?term ?predication)))