sparse-array/docs/codox/intro.html

181 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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, youre 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
=&gt; {: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 ([&amp; 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)
=&gt; {: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 &amp; 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)
=&gt; {: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 &amp; 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)))
=&gt; {: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"])
=&gt; {: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))
=&gt; [[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")))
=&gt; {: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))
=&gt; {: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>