Rewrite scm_ramapc()
[bpt/guile.git] / libguile / array-map.c
1 /* Copyright (C) 1996, 1998, 2000, 2001, 2004, 2005, 2006, 2008, 2009,
2 * 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
18 */
19
20
21 \f
22
23
24 \f
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28
29 #include "libguile/_scm.h"
30 #include "libguile/strings.h"
31 #include "libguile/arrays.h"
32 #include "libguile/smob.h"
33 #include "libguile/chars.h"
34 #include "libguile/eq.h"
35 #include "libguile/eval.h"
36 #include "libguile/feature.h"
37 #include "libguile/root.h"
38 #include "libguile/vectors.h"
39 #include "libguile/bitvectors.h"
40 #include "libguile/srfi-4.h"
41 #include "libguile/generalized-arrays.h"
42
43 #include "libguile/validate.h"
44 #include "libguile/array-map.h"
45 \f
46
47 /* The WHAT argument for `scm_gc_malloc ()' et al. */
48 static const char vi_gc_hint[] = "array-indices";
49
50 static SCM
51 AREF (SCM v, size_t pos)
52 {
53 return scm_c_array_ref_1 (v, pos);
54 }
55
56 static void
57 ASET (SCM v, size_t pos, SCM val)
58 {
59 scm_c_array_set_1_x (v, val, pos);
60 }
61
62 /* Checker for scm_array mapping functions, returns:
63
64 5 --> empty axes;
65 4 --> shapes, increments, and bases are the same;
66 3 --> shapes and increments are the same;
67 2 --> shapes are the same;
68 1 --> ras are at least as big as ra0;
69 0 --> no match.
70 */
71
72 int
73 scm_ra_matchp (SCM ra0, SCM ras)
74 {
75 int i, exact = 4, empty = 0;
76 scm_t_array_handle h0;
77
78 scm_array_get_handle (ra0, &h0);
79 for (i = 0; i < h0.ndims; ++i)
80 {
81 empty = empty || (h0.dims[i].lbnd > h0.dims[i].ubnd);
82 }
83
84 while (scm_is_pair (ras))
85 {
86 scm_t_array_handle h1;
87
88 scm_array_get_handle (SCM_CAR (ras), &h1);
89
90 if (h0.ndims != h1.ndims)
91 {
92 scm_array_handle_release (&h0);
93 scm_array_handle_release (&h1);
94 return 0;
95 }
96 if (h0.base != h1.base)
97 exact = min(3, exact);
98
99 for (i = 0; i < h0.ndims; ++i)
100 {
101 empty = empty || (h1.dims[i].lbnd > h1.dims[i].ubnd);
102 switch (exact)
103 {
104 case 4:
105 case 3:
106 if (h0.dims[i].inc != h1.dims[i].inc)
107 exact = 2;
108 case 2:
109 if (h0.dims[i].lbnd == h1.dims[i].lbnd && h0.dims[i].ubnd == h1.dims[i].ubnd)
110 break;
111 exact = 1;
112 default:
113 if (h0.dims[i].lbnd < h1.dims[i].lbnd || h0.dims[i].ubnd > h1.dims[i].ubnd)
114 {
115 scm_array_handle_release (&h0);
116 scm_array_handle_release (&h1);
117 return 0;
118 }
119 }
120 }
121 scm_array_handle_release (&h1);
122 ras = SCM_CDR (ras);
123 }
124 scm_array_handle_release (&h0);
125 return empty ? 5 : exact;
126 }
127
128 static SCM
129 make1array (SCM v, ssize_t inc)
130 {
131 SCM a = scm_i_make_array (1);
132 SCM_I_ARRAY_BASE (a) = 0;
133 SCM_I_ARRAY_DIMS (a)->lbnd = 0;
134 SCM_I_ARRAY_DIMS (a)->ubnd = scm_c_array_length (v) - 1;
135 SCM_I_ARRAY_DIMS (a)->inc = inc;
136 SCM_I_ARRAY_V (a) = v;
137 return a;
138 }
139
140 /* Find down to which rank the array is unrollable. 0 means fully
141 unrollable, which all rank-0 and rank-1 arrays are. */
142 static int
143 find_unrollk (SCM ra, int k)
144 {
145 if (k <= 0)
146 return 0;
147 else
148 {
149 ssize_t inc;
150 inc = SCM_I_ARRAY_DIMS (ra)[k].inc;
151 do {
152 size_t lenk = (SCM_I_ARRAY_DIMS (ra)[k].ubnd
153 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
154 inc *= lenk;
155 --k;
156 } while (k >= 0 && inc == SCM_I_ARRAY_DIMS (ra)[k].inc);
157 return k+1;
158 }
159 }
160
161 /* Length of the unrolled index set. */
162 static size_t
163 klen (SCM ra, int kbegin, int kend)
164 {
165 size_t len = 1;
166 int k;
167 for (k = kbegin; k < kend; ++k)
168 len *= (SCM_I_ARRAY_DIMS (ra)[k].ubnd
169 - SCM_I_ARRAY_DIMS (ra)[k].lbnd + 1);
170 return len;
171 }
172
173 /* Linear index of the NOT unrolled index set. */
174 static size_t
175 cindk (SCM ra, ssize_t *ve, int kend)
176 {
177 if (!SCM_I_ARRAYP (ra))
178 return 0; /* this is BASE */
179 else
180 {
181 int k;
182 size_t i = SCM_I_ARRAY_BASE (ra);
183 for (k = 0; k < kend; ++k)
184 i += (ve[k] - SCM_I_ARRAY_DIMS (ra)[k].lbnd) * SCM_I_ARRAY_DIMS (ra)[k].inc;
185 return i;
186 }
187 }
188
189 /* array mapper: apply cproc to each dimension of the given arrays?.
190 int (*cproc) (); procedure to call on unrolled arrays?
191 cproc (dest, source list) or
192 cproc (dest, data, source list).
193 SCM data; data to give to cproc or unbound.
194 SCM ra0; destination array.
195 SCM lra; list of source arrays.
196 const char *what; caller, for error reporting. */
197 int
198 scm_ramapc (void *cproc_ptr, SCM data, SCM ra0, SCM lra, const char *what)
199 {
200 SCM z;
201 SCM vra0;
202 SCM lvra, *plvra;
203 ssize_t *vi;
204 int k, kmax, unrollk;
205 int (*cproc) () = cproc_ptr;
206 size_t unrolled_len;
207
208 switch (scm_ra_matchp (ra0, lra))
209 {
210 default:
211 case 0:
212 scm_misc_error (what, "array shape mismatch: ~S", scm_list_1 (ra0));
213 case 1:
214 case 2:
215 case 3:
216 case 4:
217
218 /* Prepare reference argument */
219 if (SCM_I_ARRAYP (ra0))
220 {
221 kmax = SCM_I_ARRAY_NDIM (ra0)-1;
222 vra0 = make1array (SCM_I_ARRAY_V (ra0), SCM_I_ARRAY_DIMS (ra0)[kmax].inc);
223 }
224 else
225 {
226 kmax = 0;
227 vra0 = ra0 = make1array(ra0, 1);
228 }
229
230 /* Linear addressing for rest arguments */
231 lvra = SCM_EOL;
232 plvra = &lvra;
233 for (z = lra; !scm_is_null (z); z = SCM_CDR (z))
234 {
235 SCM ra1 = SCM_CAR (z);
236 SCM vra1;
237 if (SCM_I_ARRAYP (ra1))
238 vra1 = make1array (SCM_I_ARRAY_V (ra1), SCM_I_ARRAY_DIMS (ra1)[kmax].inc);
239 else
240 vra1 = make1array (ra1, 1);
241 *plvra = scm_cons (vra1, SCM_EOL);
242 plvra = SCM_CDRLOC (*plvra);
243 }
244
245 /* Find common unroll depth */
246 unrollk = find_unrollk (ra0, kmax);
247 for (z = lra; !scm_is_null (z); z = SCM_CDR (z))
248 {
249 SCM ra1 = SCM_CAR (z);
250 unrollk = max(unrollk, find_unrollk (ra1, kmax));
251 }
252 unrolled_len = klen (ra0, unrollk, kmax+1);
253
254 /* Set inner loop size */
255 SCM_I_ARRAY_DIMS (vra0)->lbnd = 0;
256 SCM_I_ARRAY_DIMS (vra0)->ubnd = unrolled_len - 1;
257 for (z = lvra; !scm_is_null (z); z = SCM_CDR (z))
258 {
259 SCM_I_ARRAY_DIMS (SCM_CAR (z))->lbnd = 0;
260 SCM_I_ARRAY_DIMS (SCM_CAR (z))->ubnd = unrolled_len - 1;
261 }
262
263 /* Set starting indices and go */
264 vi = scm_gc_malloc_pointerless (sizeof(ssize_t) * unrollk, vi_gc_hint);
265 for (k = 0; k < unrollk; ++k)
266 vi[k] = SCM_I_ARRAY_DIMS (ra0)[k].lbnd;
267 do
268 {
269 if (k == unrollk)
270 {
271 SCM y = lra;
272 SCM_I_ARRAY_BASE (vra0) = cindk (ra0, vi, unrollk);
273 for (z = lvra; !scm_is_null (z); z = SCM_CDR (z), y = SCM_CDR (y))
274 SCM_I_ARRAY_BASE (SCM_CAR (z)) = cindk (SCM_CAR (y), vi, unrollk);
275 if (SCM_UNBNDP (data))
276 cproc (vra0, lvra);
277 else
278 cproc (vra0, data, lvra);
279 k--;
280 }
281 else if (vi[k] < SCM_I_ARRAY_DIMS (ra0)[k].ubnd)
282 {
283 vi[k]++;
284 k++;
285 }
286 else
287 {
288 vi[k] = SCM_I_ARRAY_DIMS (ra0)[k].lbnd - 1;
289 k--;
290 }
291 }
292 while (k >= 0);
293
294 case 5:
295 return 1;
296 }
297 }
298
299 static int
300 rafill (SCM dst, SCM fill)
301 {
302 long n = (SCM_I_ARRAY_DIMS (dst)->ubnd - SCM_I_ARRAY_DIMS (dst)->lbnd + 1);
303 scm_t_array_handle h;
304 size_t i;
305 ssize_t inc;
306 scm_array_get_handle (SCM_I_ARRAY_V (dst), &h);
307 i = SCM_I_ARRAY_BASE (dst);
308 inc = SCM_I_ARRAY_DIMS (dst)->inc;
309
310 for (; n-- > 0; i += inc)
311 h.vset (h.vector, i, fill);
312
313 scm_array_handle_release (&h);
314 return 1;
315 }
316
317 SCM_DEFINE (scm_array_fill_x, "array-fill!", 2, 0, 0,
318 (SCM ra, SCM fill),
319 "Store @var{fill} in every element of array @var{ra}. The value\n"
320 "returned is unspecified.")
321 #define FUNC_NAME s_scm_array_fill_x
322 {
323 scm_ramapc (rafill, fill, ra, SCM_EOL, FUNC_NAME);
324 return SCM_UNSPECIFIED;
325 }
326 #undef FUNC_NAME
327
328
329 static int
330 racp (SCM src, SCM dst)
331 {
332 ssize_t n = (SCM_I_ARRAY_DIMS (src)->ubnd - SCM_I_ARRAY_DIMS (src)->lbnd + 1);
333 scm_t_array_handle h_s, h_d;
334 size_t i_s, i_d;
335 ssize_t inc_s, inc_d;
336
337 dst = SCM_CAR (dst);
338 i_s = SCM_I_ARRAY_BASE (src);
339 i_d = SCM_I_ARRAY_BASE (dst);
340 inc_s = SCM_I_ARRAY_DIMS (src)->inc;
341 inc_d = SCM_I_ARRAY_DIMS (dst)->inc;
342
343 scm_array_get_handle (SCM_I_ARRAY_V (src), &h_s);
344 scm_array_get_handle (SCM_I_ARRAY_V (dst), &h_d);
345
346 if (h_s.element_type == SCM_ARRAY_ELEMENT_TYPE_SCM
347 && h_d.element_type == SCM_ARRAY_ELEMENT_TYPE_SCM)
348 {
349 SCM const * el_s = h_s.elements;
350 SCM * el_d = h_d.writable_elements;
351 for (; n-- > 0; i_s += inc_s, i_d += inc_d)
352 el_d[i_d] = el_s[i_s];
353 }
354 else
355 for (; n-- > 0; i_s += inc_s, i_d += inc_d)
356 h_d.vset (h_d.vector, i_d, h_s.vref (h_s.vector, i_s));
357
358 scm_array_handle_release (&h_d);
359 scm_array_handle_release (&h_s);
360
361 return 1;
362 }
363
364 SCM_REGISTER_PROC(s_array_copy_in_order_x, "array-copy-in-order!", 2, 0, 0, scm_array_copy_x);
365
366
367 SCM_DEFINE (scm_array_copy_x, "array-copy!", 2, 0, 0,
368 (SCM src, SCM dst),
369 "@deffnx {Scheme Procedure} array-copy-in-order! src dst\n"
370 "Copy every element from vector or array @var{src} to the\n"
371 "corresponding element of @var{dst}. @var{dst} must have the\n"
372 "same rank as @var{src}, and be at least as large in each\n"
373 "dimension. The order is unspecified.")
374 #define FUNC_NAME s_scm_array_copy_x
375 {
376 scm_ramapc (racp, SCM_UNDEFINED, src, scm_cons (dst, SCM_EOL), FUNC_NAME);
377 return SCM_UNSPECIFIED;
378 }
379 #undef FUNC_NAME
380
381
382 #if SCM_ENABLE_DEPRECATED == 1
383
384 /* to be used as cproc in scm_ramapc to fill an array dimension with
385 "fill". */
386 int
387 scm_array_fill_int (SCM ra, SCM fill, SCM ignore SCM_UNUSED)
388 {
389 unsigned long i;
390 unsigned long n = SCM_I_ARRAY_DIMS (ra)->ubnd - SCM_I_ARRAY_DIMS (ra)->lbnd + 1;
391 long inc = SCM_I_ARRAY_DIMS (ra)->inc;
392 unsigned long base = SCM_I_ARRAY_BASE (ra);
393
394 ra = SCM_I_ARRAY_V (ra);
395
396 for (i = base; n--; i += inc)
397 ASET (ra, i, fill);
398
399 return 1;
400 }
401
402 /* Functions callable by ARRAY-MAP! */
403
404 int
405 scm_ra_eqp (SCM ra0, SCM ras)
406 {
407 SCM ra1 = SCM_CAR (ras), ra2 = SCM_CAR (SCM_CDR (ras));
408 scm_t_array_handle ra0_handle;
409 scm_t_array_dim *ra0_dims;
410 size_t n;
411 ssize_t inc0;
412 size_t i0 = 0;
413 unsigned long i1 = SCM_I_ARRAY_BASE (ra1), i2 = SCM_I_ARRAY_BASE (ra2);
414 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
415 long inc2 = SCM_I_ARRAY_DIMS (ra1)->inc;
416 ra1 = SCM_I_ARRAY_V (ra1);
417 ra2 = SCM_I_ARRAY_V (ra2);
418
419 scm_array_get_handle (ra0, &ra0_handle);
420 ra0_dims = scm_array_handle_dims (&ra0_handle);
421 n = ra0_dims[0].ubnd - ra0_dims[0].lbnd + 1;
422 inc0 = ra0_dims[0].inc;
423
424 {
425 for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2)
426 if (scm_is_true (scm_array_handle_ref (&ra0_handle, i0)))
427 if (!scm_is_eq (AREF (ra1, i1), AREF (ra2, i2)))
428 scm_array_handle_set (&ra0_handle, i0, SCM_BOOL_F);
429 }
430
431 scm_array_handle_release (&ra0_handle);
432 return 1;
433 }
434
435 /* opt 0 means <, nonzero means >= */
436
437 static int
438 ra_compare (SCM ra0, SCM ra1, SCM ra2, int opt)
439 {
440 scm_t_array_handle ra0_handle;
441 scm_t_array_dim *ra0_dims;
442 size_t n;
443 ssize_t inc0;
444 size_t i0 = 0;
445 unsigned long i1 = SCM_I_ARRAY_BASE (ra1), i2 = SCM_I_ARRAY_BASE (ra2);
446 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
447 long inc2 = SCM_I_ARRAY_DIMS (ra1)->inc;
448 ra1 = SCM_I_ARRAY_V (ra1);
449 ra2 = SCM_I_ARRAY_V (ra2);
450
451 scm_array_get_handle (ra0, &ra0_handle);
452 ra0_dims = scm_array_handle_dims (&ra0_handle);
453 n = ra0_dims[0].ubnd - ra0_dims[0].lbnd + 1;
454 inc0 = ra0_dims[0].inc;
455
456 {
457 for (; n-- > 0; i0 += inc0, i1 += inc1, i2 += inc2)
458 if (scm_is_true (scm_array_handle_ref (&ra0_handle, i0)))
459 if (opt ?
460 scm_is_true (scm_less_p (AREF (ra1, i1), AREF (ra2, i2))) :
461 scm_is_false (scm_less_p (AREF (ra1, i1), AREF (ra2, i2))))
462 scm_array_handle_set (&ra0_handle, i0, SCM_BOOL_F);
463 }
464
465 scm_array_handle_release (&ra0_handle);
466 return 1;
467 }
468
469
470
471 int
472 scm_ra_lessp (SCM ra0, SCM ras)
473 {
474 return ra_compare (ra0, SCM_CAR (ras), SCM_CAR (SCM_CDR (ras)), 0);
475 }
476
477
478 int
479 scm_ra_leqp (SCM ra0, SCM ras)
480 {
481 return ra_compare (ra0, SCM_CAR (SCM_CDR (ras)), SCM_CAR (ras), 1);
482 }
483
484
485 int
486 scm_ra_grp (SCM ra0, SCM ras)
487 {
488 return ra_compare (ra0, SCM_CAR (SCM_CDR (ras)), SCM_CAR (ras), 0);
489 }
490
491
492 int
493 scm_ra_greqp (SCM ra0, SCM ras)
494 {
495 return ra_compare (ra0, SCM_CAR (ras), SCM_CAR (SCM_CDR (ras)), 1);
496 }
497
498
499 int
500 scm_ra_sum (SCM ra0, SCM ras)
501 {
502 long n = SCM_I_ARRAY_DIMS (ra0)->ubnd - SCM_I_ARRAY_DIMS (ra0)->lbnd + 1;
503 unsigned long i0 = SCM_I_ARRAY_BASE (ra0);
504 long inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
505 ra0 = SCM_I_ARRAY_V (ra0);
506 if (!scm_is_null(ras))
507 {
508 SCM ra1 = SCM_CAR (ras);
509 unsigned long i1 = SCM_I_ARRAY_BASE (ra1);
510 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
511 ra1 = SCM_I_ARRAY_V (ra1);
512 switch (SCM_TYP7 (ra0) == SCM_TYP7 (ra1) ? SCM_TYP7 (ra0) : 0)
513 {
514 default:
515 {
516 for (; n-- > 0; i0 += inc0, i1 += inc1)
517 ASET (ra0, i0, scm_sum (AREF(ra0, i0), AREF(ra1, i1)));
518 break;
519 }
520 }
521 }
522 return 1;
523 }
524
525
526
527 int
528 scm_ra_difference (SCM ra0, SCM ras)
529 {
530 long n = SCM_I_ARRAY_DIMS (ra0)->ubnd - SCM_I_ARRAY_DIMS (ra0)->lbnd + 1;
531 unsigned long i0 = SCM_I_ARRAY_BASE (ra0);
532 long inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
533 ra0 = SCM_I_ARRAY_V (ra0);
534 if (scm_is_null (ras))
535 {
536 switch (SCM_TYP7 (ra0))
537 {
538 default:
539 {
540 for (; n-- > 0; i0 += inc0)
541 ASET (ra0, i0, scm_difference (AREF(ra0, i0), SCM_UNDEFINED));
542 break;
543 }
544 }
545 }
546 else
547 {
548 SCM ra1 = SCM_CAR (ras);
549 unsigned long i1 = SCM_I_ARRAY_BASE (ra1);
550 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
551 ra1 = SCM_I_ARRAY_V (ra1);
552 switch (SCM_TYP7 (ra0) == SCM_TYP7 (ra1) ? SCM_TYP7 (ra0) : 0)
553 {
554 default:
555 {
556 for (; n-- > 0; i0 += inc0, i1 += inc1)
557 ASET (ra0, i0, scm_difference (AREF (ra0, i0), AREF (ra1, i1)));
558 break;
559 }
560 }
561 }
562 return 1;
563 }
564
565
566
567 int
568 scm_ra_product (SCM ra0, SCM ras)
569 {
570 long n = SCM_I_ARRAY_DIMS (ra0)->ubnd - SCM_I_ARRAY_DIMS (ra0)->lbnd + 1;
571 unsigned long i0 = SCM_I_ARRAY_BASE (ra0);
572 long inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
573 ra0 = SCM_I_ARRAY_V (ra0);
574 if (!scm_is_null (ras))
575 {
576 SCM ra1 = SCM_CAR (ras);
577 unsigned long i1 = SCM_I_ARRAY_BASE (ra1);
578 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
579 ra1 = SCM_I_ARRAY_V (ra1);
580 switch (SCM_TYP7 (ra0) == SCM_TYP7 (ra1) ? SCM_TYP7 (ra0) : 0)
581 {
582 default:
583 {
584 for (; n-- > 0; i0 += inc0, i1 += inc1)
585 ASET (ra0, i0, scm_product (AREF (ra0, i0), AREF (ra1, i1)));
586 }
587 }
588 }
589 return 1;
590 }
591
592
593 int
594 scm_ra_divide (SCM ra0, SCM ras)
595 {
596 long n = SCM_I_ARRAY_DIMS (ra0)->ubnd - SCM_I_ARRAY_DIMS (ra0)->lbnd + 1;
597 unsigned long i0 = SCM_I_ARRAY_BASE (ra0);
598 long inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
599 ra0 = SCM_I_ARRAY_V (ra0);
600 if (scm_is_null (ras))
601 {
602 switch (SCM_TYP7 (ra0))
603 {
604 default:
605 {
606 for (; n-- > 0; i0 += inc0)
607 ASET (ra0, i0, scm_divide (AREF (ra0, i0), SCM_UNDEFINED));
608 break;
609 }
610 }
611 }
612 else
613 {
614 SCM ra1 = SCM_CAR (ras);
615 unsigned long i1 = SCM_I_ARRAY_BASE (ra1);
616 long inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
617 ra1 = SCM_I_ARRAY_V (ra1);
618 switch (SCM_TYP7 (ra0) == SCM_TYP7 (ra1) ? SCM_TYP7 (ra0) : 0)
619 {
620 default:
621 {
622 for (; n-- > 0; i0 += inc0, i1 += inc1)
623 {
624 SCM res = scm_divide (AREF (ra0, i0), AREF (ra1, i1));
625 ASET (ra0, i0, res);
626 }
627 break;
628 }
629 }
630 }
631 return 1;
632 }
633
634
635 int
636 scm_array_identity (SCM dst, SCM src)
637 {
638 return racp (SCM_CAR (src), scm_cons (dst, SCM_EOL));
639 }
640
641 #endif /* SCM_ENABLE_DEPRECATED */
642
643 static int
644 ramap (SCM ra0, SCM proc, SCM ras)
645 {
646 ssize_t i = SCM_I_ARRAY_DIMS (ra0)->lbnd;
647 size_t n = SCM_I_ARRAY_DIMS (ra0)->ubnd - i + 1;
648
649 scm_t_array_handle h0;
650 size_t i0, i0end;
651 ssize_t inc0;
652 scm_array_get_handle (SCM_I_ARRAY_V (ra0), &h0);
653 i0 = SCM_I_ARRAY_BASE (ra0);
654 inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
655 i0end = i0 + n*inc0;
656 if (scm_is_null (ras))
657 for (; i0 < i0end; i0 += inc0)
658 h0.vset (h0.vector, i0, scm_call_0 (proc));
659 else
660 {
661 SCM ra1 = SCM_CAR (ras);
662 scm_t_array_handle h1;
663 size_t i1;
664 ssize_t inc1;
665 scm_array_get_handle (SCM_I_ARRAY_V (ra1), &h1);
666 i1 = SCM_I_ARRAY_BASE (ra1);
667 inc1 = SCM_I_ARRAY_DIMS (ra1)->inc;
668 ras = SCM_CDR (ras);
669 if (scm_is_null (ras))
670 for (; i0 < i0end; i0 += inc0, i1 += inc1)
671 h0.vset (h0.vector, i0, scm_call_1 (proc, h1.vref (h1.vector, i1)));
672 else
673 {
674 ras = scm_vector (ras);
675 for (; i0 < i0end; i0 += inc0, i1 += inc1, ++i)
676 {
677 SCM args = SCM_EOL;
678 unsigned long k;
679 for (k = scm_c_vector_length (ras); k--;)
680 args = scm_cons (AREF (scm_c_vector_ref (ras, k), i), args);
681 h0.vset (h0.vector, i0,
682 scm_apply_1 (proc, h1.vref (h1.vector, i1), args));
683 }
684 }
685 scm_array_handle_release (&h1);
686 }
687 scm_array_handle_release (&h0);
688 return 1;
689 }
690
691
692 SCM_REGISTER_PROC(s_array_map_in_order_x, "array-map-in-order!", 2, 0, 1, scm_array_map_x);
693
694 SCM_SYMBOL (sym_b, "b");
695
696 SCM_DEFINE (scm_array_map_x, "array-map!", 2, 0, 1,
697 (SCM ra0, SCM proc, SCM lra),
698 "@deffnx {Scheme Procedure} array-map-in-order! ra0 proc . lra\n"
699 "@var{array1}, @dots{} must have the same number of dimensions\n"
700 "as @var{ra0} and have a range for each index which includes the\n"
701 "range for the corresponding index in @var{ra0}. @var{proc} is\n"
702 "applied to each tuple of elements of @var{array1}, @dots{} and\n"
703 "the result is stored as the corresponding element in @var{ra0}.\n"
704 "The value returned is unspecified. The order of application is\n"
705 "unspecified.")
706 #define FUNC_NAME s_scm_array_map_x
707 {
708 SCM_VALIDATE_PROC (2, proc);
709 SCM_VALIDATE_REST_ARGUMENT (lra);
710
711 scm_ramapc (ramap, proc, ra0, lra, FUNC_NAME);
712 return SCM_UNSPECIFIED;
713 }
714 #undef FUNC_NAME
715
716
717 static int
718 rafe (SCM ra0, SCM proc, SCM ras)
719 {
720 ssize_t i = SCM_I_ARRAY_DIMS (ra0)->lbnd;
721 size_t n = SCM_I_ARRAY_DIMS (ra0)->ubnd - i + 1;
722
723 scm_t_array_handle h0;
724 size_t i0, i0end;
725 ssize_t inc0;
726 scm_array_get_handle (SCM_I_ARRAY_V (ra0), &h0);
727 i0 = SCM_I_ARRAY_BASE (ra0);
728 inc0 = SCM_I_ARRAY_DIMS (ra0)->inc;
729 i0end = i0 + n*inc0;
730 if (scm_is_null (ras))
731 for (; i0 < i0end; i0 += inc0)
732 scm_call_1 (proc, h0.vref (h0.vector, i0));
733 else
734 {
735 ras = scm_vector (ras);
736 for (; i0 < i0end; i0 += inc0, ++i)
737 {
738 SCM args = SCM_EOL;
739 unsigned long k;
740 for (k = scm_c_vector_length (ras); k--;)
741 args = scm_cons (AREF (scm_c_vector_ref (ras, k), i), args);
742 scm_apply_1 (proc, h0.vref (h0.vector, i0), args);
743 }
744 }
745 scm_array_handle_release (&h0);
746 return 1;
747 }
748
749 SCM_DEFINE (scm_array_for_each, "array-for-each", 2, 0, 1,
750 (SCM proc, SCM ra0, SCM lra),
751 "Apply @var{proc} to each tuple of elements of @var{ra0} @dots{}\n"
752 "in row-major order. The value returned is unspecified.")
753 #define FUNC_NAME s_scm_array_for_each
754 {
755 SCM_VALIDATE_PROC (1, proc);
756 SCM_VALIDATE_REST_ARGUMENT (lra);
757 scm_ramapc (rafe, proc, ra0, lra, FUNC_NAME);
758 return SCM_UNSPECIFIED;
759 }
760 #undef FUNC_NAME
761
762 static void
763 array_index_map_1 (SCM ra, SCM proc)
764 {
765 scm_t_array_handle h;
766 ssize_t i, inc;
767 size_t p;
768 scm_array_get_handle (ra, &h);
769 inc = h.dims[0].inc;
770 for (i = h.dims[0].lbnd, p = h.base; i <= h.dims[0].ubnd; ++i, p += inc)
771 h.vset (h.vector, p, scm_call_1 (proc, scm_from_ssize_t (i)));
772 scm_array_handle_release (&h);
773 }
774
775 /* Here we assume that the array is a scm_tc7_array, as that is the only
776 kind of array in Guile that supports rank > 1. */
777 static void
778 array_index_map_n (SCM ra, SCM proc)
779 {
780 size_t i;
781 int j, k, kmax = SCM_I_ARRAY_NDIM (ra) - 1;
782 ssize_t *vi;
783
784 vi = scm_gc_malloc_pointerless (sizeof(ssize_t) * (kmax + 1), vi_gc_hint);
785
786 for (k = 0; k <= kmax; k++)
787 {
788 vi[k] = SCM_I_ARRAY_DIMS (ra)[k].lbnd;
789 if (vi[k] > SCM_I_ARRAY_DIMS (ra)[k].ubnd)
790 return;
791 }
792
793 k = kmax;
794 do
795 {
796 if (k == kmax)
797 {
798 SCM args = SCM_EOL;
799 SCM *p = &args, *q;
800 vi[kmax] = SCM_I_ARRAY_DIMS (ra)[kmax].lbnd;
801 i = cindk (ra, vi, kmax+1);
802 for (j = 0; j<=kmax; ++j)
803 {
804 *p = scm_cons (scm_from_ssize_t (vi[j]), SCM_EOL);
805 q = SCM_CARLOC (*p);
806 p = SCM_CDRLOC (*p);
807 }
808 for (; vi[kmax] <= SCM_I_ARRAY_DIMS (ra)[kmax].ubnd;
809 *q = scm_from_ssize_t (++vi[kmax]))
810 {
811 ASET (SCM_I_ARRAY_V (ra), i, scm_apply_0 (proc, args));
812 i += SCM_I_ARRAY_DIMS (ra)[kmax].inc;
813 }
814 k--;
815 }
816 else if (vi[k] < SCM_I_ARRAY_DIMS (ra)[k].ubnd)
817 {
818 vi[k]++;
819 k++;
820 }
821 else
822 {
823 vi[k] = SCM_I_ARRAY_DIMS (ra)[k].lbnd - 1;
824 k--;
825 }
826 }
827 while (k >= 0);
828 }
829
830 SCM_DEFINE (scm_array_index_map_x, "array-index-map!", 2, 0, 0,
831 (SCM ra, SCM proc),
832 "Apply @var{proc} to the indices of each element of @var{ra} in\n"
833 "turn, storing the result in the corresponding element. The value\n"
834 "returned and the order of application are unspecified.\n\n"
835 "One can implement @var{array-indexes} as\n"
836 "@lisp\n"
837 "(define (array-indexes array)\n"
838 " (let ((ra (apply make-array #f (array-shape array))))\n"
839 " (array-index-map! ra (lambda x x))\n"
840 " ra))\n"
841 "@end lisp\n"
842 "Another example:\n"
843 "@lisp\n"
844 "(define (apl:index-generator n)\n"
845 " (let ((v (make-uniform-vector n 1)))\n"
846 " (array-index-map! v (lambda (i) i))\n"
847 " v))\n"
848 "@end lisp")
849 #define FUNC_NAME s_scm_array_index_map_x
850 {
851 SCM_VALIDATE_PROC (2, proc);
852
853 switch (scm_c_array_rank (ra))
854 {
855 case 0:
856 scm_array_set_x (ra, scm_call_0 (proc), SCM_EOL);
857 break;
858 case 1:
859 array_index_map_1 (ra, proc);
860 break;
861 default:
862 array_index_map_n (ra, proc);
863 break;
864 }
865
866 return SCM_UNSPECIFIED;
867 }
868 #undef FUNC_NAME
869
870
871 static int
872 array_compare (scm_t_array_handle *hx, scm_t_array_handle *hy,
873 size_t dim, unsigned long posx, unsigned long posy)
874 {
875 if (dim == scm_array_handle_rank (hx))
876 return scm_is_true (scm_equal_p (scm_array_handle_ref (hx, posx),
877 scm_array_handle_ref (hy, posy)));
878 else
879 {
880 long incx, incy;
881 size_t i;
882
883 if (hx->dims[dim].lbnd != hy->dims[dim].lbnd
884 || hx->dims[dim].ubnd != hy->dims[dim].ubnd)
885 return 0;
886
887 i = hx->dims[dim].ubnd - hx->dims[dim].lbnd + 1;
888
889 incx = hx->dims[dim].inc;
890 incy = hy->dims[dim].inc;
891 posx += (i - 1) * incx;
892 posy += (i - 1) * incy;
893
894 for (; i > 0; i--, posx -= incx, posy -= incy)
895 if (!array_compare (hx, hy, dim + 1, posx, posy))
896 return 0;
897 return 1;
898 }
899 }
900
901 SCM
902 scm_array_equal_p (SCM x, SCM y)
903 {
904 scm_t_array_handle hx, hy;
905 SCM res;
906
907 scm_array_get_handle (x, &hx);
908 scm_array_get_handle (y, &hy);
909
910 res = scm_from_bool (hx.ndims == hy.ndims
911 && hx.element_type == hy.element_type);
912
913 if (scm_is_true (res))
914 res = scm_from_bool (array_compare (&hx, &hy, 0, 0, 0));
915
916 scm_array_handle_release (&hy);
917 scm_array_handle_release (&hx);
918
919 return res;
920 }
921
922 static SCM scm_i_array_equal_p (SCM, SCM, SCM);
923 SCM_DEFINE (scm_i_array_equal_p, "array-equal?", 0, 2, 1,
924 (SCM ra0, SCM ra1, SCM rest),
925 "Return @code{#t} iff all arguments are arrays with the same\n"
926 "shape, the same type, and have corresponding elements which are\n"
927 "either @code{equal?} or @code{array-equal?}. This function\n"
928 "differs from @code{equal?} in that all arguments must be arrays.")
929 #define FUNC_NAME s_scm_i_array_equal_p
930 {
931 if (SCM_UNBNDP (ra0) || SCM_UNBNDP (ra1))
932 return SCM_BOOL_T;
933
934 while (!scm_is_null (rest))
935 { if (scm_is_false (scm_array_equal_p (ra0, ra1)))
936 return SCM_BOOL_F;
937 ra0 = ra1;
938 ra1 = scm_car (rest);
939 rest = scm_cdr (rest);
940 }
941 return scm_array_equal_p (ra0, ra1);
942 }
943 #undef FUNC_NAME
944
945
946 void
947 scm_init_array_map (void)
948 {
949 #include "libguile/array-map.x"
950 scm_add_feature (s_scm_array_for_each);
951 }
952
953 /*
954 Local Variables:
955 c-file-style: "gnu"
956 End:
957 */