Extract tests are failing because the indexes aren't as expected

I *think* the code is right an the tests are wrong, but I'm too unwell/tired to verify that just now.
This commit is contained in:
Simon Brooke 2019-06-26 18:38:18 +01:00
parent 958413d2e3
commit 551fd00292
4 changed files with 177 additions and 6 deletions

View file

@ -53,7 +53,7 @@ However, if `*safe-sparse-operations*` is bound to `true`, exceptions will be th
ExceptionInfo Expected 3 coordinates; found 1 clojure.core/ex-info (core.clj:4617) ExceptionInfo Expected 3 coordinates; found 1 clojure.core/ex-info (core.clj:4617)
``` ```
Sanity checking data is potentially expensive; for this reason `*safe-sparse-operations*` defaults to `false`, but you make wish to bind it to `true` especially while debugging. Sanity checking data is potentially expensive; for this reason `*safe-sparse-operations*` defaults to `false`, but you may wish to bind it to `true` especially while debugging.
### Dense arrays ### Dense arrays

View file

@ -213,25 +213,34 @@
1) 1)
0)) 0))
(defn dense-array?
"Basically, any vector can be considered as a dense array of one dimension.
If we're seeking a dense array of more than one dimension, the number of
dimensions should be specified as `d`."
([x]
(vector? x))
([x d]
(and (vector? x) (< d (dense-dimensions x)))))
(defn dense-to-sparse (defn dense-to-sparse
"Return a sparse array representing the content of the dense array `x`, "Return a sparse array representing the content of the dense array `x`,
assuming these `coordinates` if specified. *NOTE THAT* if insufficient assuming these `axes` if specified. *NOTE THAT* if insufficient
values of `coordinates` are specified, the resulting sparse array will values of `axes` are specified, the resulting sparse array will
be malformed." be malformed."
([x] ([x]
(dense-to-sparse x (map #(keyword (str "i" %)) (range)))) (dense-to-sparse x (map #(keyword (str "i" %)) (range))))
([x coordinates] ([x axes]
(let (let
[dimensions (dense-dimensions x)] [dimensions (dense-dimensions x)]
(reduce (reduce
merge merge
(apply make-sparse-array (take dimensions coordinates)) (apply make-sparse-array (take dimensions axes))
(map (map
(fn [i v] (if (nil? v) nil (hash-map i v))) (fn [i v] (if (nil? v) nil (hash-map i v)))
(range) (range)
(if (if
(> dimensions 1) (> dimensions 1)
(map #(dense-to-sparse % (rest coordinates)) x) (map #(dense-to-sparse % (rest axes)) x)
x)))))) x))))))
(defn arity (defn arity

View file

@ -0,0 +1,68 @@
(ns sparse-array.extract
(:require [sparse-array.core :refer :all]))
;;; The whole point of working with sparse arrays is to work with interesting
;;; subsets of arrays most of which are uninteresting. To extract an
;;; interesting subset from an array, we're going to need an extract function.
(defn- extract-from-sparse
"Return a subset of this sparse `array` comprising all those cells for which
this `function` returns a 'truthy' value."
[array function]
(reduce
merge
(apply
make-sparse-array
(cons
(:coord array)
(if (coll? (:content array)) (:content array))))
(map
#(if
(= :data (:content array))
(if (function (array %)) {% (array %)})
(let [v (extract-from-sparse (array %) function)]
(if
(empty?
(filter integer? (keys v)))
nil
{% v})))
(filter integer? (keys array)))))
(defn extract-from-dense
"Return a subset of this dense `array` comprising all those cells for which
this `function` returns a 'truthy' value. Use these `axes` if provided."
([array function]
(extract-from-dense array function (map #(keyword (str "i" %)) (range))))
([array function axes]
(let
[dimensions (dense-dimensions array)]
(reduce
merge
(apply make-sparse-array (take dimensions axes))
(if
(= dimensions 1)
(map
(fn [i v] (if (function v) (hash-map i v)))
(range)
array)
(map
(fn [i v] (if (empty? (filter integer? (keys v))) nil (hash-map i v)))
(range)
(map #(extract-from-dense % function (rest axes)) array)))))))
(defn extract
"Return a sparse subset of this `array` - which may be either sparse or
dense - comprising all those cells for which this `function` returns a
'truthy' value."
[array function]
(cond
(sparse-array? array)
(extract-from-sparse array function)
(dense-array? array)
(extract-from-dense array function)
*safe-sparse-operations*
(throw
(ex-info
"Argument passed as `array` is neither sparse nor dense."
{:array array}))))

View file

@ -0,0 +1,94 @@
(ns sparse-array.extract-test
(:require [clojure.test :refer :all]
[sparse-array.core :refer [dense-to-sparse get]]
[sparse-array.extract :refer :all]))
(deftest sparse-tests
(testing "extraction from sparse array"
(let [dense [[[1 2 3][:one :two :three]["one" "two" "three"]]
[[1 :two "three"]["one" 2 :three][:one "two" 3]]
[[1.0 2.0 3.0][2/2 4/2 6/2]["I" "II" "III"]]]
sparse (dense-to-sparse dense '(:a :b :c))
integers (extract sparse integer?)
strings (extract sparse string?)
keywords (extract sparse keyword?)
threes (extract sparse #(if
(number? %)
(= % 3)
(= (name %) "three")))]
(map
#(let [expected nil
actual (get (extract sparse map?) %1 %2 %3)]
(is (= actual expected) "there are no cells of which `map?` is true"))
(range 3)
(range 3)
(range 3))
(let [expected 1
actual (get integers 0 0 0)]
(is (= actual expected)))
(let [expected nil
actual (get keywords 0 0 0)]
(is (= actual expected)))
(let [expected nil
actual (get strings 0 0 0)]
(is (= actual expected)))
(let [expected nil
actual (get threes 0 0 0)]
(is (= actual expected)))
(let [expected 1
actual (get integers 0 0 2)]
(is (= actual expected)))
(let [expected nil
actual (get keywords 0 0 2)]
(is (= actual expected)))
(let [expected "three"
actual (get strings 0 0 2)]
(is (= actual expected)))
(let [expected "three"
actual (get threes 0 0 2)]
(is (= actual expected))))))
(deftest dense-tests
(testing "extraction from dense array"
(let [dense [[[1 2 3][:one :two :three]["one" "two" "three"]]
[[1 :two "three"]["one" 2 :three][:one "two" 3]]
[[1.0 2.0 3.0][2/2 4/2 6/2]["I" "II" "III"]]]
integers (extract dense integer?)
strings (extract dense string?)
keywords (extract dense keyword?)
threes (extract dense #(if
(number? %)
(= % 3)
(= (name %) "three")))]
(map
#(let [expected nil
actual (get (extract dense map?) %1 %2 %3)]
(is (= actual expected) "there are no cells of which `map?` is true"))
(range 3)
(range 3)
(range 3))
(let [expected 1
actual (get integers 0 0 0)]
(is (= actual expected)))
(let [expected nil
actual (get keywords 0 0 0)]
(is (= actual expected)))
(let [expected nil
actual (get strings 0 0 0)]
(is (= actual expected)))
(let [expected nil
actual (get threes 0 0 0)]
(is (= actual expected)))
(let [expected 1
actual (get integers 0 0 2)]
(is (= actual expected)))
(let [expected nil
actual (get keywords 0 0 2)]
(is (= actual expected)))
(let [expected "three"
actual (get strings 0 0 2)]
(is (= actual expected)))
(let [expected "three"
actual (get threes 0 0 2)]
(is (= actual expected))))))