Rastgele takımsız oyun kartı verileri entropi kodlama deposuna yaklaşmak, eşleştirmek ve hatta yenmek için sıkıştırılabilir mi? Öyleyse nasıl?


19

Simüle edilmiş bir kart oyunu için kullandığım gerçek verilerim var. Ben sadece kartların saflarıyla ilgileniyorum, takım elbise ile değil. Ancak standart kart destesidir, bu yüzden destede her bir rütbeden sadece vardır . Güverte her el için iyi karıştırılır ve sonra tüm güverteyi bir dosyaya gönderirim. Dolayısıyla , çıktı dosyasında olan olası sembol vardır . ( = on derece). Yani tabii ki bu kullanarak bitpack edebilir sembol başına bit, ama sonra harcıyorsun arasında olası kodlamalardan. Bir seferde sembolü gruplandırıp sıkıştırırsak daha iyisini yapabiliriz , çünkü524132,3,4,5,6,7,8,9,T,J,Q,K,AT43164134 = ve yerine bite "rahatça" sığabilir . Teorik bitpacking limiti, olası her kart için rastgele sembol içeren veriler için log ( ) / log ( ) = . Ancak bu destede kral olamaz . Her güvertede her rütbeden sadece olmalıdır ZORUNLU, böylece entropi sembol başına yaklaşık yarım bit yaklaşık düşer .28,56115161323.70044135243.2

Tamam, işte burada düşünüyorum. Bu veriler tamamen rastgele değil. Her bir rütbeden olduğunu biliyoruz, bu yüzden kartın her bloğunda (karışık bir deste olarak adlandırın), böylece birkaç varsayım ve optimizasyon yapabiliriz. Bunlardan biri, en son kartı kodlamak zorunda değiliz, çünkü ne olması gerektiğini bileceğiz. Bir başka tasarruf da tek bir rütbede bitersek olurdu; örneğin, destedeki son kart , bunları kodlamak zorunda kalmayacağız çünkü kod çözücü o noktaya kadar kartları sayar ve diğer tüm sıralamaların doldurulduğunu ve " eksik "kartların hepsi s.452377737

Bu nedenle, bu siteye sorum, bu tür veriler üzerinde daha da küçük bir çıktı dosyası elde etmek için başka hangi optimizasyonların mümkün olduğu ve bunları kullanırsak, sembol başına bitlik teorik (basit) bitpacking entropisini veya hatta sembol başına ortalama bitlik nihai entropi sınırına yaklaşıyor mu? Öyleyse nasıl?3.700443.2

Bir ZIP tipi program (örneğin WinZip) kullandığımda, sadece sıkıştırma görüyorum , bu da bana sadece bitlik "tembel" bir bitpack yaptığını söylüyor . Verileri kendi bitpack'imi kullanarak "önceden sıkıştırırsam", daha iyi gibi görünüyor, çünkü daha sonra bir zip programı ile çalıştırdığımda, sıkıştırmadan biraz fazla alıyorum . Düşündüğüm şey, neden tüm sıkıştırmayı kendim yapmıyorum (çünkü veriler hakkında Zip programından daha fazla bilgiye sahibim). Günlük ( ) / log ( ) = entropi "limitini" kaldırabilir miyim merak ediyorum2:142:11323.70044. Bahsettiğim birkaç "hile" ile yapabileceğimi ve muhtemelen daha fazlasını bulabileceğimden şüpheleniyorum. Çıktı dosyasının elbette "insan tarafından okunabilir" olması gerekmez. Kodlama kayıpsız olduğu sürece geçerlidir.

İşte milyon insan tarafından okunabilen karıştırılmış güverte bağlantısı ( her satıra ). Herkes bu satırların küçük bir alt kümesinde "pratik" yapabilir ve daha sonra tüm dosyayı kopyalamasına izin verebilir. Bu verilere dayanarak en iyi (en küçük) dosya boyutumu güncellemeye devam edeceğim.131

https://drive.google.com/file/d/0BweDAVsuCEM1amhsNmFITnEwd2s/view

Bu arada, bu verilerin ne tür bir kart oyunu ile ilgilendiğinizde, aktif sorumun bağlantısı ( puan ödül ile). Veri depolama alanı büyük miktarda gerektireceği için (tam olarak) çözmek zor bir sorun olduğu söylendi. Ancak bazı simülasyonlar yaklaşık olasılıklarla aynı fikirde. Henüz hiçbir matematiksel çözüm sunulmamıştır (henüz). Çok zor sanırım.300

/math/1882705/probability-2-player-card-game-with-multiple-patterns-to-win-who-has-the-advant

Örnek verilerimde ilk güverte kodlamak için bit gösteren iyi bir algoritma var . Bu veriler, Fisher-Yates karıştırma algoritması kullanılarak rastgele oluşturulmuştur. Bu gerçek rastgele verilerdir, bu yüzden yeni oluşturulan algoritmam ÇOK iyi çalışıyor gibi görünüyor, bu da beni mutlu ediyor.168

Sıkıştırma "meydan okuma" ile ilgili olarak, şu anda güverte başına yaklaşık 160 bit. Sanırım belki 158'e inebilirim. Evet denedim ve güverte başına 158.43 bit aldım. Ben algoritma sınırına yaklaşıyorum düşünüyorum, bu yüzden güverte başına 166 bit altına düşmeyi başardı ama kart başına 3 bit olacağını 156 bit alamadım ama eğlenceli bir egzersiz oldu. Belki de gelecekte her desteyi ortalama 2,43 bit veya daha fazla azaltacak bir şey düşüneceğim.


8
Bu karıştırılmış desteleri kendiniz oluşturuyorsanız (örneğin, fiziksel bir kart destesinin durumunu tanımlamak yerine), desteyi saklamanız gerekmez - desteyi oluşturan RNG tohumunu saklamanız yeterlidir.
jasonharper

