Skip to content
79 changes: 40 additions & 39 deletions src/datalog/database.clj
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
;; Converted to Clojure1.4 by Martin Trojer 2012.

(ns datalog.database
(:use [datalog.util])
(:use [clojure.set :only (union intersection difference)]))
(:require
[clojure.set :as set]
[datalog.util :as util]))

(defrecord Relation
[schema ; A set of key names
Expand All @@ -28,15 +29,15 @@

(defmethod print-method ::datalog-database
[db ^java.io.Writer writer]
(binding [*out* writer]
(do
(println "(datalog-database")
(println "{")
(doseq [key (keys db)]
(println)
(println key)
(print-method (db key) writer))
(println "})"))))
(binding [*out* writer]
(do
(println "(datalog-database")
(println "{")
(doseq [key (keys db)]
(println)
(println key)
(print-method (db key) writer))
(println "})"))))

(defn datalog-database
[rels]
Expand Down Expand Up @@ -103,12 +104,12 @@

(defmacro make-database
"Makes a database, like this
(make-database
(relation :fred [:mary :sue])
(index :fred :mary)
(relation :sally [:jen :becky])
(index :sally :jen)
(index :sally :becky))"
(make-database
(relation :fred [:mary :sue])
(index :fred :mary)
(relation :sally [:jen :becky])
(index :sally :jen)
(index :sally :becky))"
[& commands]
(let [wrapper (fn [cur new]
(let [cmd (first new)
Expand Down Expand Up @@ -137,11 +138,11 @@
(defn database-counts
"Returns a map with the count of elements in each relation."
[db]
(map-values #(-> % :data count) db))
(util/map-values #(-> % :data count) db))

(defn- modify-indexes
"Perform f on the indexed tuple-set. f should take a set and tuple,
and return the new set."
and return the new set."
[idxs tuple f]
(into {} (for [ik (keys idxs)]
(let [im (idxs ik)
Expand All @@ -165,10 +166,10 @@
(defn add-tuple
"Two forms:

[db relation-name tuple] adds tuple to the named relation. Returns
the new database.
[db relation-name tuple] adds tuple to the named relation. Returns
the new database.

[rel tuple] adds to the relation object. Returns the new relation."
[rel tuple] adds to the relation object. Returns the new relation."
([db rel-name tuple]
(assert (= (-> tuple keys set) (-> rel-name db :schema)))
(assoc db rel-name (add-tuple (db rel-name) tuple)))
Expand All @@ -183,11 +184,11 @@
(defn remove-tuple
"Two forms:

[db relation-name tuple] removes the tuple from the named relation,
returns a new database.
[db relation-name tuple] removes the tuple from the named relation,
returns a new database.

[rel tuple] removes the tuple from the relation. Returns the new
relation."
[rel tuple] removes the tuple from the relation. Returns the new
relation."
([db rel-name tuple] (assoc db rel-name (remove-tuple (db rel-name) tuple)))
([rel tuple]
(let [data (:data rel)
Expand All @@ -199,9 +200,9 @@

(defn add-tuples
"Adds a collection of tuples to the db, as
(add-tuples db
[:rel-name :key-1 1 :key-2 2]
[:rel-name :key-1 2 :key-2 3])"
(add-tuples db
[:rel-name :key-1 1 :key-2 2]
[:rel-name :key-1 2 :key-2 3])"
[db & tupls]
(reduce #(add-tuple %1 (first %2) (apply hash-map (next %2))) db tupls))

Expand All @@ -225,17 +226,17 @@

(defn- scan-space
"Computes a stream of tuples from relation rn matching partial tuple (pt)
and applies fun to each"
and applies fun to each"
[fun db rn pt]
(let [rel (db rn)
idxs (find-indexes (:indexes rel) pt)
space (if (empty? idxs)
(:data rel) ; table scan :(
(reduce intersection idxs))]
(trace-datalog (when (empty? idxs)
(println (format "Table scan of %s: %s rows!!!!!"
rn
(count space)))))
(reduce set/intersection idxs))]
(util/trace-datalog (when (empty? idxs)
(println (format "Table scan of %s: %s rows!!!!!"
rn
(count space)))))
(fun #(match? % pt) space)))

(defn select
Expand All @@ -255,16 +256,16 @@

(defn merge-indexes
[idx1 idx2]
(merge-with (fn [h1 h2] (merge-with union h1 h2)) idx1 idx2))
(merge-with (fn [h1 h2] (merge-with set/union h1 h2)) idx1 idx2))

(defn merge-relations
"Merges two relations"
[r1 r2]
(assert (= (:schema r1) (:schema r2)))
(let [merged-indexes (merge-indexes (:indexes r1)
(:indexes r2))
merged-data (union (:data r1)
(:data r2))]
merged-data (set/union (:data r1)
(:data r2))]
(assoc r1 :data merged-data :indexes merged-indexes)))

(defn database-merge
Expand All @@ -275,4 +276,4 @@
(defn database-merge-parallel
"Merges databases together in parallel"
[dbs]
(preduce merge-relations dbs))
(util/preduce merge-relations dbs))
13 changes: 6 additions & 7 deletions src/datalog/datalog.clj
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@
(ns ^{:author "Jeffrey Straszheim",
:doc "A Clojure implementation of Datalog"}
datalog.datalog
(:use [datalog.rules]
[datalog.softstrat]
[datalog.database])
(:use [clojure.set :only (intersection)]))
(:require
[clojure.set :as set]
[datalog.softstrat :as softstrat]))

(defrecord WorkPlan
[work-plan ; The underlying structure
Expand All @@ -35,7 +34,7 @@
(defn- validate-work-plan
"Ensure any top level semantics are not violated"
[work-plan database]
(let [common-relations (-> work-plan :rules (intersection (-> database keys set)))]
(let [common-relations (-> work-plan :rules (set/intersection (-> database keys set)))]
(when (-> common-relations
empty?
not)
Expand All @@ -45,11 +44,11 @@
"Given a list of rules and a query, build a work plan that can be
used to execute the query."
[rules query]
(->WorkPlan (build-soft-strat-work-plan rules query) rules query ::soft-stratified))
(->WorkPlan (softstrat/build-soft-strat-work-plan rules query) rules query ::soft-stratified))

(defn run-work-plan
"Given a work plan, a database, and some query bindings, run the
work plan and return the results."
[work-plan database query-bindings]
(validate-work-plan work-plan database)
(evaluate-soft-work-set (:work-plan work-plan) database query-bindings))
(softstrat/evaluate-soft-work-set (:work-plan work-plan) database query-bindings))
36 changes: 25 additions & 11 deletions src/datalog/example.clj
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
;; Converted to Clojure1.4 by Martin Trojer 2012.

(ns datalog.example
(:use [datalog.datalog :only (build-work-plan run-work-plan)]
[datalog.rules :only (<- ?- rules-set)]
[datalog.database :only (make-database add-tuples)]
[datalog.util :only (*trace-datalog*)]))
(:require
[datalog.datalog :refer (build-work-plan run-work-plan)]
[datalog.rules :refer (<- ?- rules-set)]
[datalog.database :refer (make-database add-tuples)]
[datalog.util :refer (*trace-datalog*)]))

(def db-base
(make-database
Expand Down Expand Up @@ -77,22 +78,35 @@

(def rules
(rules-set
(<- (:works-for :employee ?x :boss ?y) (:boss :employee-id ?e-id :boss-id ?b-id)
(<- (:works-for :employee ?x :boss ?y)
(:boss :employee-id ?e-id :boss-id ?b-id)
(:employee :id ?e-id :name ?x)
(:employee :id ?b-id :name ?y))
(<- (:works-for :employee ?x :boss ?y) (:works-for :employee ?x :boss ?z)

(<- (:works-for :employee ?x :boss ?y)
(:works-for :employee ?x :boss ?z)
(:works-for :employee ?z :boss ?y))
(<- (:employee-job* :employee ?x :job ?y) (:employee :name ?x :position ?pos)

(<- (:employee-job* :employee ?x :job ?y)
(:employee :name ?x :position ?pos)
(:can-do-job :position ?pos :job ?y))
(<- (:employee-job* :employee ?x :job ?y) (:job-replacement :job ?y :can-be-done-by ?z)

(<- (:employee-job* :employee ?x :job ?y)
(:job-replacement :job ?y :can-be-done-by ?z)
(:employee-job* :employee ?x :job ?z))
(<- (:employee-job* :employee ?x :job ?y) (:can-do-job :job ?y)

(<- (:employee-job* :employee ?x :job ?y)
(:can-do-job :job ?y)
(:employee :name ?x :position ?z)
(if = ?z :boss))
(<- (:employee-job :employee ?x :job ?y) (:employee-job* :employee ?x :job ?y)

(<- (:employee-job :employee ?x :job ?y)
(:employee-job* :employee ?x :job ?y)
(:employee :id ?id :name ?x)
(not! :job-exceptions :id ?id :job ?y))
(<- (:bj :name ?x :boss ?y) (:works-for :employee ?x :boss ?y)

(<- (:bj :name ?x :boss ?y)
(:works-for :employee ?x :boss ?y)
(not! :employee-job :employee ?y :job :pc-support))))

(def wp-1 (build-work-plan rules (?- :works-for :employee '??name :boss ?x)))
Expand Down
4 changes: 2 additions & 2 deletions src/datalog/graph.clj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
^{:author "Jeffrey Straszheim",
:doc "Basic graph theory algorithms"}
datalog.graph
(:use [clojure.set :only (union)]))
(:require [clojure.set :as set]))

(defrecord DirectedGraph
[nodes ; The nodes of the graph, a collection
Expand Down Expand Up @@ -143,7 +143,7 @@
find-neighbors (fn [ns]
(let [nbs1 (map (partial get-neighbors g) ns)
nbs2 (map set nbs1)
nbs3 (apply union nbs2)]
nbs3 (apply set/union nbs2)]
(set (map find-node-set nbs3))))
nm (into {} (map (fn [ns] [ns (find-neighbors ns)]) sccs))]
(->DirectedGraph (set sccs) nm))))
Expand Down
Loading