0

I want to enumerate all vectors of length N, in which each element can have a value of [0 ... K] and for which the sum of all elements is SUM.

I solved this problem using a recursive function but I when I retyped in CUDA C I got a message that CUDA C doesn't support recursive functions. After this I made some changes and rewrote the function without using recursion, but the function was boolean and this also is not supported in CUDA C because main global function must be void without calling other functions. now I am out of ideas, any help?

The recursive function is the following:

    private static void computeVectors(int[] n, int sum, int k, int k1, int i) {


        if (sum == 0) {

            printVectors(n, n.length);
        } else if (i < n.length) {

            for (int j = k; j >= 0; j--) {

                if (j <= k1) {
                    n[i] = j;
                    computeVectors(n, sum - j, sum - j, k1, i + 1);
                }
            }
        }
    }

    private static void printVectors(int p[], int n) {

        for (int i = 0; i < n; i++) {
            System.out.print(p[i] + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {

        // TODO code application logic here
        computeVectors(new int[4], 5, 3, 3, 0);

    }

The output for this example is:

3200 3110 3101 3020 3011 3002 2300 2210 2201 2120 2111 2102 2030 2021 2012 2003 1310 1301 1220 1211 1202 1130 1121 1112 1103 1031 1022 1013 0320 0311 0302 0230 0221 0212 0203 0131 0122 0113 0032

0023

Farouq Jouti
  • 1,657
  • 9
  • 15
Dragon
  • 111
  • 3
  • 12
  • "function was boolean" - why? – Oliver Charlesworth Aug 15 '13 at 21:56
  • Because that was only way to find all vectors who satisfied the condition. One vector = one execution of this function, but in the begging I don't know how many vectors exists with the condition. – Dragon Aug 15 '13 at 22:22
  • im assuming an user can control the inputs of the initial computeVector method and then it is our responsibility to generate the placement of the values correct? – Marquis Blount Aug 15 '13 at 23:01
  • This is called [integer partitioning](http://en.wikipedia.org/wiki/Partition_%28number_theory%29), by the way. – Jashaszun Aug 15 '13 at 23:11
  • When you need to change a function from being recursive to being iterative, what you need to do is change the _implicit_ stack that you're using (the call stack) into an _explicit_ stack. – Jashaszun Aug 15 '13 at 23:18
  • http://stackoverflow.com/questions/159590/way-to-go-from-recursion-to-iteration see if this link helps you – Marquis Blount Aug 15 '13 at 23:22

2 Answers2

2

CUDA supports recursive __device__ functions on devices with Compute Capability (CC) 2.0 and later. You would need to verify that your GPU has CC 2.0 or later and compile for it with -arch=sm_20 (or higher).

__global__ kernel functions can be launched from other kernels using CUDA Dynamic Parallelism, which requires CC >= 3.5

In any case, for performance reasons you probably want to make a non-recursive version.

harrism
  • 26,505
  • 2
  • 57
  • 88
1

Here's a nonrecursive version. The basic idea is that we want to choose combinations of size sum with at most k replacements from {0,...,N-1}. Then the number of times an element is chosen gives the size of that element in the resulting vector. Thinking in terms of starts and bars, we have sum stars and N-1 bars. The bars separate the stars into bins, and the number of stars in the ith bin is the size of entry i (this means that the bars can be at most k from each other). Moving the bars from left to right as necessary, we get the reverse output of your example.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

class Combinations {
    public static void main(String... ignore) {
        int n = 4;
        int sum = 5;
        int k = 3;
        Integer[] set = new Integer[n];
        fillIncreasing(set,0,0,n);

        computeVectors(set,sum,k);
    }

    private static void fillIncreasing(Integer[] array,int from,int first,int to) {
        for ( int i = from ; i < to ; i++ ) {
            array[i] = i-from+first;
        }
    }

    public static void computeVectors(Integer[] set,int size,int maxChoose) {
        int[] vectorToPrint = new int[set.length];
        for ( List<Integer> vector : combinationsWithReplacement(set,size,maxChoose) ) {
            Arrays.fill(vectorToPrint,0);
            for ( Integer entry : vector ) {
                vectorToPrint[entry]++;
            }
            System.out.println("vector: "+Arrays.toString(vectorToPrint));
        }
    }

    public static <T> Iterable<List<T>> combinationsWithReplacement(final T[] set,final int size,final int maxChoose) {
        if ( set.length < 2 ) {
            throw new IllegalArgumentException();
        }
        return new Iterable<List<T>>() {
            public Iterator<List<T>> iterator() {
                return new Iterator<List<T>>() {
                    Integer[] barSpots = new Integer[set.length+1];
                    {
                        fillIncreasing(barSpots,0,0,barSpots.length-1);
                        barSpots[barSpots.length-1] = size+set.length;
                        while ( hasNext() && !readyToReturn() ) {
                            advance();
                        }
                    }
                    private boolean readyToReturn() {
                        if ( ! hasNext() || set.length*maxChoose < size ) {
                            return false;
                        }
                        for ( int i = 1 ; i < barSpots.length ; i++ ) {
                            if ( barSpots[i] > maxChoose+barSpots[i-1]+1 ) {
                                return false;
                            }
                        }
                        return true;
                    }
                    private void advance() {
                        int biggestThatCanMove = barSpots.length-2;
                        while ( biggestThatCanMove >= 0
                            && ( barSpots[biggestThatCanMove]+1 >= barSpots[biggestThatCanMove+1] ) ) {
                            biggestThatCanMove--;
                        }
                        fillIncreasing(barSpots,biggestThatCanMove,
                                   barSpots[biggestThatCanMove]+1,
                                   barSpots.length-1);
                    }
                    public boolean hasNext() {
                        return barSpots[0] == 0;
                    }
                    public List<T> next() {
                        List<T> toRet = new ArrayList<T>();
                        for ( int i = 0 ; i+1 < barSpots.length ; i++ ) {
                            int times = barSpots[i+1]-barSpots[i]-1;
                            for ( boolean ignore : new boolean[times] ) {
                                toRet.add(set[i]);
                            }
                        }
                        do {
                            advance();
                        } while ( hasNext() && !readyToReturn() );
                        return toRet;
                    }
                    public void remove() {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
    }
}
Teepeemm
  • 4,331
  • 5
  • 35
  • 58