Generate all sequences of bits within Hamming distance t
Asked Answered
E

4

2

Given a vector of bits v, compute the collection of bits that have Hamming distance 1 with v, then with distance 2, up to an input parameter t.

So for

011  I should get
~~~ 
111
001
010
~~~ -> 3 choose 1 in number
101
000
110
~~~ -> 3 choose 2
100
~~~ -> 3 choose 3

How to efficiently compute this? The vector won't be always of dimension 3, e.g. it could be 6. This will run numerous time in my real code, so some efficiency would be welcome as well (even by paying more memory).


My attempt:

#include <iostream>
#include <vector>

void print(const std::vector<char>& v, const int idx, const char new_bit)
{
    for(size_t i = 0; i < v.size(); ++i)
        if(i != idx)
            std::cout << (int)v[i] << " ";
        else
            std::cout << (int)new_bit << " ";
    std::cout << std::endl;
}

void find_near_hamming_dist(const std::vector<char>& v, const int t)
{
    // if t == 1
    for(size_t i = 0; i < v.size(); ++i)
    {
        print(v, i, v[i] ^ 1);
    }

    // I would like to produce t == 2
    // only after ALL the t == 1 results are reported
    /* how to? */
}

int main()
{
    std::vector<char> v = {0, 1, 1};
    find_near_hamming_dist(v, 1);
    return 0; 
}

Output:

MacBook-Pro:hammingDist gsamaras$ g++ -Wall -std=c++0x hammingDist.cpp -o ham
MacBook-Pro:hammingDist gsamaras$ ./ham
1 1 1 
0 0 1 
0 1 0 
Enthrone answered 25/11, 2016 at 22:37 Comment(2)
I recently already answers this, pretty much, though you formulated the question differently.Kopeisk
@harold yeah because it's slightly different! :)Enthrone
H
0
#include <stdio.h>
#include <stdint.h>
#include <string.h>

void magic(char* str, int i, int changesLeft) {
        if (changesLeft == 0) {
                printf("%s\n", str);
                return;
        }
        if (i < 0) return;
        // flip current bit
        str[i] = str[i] == '0' ? '1' : '0';
        magic(str, i-1, changesLeft-1);
        // or don't flip it (flip it again to undo)
        str[i] = str[i] == '0' ? '1' : '0';
        magic(str, i-1, changesLeft);
}

int main(void) {
        char str[] = "011";
        printf("%s\n", str);
        size_t len = strlen(str);
        size_t maxDistance = len;
        for (size_t i = 1 ; i <= maxDistance ; ++i) {
                printf("Computing for distance %d\n", i);
                magic(str, len-1, i);
                printf("----------------\n");
        }
        return 0;
}

Output:

MacBook-Pro:hammingDist gsamaras$ nano kastrinis.cpp
MacBook-Pro:hammingDist gsamaras$ g++ -Wall kastrinis.cpp 
MacBook-Pro:hammingDist gsamaras$ ./a.out 
011
Computing for distance 1
010
001
111
----------------
Computing for distance 2
000
110
101
----------------
Computing for distance 3
100
----------------
Hax answered 26/11, 2016 at 2:2 Comment(3)
Pure code without any description? Not very useful for future visitors...Liatrice
What's the description you would like? It's straight forward. You recursively take all possibilities (either you flip a bit or you don't)Hax
@GeorgeKastrinis thank you for your precious response. I posted an answer verifying that this can be extended to my basis example, just for the future users. Please take a look to see that everything makes sense. Thank you again very much for the precise and explicit answer!Enthrone
L
2

First: There is a bijection between hamming dist k bit-vectors and subsets (of n aka v.size()) of kardinality k (the set of indices with changed bits). Hence, I'd enumerate the subsets of changed indices instead. A quick glance at the SO history shows this reference. You'd have to keep track of the correct cardinalitites of course.

Considering efficiency is probably pointless, since the solution to your problem is exponential anyways.

Lanalanae answered 25/11, 2016 at 23:20 Comment(0)
M
2

If Hamming distance h(u, v) = k, then u^v has exactly k bits set. In other words, computing u ^ m over all masks m with k bits set gives all words with the desired Hamming distance. Notice that such set of mask does not depend on u.

That is, for n and t reasonably small, precompute sets of masks with k bits set, for all k in 1,t, and iterate over these sets as required.

If you don't have enough memory, you may generate the k-bit patterns on the fly. See this discussion for details.

Malposition answered 26/11, 2016 at 1:12 Comment(0)
H
0
#include <stdio.h>
#include <stdint.h>
#include <string.h>

void magic(char* str, int i, int changesLeft) {
        if (changesLeft == 0) {
                printf("%s\n", str);
                return;
        }
        if (i < 0) return;
        // flip current bit
        str[i] = str[i] == '0' ? '1' : '0';
        magic(str, i-1, changesLeft-1);
        // or don't flip it (flip it again to undo)
        str[i] = str[i] == '0' ? '1' : '0';
        magic(str, i-1, changesLeft);
}

int main(void) {
        char str[] = "011";
        printf("%s\n", str);
        size_t len = strlen(str);
        size_t maxDistance = len;
        for (size_t i = 1 ; i <= maxDistance ; ++i) {
                printf("Computing for distance %d\n", i);
                magic(str, len-1, i);
                printf("----------------\n");
        }
        return 0;
}

Output:

MacBook-Pro:hammingDist gsamaras$ nano kastrinis.cpp
MacBook-Pro:hammingDist gsamaras$ g++ -Wall kastrinis.cpp 
MacBook-Pro:hammingDist gsamaras$ ./a.out 
011
Computing for distance 1
010
001
111
----------------
Computing for distance 2
000
110
101
----------------
Computing for distance 3
100
----------------
Hax answered 26/11, 2016 at 2:2 Comment(3)
Pure code without any description? Not very useful for future visitors...Liatrice
What's the description you would like? It's straight forward. You recursively take all possibilities (either you flip a bit or you don't)Hax
@GeorgeKastrinis thank you for your precious response. I posted an answer verifying that this can be extended to my basis example, just for the future users. Please take a look to see that everything makes sense. Thank you again very much for the precise and explicit answer!Enthrone
E
0

In response to Kastrinis' answer, I would like to verify that this can be extended to my basis example, like this:

#include <iostream>
#include <vector>

void print(std::vector<char>&v)
{
    for (auto i = v.begin(); i != v.end(); ++i)
        std::cout << (int)*i;
    std::cout << "\n";
}

void magic(std::vector<char>& str, const int i, const int changesLeft) {
        if (changesLeft == 0) {
                print(str);
                return;
        }
        if (i < 0) return;
        // flip current bit
        str[i] ^= 1;
        magic(str, i-1, changesLeft-1);
        // or don't flip it (flip it again to undo)
        str[i] ^= 1;
        magic(str, i-1, changesLeft);
}

int main(void) {
        std::vector<char> str = {0, 1, 1};
        print(str);
        size_t len = str.size();
        size_t maxDistance = str.size();
        for (size_t i = 1 ; i <= maxDistance ; ++i) {
                printf("Computing for distance %lu\n", i);
                magic(str, len-1, i);
                printf("----------------\n");
        }
        return 0;
}

where the output is identical.


PS - I am also toggling the bit with a different way.

Enthrone answered 26/11, 2016 at 15:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.