2

Given N, B, and D: Find a set of N codewords (1 <= N <= 64), each of length B bits (1 <= B <= 8), such that each of the codewords is at least Hamming distance of D (1 <= D <= 7) away from each of the other codewords. The Hamming distance between a pair of codewords is the number of binary bits that differ in their binary notation. Consider the two codewords 0x554 and 0x234 and their differences (0x554 means the hexadecimal number with hex digits 5, 5, and 4):

    0x554 = 0101 0101 0100
    0x234 = 0010 0011 0100

Bit differences: xxx xx Since five bits were different, the Hamming distance is 5.

Example

input :- N=16 B=7 D=3
output :- 0 7 25 30 42 45 51 52 75 76 82 85 97 102 120 127

I can generate all codewords(binary string) of length B and try picking every subset of size N and see if it each number in the picked subset with other number in the subset is at least D hamming distance apart but this will require time nCk

(2**B) C  N

which can be horrible in the worst case. How can I generate the numbers efficiently?

Dominique Fortin
  • 2,212
  • 15
  • 20
Prashant Bhanarkar
  • 930
  • 3
  • 14
  • 32

1 Answers1

2

This is a similar question and the answers/comments mention that an efficient construction is an open problem!

Here is a compact approach using Integer Programming (which is NP-hard), modelled with cvxpy in python3:

import itertools
import operator
from cvxpy import *

N = 16
B = 7
D = 3

# Vars.
X = Bool(N, B)
Y = Bool(len(list(itertools.combinations(range(N), 2))), B)  # ugly -> could use bin-formula

# Objective
objective = Minimize(1)  # dummy objective -> only feasibility needed!

# Constraints
def xor_vectors(a, b, y):
    """ Linearization of y-vec = xor(a-vec, b-vec) """
    return [y <= a + b,
            y >= a-b,
            y >= b-a,
            y <= 2-a-b]

constraints_xor = reduce(operator.add, [xor_vectors(X[pair[0], :], X[pair[1], :], Y[ind, :]) for ind, pair in
                        enumerate(itertools.combinations(range(N), 2))])
constraints_hamming_dist = [sum_entries(Y, axis=1) >= D]

# Build problem
prob = Problem(objective, constraints_xor + constraints_hamming_dist)
# Solve
result = prob.solve(solver=GUROBI, MIPFocus=1, verbose=True)

print(X.value)

Output:

.... (verbose output)

111   108    0.00000   18  424          -    0.00000      -   511    5s
*  264    13              37       0.0000000    0.00000  0.00%   500    7s

Cutting planes:
Gomory: 2
Zero half: 26

Explored 270 nodes (139404 simplex iterations) in 7.74 seconds
Thread count was 4 (of 4 available processors)

Optimal solution found (tolerance 1.00e-04)
Best objective 0.000000000000e+00, best bound 0.000000000000e+00, gap 0.0%
[[ 1.  1.  1.  1.  1.  1.  1.]
[ 1.  0.  1.  0.  1.  1.  0.]
[ 1.  1.  1.  0.  0.  0.  1.]
[ 1.  1.  0.  0.  1.  0.  0.]
[ 0.  1.  1.  1.  1.  0.  0.]
[ 0.  1.  0.  0.  1.  1.  1.]
[ 0.  1.  1.  0.  0.  1.  0.]
[ 0.  1.  0.  1.  0.  0.  1.]
[ 1.  1.  0.  1.  0.  1.  0.]
[ 1.  0.  1.  1.  0.  0.  0.]
[ 0.  0.  0.  1.  1.  1.  0.]
[ 0.  0.  1.  1.  0.  1.  1.]
[ 0.  0.  0.  0.  0.  0.  0.]
[ 1.  0.  0.  0.  0.  1.  1.]
[ 1.  0.  0.  1.  1.  0.  1.]
[ 0.  0.  1.  0.  1.  0.  1.]]

EDIT: An earlier approach (different solver-params) needed 48 mins, now it took only ~8 seconds. I used a commercial solver (not free for non-academic use)!

I think a SAT-solving approach could be faster, but it seems, that this is a very hard problem indeed (as mentioned in my link above)!

Community
  • 1
  • 1
sascha
  • 32,238
  • 6
  • 68
  • 110