BACKGROUND
----------

The concept of a prefix sum is very simple. Given an integer array a,
store in each cell a[i] the value a[0]+...+a[i-1].

Example. The prefix sum of the array

[3, 1, 7, 0, 4, 1, 6, 3]

is

[0, 3, 4, 11, 11, 15, 16, 22].


Prefix sums have important applications in parallel vector programming,
where the workload of calculating the sum is distributed over several
processes. We will verify a sequential version of such an algorithm.

ALGORITHM DESCRIPTION
---------------------

We assume that the length of the array is a power of two. This allows us
to identify the array initially with the leaves of a complete binary
tree. The computation proceeds along this tree in two phases: upsweep
and downsweep.


During the upsweeep, which itself proceeds in phases, the sum of the
children nodes is propagated to the parent nodes along the tree. A part
of the array is overwritten with values stored in the inner nodes of the
tree in this process (see diagram in the accompanying PDF). After the
upsweep, the rightmost array cell is identified with the root of the
tree.


As preparation for the downsweep, a zero is inserted in the rightmost
cell.

Then, in each step, each node at the current level passes to its left
child its own value, and it passes to its right child, the sum of the
left child from the upsweep phase and its own value.
//PrefixSumIter.java
import java.util.Arrays;

class PrefixSumIter {

    private int[] a;

    PrefixSumIter(int [] a) {
	this.a = a;
    }


    public int upsweep() {
        int space = 1;
        for (; space < a.length; space=space*2) {
            int left = space - 1;
            while (left < a.length) {
                int right = left + space;
                a[right] = a[left] + a[right];
                left = left + space*2;
            }
        }
        return space;
    }
    

    public void downsweep(int space) {
        a[a.length - 1] = 0;
        space = space/2;
        for (; space > 0; space=space/2) {
            int right = space*2 - 1;
            while (right < a.length) {
                int left = right - space;
                int temp = a[right];
                a[right] = a[left] + a[right];
                a[left] = temp;
                right = right + space*2;
            }
        }
    }
 

    public static void main (String [] args) {
        int [] a = {3,1,7,0,4,1,6,3};
        PrefixSumIter p = new PrefixSumIter(a);
        System.out.println(Arrays.toString(a));
        int space = p.upsweep();
        System.out.println(space);        
        System.out.println(Arrays.toString(a));
        p.downsweep(space);
        System.out.println(Arrays.toString(a));
    }

}


/*
[3, 1, 7, 0, 4, 1, 6, 3]
[3, 4, 7, 11, 4, 5, 6, 25]
[0, 3, 4, 11, 11, 15, 16, 22]



*/


//PrefixSumRec.java
import java.util.Arrays;

class PrefixSumRec {

    private int[] a;

    PrefixSumRec(int [] a) {
	this.a = a;
    }


    public void upsweep(int left, int right) {
        if (right > left+1) {
            int space = right - left;
            upsweep(left-space/2,left);
            upsweep(right-space/2,right);
        }
        a[right] = a[left]+a[right];
    }
    

    public void downsweep(int left, int right) {
        int tmp = a[right];
        a[right] = a[right] + a[left];
        a[left] = tmp;
        if (right > left+1) {
            int space = right - left;
            downsweep(left-space/2,left);
            downsweep(right-space/2,right);
        }
    
    }

       
    public static void main (String [] args) {
        int [] a = {3,1,7,0,4,1,6,3};
        PrefixSumRec p = new PrefixSumRec(a);
        System.out.println(Arrays.toString(a));
        p.upsweep(3,7);
        System.out.println(Arrays.toString(a));
        a[7]=0;
        p.downsweep(3,7);
        System.out.println(Arrays.toString(a));
    }

}


/*
[3, 1, 7, 0, 4, 1, 6, 3]
[3, 4, 7, 11, 4, 5, 6, 25]
[0, 3, 4, 11, 11, 15, 16, 22]



*/
