(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)))) | |