3
Açıklamanız ve cevaplarınız genellikle aralık kodlaması olarak bilinen bir kavrama çok benziyor ( en.wikipedia.org/wiki/Range_encoding ). Her karttan sonra olasılıkları kalan olası kartları yansıtacak şekilde uyarlarsınız.
H. Idden

Yorumlar uzun tartışmalar için değildir; bu sohbet sohbete taşındı .
Gilles 'SO- kötü olmayı kes'

Yanıtlar:


3

Dikkate alınması gereken başka bir şey: Sadece birkaç milyon deste setini sıkıştırmayı önemsiyorsanız ve hangi sırayla olduklarını umursamıyorsanız, güverte kümesinin siparişi hakkındaki bilgileri atarak ek kodlama esnekliği elde edebilirsiniz. . Örneğin, tüm desteleri numaralandırmak ve işlemek için seti yüklemeniz gerekiyorsa, ancak hangi sırayla işlendiklerine aldırmıyorsanız, durum böyle olacaktır.

Diğer cevapların nasıl yapılacağını açıkladığı gibi, her desteyi ayrı ayrı kodlayarak başlarsınız. Ardından, bu kodlanmış değerleri sıralayın. Sıralanan kodlanmış değerler (ilk farkın kodlanmış güverte '0' dan başladığı) arasında bir dizi fark saklayın. Çok sayıda deste verildiğinde, farklar tam kodlama aralığından daha küçük olma eğilimindedir, bu nedenle küçük farkları verimli bir şekilde saklarken arada sırada büyük farkları ele almak için bir çeşit varyasyon kodlaması kullanabilirsiniz. Uygun varint şeması, sette kaç deste olduğunuza bağlıdır (böylece ortalama fark boyutunu belirler).

Ne yazık ki, bunun sıkıştırmanıza ne kadar yardımcı olacağını matematiği bilmiyorum, ancak bu fikrin dikkate alınmasında yararlı olabileceğini düşündüm.


1
Çok kabaca konuşursak, birkaç milyon rastgele desteğiniz varsa, ortalama farklar tam aralığın biri (birkaç milyonda) olacaktır, yani değer başına yaklaşık 20 şey bit tasarruf etmeyi beklersiniz. Varint kodlamanız için biraz kaybedersiniz.
Steve Jessop

2
@DavidJames: Eğer özel güverte sırası önemli değilse, sadece önyargı yok, dekompresyondan sonra 3 milyon deste yeniden karıştırılabilir (yani güvertelerden herhangi birini değiştirmeyin, sadece sırasını değiştirin 3 milyon deste listesi).
Steve Jessop

2
Bu, sipariş bilgileri önemli değilse bilgi içeriğini biraz daha azaltmanın bir yoludur; önemliyse, bu geçerli değildir ve yok sayılabilir. Bununla birlikte, güverte kümesinin sıralanmasının tek önemi 'rastgele' ise, @SteveJessop'un belirttiği gibi, dekompresyondan sonra siparişi rastgele ayarlayabilirsiniz.
Dan Bryant

@DavidJames Destelerinizin ilk 173'ünün KKKK ile başladığını ve diğer birkaç milyona bakmadığını görmek ve hepsinin KKKK ile başladığı sonucuna varmak oldukça aptalca bir şey. Özellikle açık bir şekilde sıralıysalar.
user253751

3
@DavidJames: bu veriler sıkıştırılır ve dekompresyon rutini istenirse yeniden rastgele hale getirilebilir. "Bazı saf insanlar" hiçbir şey alamayacak, hatta kart destesi olarak nasıl yorumlanacağını bile anlamayacaklar. Öyle değil (bu durumda kayıplı biçim) bir veri depolama biçiminde bir kusur, bunu kullanarak o kimse doğru verileri elde etmek KKO gerekiyor.
Steve Jessop

34

İşte teorik sınıra ulaşan eksiksiz bir algoritma.

Prolog: Tamsayı dizilerini kodlama

13 tamsayı dizisi "üst limit ile tam sayı, üst limit ile tam sayı," üst limit ile tam sayı, üst limit ile tam sayı, ... üst limit ile tam sayı " her zaman mükemmel verimlilikle kodlanabilir.B - 1 c - 1 d - 1 m - 1a1b1c1d1m1

  1. İlk tamsayıyı alın, çarpın, ikinciyi ekleyin, sonucu çarpın, üçüncüyü ekleyin, sonucu çarpın,… sonucu çarpın , onüçüncü ekleyin - ve bu arasında benzersiz bir sayı üretecektir ve .c d m 0 a b c d e f g h i j k l m - 1bcdm0abcdefghijklm1
  2. Bu sayıyı ikili olarak yazın.

Bunun tersi de kolaydır. Bölerek ve geri kalan on üçüncü tamsayıdır. Sonucu ile ayırın ve geri kalan onikinci tam sayıdır. Siz bölünene kadar devam edin : Kalan kısım ikinci tamsayıdır ve bölüm ilk tamsayıdır.l bmlb

Kartlarınızı mümkün olan en iyi şekilde kodlamak için tek yapmamız gereken 13 tamsayı dizileri (verilen üst limitlerle birlikte) ve karıştırılmış kartlarınızın düzenleri arasında mükemmel bir yazışma bulmaktır.

İşte nasıl yapılacağı.

Karıştırma ve tamsayı dizileri arasındaki yazışmalar

Önünüzdeki masada 0 kartlık bir sıra ile başlayın.

Aşama 1

Paketinizdeki dört 2'yi alın ve masanın üzerine yerleştirin.

Hangi seçeneklerin var? Bir kart veya kartlar, masa üzerinde bulunan sekansın başına veya bu sekanstaki kartlardan herhangi birine yerleştirilebilir. Bu durumda, kart koymak için olası yer olduğu anlamına gelir .1+0=1

