rlm@10: ;; Copyright (c) Jeffrey Straszheim. All rights reserved. The use and rlm@10: ;; distribution terms for this software are covered by the Eclipse Public rlm@10: ;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can rlm@10: ;; be found in the file epl-v10.html at the root of this distribution. By rlm@10: ;; using this software in any fashion, you are agreeing to be bound by the rlm@10: ;; terms of this license. You must not remove this notice, or any other, rlm@10: ;; from this software. rlm@10: ;; rlm@10: ;; util.clj rlm@10: ;; rlm@10: ;; A Clojure implementation of Datalog -- Utilities rlm@10: ;; rlm@10: ;; straszheimjeffrey (gmail) rlm@10: ;; Created 3 Feburary 2009 rlm@10: rlm@10: rlm@10: (ns clojure.contrib.datalog.util rlm@10: (:use [clojure.contrib.seq :only (separate)])) rlm@10: rlm@10: rlm@10: rlm@10: ;;; Bindings and logic vars. A binding in a hash of logic vars to rlm@10: ;;; bound values. Logic vars are any symbol prefixed with a \?. rlm@10: rlm@10: (defn is-var? rlm@10: "Is this a logic variable: e.g. a symbol prefixed with a ?" rlm@10: [sym] rlm@10: (when (symbol? sym) rlm@10: (let [name (name sym)] rlm@10: (and (= \? (first name)) rlm@10: (not= \? (fnext name)))))) rlm@10: rlm@10: (defn is-query-var? rlm@10: "Is this a query variable: e.g. a symbol prefixed with ??" rlm@10: [sym] rlm@10: (when (symbol? sym) rlm@10: (let [name (name sym)] rlm@10: (and (= \? (first name)) rlm@10: (= \? (fnext name)))))) rlm@10: rlm@10: (defn map-values rlm@10: "Like map, but works over the values of a hash map" rlm@10: [f hash] rlm@10: (let [key-vals (map (fn [[key val]] [key (f val)]) hash)] rlm@10: (if (seq key-vals) rlm@10: (apply conj (empty hash) key-vals) rlm@10: hash))) rlm@10: rlm@10: (defn keys-to-vals rlm@10: "Given a map and a collection of keys, return the collection of vals" rlm@10: [m ks] rlm@10: (vals (select-keys m ks))) rlm@10: rlm@10: (defn reverse-map rlm@10: "Reverse the keys/values of a map" rlm@10: [m] rlm@10: (into {} (map (fn [[k v]] [v k]) m))) rlm@10: rlm@10: rlm@10: ;;; Preduce -- A parallel reduce over hashes rlm@10: rlm@10: (defn preduce rlm@10: "Similar to merge-with, but the contents of each key are merged in rlm@10: parallel using f. rlm@10: rlm@10: f - a function of 2 arguments. rlm@10: data - a collection of hashes." rlm@10: [f data] rlm@10: (let [data-1 (map (fn [h] (map-values #(list %) h)) data) rlm@10: merged (doall (apply merge-with concat data-1)) rlm@10: ; Groups w/ multiple elements are identified for parallel processing rlm@10: [complex simple] (separate (fn [[key vals]] (> (count vals) 1)) merged) rlm@10: fold-group (fn [[key vals]] {key (reduce f vals)}) rlm@10: fix-single (fn [[key [val]]] [key val])] rlm@10: (apply merge (concat (pmap fold-group merged) (map fix-single simple))))) rlm@10: rlm@10: rlm@10: ;;; Debuging and Tracing rlm@10: rlm@10: (def *trace-datalog* nil) rlm@10: rlm@10: (defmacro trace-datalog rlm@10: "If *test-datalog* is set to true, run the enclosed commands" rlm@10: [& body] rlm@10: `(when *trace-datalog* rlm@10: ~@body)) rlm@10: rlm@10: rlm@10: ;; End of file