[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: propose deprecation of generalized-vector-*
From: |
Daniel Llorens |
Subject: |
Re: propose deprecation of generalized-vector-* |
Date: |
Wed, 23 Jan 2013 13:20:43 +0100 |
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