1 yere 4 kart yerleştirmenin toplam yolu . Bu yolların her birini ile arasında bir sayı olarak kodlayın . Böyle bir sayı var.0 1 - 11011

0 yazmanın yollarını 5 tamsayı toplamı olarak düşünerek 1 aldım: .4×3×2×14!

Adım 2

Paketinizdeki dört 3'ü alın ve masanın üzerine yerleştirin.

Hangi seçeneklerin var? Bir kart veya kartlar, masa üzerinde bulunan sekansın başına veya bu sekanstaki kartlardan herhangi birine yerleştirilebilir. Bu durumda, kart koymak için olası yer olduğu anlamına gelir .1+4=5

5 yere 4 kart yerleştirmenin toplam yolu . Bu yolların her birini ile arasında bir sayı olarak . 70 tane sayı var.0 70 - 1700701

4 yazma biçimini 5 tamsayı toplamı olarak düşünerek 70'im var: .8×7×6×54!

Aşama 3

Dört adet 4s'i paketinize alın ve masanın üzerine yerleştirin.

Hangi seçeneklerin var? Bir kart veya kartlar, masa üzerinde bulunan sekansın başına veya bu sekanstaki kartlardan herhangi birine yerleştirilebilir. Bu durumda, kart koymak için olası yer olduğu anlamına gelir .1+8=9

9 yere 4 kart yerleştirmenin toplam yolu . Bu yolların her birini ile arasında bir sayı olarak . 495 tane sayı var.0 495 - 149504951

8'i 5 tamsayı toplamı olarak düşünerek 495 aldım: .12×11×10×94!

Ve böyle devam edene kadar ...

Adım 13

Dört ası paketinize alın ve masanın üzerine yerleştirin.

Hangi seçeneklerin var? Bir kart veya kartlar, masa üzerinde bulunan sekansın başına veya bu sekanstaki kartlardan herhangi birine yerleştirilebilir. Bu durumda, kart koymak için olası yer olduğu anlamına gelir .1+48=49

49 yere 4 kart yerleştirmenin toplam yolu . Bu yolların her birini ile arasında bir sayı olarak . 270725 bu numaralar var.0 270.725 - 127072502707251

48 yazmanın yollarını 5 tamsayı toplamı olarak düşünerek 270725 aldım: .52×51×50×494!


Bu prosedür, (a) takım elbise ile ilgilenmediğiniz kartların karıştırılması ile (b) birincisi ile arasında, ikincisi ile , üçüncüsü ila arasındadır , ve on kadar, yani ile arasındadır .1 - 1 0 70 - 1 0 495 - 1 0 270725 - 101107010495102707251

"Tamsayı dizilerini kodlama" ile ilgili olarak, böyle bir tamsayı dizisinin ve arasındaki sayılar ile 1-1 arasında olduğunu . Eğer tamsayılar her (ifadesi "bir faktöryel bölü ürünün" bakarsak her adımın sonunda italik anlatıldığı gibi ) o zaman göreceksiniz bu vasıta arasındaki sayılar ve önceki cevabımın gösterebileceği en iyi şeydi.( 1 × 70 × 495 × × 270725 ) - 1 0 52 !0(1×70×495××270725)10

52!(4!)131,

Bu yüzden karıştırılmış kartlarınızı sıkıştırmak için mükemmel bir yöntemimiz var.


Algoritma

0'ı 5 tamsayıların toplamı, 4'ü 5 tamsayıların toplamı, 8'i 5 tamsayıların toplamı,… 48'i 5 tamsayıların toplamı olarak yazmanın tüm yollarının bir listesini hazırlayın . En uzun liste 270725 elemente sahiptir, bu yüzden özellikle büyük değildir. (Önceden hesaplama kesinlikle gerekli değildir, çünkü her listeyi ihtiyacınız olduğunda ve gerektiğinde kolayca sentezleyebilirsiniz: Microsoft QuickBasic ile denemek, 270725 element listesinden geçmek bile gözün görebildiğinden daha hızlıydı)

Karıştırmadan tamsayılar dizisine geçmek için:

2'ler hiçbir katkıda bulunmaz, bu yüzden onları görmezden gelelim. 0 ile 1-1 arasında bir sayı yazın.

3'ler: İlk 3'ten önce kaç tane 2 var? İkinci saniyeden önce kaç kişi? üçüncü? 4.? 4.den sonra mı? Bu sorunun cevabı 4'e kadar olan 5 tamsayıdır. Bu nedenle, "4'ü 5 tamsayıların toplamı" listenizde yazan 5 tamsayı dizisine bakın ve bu listedeki konumunu not edin. Bu, 0 ile 70-1 arasında bir sayı olacaktır. Bir yere yaz.

4s: İlk 4'ten önce kaç tane 2 veya 3 tane var? İkinci saniyeden önce kaç kişi? üçüncü? 4.? 4.den sonra mı? Bu sorunun cevabı, açıkça 8'e kadar toplayan 5 tamsayıdır. Bu nedenle, "yazma 8'in 5 tamsayıların toplamı" listenizdeki 5 tamsayı dizisine bakın ve bu listedeki konumunu not edin. Bu 0 ile 495-1 arasında bir sayı olacaktır. Bir yere yaz.

Ve böyle devam edene kadar…

Aslar: İlk asdan önce kaç tane as olmayan kart var? İkinci saniyeden önce kaç kişi? üçüncü? 4.? 4.den sonra mı? Bu sorunun cevabı, açıkça 48'e kadar toplayan 5 tamsayıdır. Bu nedenle, "48'i 5 tamsayıların toplamı" listenizde yazan 5 tamsayı dizisine bakın ve bu listedeki konumunu not edin. Bu 0 ile 270725-1 arasında bir sayı olacaktır. Bir yere yaz.

