guile-devel
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]