Skip to content

Instantly share code, notes, and snippets.

@carlosmcevilly
Last active July 11, 2017 14:55
Show Gist options
  • Save carlosmcevilly/a5f8dd5880404509af31 to your computer and use it in GitHub Desktop.
Save carlosmcevilly/a5f8dd5880404509af31 to your computer and use it in GitHub Desktop.
Playing with the idea of a Hamming ball. This calculates the Hamming ball starting at a given number, with given number of bits and given radius.
#!/usr/bin/env python3
# What is a hamming ball?
#
# I couldn't find any definition for it on the Internets. But reading between the lines
# of what people in the know say, I'll take a stab at a preliminary definition. Don't
# trust this... I haven't studied it and am not a mathematician. Having said that,
# It seems to be the set of all numbers having the same number of bits as a starting
# number (the center) and differing from that number by at most (radius) bits. The
# code below assumes the starting number is also included, but I haven't confirmed
# that this should be the case. This is just me playing around with a quick hack.
#
# Another word used is "Hamming sphere" but I think this might be something different,
# namely: The set of all numbers having the same number of bits as a starting number
# (the center) and differing from that number by exactly (radius) bits.
#
# This script calculates the Hamming ball according to the first definition above.
#
import os
import sys
def ball_for_number_with_bits_with_radius(number, numBits, radius):
ball = ball_for_number(number, numBits)
if radius == 1:
return ball
else:
result = ball.copy()
for neighbor in ball:
items = ball_for_number_with_bits_with_radius(neighbor, numBits, radius-1)
result = result.union(items)
return result
def ball_for_number(number, numBits):
ball = set()
start = number & 0xFFFFFFFF # limit to 64-or-smaller-bit numbers
ball.add(number)
for n in range(0,numBits):
mutated = number ^ 1<<n;
ball.add(mutated)
return ball
def legal_argument(arg):
legal_args = 'nbr'
if arg in legal_args:
return True
return False
def usage_exit():
print("\nUsage: " + sys.argv[0] + " -n number -b bits -r radius")
print(
"""
Options:
-n the starting number
-b how many bits to treat the number as (including left padding)
-r how many bit differences from the starting number to include
""")
exit(-1)
def main():
if len(sys.argv) < 7:
usage_exit()
try:
if len(sys.argv) < 4 or not legal_argument(sys.argv[1][1]) or not legal_argument(sys.argv[3][1]) or not legal_argument(sys.argv[5][1]):
usage_exit()
if sys.argv[1].startswith('-') and sys.argv[1][1] == 'n':
number = int(sys.argv[2])
if sys.argv[1].startswith('-') and sys.argv[3][1] == 'b':
numBits = int(sys.argv[4])
if sys.argv[1].startswith('-') and sys.argv[5][1] == 'r':
radius = int(sys.argv[6])
except IndexError:
usage_exit()
if numBits > 64:
numBits = 64
print("warning: limited to 64 bits")
limit = (2**(numBits+1))-1
if number > limit:
print("error: number " + str(number)
+ " is larger than " + str(limit)
+ ", the max value for " + str(numBits)
+ " bits.")
sys.exit()
ball = ball_for_number_with_bits_with_radius(number, numBits, radius)
for item in ball:
result = bin(item)[2:].zfill(numBits)
print(str(item).zfill(8) + ": " + result)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment