On Jan 23, 2013, at 10:06, Andy Wingo wrote: > For C, that makes sense. Something should be done for Scheme as well, > but it's not terribly urgent. Perhaps make scm_array_ref not be bound > to "array-ref", and instead bind "array-ref" to some function that takes > two optional arguments and a rest argument. A poor man's case-lambda...
Just saying… I have written a general rectangular selector for arrays as in APL. It depends on having a prefix-selection operator. Here's an example from numpy: In [1]: import numpy as np In [2]: a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) In [3]: a Out[3]: array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) In [4]: a[1] Out[4]: array([4, 5, 6]) In [5]: a[1, 1] Out[5]: 5 array-ref can be extended very simply to do that. It accumulates on the position as it is done now, but if the index list comes up short it makes a shared array with the remaining axes instead of giving a rank error. So it shouldn't be any slower than array_ref. This cannot be done properly from user code with current Guile because scm_i_make_array() and friends are internal. The only option is make-shared-array. Now, this is a nice interface for general slicing, but it requires creating a closure that is only going to be used rank+1 times, plus a bunch of lists. Let's say that I want to iterate through the rows of a [100000 x 3] array. Moving from row to row is fundamentally just moving a pointer. make-shared-array is not a practical way to do it. The extension of array-ref below isn't a real fix for this use case, because we're still creating a array descriptor for each iteration. But it's way faster than make-shared-array and it is a natural extension. I'm proposing a patch for this. The only wart is what happens with arrays of rank 0. The function below doesn't return views of rank 0, but the element instead, just as array-ref does. The only advantage of returning a rank 0 view is that one could in principle modify the array through it, but they are a pain to deal with otherwise. My ‘solution’ is to treat the result of array-ref as read-only. In APL/J there's no difference between an array of rank 0 and a scalar, so this problem doesn't exist. We may have a similar extension to (array-set! array obj . idxlist) where obj is an array of rank (rank(obj)-length(idxlist)) but an element if this gives 0. This would be just a wrapper over array-copy(array-ref) or the current array-set!. Otherwise I think it should be possible to manipulate SCM_I_ARRAY_DIMS directly, at least from C. Unless there is a way already and I didn't realize, that would be great. // Generalization of array-ref where the number of indices may be smaller than the rank of a. SCM from_(SCM a, SCM i_) { SCM i = i_; scm_t_array_handle ah; scm_array_get_handle(a, &ah); scm_t_array_dim * as = scm_array_handle_dims(&ah); int arank = scm_array_handle_rank(&ah); int k = arank; ssize_t pos = 0; for (; k>0 && scm_is_pair(i); --k, ++as, i=scm_cdr(i)) { ssize_t ik = scm_to_ssize_t(scm_car(i)); if (ik<as->lbnd || ik>as->ubnd) { scm_array_handle_release(&ah); scm_error_scm(scm_from_locale_symbol("out-of-range"), SCM_BOOL_F, scm_from_locale_string("indices out of range"), SCM_EOL, i_); } pos += (ik-as->lbnd)*as->inc; } SCM o; if (k>0) { if (k==arank) { o = a; } else { o = scm_i_make_array(k); SCM_I_ARRAY_V(o) = SCM_I_ARRAY_V(a); SCM_I_ARRAY_BASE(o) = pos + SCM_I_ARRAY_BASE(a); // since arank>1. scm_t_array_dim * os = SCM_I_ARRAY_DIMS(o); for (; k>0; --k, ++as, ++os) { os->ubnd = as->ubnd; os->lbnd = as->lbnd; os->inc = as->inc; } } } else if (scm_is_null(i)) { o = scm_array_handle_ref(&ah, pos); // these may be non-arrays. } else { scm_array_handle_release(&ah); scm_error_scm(scm_from_locale_symbol("out-of-range"), SCM_BOOL_F, scm_from_locale_string("too many indices"), SCM_EOL, i_); } scm_array_handle_release(&ah); return o; } > FWIW this is not the case. Vectors hold SCM objects, whereas uniform > vectors hold unpacked machine values. Ok, I think I understand that. Still I don't see where the vref field for the srfi4 types is set. The conversions seem to be done in bytevector.c, can you point this out? I've also noticed scheme@(guile-user)> (f64vector-ref #s64(1 2 3) 0) $1 = #.# scheme@(guile-user)> (c64vector-ref #f64(1 2 3) 0) $3 = 1.0+2.0i (!) Regards Daniel