(ns nal.deriver.preconditions (:require [nal.deriver.set-functions :refer [f-map not-empty-diff? not-empty-inter?]] [nal.deriver.utils :refer [walk]] [nal.deriver.substitution :refer [substitute munification-map]] [nal.deriver.terms-permutation :refer [implications equivalences]] [clojure.set :refer [union intersection]] [narjure.defaults :refer [duration]] [clojure.core.match :as m] [nal.deriver.normalization :refer [reduce-seq-conj]])) | |
(defn abs [^long n] (Math/abs n)) | |
Expands compound precondition to clojure sequence that will be evaluted later TODO preconditions :shift-occurrence-forward :shift-occurrence-backward | (defmulti compound-precondition first) |
(defmethod compound-precondition :default [_] []) | |
(defmethod compound-precondition :!= [[_ & args]] [`(not= ~@args)]) | |
(defn check-set [set-type arg] `(and (coll? ~arg) (= ~set-type (first ~arg)))) | |
(defmethod compound-precondition :set-ext? [[_ arg]] [(check-set 'ext-set arg)]) | |
(defmethod compound-precondition :set-int? [[_ arg]] [(check-set 'int-set arg)]) | |
(def sets '#{ext-set int-set}) | |
(defn set-conditions [set1 set2] [`(coll? ~set1) `(coll? ~set2) `(let [k# 1 afop# (first ~set1)] (and (sets afop#) (= afop# (first ~set2))))]) | |
(defmethod compound-precondition :difference [[_ arg1 arg2]] (concat (set-conditions arg1 arg2) [`(not-empty-diff? ~arg1 ~arg2)])) | |
(defmethod compound-precondition :union [[_ arg1 arg2]] (set-conditions arg1 arg2)) | |
(defmethod compound-precondition :intersection [[_ arg1 arg2]] (concat (set-conditions arg1 arg2) [`(not-empty-inter? ~arg1 ~arg2)])) | |
(defmethod compound-precondition :substitute-if-unifies [[_ arg1 arg2 arg3]] [`(munification-map ~arg1 ~arg2 ~arg3)]) | |
(defmethod compound-precondition :contains? [[_ arg1 arg2]] [`(some (set [~arg2]) ~arg1)]) | |
(def implications-and-equivalences (union implications equivalences)) | |
(defmethod compound-precondition :not-implication-or-equivalence [[_ arg]] [`(if (coll? ~arg) (nil? (~`implications-and-equivalences (first ~arg))) true)]) | |
(defn get-terms [st] (if (coll? st) (mapcat get-terms (rest st)) [st])) | |
(defmethod compound-precondition :no-common-subterm [[_ arg1 arg2]] [`(empty? (intersection (set (get-terms ~arg1)) (set (get-terms ~arg2))))]) | |
(defmethod compound-precondition :not-set? [[_ arg]] [`(or (not (coll? ~arg)) (not (sets (first ~arg))))]) | |
(defmethod compound-precondition :measure-time [_] [`(not= :eternal :t-occurrence) `(not= :eternal :b-occurrence) `(<= ~duration (abs (- :t-occurrence :b-occurrence)))]) | |
(defmethod compound-precondition :concurrent [_] [`(> ~duration (abs (- :t-occurrence :b-occurrence)))]) | |
(defmulti precondition-transformation (fn [arg1 _] (first arg1))) | |
(defmethod precondition-transformation :default [_ conclusion] conclusion) | |
(defn sets-transformation [[cond-name el1 el2 el3] conclusion] (walk conclusion (= :el el3) `(~(f-map cond-name) ~el1 ~el2))) | |
(doall (map #(defmethod precondition-transformation % [cond concl] (sets-transformation cond concl)) [:difference :union :intersection])) | |
(defmethod precondition-transformation :substitute [[_ el1 el2] conclusion] `(walk ~conclusion (= :el ~el1) ~el2)) | |
(defmethod precondition-transformation :substitute-from-list [[_ el1 el2] conclusion] `(mapv (fn [k#] (if (= k# ~el1) k# (walk k# (= :el ~el1) ~el2))) ~conclusion)) | |
(defmethod precondition-transformation :substitute-if-unifies [[_ p1 p2 p3] conclusion] `(substitute ~p1 ~p2 ~p3 ~conclusion)) | |
(defmethod precondition-transformation :measure-time [[_ arg] conclusion] (let [mt (gensym)] (walk `(let [~arg (abs (- :t-occurrence :b-occurrence))] ~(walk conclusion (= :el arg) [:interval arg])) (= :el arg) mt))) | |
(defn check-precondition [conclusion precondition] (if (seq? precondition) (precondition-transformation precondition conclusion) conclusion)) | |
Some transformations of conclusion may be required by precondition. | (defn preconditions-transformations [conclusion preconditions] (reduce check-precondition conclusion preconditions)) |
(defmulti conclusion-transformation (fn [arg1 _] (first arg1))) | |
(defn shift-forward-let ([sym conclusion] (shift-forward-let sym nil conclusion nil)) ([sym op conclusion duration] `(let [interval# ~sym ~@(if duration `[:t-occurrence (~op :t-occurrence ~duration)] []) :t-occurrence (if interval# (+ :t-occurrence interval#) :t-occurrence)] ~conclusion))) | |
(defmethod conclusion-transformation :shift-occurrence-forward [args concl] (m/match (mapv #(if (and (coll? %) (= 'quote (first %))) (second %) %) (rest args)) [(:or '=|> '==>)] concl ['pred-impl] `(let [:t-occurrence (+ :t-occurrence ~duration)] ~concl) ['retro-impl] `(let [:t-occurrence (- :t-occurrence ~duration)] ~concl) [sym (:or '=|> '==>)] (shift-forward-let sym concl) [sym 'pred-impl] (shift-forward-let sym `+ concl duration) [sym 'retro-impl] (shift-forward-let sym `- concl duration))) | |
(defn backward-interval-check [sym] `(and (coll? ~sym) (= (first ~sym) (quote ~'seq-conj)) (let [cnt# (count ~sym)] (and (odd? cnt#) (get-in ~sym [(dec cnt#) 1]))))) | |
(defn shift-backward-let ([sym conclusion] (shift-backward-let sym nil conclusion nil)) ([sym op conclusion duration] `(let [interval# ~(backward-interval-check sym) ~@(if duration `[:t-occurrence (~op :t-occurrence ~duration)] []) :t-occurrence (if interval# (+ :t-occurrence interval#) :t-occurrence)] (if interval# (update ~conclusion :statement reduce-seq-conj) ~conclusion)))) | |
(defmethod conclusion-transformation :shift-occurrence-backward [args concl] (let [duration (- duration)] (m/match (mapv #(if (and (coll? %) (= 'quote (first %))) (second %) %) (rest args)) [(:or '=|> '==>)] concl ['pred-impl] `(let [:t-occurrence (+ :t-occurrence ~duration)] ~concl) ['retro-impl] `(let [:t-occurrence (- :t-occurrence ~duration)] ~concl) [sym (:or '=|> '==>)] (shift-backward-let sym concl) [sym 'pred-impl] (shift-backward-let sym `+ concl duration) [sym 'retro-impl] (shift-backward-let sym `- concl duration)))) | |