Şimdi 13 tamsayı yazdınız. Bunları (daha önce açıklandığı gibi) ile arasında tek bir sayıya kodlayın . Bu sayıyı ikili olarak yazın. 166 bit'in biraz altında olacak.52 !052!(4!)13

Bu mümkün olan en iyi sıkıştırmadır, çünkü bilgi teorik sınırına ulaşır.

Dekompresyon basittir: büyük sayıdan 13 tamsayı dizisine gidin ve daha sonra bunları daha önce açıklandığı gibi kart dizisini oluşturmak için kullanın.


Yorumlar uzun tartışmalar için değildir; bu sohbet sohbete taşındı .
DW

Bu çözüm benim için belirsiz ve eksik. 166 bit numarasının nasıl alınacağını ve güverte içine nasıl çözüleceğini göstermez. Benim için gebe kalmak hiç kolay değil, bu yüzden nasıl uygulanacağını bilmeyeceğim. Basamaklı formülünüz temel olarak ayırıyor formülü parça halinde bana çok yardımcı olmuyor. Kartları düzenlemek için 70 olası yolu ile belki adım 2 için bir diyagram veya grafik yapsaydı yardımcı olacağını düşünüyorum. Çözümünüz beynimin kabul edip işleyemeyeceği kadar soyut. Gerçek örnekleri ve çizimleri tercih ederim. 1352!/(4!13)13
David James

23

Her kartı ayrı ayrı 3 veya 4 bite kodlamaya çalışmak yerine, tüm destenin durumunu 166 bite kodlamanızı öneririm. Martin KOCHANSKI olarak açıklıyor , daha az vardır tüm güverte devlet 166 bit saklanabilir o yollarla böylece takım elbise görmezden kartların olası düzenlemeleri,.2166

Bu sıkıştırma ve açma işlemini etkili bir şekilde algoritmik olarak nasıl yaparsınız? Sözlüksel sıralama ve ikili arama kullanmanızı öneririm. Bu, geniş bir arama tablosu veya diğer gerçekçi olmayan varsayımlara ihtiyaç duymadan, sıkıştırma ve dekompresyonu verimli bir şekilde (hem boşlukta hem de zamanda) yapmanızı sağlar.

Daha ayrıntılı olarak: Güvertenin sıkıştırılmamış temsili üzerinde sözlükbilimsel sıralama kullanarak güverteler sipariş edelim, yani bir güverte sıkıştırılmamış biçimde 22223333444455556666777788889999TTTTJJJQQKKKKAAAA; sözlükbilim sırasına göre sipariş edebilirsiniz. Şimdi, güvertesi verilen , ondan önce gelen güverte sayısını (sözlükbilimsel sırayla) sayan bir prosedürünüz olduğunu varsayalım . Sonra bir güverte sıkıştırmak için bu yordamı kullanabilirsiniz: bir güverte D verildiğinde , sıkıştırmak, ondan önce gelen güverte sayısını sayarak ve sonra bu sayıyı çıkararak 166 bitlik bir sayıdır. Bu sayı destenin sıkıştırılmış temsilidir.DD

Sıkıştırmak için ikili aramayı kullanın. Bir sayısı verildiğinde, tüm güvertelerin sözlük sıralamasında n. Desteyi bulmak istersiniz . Sen ikili arama çizgisinde bir prosedürü kullanarak bunu yapabilirsiniz: Bir deste almak D 0 , önce deste sayısını saymak D 0 ve yaptıklarıyla karşılaştırın n . Bu, D 0'ı ayarlayıp ayarlamayacağınızı söyleyecektirnnD0D0nD0erken ya da geç gelmek. Simgeyi yinelemeli olarak doğru şekilde denemenizi öneririm: 22223333444455556666777788889999TTTTJJJJQQQQKKKKAAAA gibi bir dizeyi kurtarmak istiyorsanız, ilk önce dizede ilk sembol olarak ne kullanacağınızı bulmak için arama yapın (12 olasılıkın tamamını deneyin veya 12 olasılık üzerinden ikili arama yapın) ), ardından ilk sembol için doğru değeri bulduğunuzda, ikinci sembolü bulmak için arama yapın vb.

Geriye kalan tek şey önce sözlükbilimsel olarak gelen güverte sayısını saymak için etkili bir prosedür bulmaktır . Bu basit ama sıkıcı bir kombinatoryal egzersize benziyor. Özellikle, aşağıdaki sorun için bir alt yordam oluşturmanızı öneririm: bir önek (222234 gibi) verildiğinde, bu önekle başlayan deste sayısını sayın. Bu sorunun cevabı, binom katsayıları ve faktöriyelerinde oldukça kolay bir egzersiz gibi görünüyor. Ardından, D'den önce gelen güverte sayısını saymak için bu alt programı az sayıda çağırabilirsiniz .DD


Yorumlar uzun tartışmalar için değildir; bu sohbet sohbete taşındı .
DW

8

Kartları olası düzenlemelerin sayısı görmezden takım elbise olduğunu logaritma tabanı 2 165.976 veya kart başına 3.1919 bittir, bu da verdiğiniz sınırdan daha iyidir.

52!(4!)13,

Sabit "kart başına bit" kodlaması anlamlı olmaz çünkü not ettiğiniz gibi son kart her zaman bit olarak kodlanabilir ve birçok durumda son birkaç kart da olabilir. Bu, paketin "kuyruğuna" doğru bir yol için, her kart için gereken bit sayısının düşündüğünüzden çok daha az olacağı anlamına gelir.0

Verileri sıkıştırmanın en iyi yolu, yine de kart verilerinizle paketlemek istediğiniz 59 bit başka veri bulmak (aslında 59.6 bit) ve bu 59 biti 13 basamaklı bir sayı modülü 24 (= ), Her karta bir takım elbise atayın (bir rakam aslara takım elbise atamanın 4 ! Yolu arasında seçim yapar, diğeri krallar için aynı şeyi yapar). Sonra 52 farklı karttan oluşan bir paketiniz var. 52 ! olasılıklar gerçekten de 225.58 bit ile kolayca kodlanabilir.4!4!52!

