On Friday, August 22, 2014 6:23:45 PM UTC-4, K leo wrote:
>
> I want to find all the possible ways to fill a 1-dimensional array A (of 
> size say 30) with only -1, 0, or 1 to each element, such that 
> sum(abs(A)) is less than say 5.  Simple loops don't seem to be very 
> efficient.  Any suggestions? 
>

If you just want to count them, it seems like a straightforward 
combinatorics problem: If the length of the array is N and the maximum 
sumabs is K, then there can be P=0,1,...K nonzero elements.  For each 
choice of P nonzero elements, there are 2^P sign choices.  So, the total 
number of possibilities is (in Julia)

sum(P -> binomial(N, P) * (1<<P), 0:K)

For (N,K)=(30,4), this is 472761.   (Maybe you can evaluate this sum 
analytically in closed form; I didn't bother.)

To enumerate them, I would just use the "combinations" function, combined 
with a gray code to loop over the sign choices, flipping one sign at a 
time.  For example, you could use:

function getcombos(N::Int, K::Int)
    combos = Vector{Int}[]
    for P=0:K
        for nonzeros in combinations(1:N, P)
            push!(combos, nonzeros)
            gray = 0
            while true
                i = trailing_ones(gray) + 1 # component to flip
                i > P && break
                nonzeros[i] = -nonzeros[i]
                push!(combos, copy(nonzeros))
                gray += 1
            end
        end
    end
    return combos
end
getcombos(N::Integer, K::Integer) = getcombos(int(N),int(K))

This returns a list of lists of indices, where positive indices indicate 
the location of the 1's and negative indices indicate the location of the 
zeros, e.g. [-27,28,-29,-30] indicates a 1 in index 28, -1's in 27,29,30, 
and 0's elsewhere.

For N,K = 30,4 (array length 30, sum < 5), this takes about 0.05 seconds on 
my machine, which seems respectable.

--SGJ

Reply via email to