2

In C++, there is a function std::partial_sum to compute prefix sum. The code

#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>

int main() {
    std::vector<int> a = {1, 2, 3, 4, 5};
    std::partial_sum(a.begin(), a.end(), a.begin());
    return 0;
}

will override a to 1 3 6 10 15, which is expected.

However, in most cases I want to use prefix sum, I want a 0 in front to indicate "empty sum" so that I can use a[2] - a[0] to query the sum of first two elements. (That allows me to use a trivial nested for loop to find sum of all subarrays). Is there a way to achieve it with the std::partial_sum function? I don't know if it will be possible since the output size will be input size + 1.

Note: I am not seeking for ways that alters the content or type of a beforehand.

If the size of a is a concern:

#include <iostream>
#include <vector>
#include <iterator>
#include <numeric>

int main() {
    std::vector<int> a = {1, 2, 3, 4, 5, -1};
    std::partial_sum(a.begin(), a.end() - 1, a.begin());
    return 0;
}

Something like this can also work for me.

TYeung
  • 2,579
  • 2
  • 15
  • 30
  • "so that I can use a[2] - a[0]" Then you are definitely going to want something else for your output iterator.... – Karl Knechtel Aug 31 '21 at 07:17
  • @KarlKnechtel Let's say I want to override the content of `a` – TYeung Aug 31 '21 at 07:19
  • You can output to a different container just fine (and *because* you can, the different output size is not a problem). However, your original version of the code used `ostream_iterator`, which is not going to leave you with something where you can easily use `[]`. At any rate, the simplest workaround I can think of is to just output the `0` value to the iterator first, before passing it to `partial_sum`. `std::accumulate` lets you specify an initial value, but it just computes the final result rather than giving all the partial results. – Karl Knechtel Aug 31 '21 at 07:21
  • @KarlKnechtel understood. Now what if I want to override `a` with `{0, 1, 3, 6, 10, 15}` without another container? Would it be possible then? – TYeung Aug 31 '21 at 07:23
  • I don't think that can work properly (even with e.g. an `insert_iterator` on a `std::vector`), because e.g. the initial `0` will overwrite the first value that you want to add, before it can be added to the running total. – Karl Knechtel Aug 31 '21 at 07:25
  • @KarlKnechtel That makes sense. I am expecting this to be not possible and just seeing if anyone can surprise me. – TYeung Aug 31 '21 at 07:25
  • not sure about your note. you definitely alter the content of `a`? – apple apple Aug 31 '21 at 08:02
  • @appleapple, yes the only requirement is the alteration is not before partial_sum. – TYeung Aug 31 '21 at 08:05
  • "I am not seeking for ways that alters the content or type of a": are you serious ? The prefix sum does alter a and the result that you want *must* increase a's length ! –  Aug 31 '21 at 08:17
  • @YvesDaoust please refresh your browser. I added the word "beforehand" a few minutes ago. – TYeung Aug 31 '21 at 08:18
  • What difference does that make ? What is modifying before modifying ? –  Aug 31 '21 at 08:19
  • @YvesDaoust Well you can alter the content of `a`, just not before the `std::partial_sum()` operation – TYeung Aug 31 '21 at 08:20
  • Prepend `0` after the prefix sum. –  Aug 31 '21 at 08:21
  • @YvesDaoust That's exactly something I want to avoid. – TYeung Aug 31 '21 at 08:23
  • Mh, you probably don't want to modify after modifying... –  Aug 31 '21 at 08:30
  • The logic of that is the same as prepending `0` beforehand. – TYeung Aug 31 '21 at 08:32

1 Answers1

2

Is there a way to achieve it with the std::partial_sum function?

Just write a 0 to the output iterator before calling std::partial_sum. Care should be taken as the output is one larger than the input, and this won't work in-place, as it writes the first output before reading the first input.

template<class InputIt, class OutputIt>
constexpr OutputIt my_partial_sum(InputIt first, InputIt last, OutputIt d_first)
{
    *d_first++ = typename std::iterator_traits<InputIt>::value_type{};
    return std::partial_sum(first, last, d_first);
}

If you want to be able to do it in place, you could adapt the possible implementation of std::partial_sum further

template<class InputIt, class OutputIt>
constexpr OutputIt partial_sum(InputIt first, InputIt last, OutputIt d_first)
{
    using value_type = typename std::iterator_traits<InputIt>::value_type;

    if (first == last) {
        *d_first++ = value_type{};
        return d_first;
    }

    value_type sum{};
    value_type next = *first;

    *d_first++ = sum;
 
    while (++first != last) {
       next = *first;
       sum = std::move(sum) + next;
       *d_first++ = sum;
    }
    return d_first;
}

but I think the simpler thing would be to prepend a 0 to your container.

template <typename Container>
void my_partial_sum(Container& c) {
    c.emplace(c.begin());
    std::partial_sum(c.begin(), std::prev(c.end()), c.begin());
}
Caleth
  • 52,200
  • 2
  • 44
  • 75
  • Won't this break when overriding the input range? – rubenvb Aug 31 '21 at 09:00
  • @rubenvb the output is one larger than the input, but OP is aware of that – Caleth Aug 31 '21 at 09:12
  • 2
    @Caleth It's not just the size, it's also that the first element is overwritten before it can be used by `partial_sum`. But the answer is already accepted, so OP seems to be aware that this solution cannot be used for naive in-place processing. – j6t Aug 31 '21 at 10:34
  • I was indeed talking about this replacing the first element of the input range before it's used by `std::partial_sum`, giving a different answer if it is not equal to the value initialized variable of the element type. – rubenvb Aug 31 '21 at 11:42
  • 1
    @j6t Yes thanks for pointing it out. In fact, I think I would stick to only prepending a `0` afterwards cause it's just one more statement. – TYeung Aug 31 '21 at 12:00