Ancak bu ekstra bitleri kodlama fırsatını kullanmadan yapmak da bir dereceye kadar mümkündür ve bunu herkesin olduğundan emin olduğum gibi düşüneceğim. Gerçekten ilginç bir sorun için teşekkür ederim!


1
Burada şifreli metin çalmaya benzer bir yaklaşım kullanılabilir mi? Bu ekstra 59 bitte kodladığınız veriler, kodlanmış gösterimin son 59 bitidir?
John Dvorak

@JanD Böyle bir şeyi araştırmayı düşünüyordum. Ama sonra teorik sınıra ulaşan ve basit ve% 100 güvenilir bir algoritmanın var olduğu ortaya çıktı , bu yüzden daha fazla bakmanın bir anlamı yoktu.
Martin Kochanski

@MartinKochanski - Bunu "takım elbise görmezden gelmek" olarak söylemezdim çünkü hala rütbe başına standart 4 elbiseyi onurlandırıyoruz. Daha iyi ifade "Güverte olası farklı düzenleme sayısı" olabilir ...
David James

3

Bu uzun zamandır çözülmüş bir sorundur.

52 kartlık bir desteyle oynadığınızda, dağıttığınız her kartta bilinen olasılıklarla 13 sıralamadan biri bulunur. Dağıtılan her kartla olasılıklar değişir. Bu, adaptif aritmetik kodlama, Huffman kodlamasında bir gelişme olarak adlandırılan eski bir teknik kullanılarak en iyi şekilde ele alınır. Genellikle bu bilinen, değişmeyen olasılıklar için kullanılır, ancak olasılıkları değiştirmek için de kullanılabilir. Aritmetik kodlama ile ilgili wikipedia makalesini okuyun:

https://en.wikipedia.org/wiki/Arithmetic_coding


Tamam, ama bu teorik entropi kodlama sınırına yaklaşabilir, eşleşebilir veya yenebilirse sorumu yanıtlamıyor. Görünüşe göre, her biri 1 / n olasılıklı n olası güverte olduğundan, entropi kodlaması sınırdır ve daha iyisini yapamayız (kod çözücüye "hile" ve kod çözücüye giriş verileri hakkında bir şey söylemedikçe).
David James

3

Hem DW hem de Martin Kochanski, aralıktaki anlaşmalar ve tamsayılar arasında bir bijection oluşturmak için algoritmalar tanımlamıştı , ancak hiçbiri sorunu en basit şekline indirmemiş gibi görünüyor. (Not 1)[0,52!(4!)13)

Biz sipariş listesi tarafından tarif edilen (kısmi) güverte olduğunu varsayalım , bir I tipi kart sayısı olan i . OP'de, ilk güverte, her biri 4 değerine sahip 13 öğeden oluşan bir liste ile tanımlanır. Böyle bir destenin farklı shuffle sayısı,aaii

c(a)=(ai)!ai!

bu, binom katsayılarının basit bir genellemesidir ve gerçekten de objeleri, Martin Kochanski'nin önerdiği gibi, her seferinde tek tip olarak düzenleyerek kanıtlanabilir. (Aşağıya bakın, not 2)

Şimdi, bu tür herhangi bir (kısmi) destede, bir i > 0 olan herhangi bir kullanarak bir seferde bir kart karıştırmayı seçebiliriz . Eşsiz değişikliğinin sayısı başlangıç i olaniai>0i

