diff options
Diffstat (limited to 'src/clojure/contrib/datalog/magic.clj')
-rw-r--r-- | src/clojure/contrib/datalog/magic.clj | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/src/clojure/contrib/datalog/magic.clj b/src/clojure/contrib/datalog/magic.clj new file mode 100644 index 00000000..f4d75588 --- /dev/null +++ b/src/clojure/contrib/datalog/magic.clj @@ -0,0 +1,115 @@ +;; Copyright (c) Jeffrey Straszheim. All rights reserved. The use and +;; distribution terms for this software are covered by the Eclipse Public +;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can +;; be found in the file epl-v10.html at the root of this distribution. By +;; using this software in any fashion, you are agreeing to be bound by the +;; terms of this license. You must not remove this notice, or any other, +;; from this software. +;; +;; magic.clj +;; +;; A Clojure implementation of Datalog -- Magic Sets +;; +;; straszheimjeffrey (gmail) +;; Created 18 Feburary 2009 + + +(ns clojure.contrib.datalog.magic + (:use clojure.contrib.datalog.util + clojure.contrib.datalog.literals + clojure.contrib.datalog.rules) + (:use [clojure.set :only (union intersection difference)])) + + +;;; Adornment + +(defn adorn-query + "Adorn a query" + [q] + (adorned-literal q (get-self-bound-cs q))) + +(defn adorn-rules-set + "Adorns the given rules-set for the given query. (rs) is a + rules-set, (q) is an adorned query." + [rs q] + (let [i-preds (all-predicates rs) + p-map (predicate-map rs)] + (loop [nrs empty-rules-set ; The rules set being built + needed #{(literal-predicate q)}] + (if (empty? needed) + nrs + (let [pred (first needed) + remaining (disj needed pred) + base-pred (get-base-predicate pred) + bindings (get-adorned-bindings pred) + new-rules (p-map base-pred) + new-adorned-rules (map (partial compute-sip bindings i-preds) + new-rules) + new-nrs (reduce conj nrs new-adorned-rules) + current-preds (all-predicates new-nrs) + not-needed? (fn [pred] + (or (current-preds pred) + (-> pred get-base-predicate i-preds not))) + add-pred (fn [np pred] + (if (not-needed? pred) np (conj np pred))) + add-preds (fn [np rule] + (reduce add-pred np (map literal-predicate (:body rule)))) + new-needed (reduce add-preds remaining new-adorned-rules)] + (recur new-nrs new-needed)))))) + +;;; Magic ! + +(defn seed-relation + "Given a magic form of a query, give back the literal form of its seed + relation" + [q] + (let [pred (-> q literal-predicate get-base-predicate) + bnds (-> q literal-predicate get-adorned-bindings)] + (with-meta (assoc q :predicate [pred :magic-seed bnds]) {}))) + +(defn seed-rule + "Given an adorned query, give back its seed rule" + [q] + (let [mq (build-seed-bindings (magic-literal q)) + sr (seed-relation mq)] + (build-rule mq [sr]))) + +(defn seed-predicate-for-insertion + "Given a query, return the predicate to use for database insertion." + [q] + (let [seed (-> q seed-rule :body first) + columns (-> seed :term-bindings keys) + new-term-bindings (-> q :term-bindings (select-keys columns))] + (assoc seed :term-bindings new-term-bindings))) + +(defn magic-transform + "Return a magic transformation of an adorned rules-set (rs). The + (i-preds) are the predicates of the intension database. These + default to the predicates within the rules-set." + ([rs] + (magic-transform rs (all-predicates rs))) + ([rs i-preds] + (let [not-duplicate? (fn [l mh bd] + (or (not (empty? bd)) + (not (= (magic-literal l) + mh)))) + xr (fn [rs rule] + (let [head (:head rule) + body (:body rule) + mh (magic-literal head) + answer-rule (build-rule head + (concat [mh] body)) + step (fn [[rs bd] l] + (if (and (i-preds (literal-predicate l)) + (not-duplicate? l mh bd)) + (let [nr (build-rule (magic-literal l) + (concat [mh] bd))] + [(conj rs nr) (conj bd l)]) + [rs (conj bd l)])) + [nrs _] (reduce step [rs []] body)] + (conj nrs answer-rule)))] + (reduce xr empty-rules-set rs)))) + + + +;; End of file |