Python 1281.375 1268.625 ไบต์
เราเข้ารหัส "การตัดสินใจ" ละตินตารางหนึ่งที่แต่ละการตัดสินใจเป็นหนึ่งในสามรูปแบบเหล่านี้:
- หมายเลขใดจะอยู่ในแถวi , คอลัมน์j ;
- ในแถวiคอลัมน์ใดที่หมายเลขkเข้าไป
- ในคอลัมน์jแถวใดที่หมายเลขkเข้า
ในแต่ละขั้นตอนเราทำการอนุมานแบบลอจิคัลทั้งหมดที่เราสามารถทำได้จากการตัดสินใจก่อนหน้าจากนั้นเลือกการตัดสินใจด้วยจำนวนทางเลือกที่น้อยที่สุดซึ่งจะใช้จำนวนบิตที่น้อยที่สุดในการเป็นตัวแทน
ตัวเลือกมีให้โดยตัวถอดรหัสเลขคณิตอย่างง่าย (div / mod ตามจำนวนตัวเลือก) แต่นั่นทำให้เหลือความซ้ำซ้อนในการเข้ารหัส: ถ้าkถอดรหัสเป็นสี่เหลี่ยมจัตุรัสซึ่งผลคูณของตัวเลือกทั้งหมดคือmดังนั้นk + m , k + 2⋅ m , k + 3⋅ m , …ถอดรหัสเป็นสี่เหลี่ยมเดียวกัน กับสถานะที่เหลือบางอย่างในตอนท้าย
เราใช้ประโยชน์จากความซ้ำซ้อนนี้เพื่อหลีกเลี่ยงการเข้ารหัสขนาดของสแควร์ ตัวขยายการบีบอัดเริ่มต้นด้วยการพยายามถอดรหัสสแควร์ขนาด 1 เมื่อใดก็ตามที่ตัวถอดรหัสเสร็จสิ้นด้วยสถานะที่เหลือมันจะส่งผลให้เกิดผลลัพธ์ดังกล่าวแล้วลบmออกจากหมายเลขเดิมเพิ่มขนาดเป็น 1 และลองอีกครั้ง
import numpy as np
class Latin(object):
def __init__(self, size):
self.size = size
self.possible = np.full((size, size, size), True, dtype=bool)
self.count = np.full((3, size, size), size, dtype=int)
self.chosen = np.full((3, size, size), -1, dtype=int)
def decision(self):
axis, u, v = np.unravel_index(np.where(self.chosen == -1, self.count, self.size).argmin(), self.count.shape)
if self.chosen[axis, u, v] == -1:
ws, = np.rollaxis(self.possible, axis)[:, u, v].nonzero()
return axis, u, v, list(ws)
else:
return None, None, None, None
def choose(self, axis, u, v, w):
t = [u, v]
t[axis:axis] = [w]
i, j, k = t
assert self.possible[i, j, k]
assert self.chosen[0, j, k] == self.chosen[1, i, k] == self.chosen[2, i, j] == -1
self.count[1, :, k] -= self.possible[:, j, k]
self.count[2, :, j] -= self.possible[:, j, k]
self.count[0, :, k] -= self.possible[i, :, k]
self.count[2, i, :] -= self.possible[i, :, k]
self.count[0, j, :] -= self.possible[i, j, :]
self.count[1, i, :] -= self.possible[i, j, :]
self.count[0, j, k] = self.count[1, i, k] = self.count[2, i, j] = 1
self.possible[i, j, :] = self.possible[i, :, k] = self.possible[:, j, k] = False
self.possible[i, j, k] = True
self.chosen[0, j, k] = i
self.chosen[1, i, k] = j
self.chosen[2, i, j] = k
def encode_sized(size, square):
square = np.array(square, dtype=int)
latin = Latin(size)
chosen = np.array([np.argmax(square[:, :, np.newaxis] == np.arange(size)[np.newaxis, np.newaxis, :], axis=axis) for axis in range(3)])
num, denom = 0, 1
while True:
axis, u, v, ws = latin.decision()
if axis is None:
break
w = chosen[axis, u, v]
num += ws.index(w)*denom
denom *= len(ws)
latin.choose(axis, u, v, w)
return num
def decode_sized(size, num):
latin = Latin(size)
denom = 1
while True:
axis, u, v, ws = latin.decision()
if axis is None:
break
if not ws:
return None, 0
latin.choose(axis, u, v, ws[num % len(ws)])
num //= len(ws)
denom *= len(ws)
return latin.chosen[2].tolist(), denom
def compress(square):
size = len(square)
assert size > 0
num = encode_sized(size, square)
while size > 1:
size -= 1
square, denom = decode_sized(size, num)
num += denom
return '{:b}'.format(num + 1)[1:]
def decompress(bits):
num = int('1' + bits, 2) - 1
size = 1
while True:
square, denom = decode_sized(size, num)
num -= denom
if num < 0:
return square
size += 1
total = 0
with open('latin_squares.txt') as f:
while True:
square = [list(map(int, l.split(','))) for l in iter(lambda: next(f), '\n')]
if not square:
break
bits = compress(square)
assert set(bits) <= {'0', '1'}
assert square == decompress(bits)
print('Square {}: {} bits'.format(len(square), len(bits)))
total += len(bits)
print('Total: {} bits = {} bytes'.format(total, total/8.0))
เอาท์พุท:
Square 1: 0 bits
Square 2: 1 bits
Square 3: 3 bits
Square 4: 8 bits
Square 5: 12 bits
Square 6: 29 bits
Square 7: 43 bits
Square 8: 66 bits
Square 9: 94 bits
Square 10: 122 bits
Square 11: 153 bits
Square 12: 198 bits
Square 13: 250 bits
Square 14: 305 bits
Square 15: 363 bits
Square 16: 436 bits
Square 17: 506 bits
Square 18: 584 bits
Square 19: 674 bits
Square 20: 763 bits
Square 21: 877 bits
Square 22: 978 bits
Square 23: 1097 bits
Square 24: 1230 bits
Square 25: 1357 bits
Total: 10149 bits = 1268.625 bytes
0
แม้ว่าn-1
:)