File: srfi-25.html

package info (click to toggle)
drscheme 1%3A352-6
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 71,608 kB
  • ctags: 55,284
  • sloc: ansic: 278,966; cpp: 63,318; sh: 32,265; lisp: 14,530; asm: 7,327; makefile: 4,846; pascal: 4,363; perl: 2,920; java: 1,632; yacc: 755; lex: 258; sed: 93; xml: 12
file content (531 lines) | stat: -rw-r--r-- 17,855 bytes parent folder | download | duplicates (11)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
  <head>
    <title>SRFI 25: Multi-dimensional Array Primitives</title>
  </head>

  <body>

<H1>Title</H1>

SRFI 25: Multi-dimensional Array Primitives

<H1>Author</H1>

Jussi Piitulainen

<H1>Status</H1>

This SRFI is currently in ``final'' status. To see an explanation of
each status that a SRFI can hold, see <a
href="http://srfi.schemers.org/srfi-process.html">here</a>.  You can access
the discussion via
<a href="http://srfi.schemers.org/srfi-25/mail-archive/maillist.html">
the archive of the mailing list</a>.
<P>
<UL>
<LI>Draft: 2001/11/12-2002/01/11 </LI>
<LI>Revised: 2002/02/03</LI>
<LI>Final: 2002/05/21</LI>
</UL>
</P>

<H1>Abstract</H1>

<p>
A core set of procedures for creating and manipulating heterogeneous
multidimensional arrays is proposed. The design is consistent with the
rest of Scheme and independent of other container data types. It
provides easy sharing of parts of an array as other arrays without
copying, encouraging a declarative style of programming.
</p>

<p>
The specification is based on an original contribution by Alan Bawden
in 1993.
</p>

<H1>Rationale</H1>

<p>
The proposed arrays encourage a natural declarative programming
style. They allow sharing of most any rectangular part of an array
through an affine index mapping, without copying. But imperative style
is equally natural.
</p>

<p>
The design is consistent with the two indexed data structures of
Scheme: vectors and strings. The design makes arrays a self-contained
type. These statements are illustrated in the following paragraphs.
</p>

<p>
First, in the one-dimensional case, the arguments of the following
relevant calls match exactly.
</p>

<pre>
    (vector-set! v k o)
    (string-set! s k c)
    (array-set! a k o)
</pre>

<p>
Likewise, <code>make-array</code> matches <code>make-vector</code> and
<code>make-string</code>. An analogue to <code>vector</code>,
<code>string</code> and <code>list</code> is provided, alleviating the
lack of an external representation. Index bounds are specified as for
<code>substring</code>, lower bound included and upper bound excluded.
</p>

<p>
Array shapes are specified as arrays. These can be made with a special
procedure <code>shape</code> that does not have a shape argument. An
array does not retain a dependence to the shape array. For example,
mutation of a shape array is allowed.
</p>

<p>
Index mappings return multiple values as multiple values.
</p>

<p>
Array dimensions can begin at any index. In particular, the choice
between <code>0</code> and <code>1</code> is left to the user.
(Shapes and index objects are zero based, though.)
</p>

<p>
The ability to pack an index sequence in a vector is useful for
implementing higher level operations. (The ability to pack it in a
one-dimensional array lets one use, say, a row of a matrix as an
index.)
</p>

<p>
It is not required that vectors not be arrays. It is not required that
they be, either.
</p>

<H1>Specification</H1>

<p>
Arrays are heterogeneous data structures whose elements are indexed by
integer sequences of fixed length.  The length of a valid index
sequence is the <dfn>rank</dfn> or the number of <dfn>dimensions</dfn>
of an array. The <dfn>shape</dfn> of an array consists of bounds for
each index.
</p>

<p>
The lower bound <var>b</var> and the upper bound <var>e</var> of a
dimension are exact integers with
<code>(&lt;=&nbsp;<var>b</var>&nbsp;<var>e</var>)</code>. A valid
index along the dimension is an exact integer <var>k</var> that
satisfies both
<code>(&lt;=&nbsp;<var>b</var>&nbsp;<var>k</var>)</code> and
<code>(&lt;&nbsp;<var>k</var>&nbsp;<var>e</var>)</code>. The length of
the array along the dimension is the difference
<code>(-&nbsp;<var>e</var>&nbsp;<var>b</var>)</code>. The
<dfn>size</dfn> of an array is the product of the lengths of its
dimensions.
</p>

<p>
A shape is specified as an even number of exact integers. These are
alternately the lower and upper bounds for the dimensions of an array.
</p>

