Compare commits
19 commits
sparse-arr
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
463df26f23 | ||
|
784e8f887c | ||
|
c6e85b5500 | ||
|
7e95669ee7 | ||
|
7cae2678a9 | ||
|
42f64db00b | ||
|
35d668984d | ||
|
d56dca3643 | ||
|
7b324e3932 | ||
|
1aa3173dc9 | ||
|
156e7c4be3 | ||
|
59fb5529aa | ||
|
60ff8c9131 | ||
|
9494421087 | ||
|
bda0630c5a | ||
|
89a17d9666 | ||
|
551fd00292 | ||
|
a60dabbef1 | ||
|
b06b5cac35 |
42
.circleci/config.yml
Normal file
42
.circleci/config.yml
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Clojure CircleCI 2.0 configuration file
|
||||
#
|
||||
# Check https://circleci.com/docs/2.0/language-clojure/ for more details
|
||||
#
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
# specify the version you desire here
|
||||
- image: circleci/clojure:lein-2.7.1
|
||||
|
||||
# Specify service dependencies here if necessary
|
||||
# CircleCI maintains a library of pre-built images
|
||||
# documented at https://circleci.com/docs/2.0/circleci-images/
|
||||
# - image: circleci/postgres:9.4
|
||||
|
||||
working_directory: ~/repo
|
||||
|
||||
environment:
|
||||
LEIN_ROOT: "true"
|
||||
# Customize the JVM maximum heap limit
|
||||
JVM_OPTS: -Xmx3200m
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Download and cache dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "project.clj" }}
|
||||
# fallback to using the latest cache if no exact match is found
|
||||
- v1-dependencies-
|
||||
|
||||
- run: lein deps
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.m2
|
||||
key: v1-dependencies-{{ checksum "project.clj" }}
|
||||
|
||||
# run tests!
|
||||
- run: lein test
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -9,3 +9,5 @@ pom.xml.asc
|
|||
/.nrepl-port
|
||||
.hgignore
|
||||
.hg/
|
||||
.clj-kondo/
|
||||
.lsp/
|
105
README.md
105
README.md
|
@ -1,12 +1,15 @@
|
|||
# sparse-array
|
||||
|
||||
A Clojure library designed to manipulate sparse *arrays* - multi-dimensional spaces accessed by indices, but containing arbitrary values rather than just numbers. For sparse spaces which contain numbers only, you're better to use a *sparse matrix* library, for example [clojure.core.matrix](https://mikera.github.io/core.matrix/).
|
||||
A Clojure library designed to manipulate sparse *arrays* - multi-dimensional spaces accessed by indices, but containing arbitrary values rather than just numbers. For sparse spaces which contain numbers only, you're better to use a *sparse matrix* library, [for example clojure.core.matrix](https://mikera.github.io/core.matrix/).
|
||||
|
||||
Arbitrary numbers of dimensions are supported, up to limits imposed by the JVM stack.
|
||||
|
||||
[](https://clojars.org/sparse-array)
|
||||
Available from Clojars: [](https://clojars.org/sparse-array)
|
||||
Tests currently [](https://circleci.com/gh/simon-brooke/sparse-array)
|
||||
|
||||
## Conventions:
|
||||
[](https://circleci.com/gh/simon-brooke/sparse-array)
|
||||
|
||||
## Conventions
|
||||
|
||||
### Sparse arrays
|
||||
|
||||
|
@ -53,7 +56,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)
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
|
@ -160,6 +163,100 @@ e.g.
|
|||
[nil nil nil "goodbye" nil]]
|
||||
```
|
||||
|
||||
### extract
|
||||
|
||||
The whole point of working with sparse arrays is because we wish to work with
|
||||
interesting subsets of arrays the entirety of which would be too large to
|
||||
conveniently handle; thus perhaps the most important operation is to be able
|
||||
to extract a sparse subset of an array.
|
||||
|
||||
`sparse-array.extract/extract ([array function])`
|
||||
|
||||
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.
|
||||
|
||||
e.g.
|
||||
|
||||
```clojure
|
||||
(extract [[[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"]]]
|
||||
#(if
|
||||
(number? %)
|
||||
(= % 3)
|
||||
(= (name %) "three")))
|
||||
|
||||
=> {:dimensions 3,
|
||||
:coord :i0,
|
||||
:content (:i1 :i2),
|
||||
0
|
||||
{:dimensions 2,
|
||||
:coord :i1,
|
||||
:content (:i2),
|
||||
0 {:dimensions 1, :coord :i2, :content :data, 2 3},
|
||||
1 {:dimensions 1, :coord :i2, :content :data, 2 :three},
|
||||
2 {:dimensions 1, :coord :i2, :content :data, 2 "three"}},
|
||||
1
|
||||
{:dimensions 2,
|
||||
:coord :i1,
|
||||
:content (:i2),
|
||||
0 {:dimensions 1, :coord :i2, :content :data, 2 "three"},
|
||||
1 {:dimensions 1, :coord :i2, :content :data, 2 :three},
|
||||
2 {:dimensions 1, :coord :i2, :content :data, 2 3}},
|
||||
2
|
||||
{:dimensions 2,
|
||||
:coord :i1,
|
||||
:content (:i2),
|
||||
1 {:dimensions 1, :coord :i2, :content :data, 2 3}}}
|
||||
```
|
||||
|
||||
### extract-from-dense
|
||||
|
||||
Note that the above example returns the default axis sequence `{i0, i1, i2...}`;
|
||||
extracting from a sparse array will always retain the axes of the array
|
||||
extracted from. Dense arrays, obviously, do not have explicit axes.
|
||||
|
||||
You may wish to specify a sequence of axes when extracting from a dense array.
|
||||
A function is provided:
|
||||
|
||||
`sparse-array.extract/extract-from-dense ([array function] [array function axes])`
|
||||
|
||||
Return a subset of this dense `array` comprising all those cells for which
|
||||
this `function` returns a 'truthy' value. Use these `axes` if provided.
|
||||
|
||||
e.g.
|
||||
|
||||
```clojure
|
||||
(extract-from-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"]]]
|
||||
integer?
|
||||
'(:p :q :r))
|
||||
|
||||
=> {:dimensions 3,
|
||||
:coord :p,
|
||||
:content (:q :r),
|
||||
0
|
||||
{:dimensions 2,
|
||||
:coord :q,
|
||||
:content (:r),
|
||||
0 {:dimensions 1, :coord :r, :content :data, 0 1, 1 2, 2 3}},
|
||||
1
|
||||
{:dimensions 2,
|
||||
:coord :q,
|
||||
:content (:r),
|
||||
0 {:dimensions 1, :coord :r, :content :data, 0 1},
|
||||
1 {:dimensions 1, :coord :r, :content :data, 1 2},
|
||||
2 {:dimensions 1, :coord :r, :content :data, 2 3}},
|
||||
2
|
||||
{:dimensions 2,
|
||||
:coord :q,
|
||||
:content (:r),
|
||||
1 {:dimensions 1, :coord :r, :content :data, 0 1, 1 2, 2 3}}}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Copyright © 2019 Simon Brooke
|
||||
|
|
264
doc/intro.md
264
doc/intro.md
|
@ -1,3 +1,263 @@
|
|||
# Introduction to sparse-array
|
||||
# Introduction to Sparse-array
|
||||
|
||||
TODO: write [great documentation](http://jacobian.org/writing/what-to-write/)
|
||||
A Clojure library designed to manipulate sparse *arrays* - multi-dimensional spaces accessed by indices, but containing arbitrary values rather than just numbers. For sparse spaces which contain numbers only, you're better to use a *sparse matrix* library, [for example clojure.core.matrix](https://mikera.github.io/core.matrix/).
|
||||
|
||||
Arbitrary numbers of dimensions are supported, up to limits imposed by the JVM stack.
|
||||
|
||||
Available from Clojars: [](https://clojars.org/sparse-array)
|
||||
Tests currently [](https://circleci.com/gh/simon-brooke/sparse-array)
|
||||
|
||||
## Conventions
|
||||
|
||||
### Sparse arrays
|
||||
|
||||
For the purposes of this library, a sparse array shall be implemented as a map, such that all keys are non-negative members of the set of integers, except for the following keyword keys, all of which are expected to be present:
|
||||
|
||||
1. `:dimensions` The number of dimensions in this array, counting the present one (value expected to be a real number);
|
||||
2. `:coord` The coordinate of the dimension represented by the current map (value expected to be a keyword);
|
||||
3. `:content` What this map contains; if the value of `:dimensions` is one, then `:data`; otherwise, an ordered sequence of the coordinates of the dimensions below this one.
|
||||
|
||||
Thus an array with a single value 'hello' at coordinates x = 3, y = 4, z = 5 would be encoded:
|
||||
|
||||
```clojure
|
||||
{:dimensions 3
|
||||
:coord :x
|
||||
:content [:y :z]
|
||||
3 {:dimensions 2
|
||||
:coord :y
|
||||
:content [:z]
|
||||
4 {:dimensions 1
|
||||
:coord :z
|
||||
:content :data
|
||||
5 "hello"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Errors and error-reporting
|
||||
|
||||
A dynamic variable, `*safe-sparse-operations*`, is provided to handle behaviour in error conditions. If this is `false`, bad data will generally not cause an exception to be thrown, and corrupt structures may be returned, thus:
|
||||
|
||||
```clojure
|
||||
(put (make-sparse-array :x :y :z) "hello" 3) ;; insufficient coordinates specified
|
||||
|
||||
=> {:dimensions 3, :coord :x, :content (:y :z), 3 {:dimensions 2, :coord :y, :content (:z), nil {:dimensions 1, :coord :z, :content :data, nil nil}}}
|
||||
```
|
||||
|
||||
However, if `*safe-sparse-operations*` is bound to `true`, exceptions will be thrown instead:
|
||||
|
||||
```clojure
|
||||
(binding [*safe-sparse-operations* true]
|
||||
(put (make-sparse-array :x :y :z) "hello" 3))
|
||||
|
||||
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 may wish to bind it to `true` especially while debugging.
|
||||
|
||||
### Dense arrays
|
||||
|
||||
For the purposes of conversion, a **dense array** is assumed to be a vector; a two dimensional dense array a vector of vectors; a three dimensional dense array a vector of vectors of vectors, and so on. For any depth `N`, all vectors at depth `N` must have the same arity. If these conventions are not respected conversion may fail.
|
||||
|
||||
## Usage
|
||||
|
||||
### make-sparse-array
|
||||
`sparse-array.core/make-sparse-array ([& dimensions])`
|
||||
|
||||
Make a sparse array with these `dimensions`. Every member of `dimensions` must be a keyword; otherwise, `nil` will be returned.
|
||||
|
||||
e.g.
|
||||
|
||||
```clojure
|
||||
(make-sparse-array :x :y :z)
|
||||
|
||||
=> {:dimensions 3, :coord :x, :content (:y :z)}
|
||||
|
||||
```
|
||||
|
||||
### sparse-array?
|
||||
|
||||
`sparse-array.core/sparse-array? ([x])`
|
||||
|
||||
`true` if `x` is a sparse array conforming to the conventions established by this library, else `false`.
|
||||
|
||||
### put
|
||||
|
||||
`sparse-array.core/put ([array value & coordinates])`
|
||||
|
||||
Return a sparse array like this `array` but with this `value` at these `coordinates`. Returns `nil` if any coordinate is invalid.
|
||||
|
||||
e.g.
|
||||
|
||||
```clojure
|
||||
(put (put (make-sparse-array :x :y) "hello" 3 4) "goodbye" 4 3)
|
||||
|
||||
=> {:dimensions 2,
|
||||
:coord :x,
|
||||
:content (:y),
|
||||
3 {:dimensions 1, :coord :y, :content :data, 4 "hello"},
|
||||
4 {:dimensions 1, :coord :y, :content :data, 3 "goodbye"}}
|
||||
```
|
||||
|
||||
### get
|
||||
|
||||
`sparse-array.core/get ([array & coordinates])`
|
||||
|
||||
Return the value in this sparse `array` at these `coordinates`.
|
||||
|
||||
### merge-sparse-arrays
|
||||
|
||||
`sparse-array.core/merge-sparse-arrays ([a1 a2])`
|
||||
|
||||
Return a sparse array taking values from sparse arrays `a1` and `a2`, but preferring values from `a2` where there is a conflict. `a1` and `a2` must have the **same** dimensions in the **same** order, or `nil` will be returned.
|
||||
|
||||
e.g.
|
||||
|
||||
```clojure
|
||||
(merge-sparse-arrays
|
||||
(put (make-sparse-array :x) "hello" 3)
|
||||
(put (make-sparse-array :x) "goodbye" 4)))
|
||||
|
||||
=> {:dimensions 1, :coord :x, :content :data, 3 "hello", 4 "goodbye"}
|
||||
```
|
||||
|
||||
### dense-to-sparse
|
||||
|
||||
`sparse-array.core/dense-to-sparse ([x] [x coordinates])`
|
||||
|
||||
Return a sparse array representing the content of the dense array `x`, assuming these `coordinates` if specified. *NOTE THAT* if insufficient values of `coordinates` are specified, the resulting sparse array will be malformed.
|
||||
|
||||
e.g.
|
||||
|
||||
```clojure
|
||||
(dense-to-sparse [nil nil nil "hello" nil "goodbye"])
|
||||
|
||||
=> {:dimensions 1, :coord :i0, :content :data, 3 "hello", 5 "goodbye"}
|
||||
```
|
||||
|
||||
### sparse-to-dense
|
||||
|
||||
`sparse-array.core/sparse-to-dense ([x] [x arity])`
|
||||
|
||||
Return a dense array representing the content of the sparse array `x`.
|
||||
|
||||
**NOTE THAT** this has the potential to consume very large amounts of memory.
|
||||
|
||||
e.g.
|
||||
|
||||
```clojure
|
||||
(sparse-to-dense
|
||||
(put
|
||||
(put
|
||||
(make-sparse-array :x :y)
|
||||
"hello" 3 4)
|
||||
"goodbye" 4 3))
|
||||
|
||||
=> [[nil nil nil nil nil]
|
||||
[nil nil nil nil nil]
|
||||
[nil nil nil nil nil]
|
||||
[nil nil nil nil "hello"]
|
||||
[nil nil nil "goodbye" nil]]
|
||||
```
|
||||
|
||||
### extract
|
||||
|
||||
The whole point of working with sparse arrays is because we wish to work with
|
||||
interesting subsets of arrays the entirety of which would be too large to
|
||||
conveniently handle; thus perhaps the most important operation is to be able
|
||||
to extract a sparse subset of an array.
|
||||
|
||||
`sparse-array.extract/extract ([array function])`
|
||||
|
||||
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.
|
||||
|
||||
e.g.
|
||||
|
||||
```clojure
|
||||
(extract [[[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"]]]
|
||||
#(if
|
||||
(number? %)
|
||||
(= % 3)
|
||||
(= (name %) "three")))
|
||||
|
||||
=> {:dimensions 3,
|
||||
:coord :i0,
|
||||
:content (:i1 :i2),
|
||||
0
|
||||
{:dimensions 2,
|
||||
:coord :i1,
|
||||
:content (:i2),
|
||||
0 {:dimensions 1, :coord :i2, :content :data, 2 3},
|
||||
1 {:dimensions 1, :coord :i2, :content :data, 2 :three},
|
||||
2 {:dimensions 1, :coord :i2, :content :data, 2 "three"}},
|
||||
1
|
||||
{:dimensions 2,
|
||||
:coord :i1,
|
||||
:content (:i2),
|
||||
0 {:dimensions 1, :coord :i2, :content :data, 2 "three"},
|
||||
1 {:dimensions 1, :coord :i2, :content :data, 2 :three},
|
||||
2 {:dimensions 1, :coord :i2, :content :data, 2 3}},
|
||||
2
|
||||
{:dimensions 2,
|
||||
:coord :i1,
|
||||
:content (:i2),
|
||||
1 {:dimensions 1, :coord :i2, :content :data, 2 3}}}
|
||||
```
|
||||
|
||||
### extract-from-dense
|
||||
|
||||
Note that the above example returns the default axis sequence `{i0, i1, i2...}`;
|
||||
extracting from a sparse array will always retain the axes of the array
|
||||
extracted from. Dense arrays, obviously, do not have explicit axes.
|
||||
|
||||
You may wish to specify a sequence of axes when extracting from a dense array.
|
||||
A function is provided:
|
||||
|
||||
`sparse-array.extract/extract-from-dense ([array function] [array function axes])`
|
||||
|
||||
Return a subset of this dense `array` comprising all those cells for which
|
||||
this `function` returns a 'truthy' value. Use these `axes` if provided.
|
||||
|
||||
e.g.
|
||||
|
||||
```clojure
|
||||
(extract-from-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"]]]
|
||||
integer?
|
||||
'(:p :q :r))
|
||||
|
||||
=> {:dimensions 3,
|
||||
:coord :p,
|
||||
:content (:q :r),
|
||||
0
|
||||
{:dimensions 2,
|
||||
:coord :q,
|
||||
:content (:r),
|
||||
0 {:dimensions 1, :coord :r, :content :data, 0 1, 1 2, 2 3}},
|
||||
1
|
||||
{:dimensions 2,
|
||||
:coord :q,
|
||||
:content (:r),
|
||||
0 {:dimensions 1, :coord :r, :content :data, 0 1},
|
||||
1 {:dimensions 1, :coord :r, :content :data, 1 2},
|
||||
2 {:dimensions 1, :coord :r, :content :data, 2 3}},
|
||||
2
|
||||
{:dimensions 2,
|
||||
:coord :q,
|
||||
:content (:r),
|
||||
1 {:dimensions 1, :coord :r, :content :data, 0 1, 1 2, 2 3}}}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Copyright © 2019 Simon Brooke
|
||||
|
||||
Distributed under the Eclipse Public License either version 1.0 or (at
|
||||
your option) any later version.
|
||||
|
|
40
docs/cloverage/coverage.css
Normal file
40
docs/cloverage/coverage.css
Normal file
|
@ -0,0 +1,40 @@
|
|||
.covered {
|
||||
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
|
||||
background-color: #558B55;
|
||||
}
|
||||
|
||||
.not-covered {
|
||||
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.partial {
|
||||
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.not-tracked {
|
||||
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
|
||||
}
|
||||
|
||||
.blank {
|
||||
font-family: 'Bitstream Vera Sans Mono', 'Courier', monospace;
|
||||
}
|
||||
|
||||
td {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
td.with-bar {
|
||||
width: 250px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
td.with-number {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
td.ns-name {
|
||||
min-width: 150px;
|
||||
padding-right: 25px;
|
||||
}
|
59
docs/cloverage/index.html
Normal file
59
docs/cloverage/index.html
Normal file
|
@ -0,0 +1,59 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="./coverage.css"/>
|
||||
<title>Coverage Summary</title>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<thead><tr>
|
||||
<td class="ns-name"> Namespace </td>
|
||||
<td class="with-bar"> Forms </td>
|
||||
<td class="with-number">Forms %</td>
|
||||
<td class="with-bar"> Lines </td>
|
||||
<td class="with-number">Lines %</td>
|
||||
<td class="with-number">Total</td><td class="with-number">Blank</td><td class="with-number">Instrumented</td>
|
||||
</tr></thead>
|
||||
<tr>
|
||||
<td><a href="sparse_array/core.clj.html">sparse-array.core</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:85.14150943396227%;
|
||||
float:left;"> 722 </div><div class="not-covered"
|
||||
style="width:14.858490566037736%;
|
||||
float:left;"> 126 </div></td>
|
||||
<td class="with-number">85.14 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:82.37885462555066%;
|
||||
float:left;"> 187 </div><div class="partial"
|
||||
style="width:6.167400881057269%;
|
||||
float:left;"> 14 </div><div class="not-covered"
|
||||
style="width:11.45374449339207%;
|
||||
float:left;"> 26 </div></td>
|
||||
<td class="with-number">88.55 %</td>
|
||||
<td class="with-number">337</td><td class="with-number">22</td><td class="with-number">227</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="sparse_array/extract.clj.html">sparse-array.extract</a></td><td class="with-bar"><div class="covered"
|
||||
style="width:94.31818181818181%;
|
||||
float:left;"> 166 </div><div class="not-covered"
|
||||
style="width:5.681818181818182%;
|
||||
float:left;"> 10 </div></td>
|
||||
<td class="with-number">94.32 %</td>
|
||||
<td class="with-bar"><div class="covered"
|
||||
style="width:89.1304347826087%;
|
||||
float:left;"> 41 </div><div class="partial"
|
||||
style="width:2.1739130434782608%;
|
||||
float:left;"> 1 </div><div class="not-covered"
|
||||
style="width:8.695652173913043%;
|
||||
float:left;"> 4 </div></td>
|
||||
<td class="with-number">91.30 %</td>
|
||||
<td class="with-number">71</td><td class="with-number">5</td><td class="with-number">46</td>
|
||||
</tr>
|
||||
<tr><td>Totals:</td>
|
||||
<td class="with-bar"></td>
|
||||
<td class="with-number">86.72 %</td>
|
||||
<td class="with-bar"></td>
|
||||
<td class="with-number">89.01 %</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
1019
docs/cloverage/sparse_array/core.clj.html
Normal file
1019
docs/cloverage/sparse_array/core.clj.html
Normal file
File diff suppressed because it is too large
Load diff
221
docs/cloverage/sparse_array/extract.clj.html
Normal file
221
docs/cloverage/sparse_array/extract.clj.html
Normal file
|
@ -0,0 +1,221 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<link rel="stylesheet" href="../coverage.css"/> <title> sparse_array/extract.clj </title>
|
||||
</head>
|
||||
<body>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
001 (ns sparse-array.extract
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
002 "Extracting interesting data from sparse arrays."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
003 (:require [sparse-array.core :refer [*safe-sparse-operations*
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
004 dense-array? dense-dimensions
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
005 make-sparse-array sparse-array?]]))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
006
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
007 ;;; The whole point of working with sparse arrays is to work with interesting
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
008 ;;; subsets of arrays most of which are uninteresting. To extract an
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
009 ;;; interesting subset from an array, we're going to need an extract function.
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
010
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
011 (defn- extract-from-sparse
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
012 "Return a subset of this sparse `array` comprising all those cells for which
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
013 this `function` returns a 'truthy' value."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
014 [array function]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
015 (reduce
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
016 merge
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
017 (apply
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
018 make-sparse-array
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
019 (cons
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
020 (:coord array)
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
021 (when (coll? (:content array)) (:content array))))
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
022 (map
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
023 #(if
|
||||
</span><br/>
|
||||
<span class="covered" title="5 out of 5 forms covered">
|
||||
024 (= :data (:content array))
|
||||
</span><br/>
|
||||
<span class="covered" title="12 out of 12 forms covered">
|
||||
025 (when (function (array %)) {% (array %)})
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
026 (let [v (extract-from-sparse (array %) function)]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
027 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
028 (empty?
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
029 (filter integer? (keys v)))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
030 nil
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
031 {% v})))
|
||||
</span><br/>
|
||||
<span class="covered" title="6 out of 6 forms covered">
|
||||
032 (filter integer? (keys array)))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
033
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
034 (defn extract-from-dense
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
035 "Return a subset of this dense `array` comprising all those cells for which
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
036 this `function` returns a 'truthy' value. Use these `axes` if provided."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
037 ([array function]
|
||||
</span><br/>
|
||||
<span class="covered" title="15 out of 15 forms covered">
|
||||
038 (extract-from-dense array function (map #(keyword (str "i" %)) (range))))
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
039 ([array function axes]
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
040 (let
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
041 [dimensions (dense-dimensions array)]
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
042 (reduce
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
043 merge
|
||||
</span><br/>
|
||||
<span class="covered" title="7 out of 7 forms covered">
|
||||
044 (apply make-sparse-array (take dimensions axes))
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
045 (if
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
046 (= dimensions 1)
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
047 (map
|
||||
</span><br/>
|
||||
<span class="covered" title="10 out of 10 forms covered">
|
||||
048 (fn [i v] (when (function v) (hash-map i v)))
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
049 (range)
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
050 array)
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
051 (map
|
||||
</span><br/>
|
||||
<span class="covered" title="15 out of 15 forms covered">
|
||||
052 (fn [i v] (if (empty? (filter integer? (keys v))) nil (hash-map i v)))
|
||||
</span><br/>
|
||||
<span class="covered" title="2 out of 2 forms covered">
|
||||
053 (range)
|
||||
</span><br/>
|
||||
<span class="covered" title="11 out of 11 forms covered">
|
||||
054 (map #(extract-from-dense % function (rest axes)) array)))))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
055
|
||||
</span><br/>
|
||||
<span class="covered" title="1 out of 1 forms covered">
|
||||
056 (defn extract
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
057 "Return a sparse subset of this `array` - which may be either sparse or
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
058 dense - comprising all those cells for which this `function` returns a
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
059 'truthy' value."
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
060 [array function]
|
||||
</span><br/>
|
||||
<span class="partial" title="2 out of 4 forms covered">
|
||||
061 (cond
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
062 (sparse-array? array)
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
063 (extract-from-sparse array function)
|
||||
</span><br/>
|
||||
<span class="covered" title="3 out of 3 forms covered">
|
||||
064 (dense-array? array)
|
||||
</span><br/>
|
||||
<span class="covered" title="4 out of 4 forms covered">
|
||||
065 (extract-from-dense array function)
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
066 *safe-sparse-operations*
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 1 forms covered">
|
||||
067 (throw
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
068 (ex-info
|
||||
</span><br/>
|
||||
<span class="not-tracked" title="0 out of 0 forms covered">
|
||||
069 "Argument passed as `array` is neither sparse nor dense."
|
||||
</span><br/>
|
||||
<span class="not-covered" title="0 out of 3 forms covered">
|
||||
070 {:array array}))))
|
||||
</span><br/>
|
||||
<span class="blank" title="0 out of 0 forms covered">
|
||||
071
|
||||
</span><br/>
|
||||
</body>
|
||||
</html>
|
551
docs/codox/css/default.css
Normal file
551
docs/codox/css/default.css
Normal file
|
@ -0,0 +1,551 @@
|
|||
body {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
font-family: Monaco, DejaVu Sans Mono, Consolas, monospace;
|
||||
font-size: 9pt;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: normal;
|
||||
font-size: 29px;
|
||||
margin: 10px 0 2px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: normal;
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
h5.license {
|
||||
margin: 9px 0 22px 0;
|
||||
color: #555;
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.document h1, .namespace-index h1 {
|
||||
font-size: 32px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
#header, #content, .sidebar {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
#header {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 22px;
|
||||
color: #f5f5f5;
|
||||
padding: 5px 7px;
|
||||
}
|
||||
|
||||
#content {
|
||||
top: 32px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
background: #fff;
|
||||
color: #333;
|
||||
padding: 0 18px;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 32px;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.sidebar.primary {
|
||||
background: #e2e2e2;
|
||||
border-right: solid 1px #cccccc;
|
||||
left: 0;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.sidebar.secondary {
|
||||
background: #f2f2f2;
|
||||
border-right: solid 1px #d7d7d7;
|
||||
left: 251px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#content.namespace-index, #content.document {
|
||||
left: 251px;
|
||||
}
|
||||
|
||||
#content.namespace-docs {
|
||||
left: 452px;
|
||||
}
|
||||
|
||||
#content.document {
|
||||
padding-bottom: 10%;
|
||||
}
|
||||
|
||||
#header {
|
||||
background: #3f3f3f;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#header h1 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 18px;
|
||||
font-weight: lighter;
|
||||
text-shadow: -1px -1px 0px #333;
|
||||
}
|
||||
|
||||
#header h1 .project-version {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.project-version {
|
||||
padding-left: 0.15em;
|
||||
}
|
||||
|
||||
#header a, .sidebar a {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#header a {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
.sidebar a {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#header h2 {
|
||||
float: right;
|
||||
font-size: 9pt;
|
||||
font-weight: normal;
|
||||
margin: 4px 3px;
|
||||
padding: 0;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
#header h2 a {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.sidebar h3 {
|
||||
margin: 0;
|
||||
padding: 10px 13px 0 13px;
|
||||
font-size: 19px;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
.sidebar h3 a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.sidebar h3.no-link {
|
||||
color: #636363;
|
||||
}
|
||||
|
||||
.sidebar ul {
|
||||
padding: 7px 0 6px 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sidebar ul.index-link {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.sidebar li {
|
||||
display: block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.sidebar li a, .sidebar li .no-link {
|
||||
border-left: 3px solid transparent;
|
||||
padding: 0 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sidebar li .no-link {
|
||||
display: block;
|
||||
color: #777;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.sidebar li .inner {
|
||||
display: inline-block;
|
||||
padding-top: 7px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.sidebar li a, .sidebar li .tree {
|
||||
height: 31px;
|
||||
}
|
||||
|
||||
.depth-1 .inner { padding-left: 2px; }
|
||||
.depth-2 .inner { padding-left: 6px; }
|
||||
.depth-3 .inner { padding-left: 20px; }
|
||||
.depth-4 .inner { padding-left: 34px; }
|
||||
.depth-5 .inner { padding-left: 48px; }
|
||||
.depth-6 .inner { padding-left: 62px; }
|
||||
|
||||
.sidebar li .tree {
|
||||
display: block;
|
||||
float: left;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
margin: 0 4px 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sidebar li.depth-1 .tree {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar li .tree .top, .sidebar li .tree .bottom {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 7px;
|
||||
}
|
||||
|
||||
.sidebar li .tree .top {
|
||||
border-left: 1px solid #aaa;
|
||||
border-bottom: 1px solid #aaa;
|
||||
height: 19px;
|
||||
}
|
||||
|
||||
.sidebar li .tree .bottom {
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.sidebar li.branch .tree .bottom {
|
||||
border-left: 1px solid #aaa;
|
||||
}
|
||||
|
||||
.sidebar.primary li.current a {
|
||||
border-left: 3px solid #a33;
|
||||
color: #a33;
|
||||
}
|
||||
|
||||
.sidebar.secondary li.current a {
|
||||
border-left: 3px solid #33a;
|
||||
color: #33a;
|
||||
}
|
||||
|
||||
.namespace-index h2 {
|
||||
margin: 30px 0 0 0;
|
||||
}
|
||||
|
||||
.namespace-index h3 {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.namespace-index .topics {
|
||||
padding-left: 30px;
|
||||
margin: 11px 0 0 0;
|
||||
}
|
||||
|
||||
.namespace-index .topics li {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.namespace-docs h3 {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.public h3 {
|
||||
margin: 0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.usage {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.public {
|
||||
margin: 0;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
padding-top: 14px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.public:last-child {
|
||||
margin-bottom: 20%;
|
||||
}
|
||||
|
||||
.members .public:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.members {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.members h4 {
|
||||
color: #555;
|
||||
font-weight: normal;
|
||||
font-variant: small-caps;
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
.members .inner {
|
||||
padding-top: 5px;
|
||||
padding-left: 12px;
|
||||
margin-top: 2px;
|
||||
margin-left: 7px;
|
||||
border-left: 1px solid #bbb;
|
||||
}
|
||||
|
||||
#content .members .inner h3 {
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
.members .public {
|
||||
border-top: none;
|
||||
margin-top: 0;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.members .public:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
h4.type,
|
||||
h4.dynamic,
|
||||
h4.added,
|
||||
h4.deprecated {
|
||||
float: left;
|
||||
margin: 3px 10px 15px 0;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
font-variant: small-caps;
|
||||
}
|
||||
|
||||
.public h4.type,
|
||||
.public h4.dynamic,
|
||||
.public h4.added,
|
||||
.public h4.deprecated {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
margin: 3px 0 0 10px;
|
||||
}
|
||||
|
||||
.members h4.type,
|
||||
.members h4.added,
|
||||
.members h4.deprecated {
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
h4.type {
|
||||
color: #717171;
|
||||
}
|
||||
|
||||
h4.dynamic {
|
||||
color: #9933aa;
|
||||
}
|
||||
|
||||
h4.added {
|
||||
color: #508820;
|
||||
}
|
||||
|
||||
h4.deprecated {
|
||||
color: #880000;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.namespace:last-child {
|
||||
margin-bottom: 10%;
|
||||
}
|
||||
|
||||
.index {
|
||||
padding: 0;
|
||||
font-size: 80%;
|
||||
margin: 15px 0;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.index * {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.index p {
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
.index li {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.index ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.type-sig {
|
||||
clear: both;
|
||||
color: #088;
|
||||
}
|
||||
|
||||
.type-sig pre {
|
||||
padding-top: 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.usage code {
|
||||
display: block;
|
||||
color: #008;
|
||||
margin: 2px 0;
|
||||
}
|
||||
|
||||
.usage code:first-child {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.public p:first-child, .public pre.plaintext {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.doc {
|
||||
margin: 0 0 26px 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.public .doc {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.namespace-index .doc {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.namespace-index .namespace .doc {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.markdown p, .markdown li, .markdown dt, .markdown dd, .markdown td {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.markdown li {
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
.markdown h2 {
|
||||
font-weight: normal;
|
||||
font-size: 25px;
|
||||
margin: 30px 0 10px 0;
|
||||
}
|
||||
|
||||
.markdown h3 {
|
||||
font-weight: normal;
|
||||
font-size: 20px;
|
||||
margin: 30px 0 0 0;
|
||||
}
|
||||
|
||||
.markdown h4 {
|
||||
font-size: 15px;
|
||||
margin: 22px 0 -4px 0;
|
||||
}
|
||||
|
||||
.doc, .public, .namespace .index {
|
||||
max-width: 680px;
|
||||
overflow-x: visible;
|
||||
}
|
||||
|
||||
.markdown pre > code {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.markdown pre > code, .src-link a {
|
||||
border: 1px solid #e4e4e4;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.markdown code:not(.hljs), .src-link a {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
pre.deps {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
border: 1px solid #e4e4e4;
|
||||
border-radius: 2px;
|
||||
padding: 10px;
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
.markdown hr {
|
||||
border-style: solid;
|
||||
border-top: none;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.doc ul, .doc ol {
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
.doc table {
|
||||
border-collapse: collapse;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.doc table td, .doc table th {
|
||||
border: 1px solid #dddddd;
|
||||
padding: 4px 6px;
|
||||
}
|
||||
|
||||
.doc table th {
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.doc dl {
|
||||
margin: 0 10px 20px 10px;
|
||||
}
|
||||
|
||||
.doc dl dt {
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 3px 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.doc dl dd {
|
||||
padding: 5px 0;
|
||||
margin: 0 0 5px 10px;
|
||||
}
|
||||
|
||||
.doc abbr {
|
||||
border-bottom: 1px dotted #333;
|
||||
font-variant: none;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.src-link {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.src-link a {
|
||||
font-size: 70%;
|
||||
padding: 1px 4px;
|
||||
text-decoration: none;
|
||||
color: #5555bb;
|
||||
}
|
97
docs/codox/css/highlight.css
Normal file
97
docs/codox/css/highlight.css
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.5em;
|
||||
color: #333;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: #998;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-selector-tag,
|
||||
.hljs-subst {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-number,
|
||||
.hljs-literal,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-tag .hljs-attr {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.hljs-string,
|
||||
.hljs-doctag {
|
||||
color: #d14;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-section,
|
||||
.hljs-selector-id {
|
||||
color: #900;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-subst {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-type,
|
||||
.hljs-class .hljs-title {
|
||||
color: #458;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-tag,
|
||||
.hljs-name,
|
||||
.hljs-attribute {
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.hljs-regexp,
|
||||
.hljs-link {
|
||||
color: #009926;
|
||||
}
|
||||
|
||||
.hljs-symbol,
|
||||
.hljs-bullet {
|
||||
color: #990073;
|
||||
}
|
||||
|
||||
.hljs-built_in,
|
||||
.hljs-builtin-name {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.hljs-meta {
|
||||
color: #999;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-deletion {
|
||||
background: #fdd;
|
||||
}
|
||||
|
||||
.hljs-addition {
|
||||
background: #dfd;
|
||||
}
|
||||
|
||||
.hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-strong {
|
||||
font-weight: bold;
|
||||
}
|
3
docs/codox/index.html
Normal file
3
docs/codox/index.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<!DOCTYPE html PUBLIC ""
|
||||
"">
|
||||
<html><head><meta charset="UTF-8" /><title>Sparse-array 0.3.0</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Sparse-array</span> <span class="project-version">0.3.0</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 current"><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="intro.html"><div class="inner"><span>Introduction to Sparse-array</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>sparse-array</span></div></div></li><li class="depth-2 branch"><a href="sparse-array.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2"><a href="sparse-array.extract.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>extract</span></div></a></li></ul></div><div class="namespace-index" id="content"><h1><span class="project-title"><span class="project-name">Sparse-array</span> <span class="project-version">0.3.0</span></span></h1><h5 class="license">Released under the <a href="http://www.eclipse.org/legal/epl-v10.html">Eclipse Public License</a></h5><div class="doc"><p>A Clojure library designed to manipulate sparse *arrays* - multi-dimensional spaces accessed by indices, but containing arbitrary values rather than just numbers. For sparse spaces which contain numbers only, you're better to use a *sparse matrix* library, for example [clojure.core.matrix](https://mikera.github.io/core.matrix/).</p></div><h2>Installation</h2><p>To install, add the following dependency to your project or build file:</p><pre class="deps">[sparse-array "0.3.0"]</pre><h2>Topics</h2><ul class="topics"><li><a href="intro.html">Introduction to Sparse-array</a></li></ul><h2>Namespaces</h2><div class="namespace"><h3><a href="sparse-array.core.html">sparse-array.core</a></h3><div class="doc"><div class="markdown"><p>Operations on sparse arrays.</p></div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="sparse-array.core.html#var-*safe-sparse-operations*">*safe-sparse-operations*</a> </li><li> <a href="sparse-array.core.html#var-arity">arity</a> </li><li> <a href="sparse-array.core.html#var-child-arity">child-arity</a> </li><li> <a href="sparse-array.core.html#var-dense-array.3F">dense-array?</a> </li><li> <a href="sparse-array.core.html#var-dense-dimensions">dense-dimensions</a> </li><li> <a href="sparse-array.core.html#var-dense-to-sparse">dense-to-sparse</a> </li><li> <a href="sparse-array.core.html#var-get">get</a> </li><li> <a href="sparse-array.core.html#var-make-sparse-array">make-sparse-array</a> </li><li> <a href="sparse-array.core.html#var-merge-arrays">merge-arrays</a> </li><li> <a href="sparse-array.core.html#var-merge-dense-with-sparse">merge-dense-with-sparse</a> </li><li> <a href="sparse-array.core.html#var-merge-sparse-arrays">merge-sparse-arrays</a> </li><li> <a href="sparse-array.core.html#var-put">put</a> </li><li> <a href="sparse-array.core.html#var-sparse-array.3F">sparse-array?</a> </li><li> <a href="sparse-array.core.html#var-sparse-to-dense">sparse-to-dense</a> </li></ul></div></div><div class="namespace"><h3><a href="sparse-array.extract.html">sparse-array.extract</a></h3><div class="doc"><div class="markdown"><p>Extracting interesting data from sparse arrays.</p></div></div><div class="index"><p>Public variables and functions:</p><ul><li> <a href="sparse-array.extract.html#var-extract">extract</a> </li><li> <a href="sparse-array.extract.html#var-extract-from-dense">extract-from-dense</a> </li></ul></div></div></div></body></html>
|
181
docs/codox/intro.html
Normal file
181
docs/codox/intro.html
Normal file
|
@ -0,0 +1,181 @@
|
|||
<!DOCTYPE html PUBLIC ""
|
||||
"">
|
||||
<html><head><meta charset="UTF-8" /><title>Introduction to Sparse-array</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Sparse-array</span> <span class="project-version">0.3.0</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 current"><a href="intro.html"><div class="inner"><span>Introduction to Sparse-array</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>sparse-array</span></div></div></li><li class="depth-2 branch"><a href="sparse-array.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2"><a href="sparse-array.extract.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>extract</span></div></a></li></ul></div><div class="document" id="content"><div class="doc"><div class="markdown"><h1><a href="#introduction-to-sparse-array" name="introduction-to-sparse-array"></a>Introduction to Sparse-array</h1>
|
||||
<p>A Clojure library designed to manipulate sparse <em>arrays</em> - multi-dimensional spaces accessed by indices, but containing arbitrary values rather than just numbers. For sparse spaces which contain numbers only, you’re better to use a <em>sparse matrix</em> library, <a href="https://mikera.github.io/core.matrix/">for example clojure.core.matrix</a>.</p>
|
||||
<p>Arbitrary numbers of dimensions are supported, up to limits imposed by the JVM stack.</p>
|
||||
<p>Available from Clojars: <a href="https://clojars.org/sparse-array"><img src="https://img.shields.io/clojars/v/sparse-array.svg" alt="Clojars Project" /></a> Tests currently <a href="https://circleci.com/gh/simon-brooke/sparse-array"><img src="https://circleci.com/gh/simon-brooke/sparse-array.svg?style=svg" alt="CircleCI" /></a></p>
|
||||
<h2><a href="#conventions" name="conventions"></a>Conventions</h2>
|
||||
<h3><a href="#sparse-arrays" name="sparse-arrays"></a>Sparse arrays</h3>
|
||||
<p>For the purposes of this library, a sparse array shall be implemented as a map, such that all keys are non-negative members of the set of integers, except for the following keyword keys, all of which are expected to be present:</p>
|
||||
<ol>
|
||||
<li><code>:dimensions</code> The number of dimensions in this array, counting the present one (value expected to be a real number);</li>
|
||||
<li><code>:coord</code> The coordinate of the dimension represented by the current map (value expected to be a keyword);</li>
|
||||
<li><code>:content</code> What this map contains; if the value of <code>:dimensions</code> is one, then <code>:data</code>; otherwise, an ordered sequence of the coordinates of the dimensions below this one.</li>
|
||||
</ol>
|
||||
<p>Thus an array with a single value ‘hello’ at coordinates x = 3, y = 4, z = 5 would be encoded:</p>
|
||||
<pre><code class="clojure">{:dimensions 3
|
||||
:coord :x
|
||||
:content [:y :z]
|
||||
3 {:dimensions 2
|
||||
:coord :y
|
||||
:content [:z]
|
||||
4 {:dimensions 1
|
||||
:coord :z
|
||||
:content :data
|
||||
5 "hello"
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h3><a href="#errors-and-error-reporting" name="errors-and-error-reporting"></a>Errors and error-reporting</h3>
|
||||
<p>A dynamic variable, <code>*safe-sparse-operations*</code>, is provided to handle behaviour in error conditions. If this is <code>false</code>, bad data will generally not cause an exception to be thrown, and corrupt structures may be returned, thus:</p>
|
||||
<pre><code class="clojure">(put (make-sparse-array :x :y :z) "hello" 3) ;; insufficient coordinates specified
|
||||
|
||||
=> {:dimensions 3, :coord :x, :content (:y :z), 3 {:dimensions 2, :coord :y, :content (:z), nil {:dimensions 1, :coord :z, :content :data, nil nil}}}
|
||||
</code></pre>
|
||||
<p>However, if <code>*safe-sparse-operations*</code> is bound to <code>true</code>, exceptions will be thrown instead:</p>
|
||||
<pre><code class="clojure">(binding [*safe-sparse-operations* true]
|
||||
(put (make-sparse-array :x :y :z) "hello" 3))
|
||||
|
||||
ExceptionInfo Expected 3 coordinates; found 1 clojure.core/ex-info (core.clj:4617)
|
||||
</code></pre>
|
||||
<p>Sanity checking data is potentially expensive; for this reason <code>*safe-sparse-operations*</code> defaults to <code>false</code>, but you may wish to bind it to <code>true</code> especially while debugging.</p>
|
||||
<h3><a href="#dense-arrays" name="dense-arrays"></a>Dense arrays</h3>
|
||||
<p>For the purposes of conversion, a <strong>dense array</strong> is assumed to be a vector; a two dimensional dense array a vector of vectors; a three dimensional dense array a vector of vectors of vectors, and so on. For any depth <code>N</code>, all vectors at depth <code>N</code> must have the same arity. If these conventions are not respected conversion may fail.</p>
|
||||
<h2><a href="#usage" name="usage"></a>Usage</h2>
|
||||
<h3><a href="#make-sparse-array" name="make-sparse-array"></a>make-sparse-array</h3>
|
||||
<p><code>sparse-array.core/make-sparse-array ([& dimensions])</code></p>
|
||||
<p>Make a sparse array with these <code>dimensions</code>. Every member of <code>dimensions</code> must be a keyword; otherwise, <code>nil</code> will be returned.</p>
|
||||
<p>e.g.</p>
|
||||
<pre><code class="clojure">(make-sparse-array :x :y :z)
|
||||
|
||||
=> {:dimensions 3, :coord :x, :content (:y :z)}
|
||||
|
||||
</code></pre>
|
||||
<h3><a href="#sparse-array-" name="sparse-array-"></a>sparse-array?</h3>
|
||||
<p><code>sparse-array.core/sparse-array? ([x])</code></p>
|
||||
<p><code>true</code> if <code>x</code> is a sparse array conforming to the conventions established by this library, else <code>false</code>.</p>
|
||||
<h3><a href="#put" name="put"></a>put</h3>
|
||||
<p><code>sparse-array.core/put ([array value & coordinates])</code></p>
|
||||
<p>Return a sparse array like this <code>array</code> but with this <code>value</code> at these <code>coordinates</code>. Returns <code>nil</code> if any coordinate is invalid.</p>
|
||||
<p>e.g.</p>
|
||||
<pre><code class="clojure">(put (put (make-sparse-array :x :y) "hello" 3 4) "goodbye" 4 3)
|
||||
|
||||
=> {:dimensions 2,
|
||||
:coord :x,
|
||||
:content (:y),
|
||||
3 {:dimensions 1, :coord :y, :content :data, 4 "hello"},
|
||||
4 {:dimensions 1, :coord :y, :content :data, 3 "goodbye"}}
|
||||
</code></pre>
|
||||
<h3><a href="#get" name="get"></a>get</h3>
|
||||
<p><code>sparse-array.core/get ([array & coordinates])</code></p>
|
||||
<p>Return the value in this sparse <code>array</code> at these <code>coordinates</code>.</p>
|
||||
<h3><a href="#merge-sparse-arrays" name="merge-sparse-arrays"></a>merge-sparse-arrays</h3>
|
||||
<p><code>sparse-array.core/merge-sparse-arrays ([a1 a2])</code></p>
|
||||
<p>Return a sparse array taking values from sparse arrays <code>a1</code> and <code>a2</code>, but preferring values from <code>a2</code> where there is a conflict. <code>a1</code> and <code>a2</code> must have the <strong>same</strong> dimensions in the <strong>same</strong> order, or <code>nil</code> will be returned.</p>
|
||||
<p>e.g.</p>
|
||||
<pre><code class="clojure">(merge-sparse-arrays
|
||||
(put (make-sparse-array :x) "hello" 3)
|
||||
(put (make-sparse-array :x) "goodbye" 4)))
|
||||
|
||||
=> {:dimensions 1, :coord :x, :content :data, 3 "hello", 4 "goodbye"}
|
||||
</code></pre>
|
||||
<h3><a href="#dense-to-sparse" name="dense-to-sparse"></a>dense-to-sparse</h3>
|
||||
<p><code>sparse-array.core/dense-to-sparse ([x] [x coordinates])</code></p>
|
||||
<p>Return a sparse array representing the content of the dense array <code>x</code>, assuming these <code>coordinates</code> if specified. <em>NOTE THAT</em> if insufficient values of <code>coordinates</code> are specified, the resulting sparse array will be malformed.</p>
|
||||
<p>e.g.</p>
|
||||
<pre><code class="clojure">(dense-to-sparse [nil nil nil "hello" nil "goodbye"])
|
||||
|
||||
=> {:dimensions 1, :coord :i0, :content :data, 3 "hello", 5 "goodbye"}
|
||||
</code></pre>
|
||||
<h3><a href="#sparse-to-dense" name="sparse-to-dense"></a>sparse-to-dense</h3>
|
||||
<p><code>sparse-array.core/sparse-to-dense ([x] [x arity])</code></p>
|
||||
<p>Return a dense array representing the content of the sparse array <code>x</code>.</p>
|
||||
<p><strong>NOTE THAT</strong> this has the potential to consume very large amounts of memory.</p>
|
||||
<p>e.g.</p>
|
||||
<pre><code class="clojure">(sparse-to-dense
|
||||
(put
|
||||
(put
|
||||
(make-sparse-array :x :y)
|
||||
"hello" 3 4)
|
||||
"goodbye" 4 3))
|
||||
|
||||
=> [[nil nil nil nil nil]
|
||||
[nil nil nil nil nil]
|
||||
[nil nil nil nil nil]
|
||||
[nil nil nil nil "hello"]
|
||||
[nil nil nil "goodbye" nil]]
|
||||
</code></pre>
|
||||
<h3><a href="#extract" name="extract"></a>extract</h3>
|
||||
<p>The whole point of working with sparse arrays is because we wish to work with interesting subsets of arrays the entirety of which would be too large to conveniently handle; thus perhaps the most important operation is to be able to extract a sparse subset of an array.</p>
|
||||
<p><code>sparse-array.extract/extract ([array function])</code></p>
|
||||
<p>Return a sparse subset of this <code>array</code> - which may be either sparse or dense - comprising all those cells for which this <code>function</code> returns a ‘truthy’ value.</p>
|
||||
<p>e.g.</p>
|
||||
<pre><code class="clojure">(extract [[[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"]]]
|
||||
#(if
|
||||
(number? %)
|
||||
(= % 3)
|
||||
(= (name %) "three")))
|
||||
|
||||
=> {:dimensions 3,
|
||||
:coord :i0,
|
||||
:content (:i1 :i2),
|
||||
0
|
||||
{:dimensions 2,
|
||||
:coord :i1,
|
||||
:content (:i2),
|
||||
0 {:dimensions 1, :coord :i2, :content :data, 2 3},
|
||||
1 {:dimensions 1, :coord :i2, :content :data, 2 :three},
|
||||
2 {:dimensions 1, :coord :i2, :content :data, 2 "three"}},
|
||||
1
|
||||
{:dimensions 2,
|
||||
:coord :i1,
|
||||
:content (:i2),
|
||||
0 {:dimensions 1, :coord :i2, :content :data, 2 "three"},
|
||||
1 {:dimensions 1, :coord :i2, :content :data, 2 :three},
|
||||
2 {:dimensions 1, :coord :i2, :content :data, 2 3}},
|
||||
2
|
||||
{:dimensions 2,
|
||||
:coord :i1,
|
||||
:content (:i2),
|
||||
1 {:dimensions 1, :coord :i2, :content :data, 2 3}}}
|
||||
</code></pre>
|
||||
<h3><a href="#extract-from-dense" name="extract-from-dense"></a>extract-from-dense</h3>
|
||||
<p>Note that the above example returns the default axis sequence <code>{i0, i1, i2...}</code>; extracting from a sparse array will always retain the axes of the array extracted from. Dense arrays, obviously, do not have explicit axes.</p>
|
||||
<p>You may wish to specify a sequence of axes when extracting from a dense array. A function is provided:</p>
|
||||
<p><code>sparse-array.extract/extract-from-dense ([array function] [array function axes])</code></p>
|
||||
<p>Return a subset of this dense <code>array</code> comprising all those cells for which this <code>function</code> returns a ‘truthy’ value. Use these <code>axes</code> if provided.</p>
|
||||
<p>e.g.</p>
|
||||
<pre><code class="clojure">(extract-from-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"]]]
|
||||
integer?
|
||||
'(:p :q :r))
|
||||
|
||||
=> {:dimensions 3,
|
||||
:coord :p,
|
||||
:content (:q :r),
|
||||
0
|
||||
{:dimensions 2,
|
||||
:coord :q,
|
||||
:content (:r),
|
||||
0 {:dimensions 1, :coord :r, :content :data, 0 1, 1 2, 2 3}},
|
||||
1
|
||||
{:dimensions 2,
|
||||
:coord :q,
|
||||
:content (:r),
|
||||
0 {:dimensions 1, :coord :r, :content :data, 0 1},
|
||||
1 {:dimensions 1, :coord :r, :content :data, 1 2},
|
||||
2 {:dimensions 1, :coord :r, :content :data, 2 3}},
|
||||
2
|
||||
{:dimensions 2,
|
||||
:coord :q,
|
||||
:content (:r),
|
||||
1 {:dimensions 1, :coord :r, :content :data, 0 1, 1 2, 2 3}}}
|
||||
</code></pre>
|
||||
<h2><a href="#license" name="license"></a>License</h2>
|
||||
<p>Copyright © 2019 Simon Brooke</p>
|
||||
<p>Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.</p></div></div></div></body></html>
|
2
docs/codox/js/highlight.min.js
vendored
Normal file
2
docs/codox/js/highlight.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
docs/codox/js/jquery.min.js
vendored
Normal file
4
docs/codox/js/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
112
docs/codox/js/page_effects.js
Normal file
112
docs/codox/js/page_effects.js
Normal file
|
@ -0,0 +1,112 @@
|
|||
function visibleInParent(element) {
|
||||
var position = $(element).position().top
|
||||
return position > -50 && position < ($(element).offsetParent().height() - 50)
|
||||
}
|
||||
|
||||
function hasFragment(link, fragment) {
|
||||
return $(link).attr("href").indexOf("#" + fragment) != -1
|
||||
}
|
||||
|
||||
function findLinkByFragment(elements, fragment) {
|
||||
return $(elements).filter(function(i, e) { return hasFragment(e, fragment)}).first()
|
||||
}
|
||||
|
||||
function scrollToCurrentVarLink(elements) {
|
||||
var elements = $(elements);
|
||||
var parent = elements.offsetParent();
|
||||
|
||||
if (elements.length == 0) return;
|
||||
|
||||
var top = elements.first().position().top;
|
||||
var bottom = elements.last().position().top + elements.last().height();
|
||||
|
||||
if (top >= 0 && bottom <= parent.height()) return;
|
||||
|
||||
if (top < 0) {
|
||||
parent.scrollTop(parent.scrollTop() + top);
|
||||
}
|
||||
else if (bottom > parent.height()) {
|
||||
parent.scrollTop(parent.scrollTop() + bottom - parent.height());
|
||||
}
|
||||
}
|
||||
|
||||
function setCurrentVarLink() {
|
||||
$('.secondary a').parent().removeClass('current')
|
||||
$('.anchor').
|
||||
filter(function(index) { return visibleInParent(this) }).
|
||||
each(function(index, element) {
|
||||
findLinkByFragment(".secondary a", element.id).
|
||||
parent().
|
||||
addClass('current')
|
||||
});
|
||||
scrollToCurrentVarLink('.secondary .current');
|
||||
}
|
||||
|
||||
var hasStorage = (function() { try { return localStorage.getItem } catch(e) {} }())
|
||||
|
||||
function scrollPositionId(element) {
|
||||
var directory = window.location.href.replace(/[^\/]+\.html$/, '')
|
||||
return 'scroll::' + $(element).attr('id') + '::' + directory
|
||||
}
|
||||
|
||||
function storeScrollPosition(element) {
|
||||
if (!hasStorage) return;
|
||||
localStorage.setItem(scrollPositionId(element) + "::x", $(element).scrollLeft())
|
||||
localStorage.setItem(scrollPositionId(element) + "::y", $(element).scrollTop())
|
||||
}
|
||||
|
||||
function recallScrollPosition(element) {
|
||||
if (!hasStorage) return;
|
||||
$(element).scrollLeft(localStorage.getItem(scrollPositionId(element) + "::x"))
|
||||
$(element).scrollTop(localStorage.getItem(scrollPositionId(element) + "::y"))
|
||||
}
|
||||
|
||||
function persistScrollPosition(element) {
|
||||
recallScrollPosition(element)
|
||||
$(element).scroll(function() { storeScrollPosition(element) })
|
||||
}
|
||||
|
||||
function sidebarContentWidth(element) {
|
||||
var widths = $(element).find('.inner').map(function() { return $(this).innerWidth() })
|
||||
return Math.max.apply(Math, widths)
|
||||
}
|
||||
|
||||
function calculateSize(width, snap, margin, minimum) {
|
||||
if (width == 0) {
|
||||
return 0
|
||||
}
|
||||
else {
|
||||
return Math.max(minimum, (Math.ceil(width / snap) * snap) + (margin * 2))
|
||||
}
|
||||
}
|
||||
|
||||
function resizeSidebars() {
|
||||
var primaryWidth = sidebarContentWidth('.primary')
|
||||
var secondaryWidth = 0
|
||||
|
||||
if ($('.secondary').length != 0) {
|
||||
secondaryWidth = sidebarContentWidth('.secondary')
|
||||
}
|
||||
|
||||
// snap to grid
|
||||
primaryWidth = calculateSize(primaryWidth, 32, 13, 160)
|
||||
secondaryWidth = calculateSize(secondaryWidth, 32, 13, 160)
|
||||
|
||||
$('.primary').css('width', primaryWidth)
|
||||
$('.secondary').css('width', secondaryWidth).css('left', primaryWidth + 1)
|
||||
|
||||
if (secondaryWidth > 0) {
|
||||
$('#content').css('left', primaryWidth + secondaryWidth + 2)
|
||||
}
|
||||
else {
|
||||
$('#content').css('left', primaryWidth + 1)
|
||||
}
|
||||
}
|
||||
|
||||
$(window).ready(resizeSidebars)
|
||||
$(window).ready(setCurrentVarLink)
|
||||
$(window).ready(function() { persistScrollPosition('.primary')})
|
||||
$(window).ready(function() {
|
||||
$('#content').scroll(setCurrentVarLink)
|
||||
$(window).resize(setCurrentVarLink)
|
||||
})
|
4
docs/codox/sparse-array.core.html
Normal file
4
docs/codox/sparse-array.core.html
Normal file
File diff suppressed because one or more lines are too long
3
docs/codox/sparse-array.extract.html
Normal file
3
docs/codox/sparse-array.extract.html
Normal file
|
@ -0,0 +1,3 @@
|
|||
<!DOCTYPE html PUBLIC ""
|
||||
"">
|
||||
<html><head><meta charset="UTF-8" /><title>sparse-array.extract documentation</title><link rel="stylesheet" type="text/css" href="css/default.css" /><link rel="stylesheet" type="text/css" href="css/highlight.css" /><script type="text/javascript" src="js/highlight.min.js"></script><script type="text/javascript" src="js/jquery.min.js"></script><script type="text/javascript" src="js/page_effects.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body><div id="header"><h2>Generated by <a href="https://github.com/weavejester/codox">Codox</a></h2><h1><a href="index.html"><span class="project-title"><span class="project-name">Sparse-array</span> <span class="project-version">0.3.0</span></span></a></h1></div><div class="sidebar primary"><h3 class="no-link"><span class="inner">Project</span></h3><ul class="index-link"><li class="depth-1 "><a href="index.html"><div class="inner">Index</div></a></li></ul><h3 class="no-link"><span class="inner">Topics</span></h3><ul><li class="depth-1 "><a href="intro.html"><div class="inner"><span>Introduction to Sparse-array</span></div></a></li></ul><h3 class="no-link"><span class="inner">Namespaces</span></h3><ul><li class="depth-1"><div class="no-link"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>sparse-array</span></div></div></li><li class="depth-2 branch"><a href="sparse-array.core.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>core</span></div></a></li><li class="depth-2 current"><a href="sparse-array.extract.html"><div class="inner"><span class="tree"><span class="top"></span><span class="bottom"></span></span><span>extract</span></div></a></li></ul></div><div class="sidebar secondary"><h3><a href="#top"><span class="inner">Public Vars</span></a></h3><ul><li class="depth-1"><a href="sparse-array.extract.html#var-extract"><div class="inner"><span>extract</span></div></a></li><li class="depth-1"><a href="sparse-array.extract.html#var-extract-from-dense"><div class="inner"><span>extract-from-dense</span></div></a></li></ul></div><div class="namespace-docs" id="content"><h1 class="anchor" id="top">sparse-array.extract</h1><div class="doc"><div class="markdown"><p>Extracting interesting data from sparse arrays.</p></div></div><div class="public anchor" id="var-extract"><h3>extract</h3><div class="usage"><code>(extract array function)</code></div><div class="doc"><div class="markdown"><p>Return a sparse subset of this <code>array</code> - which may be either sparse or dense - comprising all those cells for which this <code>function</code> returns a ‘truthy’ value.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/sparse-array/blob/master/src/sparse_array/extract.clj#L56">view source</a></div></div><div class="public anchor" id="var-extract-from-dense"><h3>extract-from-dense</h3><div class="usage"><code>(extract-from-dense array function)</code><code>(extract-from-dense array function axes)</code></div><div class="doc"><div class="markdown"><p>Return a subset of this dense <code>array</code> comprising all those cells for which this <code>function</code> returns a ‘truthy’ value. Use these <code>axes</code> if provided.</p></div></div><div class="src-link"><a href="https://github.com/simon-brooke/sparse-array/blob/master/src/sparse_array/extract.clj#L34">view source</a></div></div></div></body></html>
|
14
docs/index.html
Normal file
14
docs/index.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>Sparse Array: Documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="codox/css/default.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Sparse Array: Documentation</h1>
|
||||
<ul>
|
||||
<li><a href="codox/index.html">Primary documentaion</a></li>
|
||||
<li><a href="cloverage/index.html">Test coverage</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
22
project.clj
22
project.clj
|
@ -1,11 +1,18 @@
|
|||
(defproject sparse-array "0.1.0"
|
||||
(defproject sparse-array "0.3.0"
|
||||
:aot :all
|
||||
:cloverage {:output "docs/cloverage"}
|
||||
:codox {:metadata {:doc "**TODO**: write docs"
|
||||
:doc/format :markdown}
|
||||
:output-path "docs/codox"
|
||||
:source-uri "https://github.com/simon-brooke/sparse-array/blob/master/{filepath}#L{line}"}
|
||||
|
||||
:dependencies [[org.clojure/clojure "1.11.1"]]
|
||||
|
||||
:description "A Clojure library designed to manipulate sparse *arrays* - multi-dimensional spaces accessed by indices, but containing arbitrary values rather than just numbers. For sparse spaces which contain numbers only, you're better to use a *sparse matrix* library, for example [clojure.core.matrix](https://mikera.github.io/core.matrix/)."
|
||||
:url "http://example.com/FIXME"
|
||||
:license {:name "Eclipse Public License"
|
||||
:url "http://www.eclipse.org/legal/epl-v10.html"}
|
||||
:dependencies [[org.clojure/clojure "1.8.0"]]
|
||||
|
||||
:plugins [[lein-codox "0.10.4"]
|
||||
:plugins [[lein-cloverage "1.2.2"]
|
||||
[lein-codox "0.10.7"]
|
||||
[lein-release "1.0.5"]]
|
||||
|
||||
|
||||
|
@ -21,7 +28,8 @@
|
|||
;; ["vcs" "tag"] -- not working, problems with secret key
|
||||
["uberjar"]
|
||||
["install"]
|
||||
["deploy" "clojars"]
|
||||
;; ["deploy" "clojars"] -- also not working now. Security tightened at Clojars?
|
||||
["change" "version" "leiningen.release/bump-version"]
|
||||
["vcs" "commit"]])
|
||||
["vcs" "commit"]]
|
||||
:url "https://simon-brooke.github.io/sparse-array/docs/")
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
(ns sparse-array.core)
|
||||
(ns sparse-array.core
|
||||
"Operations on sparse arrays.")
|
||||
|
||||
(declare put get)
|
||||
|
||||
|
@ -17,7 +18,7 @@
|
|||
"Make a sparse array with these `dimensions`. Every member of `dimensions`
|
||||
must be a keyword; otherwise, `nil` will be returned."
|
||||
[& dimensions]
|
||||
(if
|
||||
(when
|
||||
(and (pos? (count dimensions))
|
||||
(every? keyword? dimensions))
|
||||
{:dimensions (count dimensions)
|
||||
|
@ -42,6 +43,10 @@
|
|||
(defn sparse-array?
|
||||
"`true` if `x` is a sparse array conforming to the conventions established
|
||||
by this library, else `false`."
|
||||
;; TODO: sparse-array? should not throw exceptions even when
|
||||
;; *safe-sparse-operations* is true, since we may use to test
|
||||
;; whether an object is a sparse array. The place to throw the exceptions
|
||||
;; (if required) is after it has failed.
|
||||
([x]
|
||||
(apply
|
||||
sparse-array?
|
||||
|
@ -49,7 +54,7 @@
|
|||
x
|
||||
(cons
|
||||
(:coord x)
|
||||
(if
|
||||
(when
|
||||
(coll? (:content x))
|
||||
(:content x))))))
|
||||
([x & axes]
|
||||
|
@ -129,9 +134,7 @@
|
|||
:coordinates coordinates
|
||||
:invalid (remove #(and (pos? %) (integer? %)) coordinates)}))
|
||||
:else
|
||||
(unsafe-put array value coordinates)
|
||||
value
|
||||
*safe-sparse-operations*))
|
||||
(unsafe-put array value coordinates)))
|
||||
|
||||
(defn- unsafe-get
|
||||
;; TODO: I am CERTAIN there is a more elegant solution to this.
|
||||
|
@ -171,6 +174,30 @@
|
|||
:else
|
||||
(unsafe-get array coordinates)))
|
||||
|
||||
(defn dense-dimensions
|
||||
"How many usable dimensions (represented as vectors) does the dense array
|
||||
`x` have?"
|
||||
[x]
|
||||
(if
|
||||
(vector? x)
|
||||
(if
|
||||
(every? vector? x)
|
||||
(inc (apply min (map dense-dimensions x)))
|
||||
;; `min` is right here, not `max`, because otherwise
|
||||
;; we will get malformed arrays. Be liberal with what you
|
||||
;; consume, conservative with what you return!
|
||||
1)
|
||||
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 merge-sparse-arrays
|
||||
"Return a sparse array taking values from sparse arrays `a1` and `a2`,
|
||||
but preferring values from `a2` where there is a conflict. `a1` and `a2`
|
||||
|
@ -198,40 +225,75 @@
|
|||
(keys a1)
|
||||
(keys a2))))))))
|
||||
|
||||
(defn dense-dimensions
|
||||
"How many usable dimensions (represented as vectors) does the dense array
|
||||
`x` have?"
|
||||
[x]
|
||||
(if
|
||||
(vector? x)
|
||||
(if
|
||||
(every? vector? x)
|
||||
(inc (apply min (map dense-dimensions x)))
|
||||
;; `min` is right here, not `max`, because otherwise
|
||||
;; we will get malformed arrays. Be liberal with what you
|
||||
;; consume, conservative with what you return!
|
||||
1)
|
||||
0))
|
||||
(defn merge-dense-with-sparse
|
||||
"Merge this dense array `d` with this sparse array `s`, returning a new
|
||||
dense array with the same arity as `d`, preferring values from `s` where
|
||||
there is conflict"
|
||||
[d s]
|
||||
(apply
|
||||
vector
|
||||
(map
|
||||
#(cond
|
||||
(= :data (:content s))
|
||||
(or (s %2) %1)
|
||||
(nil? (s %2))
|
||||
%1
|
||||
:else
|
||||
(merge-dense-with-sparse %1 (s %2)))
|
||||
d
|
||||
(range))))
|
||||
|
||||
(defn merge-arrays
|
||||
"Merge two arrays `a1`, `a2`, which may be either dense or sparse but which
|
||||
should have the same number of axes and compatible dimensions, and return a
|
||||
new dense array preferring values from `a2`."
|
||||
[a1 a2]
|
||||
(cond
|
||||
(dense-array? a2)
|
||||
a2 ;; if a2 is dense, no values from a1 will be returned
|
||||
(sparse-array? a1)
|
||||
(cond
|
||||
(sparse-array? a2)
|
||||
(merge-sparse-arrays a1 a2)
|
||||
*safe-sparse-operations*
|
||||
(throw
|
||||
(ex-info
|
||||
"Object passed as array is neither dense not sparse"
|
||||
{:array a2})))
|
||||
(dense-array? a1)
|
||||
(cond
|
||||
(sparse-array? a2)
|
||||
(merge-dense-with-sparse a1 a2)
|
||||
*safe-sparse-operations*
|
||||
(throw
|
||||
(ex-info
|
||||
"Object passed as array is neither dense not sparse"
|
||||
{:array a2})))
|
||||
*safe-sparse-operations*
|
||||
(throw
|
||||
(ex-info
|
||||
"Object passed as array is neither dense not sparse"
|
||||
{:array a1}))))
|
||||
|
||||
(defn dense-to-sparse
|
||||
"Return a sparse array representing the content of the dense array `x`,
|
||||
assuming these `coordinates` if specified. *NOTE THAT* if insufficient
|
||||
values of `coordinates` are specified, the resulting sparse array will
|
||||
assuming these `axes` if specified. *NOTE THAT* if insufficient
|
||||
values of `axes` are specified, the resulting sparse array will
|
||||
be malformed."
|
||||
([x]
|
||||
(dense-to-sparse x (map #(keyword (str "i" %)) (range))))
|
||||
([x coordinates]
|
||||
([x axes]
|
||||
(let
|
||||
[dimensions (dense-dimensions x)]
|
||||
(reduce
|
||||
merge
|
||||
(apply make-sparse-array (take dimensions coordinates))
|
||||
(apply make-sparse-array (take dimensions axes))
|
||||
(map
|
||||
(fn [i v] (if (nil? v) nil (hash-map i v)))
|
||||
(range)
|
||||
(if
|
||||
(> dimensions 1)
|
||||
(map #(dense-to-sparse % (rest coordinates)) x)
|
||||
(map #(dense-to-sparse % (rest axes)) x)
|
||||
x))))))
|
||||
|
||||
(defn arity
|
||||
|
|
71
src/sparse_array/extract.clj
Normal file
71
src/sparse_array/extract.clj
Normal file
|
@ -0,0 +1,71 @@
|
|||
(ns sparse-array.extract
|
||||
"Extracting interesting data from sparse arrays."
|
||||
(:require [sparse-array.core :refer [*safe-sparse-operations*
|
||||
dense-array? dense-dimensions
|
||||
make-sparse-array sparse-array?]]))
|
||||
|
||||
;;; 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)
|
||||
(when (coll? (:content array)) (:content array))))
|
||||
(map
|
||||
#(if
|
||||
(= :data (:content array))
|
||||
(when (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] (when (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}))))
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
(ns sparse-array.core-test
|
||||
(:require [clojure.test :refer :all]
|
||||
[sparse-array.core :refer :all]))
|
||||
(:require [clojure.test :refer [deftest is testing]]
|
||||
[sparse-array.core :refer [*safe-sparse-operations*
|
||||
dense-dimensions dense-to-sparse
|
||||
get make-sparse-array
|
||||
merge-arrays put
|
||||
sparse-array? sparse-to-dense]]))
|
||||
|
||||
(deftest creation-and-testing
|
||||
(testing "Creation and testing."
|
||||
|
@ -172,20 +176,30 @@
|
|||
(get (make-sparse-array :x :y :z) 3 4 5 6))))))
|
||||
|
||||
(deftest merge-test
|
||||
(testing "merge, one dimension"
|
||||
(testing "merge, sparse arrays, one dimension"
|
||||
(let
|
||||
[merged (merge-sparse-arrays
|
||||
[merged (merge-arrays
|
||||
(put (make-sparse-array :x) "hello" 3)
|
||||
(put (make-sparse-array :x) "goodbye" 4))]
|
||||
(is (= "hello" (get merged 3)))
|
||||
(is (= "goodbye" (get merged 4)))))
|
||||
(testing "merge, two dimensions"
|
||||
(testing "merge, sparse arrays, two dimensions"
|
||||
(let
|
||||
[merged (merge-sparse-arrays
|
||||
[merged (merge-arrays
|
||||
(put (make-sparse-array :x :y) "hello" 3 4)
|
||||
(put (make-sparse-array :x :y) "goodbye" 4 3))]
|
||||
(is (= "hello" (get merged 3 4)))
|
||||
(is (= "goodbye" (get merged 4 3))))))
|
||||
(is (= "goodbye" (get merged 4 3)))))
|
||||
(testing "merge, dense with sparse, two dimensions")
|
||||
(let [dense [[[nil nil nil][nil nil nil][nil nil nil]]
|
||||
[[nil nil nil][nil nil nil][nil nil nil]]
|
||||
[[nil nil nil][nil nil nil][nil nil nil]]]
|
||||
sparse (put (put (make-sparse-array :x :y :z) "hello" 0 0 0) "goodbye" 2 2 2)
|
||||
expected [[["hello" nil nil] [nil nil nil] [nil nil nil]]
|
||||
[[nil nil nil] [nil nil nil] [nil nil nil]]
|
||||
[[nil nil nil] [nil nil nil] [nil nil "goodbye"]]]
|
||||
actual (merge-arrays dense sparse)]
|
||||
(is (= actual expected))))
|
||||
|
||||
(deftest dense-to-sparse-tests
|
||||
(testing "dense-to-sparse, one dimension"
|
||||
|
|
113
test/sparse_array/extract_test.clj
Normal file
113
test/sparse_array/extract_test.clj
Normal file
|
@ -0,0 +1,113 @@
|
|||
(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 3
|
||||
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 keywords 0 1 2)]
|
||||
(is (= actual expected)))
|
||||
(let [expected nil
|
||||
actual (get strings 0 0 2)]
|
||||
(is (= actual expected)))
|
||||
(let [expected 3
|
||||
actual (get threes 0 0 2)]
|
||||
(is (= actual expected)))
|
||||
(let [expected :three
|
||||
actual (get threes 0 1 2)]
|
||||
(is (= actual expected)))
|
||||
(let [expected "three"
|
||||
actual (get threes 0 2 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 3
|
||||
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 keywords 0 1 2)]
|
||||
(is (= actual expected)))
|
||||
(let [expected nil
|
||||
actual (get strings 0 0 2)]
|
||||
(is (= actual expected)))
|
||||
(let [expected 3
|
||||
actual (get threes 0 0 2)]
|
||||
(is (= actual expected)))
|
||||
(let [expected :three
|
||||
actual (get threes 0 1 2)]
|
||||
(is (= actual expected)))
|
||||
(let [expected "three"
|
||||
actual (get threes 0 2 2)]
|
||||
(is (= actual expected))))))
|
Loading…
Reference in a new issue