0

Here is my previous question about finding next bit permutation. It occurs to me that I have to modify my code to achieve something similiar to next bit permutation, but quite different.

I am coding information about neighbors of vertex in graph in bit representation of int. For example if n = 4 (n - graph vertices) and graph is full, my array of vertices looks like:

vertices[0]=14 // 1110 - it means vertex no. 1 is connected with vertices no. 2, 3, and 4
vertices[1]=13 // 1101 - it means vertex no. 2 is connected with vertices no. 1, 3, and 4
vertices[2]=11 // 1011 - it means vertex no. 3 is connected with vertices no. 1, 2, and 4
vertices[3]=7  // 0111 - it means vertex no. 4 is connected with vertices no. 1, 2, and 3

First (main) for loop is from 0 to 2^n (cause 2^n is number of subsets of a set).

So if n = 4, then there are 16 subsets:

{empty}, {1}, ..., {4}, {0,1}, {0,2}, ..., {3,4}, {0,1,2}, ..., {1,2,3}, {1,2,3,4}

These subsets are represented by index value in for loop

for(int i=0; i < 2^n; ++i) // i - represents value of subset

Let's say n = 4, and actually i = 5 //0101. I'd like to check subsets of this subset, so I would like to check:

0000
0001
0100
0101

Now I'm generating all bit permutation of 1 bit set, then permutation of 2 bits set ... and so on (until I reach BitCount(5) = 2) and I only take permutation I want (by if statement). It's too many unneeded computations.

So my question is, how to generate all possible COMBINATIONS WITHOUT REPETITIONS (n,k) where n - graph vertices and k - number of bits in i (stated above)

My actual code (that generates all bit permutation and selects wrong):

for (int i = 0; i < PowerNumber; i++) 
    {
        int independentSetsSum = 0;
        int bc = BitCount(i);

        if(bc == 1) independentSetsSum = 1;
        else if (bc > 1)
        {           
            for(int j = 1; j <= bc; ++j)
            {
                unsigned int v = (1 << j) - 1; // current permutation of bits 
                int bc2 = BitCount(j);
                while(v <= i)
                {
                    if((i & v) == v)
                        for(int neigh = 1; neigh <= bc2; neigh++)
                            if((v & vertices[GetBitPositionByNr(v, neigh) - 1]) == 0)
                                independentSetsSum ++;

                    unsigned int t = (v | (v - 1)) + 1;  
                    v = t | ((((t & -t) / (v & -v)) >> 1) - 1);     
                } 
            }
        }
    }

All of this is because I have to count independent set number of every subset of n.

EDIT

I'd like to do it without creating any arrays or generally I'd like to avoid allocating any memory (neither vectors).

A little bit of an explanation: n=5 //00101 - it is bit count of a number i - stated above, k=3, numbers in set (number represents bit position set to 1)

{
1, // 0000001
2, // 0000010
4, // 0001000
6, // 0100000
7  // 1000000
}

So correct combination is {1,2,6} // 0100011, but {1,3,6} // 0100101 is a wrong combination. In my code there are plenty of wrong combinations which I have to filter.

Community
  • 1
  • 1
db_k
  • 293
  • 2
  • 15
  • 1
    Do you need the efficiency of bitwise operations? If not you could save a lot of headaches (wrt manipulating graphs) by abstracting a bit. – Kyle Jul 30 '15 at 14:42
  • My goal is to write the most efficient function so if it's possible - I'd like to use bitwise operations like in my code. – db_k Jul 30 '15 at 14:48

2 Answers2

3

Not sure I correctly understand what you exactly want but based from your example (where i==5) you want all the subsets of a given subset.

If it's the case you can directly generate all these subsets.

int subset = 5;
int x = subset;
while(x) {
    //at this point x is a valid subset
    doStuff(x);
    x = (x-1)&subset;
}
doStuff(0) //0 is always valid