<p>
The following ten procedures should be implemented.
</p>

<p><a name="array-p"></a>
<code>(array? <var>obj</var>)</code><br> 

Returns <samp>#t</samp> if <var>obj</var> is an array, otherwise
returns <samp>#f</samp>.
</p>

<p>
Note: there is no reasonable way to implement this procedure
accurately in R5RS; <a href="http://srfi.schemers.org/srfi-9/">SRFI
9</a> (Defining Record Types) specifies a way, and many Scheme
implementations provide something similar.
</p>

<p><a name="make-array"></a>
<code>(make-array <var>shape</var>)</code><br>
<code>(make-array <var>shape</var> <var>obj</var>)</code><br>

Returns a newly allocated array whose shape is given by
<var>shape</var>.  If <var>obj</var> is provided, then each element is
initialized to it. Otherwise the initial contents of each element is
unspecified. The array does not retain a dependence to
<var>shape</var>.
</p>

<p><a name="shape"></a>
<code>(shape <var>bound ...</var>)</code><br> 

Returns a shape. The sequence <var>bound ...</var> must consist of an
even number of exact integers that are pairwise not decreasing. Each
pair gives the lower and upper bound of a dimension. If the shape is
used to specify the dimensions of an array and <var>bound ...</var> is
the sequence <var>b0 e0 ... bk ek ...</var> of <var>n</var> pairs of
bounds, then a valid index to the array is any sequence <var>j0 ... jk
...</var> of <var>n</var> exact integers where each <var>jk</var>
satisfies <code>(&lt;=&nbsp;<var>bk</var>&nbsp;<var>jk</var>)</code>
and <code>(&lt;&nbsp;<var>jk</var>&nbsp;<var>ek</var>)</code>.
</p>

<p>
The shape of a <var>d</var>-dimensional array is a
<var>d</var>&nbsp;&times;&nbsp;<var>2</var> array where the element at
<var>k 0</var> contains the lower bound for an index along dimension
<var>k</var> and the element at <var>k 1</var> contains the
corresponding upper bound, where <var>k</var> satisfies
<code>(&lt;=&nbsp;0&nbsp;<var>k</var>)</code> and
<code>(&lt;&nbsp;<var>k</var>&nbsp;<var>d</var>)</code>.
</p>

<p><a name="array"></a>
<code>(array <var>shape</var> <var>obj ...</var>)</code><br>

Returns a new array whose shape is given by <var>shape</var> and the
initial contents of the elements are <var>obj ...</var> in row major
order. The array does not retain a dependence to <var>shape</var>.
</p>

<p><a name="array-rank"></a>
<code>(array-rank <var>array</var>)</code><br>

Returns the number of dimensions of <var>array</var>.
<pre>
    (array-rank
       (make-array (shape 1 2 3 4)))
</pre>

<p>
Returns <samp>2</samp>.
</p>

<p><a name="array-start"></a>
<code>(array-start <var>array</var> <var>k</var>)</code><br>

Returns the lower bound for the index along dimension <var>k</var>.
</p>

<p><a name="array-end"></a>
<code>(array-end <var>array</var> <var>k</var>)</code><br>

Returns the upper bound for the index along dimension <var>k</var>.
</p>

<!--
<p>
<code>(array-shape <var>array</var>)</code><br>

Returns a newly allocated shape of <var>array</var>.
</p>

<pre>
    (= (array-rank a)
       (array-ref (array-shape (array-shape a)) 0 1))
</pre>

<p>
Returns <samp>#t</samp>.
</p>

<p>
Implementation note: <code>array-shape</code> has <code>(shape 0 2 0
2)</code> as a fixed point which is reached in two or three iterations
from any array.
</p>
-->

<p><a name="array-ref"></a>
<code>(array-ref <var>array</var> <var>k ...</var>)</code><br>
<code>(array-ref <var>array</var> <var>index</var>)</code><br>

Returns the contents of the element of <var>array</var> at index
<var>k ...</var>. The sequence <var>k ...</var> must be a valid index
to <var>array</var>. In the second form, <var>index</var> must be
either a vector or a 0-based 1-dimensional array containing <var>k
...</var>.
</p>