{0if ai=0c(a1,...,ai1,ai1,ai+1,...,an)if ai>0.

ve yukarıdaki formülle,

c(a1,...,ai1,ai1,ai+1,...,an)=aic(a)ai

Karışık kadar önek daha öneki tekabül karıştırır sayısı sözlük sırasında küçük gözlenmesiyle tamamlanana kadar Sonra güverteye recurse (veya yineleme) olabilir olduğui

c(a)j=1iajj=1naj

Bunu algoritmayı göstermek için Python'da yazdım; Python herhangi bir sahte koddur. Aritmetiğin çoğunun genişletilmiş hassasiyet içerdiğini unutmayın; değerleri (karışık sıralı temsil eder) ve N (kalan kısmi güverte mümkün shuffles toplam sayısı), hem 166 bit bignums bulunmaktadır. Kodu başka bir dile çevirmek için bir çeşit bignum kütüphanesi kullanmak gerekecektir.kn

Ayrıca, sadece kart isimleri yerine tamsayıların listesini kullanıyorum ve - yukarıdaki matematiklerin aksine - tamsayılar 0 tabanlı.

Bir shuffle'ı kodlamak için, her formülde yukarıdaki formülü kullanarak daha küçük bir kartla başlayan shuffle sayısını biriktirerek shuffle boyunca yürüyoruz:

from math import factorial
T = factorial(52) // factorial(4) ** 13

def encode(vec):
    a = [4] * 13
    cards = sum(a)
    n = T
    k = 0
    for idx in vec:
        k += sum(a[:idx]) * n // cards
        n = a[idx] * n // cards
        a[idx] -= 1
        cards -= 1
    return k

166 bitlik bir sayının deşifre edilmesi basit tersidir. Her adımda, kısmi bir deste ve bir ordinal tanımımız var; sıraya karşılık gelen karttan daha küçük kartlarla başlayarak karıştırmaları atlamamız ve ardından seçilen kartı çıktıyı hesaplamamız, kalan desteden çıkarmamız ve olası önekle seçili önekle ayarlamamız gerekir:

def decode(k):
    vec = []
    a = [4] * 13
    cards = sum(a)
    n = T
    while cards > 0:
        i = cards * k // n
        accum = 0
        for idx in range(len(a)):
            if i < accum + a[idx]:
                k -= accum * n // cards
                n = a[idx] * n // cards
                a[idx] -= 1
                vec.append(idx)
                break
            accum += a[idx]
        cards -= 1
    return vec

Yukarıdaki kodu optimize etmek için gerçek bir girişimde bulunmadım. encode(decode(line))Orijinal kodlama ile sonuçlanan kontrol, tüm 3mil.TXT dosyasına karşı koştu ; 300 saniyenin biraz altında sürdü. (Satırlardan yedisi ideone on-line testinde görülebilir .) Daha düşük bir dilde yeniden yazmak ve bölünmeyi optimize etmek (mümkün olan) muhtemelen bu süreyi yönetilebilir bir şeye indirecektir.

Kodlanan değer basitçe bir tamsayı olduğu için 166 bit olarak verilebilir. Baştaki sıfırları silmenin bir değeri yoktur, çünkü o zaman bir kodlamanın nerede sonlandığını bilmenin bir yolu olmayacaktır, bu yüzden gerçekten 166 bit kodlamadır.

Bununla birlikte, pratik bir uygulamada, bir shuffle'ı kodlamanın muhtemelen gerekli olmadığını belirtmek gerekir; rastgele bir rasgele 166-bit sayı üreterek ve kodunu çözerek bir rastgele karıştırma üretilebilir. Ve 166 bitin hepsinin rastgele olması gerekli değildir; örneğin, 32-bit rasgele bir tamsayı ile başlamak ve daha sonra 32-bit sayı ile ekilmiş herhangi bir standart RNG kullanarak 166 bit doldurmak mümkün olacaktır. Dolayısıyla, amaç çok sayıda rastgele karıştırmayı tekrarlanabilir bir şekilde depolamaksa, anlaşma başına depolama gereksinimini az çok keyfi olarak azaltabilirsiniz.

Nlog2N

N k

  1. plog2N

  2. 2pkpkpN(kp)

  3. 2p0012p+N2p 1N 0

01

N(kp)+N+2pN(kp)+N+NN(kp+2)kp+2

notlar

  1. 52!(4!)1392024242230271040357108320801872044844750000000000log252!(4!)13165.9765166
  2. Ski=knaia11(S1a1)( S 22 ( Si(S2a2)(Siai)=Si!ai!(Siai)!=Si!ai!Si+1!

i=1nSi!i=1nai!Si+1!

Bu, yukarıdaki formüle basitleştirir.


Yorumlar uzun tartışmalar için değildir; bu sohbet sohbete taşındı .
DW

@rici - Kodla birlikte daha iyi bir sunum gibi görünen cevabınızı açıkladığınız +100 ödül cuzunu verdim, diğer cevaplar daha soyut / teorikken, kodlama / kod çözmenin gerçekte nasıl uygulanacağına dair bazı ayrıntılar bıraktı. Bildiğiniz gibi, kod yazarken birçok ayrıntı var. Benim algoritmamın en basit, basit, anlaşılması kolay olmadığını itiraf ediyorum ama aslında çok fazla çaba harcamadan çalıştım ve zamanla daha fazla sıkıştırma ile daha hızlı çalışmasını sağlayabiliyorum. Cevabınız için teşekkürler ve iyi çalışmaya devam edin.
David James

2

Bu soruna alternatif bir çözüm olarak, algoritmam, kaç tane doldurulmamış sıralama kaldığına bağlı olarak destedeki kart grupları için kart başına bileşik kesirli (tamsayı olmayan) bitler kullanır. Oldukça zarif bir algoritmadır. Kodlama algoritmamı elle kontrol ettim ve iyi görünüyor. Kodlayıcı, doğru bit dizeleri gibi görünen çıktıları (basitlik için bayt formunda) çıkarır.

3754A236J7131372613762,748,51722667,108,864241313428,56121532,76815/4=3.7526/7=3.71426/7

54A236J23456789TJQKA547131015,565,9752600111011011000010010010111

2615,565,9751354A236J7

13,12,11...,2,1)13,12,11...21312122125248,832218262,14418/53.61326/73.71455553333

İşte tüm olası sıra sayısı için maliyetlerin tam listesi (kart başına bit sayısı):

13    26/7=3.714=3  5/7
12    18/5=3.600=3  3/5
11      7/2=3.500=3  1/2
10    10/3=3.333=3  1/3
  9    16/5=3.200=3  1/5
  8      3/1=3.000=3
  7    17/6=2.833=2  5/6
  6    13/5=2.600=2  3/5
  5      7/3=2.333=2  1/3
  4      2/1=2.000=2
  3      5/3=1.667=1  2/3
  2      1/1=1.000=1
  1      0/1..4=0.0=0

75,6,7,7,7,7,KK1312713K21,2,3...3131720

16813,12,11

10777748747s. Eğer güverte bir çift (77 gibi), üçlü / set (777 gibi) veya dörtlü (7777 gibi) ile biterse, algoritmamı kullanarak bu güverte için ek tasarruf elde ederiz.

3222613163232

Veri dosyasındaki ilk destede, kartların kodlanması aşağıdaki gibidir (daha sonra gelecek diyagram). Biçim (grup boyutu, bitler, sıralama kodlama modu):

7,26,1372613
7,26,13
7,26,13
5,18,12
5,18,12
3,10,10
3,  9,  8
6,17,  7
5,13,  6
3,  5,  3
1,  0,  1

521683.23

181/33.23.254545454722772277...322223333444455556666777788889999TTTTJJJJQQQQKKKKAAAA40

1103,7K8101kart kaldı. Bu önemlidir, çünkü kod çözücü ilave mesajlar iletmek zorunda kalmadan kod çözücü doğru varsayımlar yapabildiğinde kodlama işlemini daha verimli hale getirir.

313121110

         26             26             26            18         18       10      9          17           13        5     0
    54A236J  87726Q3  3969AAA  QJK7T  9292Q  36K  J57   T8TKJ4  48Q8T  55K  4
13                                            12                    xy     98         7              6        543     2 1  0

2166175168bit. Güverte sonunda sadece tek bir 4 var, ancak bunun yerine dört 4s'nin hepsi varsa, bu daha iyi bir durumdur ve bu güverteyi kodlamak için sadece 161 bite ihtiyacımız olurdu, bu da ambalajın sıralı pozisyonunun düz bir ikili kodlamasının entropisi.

Şimdi bit gereksinimlerini hesaplamak için uygulanan kod var ve ortalama 3 milyon güverte test dosyası için 155 düşük ve 183 yüksek güverte başına yaklaşık 175 bit gösteriyor. Yani algoritmam sıra başına pozisyon yönteminin düz ikili kodlamasına karşı güverte başına 9 ekstra bit kullanıyor gibi görünüyor. Sadece% 5,5 ilave depolama alanında çok kötü değil. 176 bit tam olarak 22 bayttır, bu nedenle güverte başına 52 bayttan biraz daha iyidir. 136 bite kadar en iyi durum güvertesi (3 milyon güverte test dosyasında görünmedi) paketleri ve en kötü durum güvertesi (8206 kez test dosyasında göründü), 183 bittir. Analiz, en kötü durumun kart 40'a (veya kartın) yakınına kadar (veya dört kartta) ilk çeyreği alamadığımız durum olduğunu gösterir. Daha sonra kodlama modu hızlı bir şekilde düşmek istediği için, daha yüksek bit kodlama modu. Kart 40'a kadar dörtlü almamanın iyi karıştırılmış bir desteyi kullanarak oldukça nadir olacağını düşünebilirim, ancak programım bana her 3 milyon desteğin test dosyasında 321 kez olduğunu ve her 9346 desteden yaklaşık 1'inde olduğunu söylüyor. Bu daha çok beklerdim. Bu durumu kontrol edebilir ve daha az bitle başa çıkabilirim, ancak ortalama bitleri yeterince etkilemeyecek kadar nadirdir.

Ayrıca burada çok ilginç başka bir şey var. Ham güverte verilerinde desteyi sıralarsam, önemli sayıda # tekrar eden öneklerin uzunluğu yalnızca yaklaşık 6'dır (222244 gibi). Bununla birlikte, paketlenmiş verilerle bu uzunluk yaklaşık 16'ya yükselir. Bu, paketlenmiş verileri sıralarsam, kod çözücüye sadece 16 bit önek belirterek ve sadece desteğin kalanını çıkararak önemli bir tasarruf elde edebilmem gerektiği anlamına gelir. (önek eksi eksi) ekini tıklayın, ardından bir sonraki önekin üzerine gelin ve işlemi tekrarlayın. Güverte başına sadece 10 bit kurtardığımı varsayarsak, güverte başına 166 bit yendi. Başkaları tarafından belirtilen numaralandırma tekniğiyle, önekin algoritmamla olduğu kadar uzun olacağından emin değilim. Ayrıca algoritmamı kullanarak paketleme ve açma hızı şaşırtıcı derecede iyi.

Algoritmamın çıkış bit dizilerini sıraladığım 2. sıkıştırma düzeyiyle ilgili olarak, "fark" kodlamasını kullanın: Çok basit bir yöntem, çıkış verilerinde en az iki kez görünen 61.278 benzersiz 16 bit önekleri kodlamak (ve bir maksimum 2. seviye dekompresöre bir önek kodladığımızı (0000111100001111 gibi) göstermek için çıkıştaki 0 ​​önde gelen bit olarak ve daha sonra aynı önekle paketlenmiş tüm desteler, paketlenmiş destenin önek olmayan kısmını belirtir. Aynı önekle paketlenmiş güvertelerin ortalama sayısı, benzersiz olanlardan azı dahil olmak üzere her önek için yaklaşık 49'dur (yalnızca 1 destenin belirli öneki vardır). Görünüşe göre bu basit stratejiyi kullanarak (ortak önekleri bir kez saklayarak) güverte başına yaklaşık 15 bit kaydedebilirim.

Birinci kodlayıcının sıralı bit dizisi çıktısının fark (önek) kodlamasını kullanarak 2. sıkıştırma seviyesinden sonra, şimdi güverte başına yaklaşık 160 bit alıyorum. Uzunluk 18 önekini kullanıyorum ve sadece sağlam saklıyorum. Olası 18 bit öneklerin neredeyse tamamı (262144 =% 93,5) 245013 olduğundan, önekleri kodlamak daha da iyi olacaktır. Belki de sahip olduğum veri türünü kodlamak için 2 bit kullanabilirim. 00 = normal uzunluk 18 önek kaydedildi, 01 = "1 yukarı önek" (eklenen 1 hariç önceki önekle aynı), 11 = 1. seviye ambalajdan düz kodlama (ortalama yaklaşık 175 bit). 10 = kodlamak için bitleri kurtaracak başka bir şey düşündüğümde gelecekteki genişleme.

Henüz güverte başına 160 bit yenen var mı? Yukarıda bahsettiğim 2 bit tanımlayıcıları kullanarak biraz deneme yaparak benimkini biraz düşürebilirim. Belki de 158ish dibe inecek. Amacım bunu 156 bit (veya daha iyisi) elde etmektir, çünkü bu kart başına 3 bit veya daha az olacaktır. Çok etkileyici. İlk seviye kodlamasını değiştirirsem en iyi 2. seviye kodlaması olan ve tekrar denemek için birçok kombinasyon var. Yaptığım bazı değişiklikler diğer benzer rastgele veriler için iyi olabilir, ancak bazıları bu veri kümesine doğru eğilimli olabilir. Gerçekten emin değilim ama dürtüyü alırsam, benzer sonuçlar alırsam nasıl olacağını görmek için 3 milyonluk bir güverte veri seti deneyebilirim.

1050

Herkes algoritma nasıl daha iyi kodlamak için her durumda her güverte için depolama bitlerini azaltacak diğer durumlarda gibi daha iyi yapmak hakkında herhangi bir fikri var mı? Kimse?

2 daha fazla şey: 1) Uzayda en uygun olmasa da, hala iyi ve uygulanması oldukça kolay olan daha fazla insanın çözümümü desteklemediğini hayal kırıklığına uğrattım (benim iyi çalışıyor). 2) 3 milyon deste veri dosyam üzerinde analiz yaptım ve 1. derecenin (4444 gibi) doldurduğu en sık görülen kartın 26. kartta olduğunu fark ettim. Bu, zamanın yaklaşık% 6.711'inde (3 milyon desteğin 201322'si için) olur ). Bu bilgiyi 12 sembol kodlama modunda başlamak gibi daha fazla sıkıştırmak için kullanmayı umuyordum, çünkü ortalama olarak middeck'e kadar her rütbeyi görmeyeceğimizi biliyoruz, ancak bu yöntem yükü tasarrufları aştığı için herhangi bir sıkıştırmayı başaramadı. Algoritmamda bitleri kaydedebilecek bazı değişiklikler arıyorum.