Hope this helps.

  • Yes, that is exactly what I want to achieve! Thanks a lot! – db_k Jul 30 '15 at 15:50
  • 1
    I think with `do while()` loop you can avoid 2 calls to `doStuff()`, or even better with `while(true)` and `break` inside – Slava Jul 30 '15 at 15:54
  • I don't see how, if `x==0` when you update it this will kill the stop condition. I found the `while(true) break` ugly but yes it's a solution. –  Jul 30 '15 at 16:00
  • 2
    Alternatively (to correct Slava), use an `unsigned int`, a `do while` loop, start with `x = 0`, and move the doStuff call after `x=(x-1)&subset;` (the first iteration will set `x` to `(2^32 - 1) & subset` if `sizeof(unsigned int)=4`). But who cares that code is already simple and efficient enough like it is. (really elegant solution btw) – Caninonos Jul 30 '15 at 16:04
0

My first guess to generate all the possible combinations would be the following rules (sorry if it's a bit hard to read)

start from the combination where all the 1s are on the left, all the 0s are on the right

move the leftmost 1 with a 0 on its immediate right to the right
if that bit had a 1 on its immediate left then
  move all the 1s on its left all the way to the left

you're finished when you reach the combination with all the 1s on the right, and all the 0s on the left

Applying these rules for n=5 and k=3 would give this:

11100
11010
10110
01110
11001
10101
01101
10011
01011
00111

But that doesn't strikes me as really efficient (and/or elegant).
A better way would be to find a way to iterate through these numbers by flipping only a finite number of bits (i mean, you'd always need to flip O(1) bits to reach the next combination, rather than O(n)), that may allow a more efficient iteration (a bit like the https://en.wikipedia.org/wiki/Gray_code ).
I'll edit or post another andwer if i find better.

Caninonos
  • 1,062
  • 6
  • 12
  • Okay, but this solution requires that where `n=5` set contains numbers (or bit positions) `1,2,3,4,5`. But `n=5` could contains numbers (or bit positions) `1,2,4,7,12`. What you write is actually in my code - too many unneeded combinations. – db_k Jul 30 '15 at 15:04
  • Check out edit to my post, maybe now it's more clearly explained. – db_k Jul 30 '15 at 15:12
  • Ah, i thought k was the number of elements you wanted in each subset. It's actually the elements that may be present in each subset. (concerning your code, to be honest, i didn't read it in detail, i should have my mistake) – Caninonos Jul 30 '15 at 15:15
  • I guess my explanation is a liitle bit confusing (a lot of informations) but I think now it's clear what I want to achieve. Generally all combinations of elements in set (not necessarily the following numbers) but using bit representation of int. Then maximal number of a set is obviously 32. – db_k Jul 30 '15 at 15:19
  • Ah, no, i think i finally got it. You have a set of integers (let's call it `S`), this set of integers is actually stored as a bitset. `n` is the cardinal of `S` (i.e. the number of integers in `S`). What you want is to compute the subset `S_k,{x+1}` from `S_k,x` where, for all `x` in `[0; (n choose k) - 1)`, for all `k` in `(0; n)`, `S_k,x` is a subset of `S` whose cardinal is `k` and `S_k,x` is different of `S_k,y` for each `y` such that `0 <= y < x` – Caninonos Jul 30 '15 at 15:33
  • Unfortunately, I don't understand your notation, but I guess you're right :) Another view of my problem: `for i = every subset (2^n elements) of a set (n elements) for j = every subset of a subset i (2^i elements) end end` – db_k Jul 30 '15 at 15:39
  • 1
    If that's the case, you could simply reduce a case where your set has `n` elements (for instance `1,2,4,7,12` or `3,17,23,42,134` with `n=5`) to the case where your set contains exactly the positions `1,2,...,n` by inserting 0s between these positions (for instance if you have the subset 01101 of `1,2,3,4,5` with `(n=5, k=3`) but you actually want a subset of `1,2,4,7,12`, map this subset to 0()1(0)1(00)0(0000)1 = 0101000000001 where the 0s in the parentheses are inserted 0s) "inserting 0s" in a bitset isn't very natural but it's probably the simplest – Caninonos Jul 30 '15 at 15:50
  • +1 for you for an another idea, but I guess answer from @Blabla404 is more elegant (and maybe faster). Anyway thanks for an interesting. – db_k Jul 30 '15 at 15:53
  • Indeed, but you don't control the cardinal of each subset anymore, i thought you needed that (otherwise his method is extremely simple and efficient) – Caninonos Jul 30 '15 at 15:59
  • I thought I needed that, but now I know I can rearrage my algorithm to not needed that :) – db_k Jul 30 '15 at 16:04