<pre>
    (array-ref (array (shape 0 2 0 3)
                  'uno 'dos 'tres
                  'cuatro 'cinco 'seis)
       1 0)
</pre>

<p>
Returns <samp>cuatro</samp>.
</p>

<pre>
    (let ((a (array (shape 4 7 1 2) 3 1 4)))
       (list (array-ref a 4 1)
             (array-ref a (vector 5 1))
             (array-ref a (array (shape 0 2)
                             6 1))))
</pre>

<p>
Returns <samp>(3 1 4)</samp>.
</p>

<p><a name="array-set!"></a>
<code>(array-set! <var>array</var> <var>k ...</var> <var>obj</var>)</code><br>
<code>(array-set! <var>array</var> <var>index</var> <var>obj</var>)</code><br>

Stores <var>obj</var> in the element of <var>array</var> at index
<var>k ...</var>. Returns an unspecified value. The sequence <var>k
...</var> must be a valid index to <var>array</var>. In the second
form, <var>index</var> must be either a vector or a 0-based
1-dimensional array containing <var>k ...</var>.

<pre>
    (let ((a (make-array
                (shape 4 5 4 5 4 5))))
       (array-set! a 4 4 4 'huuhkaja)
       (array-ref a 4 4 4))
</pre>

<p>
Returns <samp>huuhkaja</samp>.
</p>

<p><a name="share-array"></a>
<code>(share-array <var>array</var> <var>shape</var> <var>proc</var>)</code>
<br> 

Returns a new array of shape <var>shape</var> that shares elements of
<var>array</var> through <var>proc</var>. The procedure
<var>proc</var> must implement an affine function that returns indices
of <var>array</var> when given indices of the array returned by
<code>share-array</code>. The array does not retain a dependence to
<var>shape</var>.
</p>

<pre>
    (define i_4
       (let* ((i (make-array
                    (shape 0 4 0 4)
                    0))
              (d (share-array i
                    (shape 0 4)
                    (lambda (k)
                       (values k k)))))
          (do ((k 0 (+ k 1)))
              ((= k 4))
             (array-set! d k 1))
          i))
</pre>

<p>
Note: the affinity requirement for <var>proc</var> means that each
value must be a sum of multiples of the arguments passed to
<var>proc</var>, plus a constant.
</p>

<p>
Implementation note: arrays have to maintain an internal index mapping
from indices <var>k1 ... kd</var> to a single index into a backing
vector; the composition of this mapping and <var>proc</var> can be
recognised as <code>(+ n0 (* n1 <var>k1</var>) ... (* nd
<var>kd</var>))</code> by setting each index in turn to <code>1</code>
and others to <code>0</code>, and all to <code>0</code> for the
constant term; the composition can then be compiled away, together
with any complexity that the user introduced in their procedure.
</p>

<p>
This document does not specify any external representation for arrays.
This document does not specify when arrays are <code>equal?</code>.
(Indeed, R5RS <code>equal?</code> will do the wrong thing.)
</p>

<h1>Examples</h1>

<p>
The reference implementation comes with a number of files that
illustrate some ways to use the proposed system (and are very useful
in <em>testing</em> an implementation; that is their origin).
</p>

<ol>

<li> A library <a href="http://srfi.schemers.org/srfi-25/arlib.scm">arlib.scm</a> that contains, among
     several other things, <code>tabulate-array</code> for a more
     useful initialization of a new array, an
     <code>array-equal?</code>, and a <code>transpose</code> that can
     permute the dimensions of an array any which way.

<li> A test suite <a href="http://srfi.schemers.org/srfi-25/test.scm">test.scm</a> for <em>array</em>,
     and another test suite <a href="http://srfi.schemers.org/srfi-25/list.scm">list.scm</a> for
     <em>arlib</em>.

<li> A rudimentary display procedure <code>(play array)</code> in <a
     href="http://srfi.schemers.org/srfi-25/play.scm">play.scm</a>, for playing around with the system.

</ol>

<H1>Implementation</H1>

<p>
A portable reference implementation is provided. It uses a minimal
error reporting mechanism that conforms to <a
href="http://srfi.schemers.org/srfi-23/">SRFI 23</a> (Error reporting
mechanism). Type disjointness requires support from the host
implementation, such as support for <a
href="http://srfi.schemers.org/srfi-9/">SRFI 9</a> (Defining Record
Types). All names not defined in this proposal are in the prefix
"<code>array:</code>", which serves as a module system.
</p>

<p>
You can get <a href="http://srfi.schemers.org/srfi-25/srfi-25-reference.scm">source for the reference
implementation</a> as a single file and stop reading. But there are
variations. This single file represents arrays as procedures (so the
type predicate is very approximate); it represents index mapping as
vectors of coefficients; map recognition is not optimised for any
number of dimensions as that would be redundant in this
representation.
</p>

<p>
The real source comes in too many files. A working installation
consists of the following parts, each in its own file.
</p>

<ol>

<li> a <dfn>record type definition</dfn>, either system specific for
     type disjointness, or portable as procedures, in a file
     <em>as-*.scm</em>, and

<li> <dfn>indexing operations</dfn> to match the type, in a file
     <em>ix-*.scm</em>, and

<li> an <dfn>affine recogniser</dfn> of one of three types, optimised
     up to some number of dimensions, in a file <em>op-*.scm</em>, and

<li> the main source file <a href="http://srfi.schemers.org/srfi-25/array.scm">array.scm</a>.

</ol>

<p>
Affine recognisers are made by a program <a href="http://srfi.schemers.org/srfi-25/opt.scm">opt.scm</a>
but one of each type is also available here, optimized for 0, 1, 2 and
3 dimensions. Choose one type: pick a recogniser with matching index
procedures; load <tt>as-</tt>, <tt>ix-</tt> and <tt>op-</tt> and
<tt>array</tt>.)
</p>

<ol>

<li> In the <a href="http://srfi.schemers.org/srfi-25/op-mbda.scm">mbda</a> type representation, index
     mappings are procedures that accept an optional argument.  The
     matching <a href="http://srfi.schemers.org/srfi-25/ix-mbda.scm">access procedures</a> apply the
     mapping to the arguments of <code>array-ref</code> and
     <code>array-set!</code>.

<li> In the <a href="http://srfi.schemers.org/srfi-25/op-tter.scm">tter</a> type representation, index
     mappings are pairs of procedures: one takes exactly the indices,
     the other takes indices and an object. The matching <a
     href="http://srfi.schemers.org/srfi-25/ix-tter.scm">access procedures</a> apply the first
     procedure to the argumets of <code>array-ref</code> and the
     second procedure to the arguments of <code>array-set!</code>.

<li> In <a href="http://srfi.schemers.org/srfi-25/op-ctor.scm">ctor</a> representation, index mappings
     are coefficient vectors. The <a href="http://srfi.schemers.org/srfi-25/ix-ctor.scm">access
     procedures</a> compute the sum of products of coefficients and
     indexes in a loop on the list.

</ol>

<p>
Record implementations are available <a href="http://srfi.schemers.org/srfi-25/as-procedure.scm">for
generic Scheme</a> (arrays are not disjoint from procedures), <a
href="http://srfi.schemers.org/srfi-25/as-srfi-9-record.scm">for SRFI 9</a> (Defining Record Types)
(<em>not tested</em>), and <a href="http://srfi.schemers.org/srfi-25/as-plt-struct.scm">for PLT
Scheme</a> (arrays belong to a struct type).
</p>

<p>
With the three files from above, the <a href="http://srfi.schemers.org/srfi-25/array.scm">main source
file</a> should work in any Scheme implementation without need of
modification.
</p>

<p>
Error checking in the implementation may be a tad expensive. The
places where it occurs are cleanly separated from the surrounding
code. (Sharing uses a check that is exponential in the number of
dimensions. It is disabled above a threshold rank.)
</p>

<h1>Acknowledgements</h1>

<p>
The original concept comes from a message to the Usenet newsgroup
<tt>comp.lang.scheme</tt> by Alan Bawden in 1993. A variant of that
implementation by Richard Kelsey in the Scheme 48 system was also an
influence. Apart from the origins, the main design goal has been
consistency with the core types of Scheme.
</p>

<p>
Alan Bawden and Mark K. Gardner gave useful comments at an earlier
attempt to make this specification public. (There was at least one
other. Notes have gone missing.) SRFI feedback led to improved
wording, hidden shapes, and two kinds of index objects.
</p>

<p>
The exact title of the proposal comes from a <a href="http://zurich.ai.mit.edu/pipermail/rrrs-authors/1998-May/002349.html">message titled "a process that might work"</a> by William D. Clinger to the <tt>rrrs-authors</tt>
mailing list in 1998. That appears to be a part of the past of the <a
href="http://srfi.schemers.org">SRFI process</a>.
</p>

<H1>Copyright</H1>
<p>Copyright (C) Jussi Piitulainen (2001). All Rights Reserved.</p>

<p>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
</p>
<p>
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
</p>
<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</p>

    <hr>
    <address>Editor: <a
    href="mailto:srfi-editors@srfi.schemers.org">Mike Sperber</a></address>
<!-- Created: Tue Sep 29 19:20:08 EDT 1998 -->
<!-- hhmts start -->
Last modified: Tue May 28 18:46:09 MST 2002
<!-- hhmts end -->
  </body>
</html>