Yani kimse algoritma kullanarak güverte başına birkaç bit kaydetmek için ne denemek gerekir herhangi bir fikir var mı? Kod çözücüye hangi desenin beklemesini söyleyen ekstra yükten sonra bile güverte başına bitleri azaltabilmem için yeterince sık olan bir desen arıyorum. Kalan görünmeyen kartların beklenen olasılıkları ile bir şey düşünüyordum ve kalan tüm kartları tek bir kovaya topladım. Bu, daha düşük bir kodlama moduna daha hızlı düşmeme ve belki de bazı bitleri kaydetmeme izin verecek, ancak bundan şüpheliyim.

Ayrıca, FYI, 10 milyon rastgele karıştırmayı oluşturdum ve kolay analiz için bir veritabanında sakladım. Sadece 488'i dörtlüdür (5555 gibi). Sadece algoritmamı kullananları paketlersem, ortalama 157 bit ve yüksek 173 bit ile 165.71712 bit elde ederim. Diğer kodlama yöntemini kullanarak 166 bitin biraz altında. Bu vakanın ne kadar seyrek olduğuna biraz şaşırdım (ortalama her 20.492 karıştırmadan yaklaşık 1'i).


3
9 saat içinde yaklaşık 24 düzenleme yaptığınızı fark ettim. Cevabınızı geliştirme isteğiniz için teşekkür ederim. Ancak, yanıtı her düzenlediğinizde, bunu ön sayfanın en üstüne götürür. Bu nedenle, aşırı düzenlemeyi önermiyoruz. Çok sayıda düzenleme yapmayı bekliyorsanız, düzenlemelerinizi toplu hale getirmek mümkün olur, bu nedenle birkaç saatte bir düzenleme yapar mısınız? (Bu arada, cevabınıza "DÜZENLE:" ve "GÜNCELLEME:" ifadesini koymanın genellikle kötü bir stil olduğunu unutmayın. Bkz. Meta.cs.stackexchange.com/q/657/755. )
DW

