Skip to content

Cumulative map #506

Description

@sebasv

Like numpy.cumsum() or numpy.cumprod() but with map, mapv, map_inplace, map_into since unlike Numpy, in Rust we don't take a performance hit by supplying user functions. I imagine the signature to be something like

fn cum_mapv<F: Fn(T,T) -> T>(&self<T>, f: F) -> Self// T being the element type

// cumsum example:
let a = Array::linspace(0., 100., 100).cummapv(|acc, cur| acc + cur);

If this will be considered for inclusion, I can write up a PR!

Activity

  1. jturner314 commented on Oct 23, 2018

    @jturner314
    Member

    I assume you're interested in summing over only one axis? If so, this seems reasonable:

    fn accumulate_axis<F>(&self, axis: Axis, f: F) -> Array<A, D>
    where
        A: Clone,
        F: FnMut(&A, &A) -> A,

    This is similar to Python's itertools.accumulate. The changes from your proposal are adding an axis parameter, adding the A: Clone bound, changing the return type to Array, and changing F to take elements by reference to avoid unnecessary clones. It could be used basically the same way:

    arr.accumulate_axis(Axis(1), ::std::ops::Add::add);
    // or
    arr.accumulate_axis(Axis(1), |acc, x| acc + x);

    With this method, the first element of the result along each lane is always the clone of the first element of the input along that lane. I'm not quite sure what to call this method, but accumulate_axis seems pretty good.

    Another related method would be this:

    fn scan_axis<St, B, F>(&self, axis: Axis, initial_state: St, f: F) -> Array<B, D>
    where
        F: FnMut(&mut St, &A) -> B,

    This emulates std::iter::Iterator::scan. For a cumulative sum, it could be used like this:

    arr.scan_axis(Axis(1), 0., |acc, &x| {
        *acc += x;
        *acc
    });

    It isn't quite as concise for computing a cumulative sum/product, but it is more flexible because the first element can be different between the input and result, and the element type can change.

    I think both methods are useful and would be good additions to ndarray.

    The tricky part of implementing these methods is initializing the result. (Ideally, the result array would be uninitialized initially. This requires unsafe code, and doing this without accidentally causing undefined behavior is tricky. Doing this correctly would be easier once #496 is merged.) For a first-pass implementation, though, we could sacrifice performance and use only safe code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions