लैटिन वर्ग संपीड़न


31

एक लैटिन वर्ग एक वर्ग है जिसमें पंक्तियों या स्तंभों में कोई दोहराया प्रतीक नहीं है :।

13420
21304
32041
04213
40132

और जितने भी सुडोकू खिलाड़ी जानते हैं, आपको बाकी नंबरों को घटाने के लिए सभी नंबरों की जरूरत नहीं है।

आपकी चुनौती एक लैटिन वर्ग को संभव के रूप में कुछ बाइट्स में संपीड़ित करना है। आपको एक या दो प्रोग्राम (ओं) प्रदान करने की आवश्यकता है जो संपीड़ित / विघटित करते हैं।

विभिन्न जानकारी:

  • उपयोग किए गए नंबर हमेशा होंगे 0..N-1, जहां Nवर्ग के किनारे की लंबाई है, औरN<=25
  • विघटन पर, लैटिन वर्ग इनपुट के समान होना चाहिए।
  • आपका कार्यक्रम (ओं) को किसी भी लैटिन वर्ग (अधिकतम वर्ग आकार के भीतर ) को संपीड़ित करने में सक्षम होना चाहिए , न कि केवल जो मैंने प्रदान किया है। संपीड़न अनुपात भी समान होना चाहिए।
  • आपको वास्तव में अपना स्कोर प्राप्त करने के लिए कंप्रेशन और डीकंप्रेसर चलाना चाहिए (नो एंड-ऑफ-ब्रह्मांड रनटाइम्स)

परीक्षण मामलों को जीथब पर पाया जा सकता है । आपका स्कोर संपीडित परीक्षण मामलों का कुल आकार है।

EDIT: 7 जुलाई को 20:07 तक, मैंने परीक्षण मामलों को अपडेट किया (एक पीढ़ी के मुद्दे को ठीक करने के लिए)। कृपया नए परीक्षण मामलों पर अपने कार्यक्रम को फिर से चलाएँ। धन्यवाद एंडर्स कसीगोर


1
खैर, परिभाषा के द्वारा, किसी भी प्रतीक इस्तेमाल किया जा सकता, लेकिन मेरे परीक्षण मामलों बस हो उपयोग करने के लिए 0हालांकि n-1:)
नाथन मेरिल


3
@NathanMerrill अच्छी तरह से, बिंदु को केवल nविभिन्न प्रतीकों का उपयोग करने की अनुमति दी जा रही थी । : पी
मार्टिन एंडर

1
@DavidC यह मायने नहीं रखता, क्योंकि आकार बाइट्स में मापा जाता है ।
flawr

2
आपके 25 परीक्षण मामलों में से 19 (4, 6, 8, 10, 12, 14 को छोड़कर सभी) तुच्छ लैटिन वर्ग की पंक्तियों और स्तंभों की अनुमति देकर उत्पन्न किए गए थे जिनकी ( i , j ) प्रविष्टि i + j mod n है । यह एक यादृच्छिक लैटिन वर्ग की तुलना में बहुत अधिक संपीड़ित करने के लिए उन्हें बहुत आसान बनाता है। हालांकि आपके नियम कहते हैं कि हमें सभी लैटिन वर्गों के लिए समान संपीड़न अनुपात होना चाहिए, यह दुर्घटना से टूटना आसान हो सकता है। परीक्षण के मामले अधिक प्रतिनिधि होने चाहिए।
एंडर्स कासोर्ग

जवाबों:


10

पायथन, 1281.375 1268.625 बाइट्स

हम एक समय में लैटिन वर्ग एक "निर्णय" को सांकेतिक शब्दों में बदलना, जहां प्रत्येक निर्णय इन तीन रूपों में से एक है:

  • पंक्ति i , कॉलम j में कौन सी संख्या जाती है ;
  • पंक्ति में मैं , जो स्तंभ संख्या कश्मीर में चला जाता है,
  • कॉलम j में , संख्या k किस क्रम में जाती है।

प्रत्येक चरण में, हम उन सभी तार्किक निष्कर्षों को बनाते हैं जो हम पिछले निर्णयों के आधार पर कर सकते हैं, फिर संभव विकल्पों की सबसे छोटी संख्या के साथ निर्णय लें, जो कि प्रतिनिधित्व करने के लिए छोटी संख्या में बिट्स लेते हैं।

विकल्प एक साधारण अंकगणित विकोडक (विकल्प की संख्या से div / mod) द्वारा प्रदान किए जाते हैं। लेकिन उस पत्ते एन्कोडिंग में कुछ अतिरेक: अगर कश्मीर एक वर्ग जहां सभी की उत्पाद विकल्पों की संख्या थी डीकोड मीटर , तो k + मीटर , कश्मीर + 2⋅ मीटर , कश्मीर + 3⋅ मीटर , ... एक ही वर्ग के लिए डिकोड अंत में कुछ बचे हुए राज्य के साथ।

हम इस अतिरेक का लाभ उठाते हैं ताकि वर्ग के आकार को स्पष्ट रूप से कूट-कूट कर भरा जा सके। डिकम्प्रेसर आकार के एक वर्ग को डिकोड करने की कोशिश करके शुरू होता है। 1. जब भी डिकोडर बचे हुए राज्य के साथ खत्म होता है, तो यह उस परिणाम को बाहर निकालता है, मूल संख्या से मीटर घटाता है , आकार 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

मैं इस कोड को ideone पर आज़मा रहा हूं, लेकिन यह सिर्फ रनटाइम त्रुटियाँ देता है। मैंने इसे फ़ाइल f के बजाय stdin का उपयोग करके संशोधित किया। ideone.com/fKGSQd
edc65

@ edc65 यह काम नहीं करता क्योंकि Ideone का NumPy पुराना है।
डेनिस

@ edc65 Ideone में NumPy 1.8.2 है जो बहुत पुराना है np.stack()। इस मामले में इसे बदला जा सकता है np.array([…]), और मैंने वर्तमान संस्करण में ऐसा किया है।
एंडर्स कासोर्ग जुले

हममम। क्या सभी वर्ग एक बाइट स्ट्रीम में संग्रहीत हैं? क्या उनके आकार के बारे में भी जानकारी संग्रहीत है, या डिकोडर मानता है कि वे आकार 1,2,3,… आदि हैं?
सर्ज बोर्स्च

@ सर्जबॉर्श प्रत्येक वर्ग एक अलग बिटस्ट्रीम पर संपीड़ित होता है। डिकम्प्रेसर ने वर्णित एल्गोरिथ्म का उपयोग करके, बिट स्ट्रीम से स्पष्ट रूप से वर्ग आकार को ठीक किया है। किसी धारणा का उपयोग नहीं किया जाता है।
एंडर्स केसोर्ग

7

MATLAB, 3'062.5 2'888.125 बाइट्स

यह दृष्टिकोण बस अंतिम पंक्ति और वर्ग के अंतिम स्तंभ को खोदता है, और प्रत्येक प्रविष्टि को एक निश्चित बिट गहराई के शब्दों में परिवर्तित करता है। दी गई आकार वर्ग के लिए बिट गहराई को न्यूनतम चुना जाता है। (@KarlNapf द्वारा सुझाव) ये शब्द सिर्फ एक-दूसरे से जुड़े हैं। विघटन सिर्फ रिवर्स है।

सभी परीक्षण मामलों का योग 23'105 बिट्स या 2'888.125 बाइट्स है। (अभी भी अद्यतन किए गए परीक्षण मामलों के लिए है, क्योंकि मेरे आउटपुट का आकार केवल इनपुट के आकार पर निर्भर है।)

function bin=compress(a)
%get rid of last row and column:
s=a(1:end-1,1:end-1);
s = s(:)';
bin = [];
%choose bit depth:
bitDepth = ceil(log2(numel(a(:,1))));
for x=s;
    bin = [bin, dec2bin(x,bitDepth)];
end
end

function a=decompress(bin)
%determine bit depth
N=0;
f=@(n)ceil(log2(n)).*(n-1).^2;
while f(N)~= numel(bin)
    N=N+1; 
end
bitDepth = ceil(log2(N));
%binary to decimal:
assert(mod(numel(bin),bitDepth)==0,'invalid input length')
a=[];
for k=1:numel(bin)/bitDepth;
    number = bin2dec([bin(bitDepth*(k-1) + (1:bitDepth)),' ']);
    a = [a,number];    
end
n = sqrt(numel(a));
a = reshape(a,n,n);
disp(a)
%reconstruct last row/column:
n=size(a,1)+1;
a(n,n)=0;%resize
%complete rows:
v = 0:n-1;
for k=1:n
    a(k,n) = setdiff(v,a(k,1:n-1));
    a(n,k) = setdiff(v,a(1:n-1,k));
end
end

आप एक चर बिटरेट का उपयोग करके थोड़ा अधिक संपीड़ित कर सकते हैं, जैसे कि n=9..164 बिट पर्याप्त हैं।
कार्ल नेप

@KarlNapf आप अलग-अलग लंबाई के शब्दों में कैसे भेदभाव करते हैं? जहां तक ​​मैं जानता हूं कि आपको अतिरिक्त उपसर्गों की आवश्यकता है, क्या आपको नहीं?
दोष

एक संपीड़न के अंदर चर नहीं, वर्ग के आकार के आधार पर अधिक पसंद है। यदि n> 16 तो 5 बिट्स का उपयोग करें, यदि 8 <n = 16 का उपयोग 4 बिट्स तय किया गया और इसी तरह।
कार्ल नेफ

ओह सही यह समझ में आता है, धन्यवाद!
दोष

3
उसी कारण से आप इसे दूसरे तरीके से कर रहे हैं, यह संभवत: आपके द्वारा उपयोग किए जाने का तरीका है। =)
दोषपूर्ण

7

पायथन 3, 10772 बिट्स (1346.5 बाइट्स)

def compress(rows):
    columns = list(zip(*rows))
    size = len(rows)
    symbols = range(size)
    output = size - 1
    weight = 25
    for i in symbols:
        for j in symbols:
            choices = set(rows[i][j:]) & set(columns[j][i:])
            output += weight * sorted(choices).index(rows[i][j])
            weight *= len(choices)
    return bin(output + 1)[3:]

def decompress(bitstring):
    number = int('1' + bitstring, 2) - 1
    number, size = divmod(number, 25)
    size += 1
    symbols = range(size)
    rows = [[None] * size for _ in symbols]
    columns = [list(column) for column in zip(*rows)]
    for i in symbols:
        for j in symbols:
            choices = set(symbols) - set(rows[i]) - set(columns[j])
            number, index = divmod(number, len(choices))
            rows[i][j] = columns[j][i] = sorted(choices)[index]
    return rows

संयुक्त परीक्षण मामलों को संपीड़ित और विघटित करने के लिए 0.1 सेकंड का समय लगता है।

Ideone पर स्कोर सत्यापित करें ।


वाह, समझाने की परवाह?
नाथन मेरिल

1
संक्षेप में, कंप्रेसर रीडिंग ऑर्डर में वर्ग के माध्यम से यात्रा करता है, जो कि पहले से ही उस पंक्ति और स्तंभ में दिखाई देने वाले प्रतीकों का ट्रैक रखता है, और संभव प्रतीकों के आरोही सूची में अंक के प्रतीक को अंकगणित करता है। मैं अपने कोड को थोड़ा साफ करने और परीक्षण करने के बाद एक विस्तृत विवरण जोड़ूंगा कि यदि कोई विशेष आधार 256 बाइट्स बचाता है।
डेनिस

मुझे पूरा यकीन नहीं है कि आपका कोड क्या कर रहा है, लेकिन क्या अंतिम पंक्ति को छोड़ना और इसे डिकॉम्प्रेस करते समय हल करना संभव नहीं है?
यति

@TuukkaX जब केवल एक संभव प्रतीक नहीं है len(possible)है 1 और possible.index(rows[i][j])है 0 ताकि प्रतीक किसी कीमत पर एन्कोड किया गया है,।
डेनिस

याय, नए परीक्षण के मामलों ने 6 बिट्स को बचाया। :)
डेनिस

3

जे , 2444 बाइट्स

A.पूर्णांक के एक क्रमपरिवर्तन से [0, n) और क्रमपरिवर्तन सूचकांक बनाने के लिए अंतर्निहित पर निर्भर करता है ।

संपीड़ित करें, 36 बाइट्स

({:a.)joinstring<@(a.{~255&#.inv)@A.

इनपुट लैटिन वर्ग का प्रतिनिधित्व करने वाला 2d सरणी है। प्रत्येक पंक्ति को क्रमपरिवर्तन सूचकांक में बदल दिया जाता है, और उस सूचकांक को आधार 255 अंकों की सूची में बदल दिया जाता है और इसे ASCII मान के साथ बदल दिया जाता है। प्रत्येक स्ट्रिंग को 255 पर ASCII वर्ण का उपयोग करके जोड़ा जाता है।

डीकंप्रेस, 45 बाइट्स

[:(A.i.@#)[:(_&,(255&#.&x:);._1~1,255&=)u:inv

255 के प्रत्येक ASCII मूल्य पर इनपुट स्ट्रिंग को विभाजित करता है, और प्रत्येक समूह को आधार 255 अंकों के रूप में पार्स करता है। फिर समूहों की संख्या का उपयोग करते हुए, पूर्णांक [0, लंबाई) की एक सूची बनाएं और प्रत्येक सूचकांक के अनुसार इसे अनुमति दें और इसे 2d सरणी के रूप में लौटाएं।


2

पायथन, 6052 4521 3556 बाइट्स

compressउदाहरण की तरह वर्ग को एक बहु-स्ट्रिंग स्ट्रिंग के रूप में लेता है, और एक बाइनरी स्ट्रिंग लौटाता है, जबकि decompressइसके विपरीत होता है।

import bz2
import math

def compress(L):
 if L=="0": 
  C = []
 else:
  #split elements
  elems=[l.split(',') for l in L.split('\n')]
  n=len(elems)
  #remove last row and col
  cropd=[e[:-1] for e in elems][:-1]
  C = [int(c) for d in cropd for c in d]

 #turn to string
 B=map(chr,C)
 B=''.join(B)

 #compress if needed
 if len(B) > 36:
  BZ=bz2.BZ2Compressor(9)
  BZ.compress(B)
  B=BZ.flush()

 return B

def decompress(C):

 #decompress if needed
 if len(C) > 40:
  BZ=bz2.BZ2Decompressor()
  C=BZ.decompress(C)

 #return to int and determine length
 C = map(ord,C)
 n = int(math.sqrt(len(C)))
 if n==0: return "0"

 #reshape to list of lists
 elems = [C[i:i+n] for i in xrange(0, len(C), n)]

 #determine target length
 n = len(elems[0])+1
 L = []
 #restore last column
 for i in xrange(n-1):
  S = {j for j in range(n)}
  L.append([])
  for e in elems[i]:
   L[i].append(e)
   S.remove(e)
  L[i].append(S.pop())
 #restore last row
 L.append([])
 for col in xrange(n):
  S = {j for j in range(n)}
  for row in xrange(n-1):
   S.remove(L[row][col])
  L[-1].append(S.pop())
 #merge elements
 orig='\n'.join([','.join([str(e) for e in l]) for l in L])
 return orig

अंतिम पंक्ति + कॉलम निकालें और बाकी को ज़िप करें।

  • Edit1: अच्छी तरह से base64आवश्यक नहीं लगता है
  • Edit2: अब कटा हुआ टेबल को एक बाइनरी स्ट्रिंग में परिवर्तित करना और केवल आवश्यक होने पर संपीड़ित करना

2

पायथन 3, 1955 बाइट्स

फिर भी एक और है कि क्रमचय सूचकांकों का उपयोग करता है ...

from math import factorial

test_data_name = 'latin_squares.txt'

def grid_reader(fname):
    ''' Read CSV number grids; grids are separated by empty lines '''
    grid = []
    with open(fname) as f:
        for line in f:
            line = line.strip()
            if line:
                grid.append([int(u) for u in line.split(',') if u])
            elif grid:
                yield grid
                grid = []
    if grid:
        yield grid

def show(grid):
    a = [','.join([str(u) for u in row]) for row in grid]
    print('\n'.join(a), end='\n\n')

def perm(seq, base, k):
    ''' Build kth ordered permutation of seq '''
    seq = seq[:]
    p = []
    for j in range(len(seq) - 1, 0, -1):
        q, k = divmod(k, base)
        p.append(seq.pop(q))
        base //= j
    p.append(seq[0])
    return p

def index(p):
    ''' Calculate index number of sequence p,
        which is a permutation of range(len(p))
    '''
    #Generate factorial base code
    fcode = [sum(u < v for u in p[i+1:]) for i, v in enumerate(p[:-1])]

    #Convert factorial base code to integer
    k, base = 0, 1
    for j, v in enumerate(reversed(fcode), 2):
        k += v * base
        base *= j
    return k

def encode_latin(grid):
    num = len(grid)
    fbase = factorial(num)

    #Encode grid rows by their permutation index,
    #in reverse order, starting from the 2nd-last row
    codenum = 0
    for row in grid[-2::-1]:
        codenum = codenum * fbase + index(row)
    return codenum

def decode_latin(num, codenum):
    seq = list(range(num))
    sbase = factorial(num - 1)
    fbase = sbase * num

    #Extract rows
    grid = []
    for i in range(num - 1):
        codenum, k = divmod(codenum, fbase)
        grid.append(perm(seq, sbase, k))

    #Build the last row from the missing element of each column
    allnums = set(seq)
    grid.append([allnums.difference(t).pop() for t in zip(*grid)])
    return grid

byteorder = 'little'

def compress(grid):
    num = len(grid)
    codenum = encode_latin(grid)
    length = -(-codenum.bit_length() // 8)
    numbytes = num.to_bytes(1, byteorder)
    codebytes = codenum.to_bytes(length, byteorder)
    return numbytes + codebytes

def decompress(codebytes):
    numbytes, codebytes= codebytes[:1], codebytes[1:]
    num = int.from_bytes(numbytes, byteorder)
    if num == 1:
        return [[0]]
    else:
        codenum = int.from_bytes(codebytes, byteorder)
        return decode_latin(num, codenum)

total = 0
for i, grid in enumerate(grid_reader(test_data_name), 1):
    #show(grid)
    codebytes = compress(grid)
    length = len(codebytes)
    total += length
    newgrid = decompress(codebytes)
    ok = newgrid == grid
    print('{:>2}: Length = {:>3}, {}'.format(i, length, ok))
    #print('Code:', codebytes)
    #show(newgrid)

print('Total bytes: {}'.format(total))

उत्पादन

 1: Length =   1, True
 2: Length =   1, True
 3: Length =   2, True
 4: Length =   3, True
 5: Length =   5, True
 6: Length =   7, True
 7: Length =  11, True
 8: Length =  14, True
 9: Length =  20, True
10: Length =  26, True
11: Length =  33, True
12: Length =  41, True
13: Length =  50, True
14: Length =  61, True
15: Length =  72, True
16: Length =  84, True
17: Length =  98, True
18: Length = 113, True
19: Length = 129, True
20: Length = 147, True
21: Length = 165, True
22: Length = 185, True
23: Length = 206, True
24: Length = 229, True
25: Length = 252, True
Total bytes: 1955

2

पायथन 3 - 3,572 3,581 बाइट्स

from itertools import *
from math import *

def int2base(x,b,alphabet='0123456789abcdefghijklmnopqrstuvwxyz'):
    if isinstance(x,complex):
        return (int2base(x.real,b,alphabet) , int2base(x.imag,b,alphabet))
    if x<=0:
        if x==0:return alphabet[0]
        else:return  '-' + int2base(-x,b,alphabet)
    rets=''
    while x>0:
        x,idx = divmod(x,b)
        rets = alphabet[idx] + rets
    return rets

def lexicographic_index(p):
    result = 0
    for j in range(len(p)):
        k = sum(1 for i in p[j + 1:] if i < p[j])
        result += k * factorial(len(p) - j - 1)
    return result

def getPermutationByindex(sequence, index):
    S = list(sequence)
    permutation = []
    while S != []:
        f = factorial(len(S) - 1)
        i = int(floor(index / f))
        x = S[i]
        index %= f
        permutation.append(x)
        del S[i]
    return tuple(permutation)

alphabet = "abcdefghijklmnopqrstuvwxyz"

def dataCompress(lst):
    n = len(lst[0])

    output = alphabet[n-1]+"|"

    for line in lst:
        output += "%s|" % int2base(lexicographic_index(line), 36)

    return output[:len(output) - 1]

def dataDeCompress(data):
    indexes = data.split("|")
    n = alphabet.index(indexes[0]) + 1
    del indexes[0]

    lst = []

    for index in indexes:
        if index != '':
            lst.append(getPermutationByindex(range(n), int(index, 36)))

    return lst

dataCompress पूर्णांक ट्यूपल्स की सूची लेता है और एक स्ट्रिंग लौटाता है।

dateDeCompress एक स्ट्रिंग लेता है और पूर्णांक ट्यूपल्स की सूची देता है।

संक्षेप में, प्रत्येक पंक्ति के लिए, यह प्रोग्राम उस रेखा को क्रमबद्धता सूचकांक लेता है और इसे बेस 36 में बचाता है। Decompressing को बड़े इनपुट के साथ एक लंबा समय लगता है लेकिन बड़े इनपुट पर भी संपीड़न वास्तव में तेज है।

उपयोग:

dataCompress([(2,0,1),(1,2,0),(0,1,2)])

परिणाम: c|4|3|0

dataDeCompress("c|4|3|0")

परिणाम: [(2, 0, 1), (1, 2, 0), (0, 1, 2)]


2
अगर आप अपने permutationsकॉल को कॉल में नहीं लपेटते हैं, तो आपको बहुत बेहतर रनटाइम मिलेगा list- permutationsजेनरेटर लौटाता है, जो आलसी रूप से सभी क्रमपरिवर्तन उत्पन्न करता है, लेकिन यदि आप इसे बनाने की कोशिश करते हैं list, तो यह उत्सुकता से सभी क्रमपरिवर्तन उत्पन्न करता है, जो लेता है बहुत ज्यादा समय।
मेगो

क्या आप थोड़ा बेहतर समझा सकते हैं कि अपने कोड का उपयोग कैसे करें?
मेगो

@Mego ज़रूर, शायद मैं आलसी मूल्यांकन को भी लागू करूंगा, हालांकि यह अभी भी काफी असुविधाजनक है।
यति जूल



1

जावा, 2310 बाइट्स

हम वर्ग की प्रत्येक पंक्ति को एक संख्या में बदल देते हैं, जिसमें यह दर्शाया जाता है कि यह फैक्टरैडिक संख्याओं का उपयोग कर रहा है, जिसे फैक्टोरियल नंबर सिस्टम के रूप में भी जाना जाता है , जो क्रमांकन क्रमांकन के लिए उपयोगी है।

हम स्क्वायर को एक बाइनरी फ़ाइल में लिखते हैं जहां पहला बाइट वर्ग का आकार होता है, और फिर प्रत्येक पंक्ति में एक बाइट्स की संख्या के लिए एक बाइट होता है जो जावा बिगइन्टेगर के बाइनरी प्रतिनिधित्व में होता है, उसके बाद उस बिगइंटर के बाइट्स होते हैं।

प्रक्रिया को उलटने के लिए और वर्ग को कम करने के लिए हम आकार को वापस और फिर प्रत्येक BigInteger को पढ़ते हैं, और वर्ग की प्रत्येक पंक्ति को उत्पन्न करने के लिए उस संख्या का उपयोग करते हैं।

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Latin {
    public static void main(String[] args) {
        if (args.length != 3) {
            System.out.println("java Latin {-c | -d} infile outfile");
        } else if (args[0].equals("-c")) {
            compress(args[1], args[2]);
        } else if (args[0].equals("-d")) {
            decompress(args[1], args[2]);
        } else {
            throw new IllegalArgumentException(
                "Invalid mode: " + args[0] + ", not -c or -d");
        }
    }

    public static void compress(String filename, String outname) {
        try (BufferedReader br = Files.newBufferedReader(Paths.get(filename))) {
            try (OutputStream os =
                    new BufferedOutputStream(new FileOutputStream(outname))) {
                String line = br.readLine();
                if (line == null) return;
                int size = line.split(",").length;
                if (size > 127) throw new ArithmeticException(
                    "Overflow: square too large");
                Permutor perm = new Permutor(size);
                os.write((byte) size); // write size of square

                do {
                    List<Integer> nums = Arrays.stream(line.split(","))
                        .map(Integer::new)
                        .collect(Collectors.toList());
                    byte[] bits = perm.which(nums).toByteArray();
                    os.write((byte) bits.length); // write length of bigint
                    os.write(bits); // write bits of bigint
                } while ((line = br.readLine()) != null);
            }
        } catch (IOException e) {
            System.out.println("Error compressing " + filename);
            e.printStackTrace();
        }
    }

    public static void decompress(String filename, String outname) {
        try (BufferedInputStream is =
                new BufferedInputStream(new FileInputStream(filename))) {
            try (BufferedWriter bw =
                    Files.newBufferedWriter(Paths.get(outname))) {
                int size = is.read(); // size of latin square
                Permutor perm = new Permutor(size);
                for (int i = 0; i < size; ++i) {
                    int num = is.read(); // number of bytes in bigint
                    if (num == -1) {
                        throw new IOException(
                            "Unexpected end of file reading " + filename);
                    }
                    byte[] buf = new byte[num];
                    int read = is.read(buf); // read bits of bigint into buf
                    if (read != num) {
                        throw new IOException(
                            "Unexpected end of file reading " + filename);
                    }
                    String row = perm.nth(new BigInteger(buf)).stream()
                        .map(Object::toString)
                        .collect(Collectors.joining(","));
                    bw.write(row);
                    bw.newLine();
                }
            }
        } catch (IOException e) {
            System.out.println("Error reading " + filename);
            e.printStackTrace();
        }
    }
}

क्रमपरिवर्तन के साथ काम करने के लिए कुछ साल पहले लिखी गई कक्षा से पर्मुटर को अनुकूलित किया गया है:

import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.math.BigInteger;
import static java.math.BigInteger.ZERO;
import static java.math.BigInteger.ONE;

public class Permutor {
    private final List<Integer> items;

    public Permutor(int n) {
        items = new ArrayList<>();
        for (int i = 0; i < n; ++i) items.add(i);
    }

    public BigInteger size() {
        return factorial(items.size());
    }

    private BigInteger factorial(int x) {
        BigInteger f = ONE;
        for (int i = 2; i <= x; ++i) {
            f = f.multiply(BigInteger.valueOf(i));
        }
        return f;
    }

    public List<Integer> nth(long n) {
        return nth(BigInteger.valueOf(n));
    }

    public List<Integer> nth(BigInteger n) {
        if (n.compareTo(size()) > 0) {
            throw new IllegalArgumentException("too high");
        }
        n = n.subtract(ONE);
        List<Integer> perm = new ArrayList<>(items);
        int offset = 0, size = perm.size() - 1;
        while (n.compareTo(ZERO) > 0) {
            BigInteger fact = factorial(size);
            BigInteger mult = n.divide(fact);
            n = n.subtract(mult.multiply(fact));
            int pos = mult.intValue();
            Integer t = perm.get(offset + pos);
            perm.remove((int) (offset + pos));
            perm.add(offset, t);
            --size;
            ++offset;
        }
        return perm;
    }

    public BigInteger which(List<Integer> perm) {
        BigInteger n = ONE;
        List<Integer> copy = new ArrayList<>(items);
        int size = copy.size() - 1;
        for (Integer t : perm) {
            int pos = copy.indexOf(t);
            if (pos < 0) throw new IllegalArgumentException("invalid");
            n = n.add(factorial(size).multiply(BigInteger.valueOf(pos)));
            copy.remove((int) pos);
            --size;
        }
        return n;
    }
}

उपयोग:

लैटिन वर्ग के साथ latin.txt, इसे संपीड़ित करें:

java Latin -c latin.txt latin.compressed

और इसे विघटित करें:

java Latin -d latin.compressed latin.decompressed
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.