4
Burası ilerleme raporları, durum güncellemeleri veya blog öğeleri koymak için uygun bir yer değil. "Yakında gelmek" ya da "bir çözümüm var ama ne olduğunu anlatmayacağım" şeklinde tam olarak cevaplar istiyoruz.
DW

3
Birisi ilgilenirse, geliştirilmiş çözümü bulacaktır. En iyi yol tam cevabı beklemek ve daha sonra göndermek. Bazı güncellemeleriniz varsa bir blog bunu yapar. Bunu teşvik etmiyorum, ancak gerçekten (neden geçerli bir neden göremiyorum) gerekiyorsa, yazınızın altına yorum yazabilir ve daha sonra birleştirebilirsiniz. Ayrıca tüm eski yorumları silmenizi ve bunları tek bir sorunsuz soruya dahil etmenizi öneririm - hepsini okumak zorlaşır. Sunulanlardan farklı olarak kendi algoritmamı yapmaya çalışıyorum, ancak sonuçlardan memnun değilim - bu yüzden düzenlenecek kısmi yayınlamıyorum - cevap kutusu tam olanlar için.
Kötülük

3
@DavidJames, anlıyorum. Ancak, bu yine de yönergelerimizi değiştirmez: lütfen çok fazla düzenleme yapmayın. (Web sitesinde iyileştirmeler önermek istiyorsanız, Computer Science Meta veya meta.stackexchange.com adresinde bunu öneren bir yayın yapmaktan çekinmeyin . Geliştiriciler bu yorum dizisini okumuyor .) Ancak bu arada, biz sahip olduğumuz yazılımla çalışmak ve birçok düzenleme yapmak cesaret kırıcıdır çünkü soruyu en üste çıkarır. Bu noktada, kendinizi günde bir düzenlemeyle sınırlamak çekim yapmak için iyi bir rehber olabilir. Çevrimdışı editörleri veya StackEdit'i kullanmaktan çekinmeyin!
DW

3
Cevabınızı çeşitli nedenlerle desteklemiyorum. 1) gereksiz uzun ve FAR çok ayrıntılı. Sunumunu büyük ölçüde azaltabilirsiniz. 2) Bana göre nedenlerden dolayı görmezden gelmeyi tercih ettiğiniz daha iyi cevaplar var. 3) upvotes eksikliği hakkında sormak genellikle bana bir "kırmızı bayrak". 4) Bu, INSANE düzenleme sayısı nedeniyle sürekli olarak ön sayfada kalmıştır.
Nicholas Mancuso
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.