임의의 적합한 카드 데이터를 압축하여 엔트로피 인코딩 스토리지에 접근, 일치 또는 이길 수 있습니까? 그렇다면 어떻게?


19

시뮬레이션 카드 게임에 사용중인 실제 데이터가 있습니다. 나는 소송이 아닌 카드의 등급에만 관심이 있습니다. 그러나 표준 카드 덱이므로 덱에는 개의 등급 만 있습니다. 데크는 각 손에 대해 잘 섞은 다음 전체 데크를 파일로 출력합니다. 따라서 출력 파일에는 가능한 기호 만 있습니다 . ( = 10 등급). 물론 심볼 당 비트를 사용하여 비트 팩을 비트 팩 할 수 있지만 가능한 가지 인코딩 중 를 낭비하고 있습니다. 한 번에 심볼을 그룹화 한 다음 압축하면 더 잘 수행 할 수 있습니다.524132,3,4,5,6,7,8,9,T,J,Q,K,AT43164134 = 은 대신 비트로 " "맞을 수 있습니다 . 이론적으로 비트 패킹 한도는 가능한 모든 카드에 임의의 기호가있는 데이터의 경우 log ( ) / log ( ) = 입니다 . 그러나 우리는 이 갑판에서 명의 왕을 가질 수 없습니다 . 엔트로피 인코딩은 심볼 당 약 반 비트 씩 약 떨어지도록 각 데크에 각 랭크 중 개만 있어야 합니다.28,56115161323.70044135243.2

좋아, 여기 내가 생각하는 것입니다. 이 데이터는 완전히 무작위가 아닙니다. 우리 는 각 카드 블록에 각 등급의 가 있다는 것을 알고 있으므로 (셔플 데크라고 함) 몇 가지 가정과 최적화를 할 수 있습니다. 우리는 마지막 카드를 인코딩 할 필요가 없습니다. 왜냐하면 카드가 무엇인지 알아야하기 때문입니다. 우리가 단일 순위에서 끝날 경우 또 다른 절감 효과가 있습니다. 마지막 예를 들어, 갑판에서 카드가 , 우리는 디코더가 그 시점에 계산 카드를하고 다른 모든 순위가 작성되어있는 것을 볼 것이기 때문에 사람들을 인코딩 할 필요가 없습니다 것입니다, 그리고 가정 할 것이다 " missing "카드는 모두 초입니다.452377737

따라서이 사이트에 대한 나의 질문은이 유형의 데이터에 대해 더 작은 출력 파일을 얻을 수있는 다른 최적화 방법이며, 사용하는 경우 심볼 당 비트 의 이론적 (간단한) 비트 패킹 엔트로피를 평균적으로 심볼 당 약 3.2 비트 의 최대 엔트로피 한계에 접근 합니까? 그렇다면 어떻게?3.700443.2

ZIP 유형 프로그램 (예 : WinZip)을 사용할 때 2:1 압축 만 볼 수 있습니다 . 이는 단지 "게으른" 비트 팩을 4 비트로하고 있음을 나타냅니다. 내 자신의 비트 팩킹을 사용하여 데이터를 "사전 압축"하면 압축 프로그램을 통해 데이터를 실행할 때 2:1 압축 이 약간 초과되기 때문에 더 좋아 보입니다 . 내가 생각하는 것은 모든 압축을 직접하지 않는 이유입니다 (Zip 프로그램보다 데이터에 대한 지식이 많기 때문입니다). log ( 13 ) / log ( 2 ) = 3.70044 의 엔트로피 "제한"을 이길 수 있는지 궁금합니다.3.70044. 내가 언급 한 몇 가지 "트릭"과 함께 몇 가지 더 알아낼 수있을 것 같아요. 물론 출력 파일은 "사람이 읽을 수있는"파일 일 필요는 없습니다. 인코딩이 손실이없는 한 유효합니다.

다음은 3 백만 개의 사람이 읽을 수있는 셔플 데크에 대한 링크입니다 (한 줄에 1 개). 누구나이 줄의 작은 부분 집합을 "연습"한 다음 전체 파일에서 찢어지게 할 수 있습니다. 이 데이터를 기반으로 최상의 (최소) 파일 크기를 계속 업데이트합니다.

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

그건 그렇고,이 데이터가 어떤 유형의 카드 게임에 사용되는지에 관심이 있다면, 내 적극적인 질문 ( 포인트 현상금)에 대한 링크가 있습니다. 엄청난 양의 데이터 저장 공간이 필요하기 때문에 해결하기 어려운 문제라고 들었습니다. 그러나 여러 시뮬레이션은 대략적인 확률에 동의합니다. 순전히 수학적인 해결책은 제공되지 않았습니다 (아직). 너무 어려워요.300

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

샘플 데이터의 첫 번째 데크를 인코딩하기 위해 비트를 보여주는 좋은 알고리즘이 있습니다. 이 데이터는 Fisher-Yates 셔플 알고리즘을 사용하여 임의로 생성되었습니다. 실제 무작위 데이터이므로 새로 작성된 알고리즘이 매우 잘 작동하는 것 같습니다.168

압축 "도전"과 관련하여 현재 데크 당 약 160 비트입니다. 나는 아마도 158로 내려갈 수 있다고 생각한다. 그렇다. 나는 시도했고 갑판 당 158.43 비트를 얻었다. 나는 알고리즘의 한계에 가까워져 갑판 당 166 비트 아래로 떨어지는 데 성공했지만 카드 당 3 비트 인 156 비트를 얻지 못했지만 재미있는 운동이었습니다. 아마도 미래에는 각 데크를 평균 2.43 비트 이상 줄이려고 생각할 것입니다.


8
예를 들어 물리적 카드 덱의 상태를 설명하기보다는 이러한 셔플 덱을 직접 생성하는 경우에는 덱을 전혀 저장할 필요가 없습니다. 덱을 생성 한 RNG 시드 만 저장하면됩니다.
jasonharper

3
설명과 답변에 대한 설명은 일반적으로 범위 인코딩 ( en.wikipedia.org/wiki/Range_encoding ) 이라는 개념과 매우 유사합니다 . 남은 가능한 카드를 반영하도록 각 카드 다음에이 기능을 조정하십시오.
H. Idden

의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
Gilles 'SO- 악한 중지'

답변:


3

고려해야 할 또 다른 사항 : 수백만 개의 데크 전체를 압축하는 데 관심이 있고 순서가 신경 쓰지 않는 경우 데크 세트의 순서에 대한 정보를 삭제하여 추가 인코딩 유연성을 얻을 수 있습니다 . 예를 들어, 모든 데크를 열거하고 처리하기 위해 세트를로드해야하지만 처리 순서를 신경 쓰지 않는 경우가 여기에 해당합니다.

다른 답변에서 방법을 설명했듯이 각 데크를 개별적으로 인코딩하여 시작합니다. 그런 다음 인코딩 된 값을 정렬하십시오. 정렬 된 인코딩 된 값 (첫 번째 차이는 인코딩 된 데크 '0'에서 시작) 사이에 일련의 차이를 저장하십시오. 데크가 많으면 차이가 전체 인코딩 범위보다 작은 경향이 있으므로 작은 차이를 효율적으로 저장하면서 일부 형태의 바 린트 인코딩을 사용하여 가끔 큰 차이를 처리 할 수 ​​있습니다. 적절한 varint 구성표는 세트에있는 데크의 수에 따라 다릅니다 (따라서 평균 차이 크기를 결정합니다).

불행히도 이것이 압축에 얼마나 도움이 될지에 대한 수학을 모르지만이 아이디어가 고려하는 것이 유용 할 것이라고 생각했습니다.


1
매우 대략적으로 말하면, 수백만 개의 랜덤 데크가 있다면 평균 차이는 전체 범위의 1 (수백만 백만)가 될 것이므로 값 당 약 20 비트를 절약 할 수 있습니다. 당신은 당신의 varint 인코딩을 위해 약간을 잃는다.
Steve Jessop

2
@DavidJames : 데크의 특정 순서가 중요하지 않은 경우, 편향이없는 것만으로 압축 해제 후 3 백만 개의 데크를 다시 섞을 수 있습니다 (즉, 데크를 변경하지 않고 그냥 3 백만 데크 목록).
Steve Jessop

2
이것은 주문 정보가 중요하지 않은 경우 정보 내용을 조금 더 줄이는 방법입니다. 중요한 경우 적용 할 수 없으며 무시할 수 있습니다. 즉, 데크 세트의 순서를 결정하는 데있어 가장 중요한 것이 그것이 '무작위'라면 @SteveJessop이 말한 것처럼 압축 해제 후 순서를 무작위로 지정할 수 있습니다.
Dan Bryant

@DavidJames 덱의 첫 173 개가 KKKK로 시작하고 다른 수백만을 보지 않고 모두 KKKK로 시작한다는 결론은 꽤 어리석은 일입니다. 특히 그것들이 분명히 정렬 된 순서라면.
user253751

3
@DavidJames :이 데이터는 압축되며 압축 해제 루틴은 원하는 경우 다시 임의 추출 할 수 있습니다. "일부 순진한 사람"은 전혀 아무것도 얻지 못할 것이며, 카드 덱으로 해석하는 방법조차 찾지 못할 것입니다. 데이터 저장 형식 (이 경우 손실 형식)의 결함 은 아닙니다 .이 형식을 사용하는 사람은 RTFM을 통해 올바른 데이터를 가져와야합니다.
Steve Jessop

34

이론적 한계에 도달하는 완전한 알고리즘은 다음과 같습니다.

프롤로그 : 정수 시퀀스 인코딩

13 개의 정수 시퀀스 "상한이 인 정수, 상한이 b - 1 인 정수,"상한이 c - 1 인 정수, 상한이 d - 1 인 정수, ... 상한이 m - 1 인 정수 " 항상 완벽한 효율성으로 코딩 할 수 있습니다.a1b1c1d1m1

  1. 첫 번째 정수에 곱하고 , 두 번째에 곱하고, 결과에 c를 곱하고, 세 번째에 더하고, 결과에 d 를 곱하고, 결과에 m을 곱한 다음 , 13을 더하십시오. 그러면 0 사이의 고유 한 숫자가 생성됩니다. 및 a b c d e f g h i j k l m - 1 .bcdm0abcdefghijklm1
  2. 이 숫자를 이진수로 기록하십시오.

반대로도 쉽습니다. 나누면 나머지는 13 번째 정수입니다. 결과를 나누면 나머지는 12 번째 정수입니다. 로 나눌 때까지 계속 하십시오. 나머지는 두 번째 정수이고 몫은 첫 번째 정수입니다.l bmlb

따라서 가능한 최상의 방식으로 카드를 코딩하려면 13 개의 정수 시퀀스 (상한이 주어진 상태)와 셔플 카드 배열 사이의 완벽한 대응 관계를 찾아야합니다.

방법은 다음과 같습니다.

셔플 링과 정수 시퀀스의 대응

앞의 테이블에서 일련의 0 장의 카드로 시작하십시오.

1 단계

팩에있는 4 개의 2를 가져 와서 테이블 위에 놓으십시오.

어떤 선택이 있습니까? 카드는 이미 테이블에있는 순서의 시작 부분이나 해당 순서의 카드 중 하나 뒤에 배치 될 수 있습니다. 이 경우 이는 카드를 넣을 수있는 장소 가 것을 의미합니다 .1+0=1

1 개 장소에 4 장의 카드를 배치하는 총 방법 수는 입니다. 각 방법을 과 사이의 숫자로 인코딩하십시오 . 그러한 숫자는 1입니다.1011

0을 5 정수의 합계로 쓰는 방법을 고려하여 1을 얻었습니다. 입니다.4×3×2×14!

2 단계

당신의 팩에있는 4 개의 3을 가지고 테이블에 놓으십시오.

어떤 선택이 있습니까? 카드는 이미 테이블에있는 순서의 시작 부분이나 해당 순서의 카드 중 하나 뒤에 배치 될 수 있습니다. 이 경우 카드를 넣을 수있는 장소 가 라는 의미입니다 .1+4=5

5 개 장소에 4 장의 카드를 배치하는 총 방법 수는 입니다. 사이의 값으로 이러한 방식으로 각각 인코딩 070 - 1 . 70 개의 숫자가 있습니다.700701

4를 5 정수의 합으로 쓰는 방법을 고려하여 70을 얻었습니다 .8×7×6×54!

3 단계

당신의 팩에있는 4 개의 4를 가지고 테이블에 놓으십시오.

어떤 선택이 있습니까? 카드는 이미 테이블에있는 순서의 시작 부분이나 해당 순서의 카드 중 하나 뒤에 배치 될 수 있습니다. 이 경우 카드를 넣을 수있는 장소 는 입니다.1+8=9

9 개 장소에 4 장의 카드를 배치하는 총 방법 수는 입니다. 사이의 숫자로 그 각각의 방법을 인코딩 0(495) - (1) . 495 개의 숫자가 있습니다.49504951

8을 5 정수의 합으로 쓰는 방법을 고려하여 495를 얻었습니다 .12×11×10×94!

그리고 계속해서 ...

13 단계

팩에있는 4 개의 에이스를 가져 와서 테이블 위에 놓습니다.

어떤 선택이 있습니까? 카드는 이미 테이블에있는 순서의 시작 부분이나 해당 순서의 카드 중 하나 뒤에 배치 될 수 있습니다. 이 경우 카드를 넣을 수있는 장소 는 입니다.1+48=49

49 개 장소에 4 장의 카드를 배치하는 총 방법은 입니다. 사이의 값으로 이러한 방식으로 각각 인코딩 0270,725 - 1 . 270725 개의 숫자가 있습니다.27072502707251

나는 5 개 정수의 합으로 (48)를 작성하는 방법을 고려하여 270,725을 가지고 : 그것이 .52×51×50×494!


이 절차는 사이에 1 대 1 대응을 산출 (가) 당신이이 사이에 처음으로 정장 및 정수의 (b)의 시퀀스에 대한 상관 없어 카드의 shufflings 1 - 1 , 두 번째는 사이에 070 - 1 , 세 번째 사이에 0495 - 1 등 사이 인 13 일까지에 027만7백25 - 1 .01107010495102707251

"정수 시퀀스를 인코딩"을 참조하면, 당신은 정수의 이러한 순서는 1-1 사이의 숫자에 대응에 볼 수있는 ( 1 × 70 × 495 × ... × 270725 ) - 1 . 각 정수의 "인수를 계승으로 나눈"식을 보면 ( 각 단계의 끝에 이탤릭체로 설명되어 있음) 이것이 0 에서 52 사이의 숫자를 의미 함을 알 수 있습니다 !0(1×70×495××270725)10내 이전 대답했다 최상의이었다.

52!(4!)131,

셔플 카드를 압축하는 완벽한 방법이 있습니다.


알고리즘

0을 5 개의 정수의 합계로 쓰고, 4를 5 개의 정수의 합계로 쓰고, 8을 5 개의 정수의 합계로 쓰고, 48을 5 개의 정수의 합계로 쓰는 모든 방법의 목록을 미리 계산 하십시오. 가장 긴 목록에는 270725 개의 요소가 있으므로 특별히 크지는 않습니다. (각 목록을 필요할 때마다 쉽게 합성 할 수 있기 때문에 사전 계산이 반드시 필요한 것은 아닙니다. Microsoft QuickBasic을 사용하면 270725 요소 목록을 살펴 보는 것이 눈에 보이는 것보다 빠릅니다.)

셔플 링에서 정수 시퀀스로 가져 오려면 :

2는 아무 것도 기여하지 않으므로 무시하십시오. 0과 1-1 사이의 숫자를 기록하십시오.

3 : 첫 3 전에 몇이 있습니까? 두 번째 전에 몇 명입니까? 세 번째? 넷째? 4 일 이후? 정답은 4를 더한 5 개의 정수입니다. 따라서 "4를 5 개의 정수의 합계로 작성"목록에서 5 개의 정수 시퀀스를 찾아 해당 목록의 위치를 ​​확인하십시오. 0에서 70-1 사이의 숫자입니다. 받아 적어.

The 4s : 첫 4 개 전에 몇 개나 3 개가 있습니까? 두 번째 전에 몇 명입니까? 세 번째? 넷째? 4 일 이후? 정답은 8을 더한 5 개의 정수입니다. 따라서 "5 개의 정수의 합으로 8을 작성"목록에서 5 개의 정수 시퀀스를 찾아 해당 목록의 위치를 ​​확인하십시오. 0에서 495-1 사이의 숫자입니다. 받아 적어.

그리고 계속해서 ...

에이스 : 첫 에이스 전에 몇 개의 비-에이스 카드가 있습니까? 두 번째 전에 몇 명입니까? 세 번째? 넷째? 4 일 이후? 답은 5 개의 정수로, 분명히 48을 더한 것입니다. 따라서 "48을 5 개의 정수의 합으로 작성"목록에서 5 개의 정수 시퀀스를 찾아 해당 목록의 위치를 ​​기록하십시오. 0에서 270725-1 사이의 숫자입니다. 받아 적어.

이제 13 개의 정수를 기록했습니다. (앞서 설명한 것처럼) 에서 52 사이의 단일 숫자로 인코딩하십시오 !0 . 이 숫자를 이진수로 쓰십시오. 166 비트 미만이 소요됩니다.52!(4!)13

정보 이론적 한계에 도달하기 때문에 가능한 최상의 압축입니다.

압축 해제는 간단합니다. 큰 숫자에서 13 개의 정수 시퀀스로 이동 한 다음이를 사용하여 이미 설명한대로 카드 시퀀스를 빌드하십시오.


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
DW

이 솔루션은 명확하지 않으며 불완전합니다. 실제로 166 비트 숫자를 가져 와서 다시 데크로 디코딩하는 방법을 보여주지 않습니다. 나를 생각하기가 전혀 쉽지 않으므로 구현 방법을 모릅니다. 단계별 수식은 기본적으로 분해합니다 ! / ( 4 ! 13 ) 공식을 13 개로 나눠서 정말 도움이되지 않습니다. 카드를 배열하는 70 가지 가능한 방법으로 2 단계에 대한 다이어그램이나 차트를 만들면 도움이 될 것이라고 생각합니다. 당신의 솔루션은 뇌가 받아들이고 처리하기에는 너무 추상적입니다. 실제 사례와 삽화를 선호합니다. 52!/(4!13)13
David James

23

각 카드를 3 ​​비트 또는 4 비트로 개별적으로 인코딩하는 대신 전체 데크의 상태를 166 비트로 인코딩하는 것이 좋습니다. 마틴 Kochanski 같이 설명 미만의 존재 전체 갑판의 상태 비트 (166)에 저장 될 수 있다는 것을 의미하므로 슈트 무시 카드의 배열이 가능.2166

이 압축 및 압축 풀기를 어떻게 효율적으로 알고리즘 적으로 수행합니까? 사전 식 순서와 이진 검색을 사용하는 것이 좋습니다. 이렇게하면 큰 조회 테이블이나 기타 비현실적인 가정없이 공간과 시간 모두에서 효율적으로 압축 및 압축 해제를 수행 할 수 있습니다.

세부 사항 : 압축되지 않은 데크 표시에 사전 식 순서를 사용하여 데크를 주문하십시오. 즉, 데크는 압축되지 않은 형식으로 22223333444455556666777788889999TTTTJJJJQQQQKKKKAAAA와 같은 문자열로 표시됩니다. 사전 순서에 따라 주문할 수 있습니다. 이제 데크 가 주어지고 그 앞에 오는 데크 수를 사전 식 순서로 계산 하는 절차가 있다고 가정하십시오 . 그런 다음이 절차를 사용하여 데크를 압축 할 수 있습니다. 데크 D가 주어진 경우 압축은 덱의 수를 세고 그 수를 출력하여 166- 비트 수입니다. 이 숫자는 데크의 압축 표현입니다.DD

압축을 풀려면 이진 검색을 사용하십시오. 숫자 주어지면 모든 데크의 사전 순서에서 n 번째 데크 를 찾고 싶습니다 . 당신은 이진 검색의 라인을 따라 절차를 사용하여이 작업을 수행 할 수 있습니다 갑판의 선택 D 0 , 전에 데크의 수를 계산 D 0 , 및 해당 비교 N . D 0 조정 여부를 알려줍니다nnD0D0nD0일찍 또는 나중에 올 것이다. 반복적으로 기호를 올바르게 얻으려고 제안하십시오 .22223333444455556666777788889999TTTTJJJJQQQQKKKKAAAA와 같은 문자열을 복구하려면 먼저 문자열의 첫 번째 기호로 사용할 항목을 찾기 위해 검색하십시오 (12 가지 가능성 모두를 시도하거나 12 가지 가능성에 대한 이진 검색 사용) )를 찾은 다음 첫 번째 기호에 대한 올바른 값을 찾으면 두 번째 기호 등을 찾기 위해 검색하십시오.

남아있는 것은 이전에 사 전적으로 오는 데크 수를 계산하는 효율적인 절차를 마련하는 것 입니다. 이것은 간단하지만 지루한 조합 운동처럼 보입니다. 특히 다음과 같은 문제에 대한 서브 루틴을 빌드하는 것이 좋습니다. 접두사 (예 : 222234)가 있으면 해당 접두사로 시작하는 데크 수를 세십시오. 이 문제에 대한 답은 이항 계수와 계승에서 매우 쉬운 운동처럼 보입니다. 그런 다음이 서브 루틴을 약간 호출하여 D 앞에 오는 데크 수를 계산할 수 있습니다.DD


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
DW

8

슈트를 무시 하는 카드의 가능한 배열의 수 는 로그 밑이 2 인 165.976 또는 카드 당 3.1919 비트로, 지정한 한도보다 낫습니다.

52!(4!)13,

마지막으로 카드를 항상 비트로 인코딩 할 수 있고 대부분의 경우 마지막 카드도 가능 하기 때문에 고정 된 "카드 당 비트"인코딩은 의미가 없습니다 . 즉, 팩의 "꼬리"를 향한 방법으로 각 카드에 필요한 비트 수가 생각보다 훨씬 적습니다.0

지금까지 데이터를 압축하는 가장 좋은 방법은 카드 데이터로 압축하려는 다른 데이터의 59 비트 (실제로 59.6 비트)를 찾아 해당 59 비트를 13 자리 숫자 모듈로 24 (= ), 사이 각 카드 (한 자리 선택한다면에 정장 지정 4 ! 에이스로 정장을 할당하는 방법을, 다른 하나는, 등)에 왕에 대해 동일한 작업을 수행합니다. 그런 다음 52 개의 완전히 다른 카드 팩이 있습니다. 52 ! 가능성은 실제로 매우 쉽게 225.58 비트로 인코딩 될 수 있습니다.4!4!52!

그러나 여분의 비트를 인코딩 할 기회를 얻지 않고 그것을 수행하는 것도 어느 ​​정도 가능하며 다른 모든 사람들이 확신하기 때문에 그것에 대해 생각할 것입니다. 정말 흥미로운 문제에 감사드립니다!


1
암호문 훔치기 와 유사한 접근 방식을 여기서 사용할 수 있습니까? 마찬가지로 추가 59 비트로 인코딩 한 데이터는 인코딩 된 표현의 마지막 59 비트입니까?
John Dvorak

@JanD 나는 이런 것을 조사하는 것에 대해 생각하고 있었다. 그러나 이론적 한계에 도달하고 간단하고 100 % 신뢰할 수있는 알고리즘이 존재하므로 더 이상 살펴볼 필요가 없습니다.
Martin Kochanski

@MartinKochanski-나는 "수트를 무시하고"cuz로 말하지 않을 것입니다. 우리는 여전히 순위 당 표준 4 수트를 존중하고 있습니다. 더 나은 표현은 "갑판의 가능한 뚜렷한 배치의 수는"입니다.
David James

3

이것은 오랫동안 해결 된 문제입니다.

당신이 52 장의 카드를 처리 할 때, 당신이 취급하는 모든 카드는 알려진 확률로 최대 13 개의 등급 중 하나를가집니다. 처리 할 때마다 확률이 바뀝니다. 그것은 허프만 코딩의 개선 인 적응 적 산술 코딩 (adaptive arithmetic coding)이라 불리는 고대 기술을 사용하여 최적으로 처리된다. 일반적으로 알려진 변경되지 않은 확률에 사용되지만 확률을 변경하는 데에도 사용할 수 있습니다. 산술 코딩에 대한 Wikipedia 기사를 읽으십시오.

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


하지만 이론적 엔트로피 인코딩 한계에 도달하거나 일치하거나 이길 수 있다면 이것은 내 질문에 대답하지 않습니다. 각각 1 / n 확률로 n 개의 가능한 데크가 있기 때문에 엔트로피 인코딩은 한계이며 더 나은 방법은 없습니다.
David James

3

DW와 Martin Kochanski는 이미 [ 0 , 52] 범위의 거래와 정수 사이의 궤적을 구성하는 알고리즘을 설명했습니다 .그러나 그들 중 어느 것도 문제를 가장 단순한 형태로 줄인 것 같지 않습니다. (주 1)[0,52!(4!)13)

우리가 정렬 된 목록의 설명 (부분) 갑판 있다고 가정 , 내가 유형의 카드의 수 난을 . OP에서 초기 데크는 13 개의 요소 목록으로 설명되며 각 요소는 값이 4입니다. 이러한 데크의 개별 셔플 수는 다음과 같습니다.aaii

기음()=(나는)!나는!

이것은 이항 계수의 간단한 일반화이며 실제로 Martin Kochanski가 제안한 것처럼 한 번에 한 가지 유형의 객체를 정렬하여 증명할 수 있습니다. (아래 참고 2 참조)

이제 이러한 (부분) 덱의 경우 i > 0 인 를 사용하여 한 번에 하나의 카드 셔플을 선택할 수 있습니다 . i 로 시작하는 고유 셔플 수 는나는나는>0나는

{0만약 나는=0기음(1,...,나는1,나는1,나는+1,...,)만약 나는>0.

위의 공식으로, 우리는

기음(1,...,나는1,나는1,나는+1,...,)=나는기음()나는

그런 다음 접두사보다 보다 작은 접두사에 해당하는 접두사의 수 는나는

기음()j=1나는jj=1j

알고리즘을 설명하기 위해 이것을 파이썬으로 작성했습니다. 파이썬은 의사 코드만큼이나 합리적입니다. 대부분의 산술에는 확장 된 정밀도가 포함됩니다. 값 (셔플 서수를 나타냄)와 n (나머지 부분 데크에 가능한 총 셔플 수)은 모두 166- 비트 큰 숫자입니다. 코드를 다른 언어로 번역하려면 일종의 bignum 라이브러리를 사용해야합니다.케이

또한 카드 이름 대신 정수 목록을 사용하며 위의 수학과 달리 정수는 0부터 시작합니다.

셔플을 인코딩하기 위해, 우리는 셔플을 통해 걸으며, 위의 공식을 사용하여 더 작은 카드로 시작하는 셔플 수를 각 지점에 누적합니다.

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- 비트 숫자를 해독하는 것은 간단한 역수입니다. 각 단계마다 부분 데크와 서수에 대한 설명이 있습니다. 서수에 해당하는 것보다 작은 카드로 시작하는 셔플을 건너 뛰고 선택한 카드의 출력을 계산하고 나머지 데크에서 카드를 제거한 다음 선택한 접두어로 가능한 셔플 수를 조정합니다.

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

위의 코드를 최적화하려고 시도하지 않았습니다. 전체 3mil.TXT 파일에 대해 실행 encode(decode(line))하여 원래 인코딩 이 발생 했는지 확인했습니다 . 300 초도 채 걸리지 않았습니다. ( ideon 에 대한 온라인 테스트에서 7 개의 라인을 볼 수 있습니다 .) 낮은 수준의 언어로 다시 작성하고 나누기 (가능한 경우)를 최적화하면 해당 시간을 관리하기 쉬운 것으로 줄일 수 있습니다.

인코딩 된 값은 단순히 정수이므로 166 비트로 출력 될 수 있습니다. 인코딩이 끝나는 위치를 알 수있는 방법이 없으므로 실제로는 166 비트 인코딩이므로 선행 0을 삭제하는 데 아무런 가치가 없습니다.

그러나 실제 응용 프로그램에서는 셔플을 인코딩 할 필요가 없습니다. 랜덤 셔플은 랜덤 166- 비트 수를 생성하고 디코딩함으로써 생성 될 수있다. 그리고 166 비트가 모두 무작위 일 필요는 없습니다. 예를 들어 32 비트 임의의 정수로 시작한 다음 32 비트 숫자로 시드 된 표준 RNG를 사용하여 166 비트를 채울 수 있습니다. 따라서 목표가 단순히 많은 수의 임의 셔플을 재현 가능하게 저장할 수 있다면 거래 별 저장 요구 사항을 임의로 줄일 수 있습니다.

당신은 많은 수의 인코딩하려면 약 절약, (다른 방식으로 생성 된) 실제 거래를하지만, 당신은 델타 인코딩 숫자의 정렬 된 목록 수있는 거래의 순서에 대해 걱정하지 않는다 로그 2 개 N 각 비트를 번호. 정렬 된 시퀀스는 정렬되지 않은 시퀀스보다 엔트로피가 적기 때문에 절약 효과가 있습니다. 시퀀스에서 단일 값의 엔트로피를 줄이지 않습니다.로그2

정렬 된 k 비트 숫자 목록을 인코딩해야한다고 가정하면 다음과 같이 진행할 수 있습니다. 케이

  1. log 2 N에 가까운 정수로 선택하십시오 (바닥이나 천장이 작동합니다. 보통 천장으로갑니다).로그2

  2. 우리는 암시 적으로 숫자의 범위를 분할 이진 접두어로 간격. 각각의 k- 비트 수는 p- 비트 접두사와 k - p- 비트 접미사 로 나뉩니다 . 접미사 만 (순서대로) 작성합니다. 이를 위해서는 N * ( k - p ) 비트가 필요합니다.2케이케이(케이)

  3. 또한, 우리는 비트 시퀀스를 생성합니다 : 접두사 (접두사 0 제외 ) 각각에 대해 접두사 (있는 경우) 뒤에 1이 오는 각 숫자에 대해 0 을 씁니다 . 이 시퀀스는 분명히 2 p + N 비트 : 2 p 1 s 및 N 0 s를 갖습니다 .20012+2 1 0

숫자를 해독하기 위해 0에서 접두사 카운터를 시작하고 비트 시퀀스를 진행합니다. 우리가 볼 때 , 우리는 출력을 현재의 접두사와 접미사 목록에서 다음 접미사; 우리가 볼 때 1 , 우리는 현재의 접두사를 증가.01

부호화의 총 길이는 가까이에있다 N * ( K - P ) + N + N 또는 N * ( K - P + 2 ) 평균 들면 의 K - P + 2 값당 비트.(케이)++2(케이)++(케이+2)케이+2

노트

  1. 92024242230271040357108320801872044844750000000000이고로그252입니다!52!(4!)1392024242230271040357108320801872044844750000000000 은 약165.9765입니다. 본문에서 나는 때때로 2 진 대수가 실제로166 인것처럼 가장합니다. 범위 내에서 임의의 서수를 생성하는 경우, 생성 된 난수를 거의 거부하지 않는 거부 알고리즘을 사용할 수 있습니다.로그252!(4!)13165.9765166
  2. 편의를 위해 물품 위한 N Σ는= 케이 I를 ; 다음 1 유형의 오브젝트 1 에 위치 할 수있다 ( S 1에스케이나는=케이나는11방법, 다음 형태의 물체(2)에 배치 될 수있다(S2(에스11)2방법, 등등. 이후 ( Si(에스22)총 수에 이르게(에스나는나는)=에스나는!나는!(에스나는나는)!=에스나는!나는!에스나는+1!

나는=1에스나는!나는=1나는!에스나는+1!

위의 공식으로 단순화됩니다.


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
DW

@rici-나는 당신에게 코드를 포함하여 더 나은 프리젠 테이션처럼 보이는 것에 대한 당신의 답변을 설명하는 +100 현상금을주었습니다. 다른 답변은 더 추상적 / 이론적이며 실제로 인코딩 / 디코딩을 구현하는 방법에 대한 세부 정보는 생략했습니다. 아시다시피, 코드를 작성할 때 많은 세부 사항이 있습니다. 내 알고리즘이 가장 간단하고 간단하며 이해하기 쉽지는 않지만 실제로 많은 노력을 기울이지 않고 작동하며 시간이 지남에 따라 더 많은 압축으로 더 빠르게 실행할 수 있습니다. 답변을 주셔서 감사하고 좋은 일을 유지하십시오.
David James

2

이 문제에 대한 대체 솔루션으로, 내 알고리즘은 남아있는 채워지지 않은 순위 수에 따라 데크의 카드 그룹에 대해 카드 당 복합 소수 (비정 수) 비트를 사용합니다. 다소 우아한 알고리즘입니다. 인코딩 알고리즘을 손으로 확인했는데 좋아 보인다. 인코더가 올바른 비트 스트링 (간단 성을 위해 바이트 형식)으로 보이는 것을 출력하고 있습니다.

754에이236제이7131372613762,748,51722667,108,864241313428,56121532,76815/4=3.7526/7=3.714. 우리가 사용하는 경우 카드 당 비트 수 그래서 카드 당 약간 낮은 포장 방법을.26/7

그래서보고 , 우리는 단순히 우리의 마스터 "에서 그 계급의 서수 위치를 찾아 23456789 T J Q K "정렬 된 계급의 목록을. 예를 들어, 첫 번째 실제 카드 순위 5 는 순위 조회 문자열에서 조회 위치가 4 입니다. 우리는이 7 순위 위치 를 0으로 시작 하는 기본 13 숫자 로 취급합니다 (따라서 이전에 얻은 위치 4는 실제로 3이됩니다). (확인 목적으로) 기본 10으로 다시 변환 하면 15 , 565 , 975가 됩니다. 에서 (26)54에이236제이23456789제이케이에이547131015,565,97526이진 비트는 입니다.00111011011000010010010111

2615,565,9751354에이236제이7

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

다음은 가능한 모든 순위의 비용에 대한 전체 비용 목록 (카드 당 비트 수)입니다.

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

75,6,7,7,7,7,케이케이1312713케이21,2,삼...131720

16813,12,11

10777748747에스. 데크가 쌍 (예 : 77), 트리플 / 세트 (예 : 777) 또는 쿼드 (예 : 7777)로 끝나면 알고리즘을 사용하여 해당 데크를 추가로 절약 할 수 있습니다.

3222613163232

데이터 파일의 첫 번째 데크에서 카드 인코딩은 다음과 같습니다 (나중에 다이어그램). 형식은 (그룹 크기, 비트, 순위 인코딩 모드)입니다.

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

521683.23

181/3.23.254545454722772277 ...22223333444455556666777788889999제이제이제이제이케이케이케이케이에이에이에이에이40

110,7케이810순위 모드, 아마도 그 갑판에 더 적은 비트를 사용할 수 있습니다. 여러 카드의 특수 "그룹화 된"버킷에있는 카드 중 하나를 볼 때, 그 특수 "랭크"(실제 등급이 아니라 특정 버킷에서 무언가를 본 지표)를 출력 한 다음 몇 가지 더 비트가 디코더에서 내가 본 버킷의 카드를 알려 주면 그 카드를 그룹에서 제거합니다 (방금 채워 졌으므로). 나는 이것을 사용하여 비트 절약이 가능한지 알아보기 위해 이것을 손으로 추적 할 것입니다. 이 특수 버킷을 사용하면 모호성이 없어야합니다. 인코더와 디코더 모두 카드를 계산하고 어느 등급이 인지 만 알기 때문입니다.1남은 카드. 이는 인코더가 추가 메시지를 전달하지 않고 디코더가 올바른 가정을 할 수있을 때 인코딩 프로세스를보다 효율적으로 만들기 때문에 중요합니다.

13121110

         26             26             26            18         18       10      9          17           13        5     0
    54에이236제이  87726  3969에이에이에이  제이케이7  9292  36케이  제이57   8케이제이4  488  55케이  4
13                                            12                    엑스와이     98         7              6        543     2 1  0

2166175168비트. 데크 끝 부분에 단일 4 개만 있지만 대신 4 개 4 개가 모두있는 경우 더 나은 경우이며 해당 데크를 인코딩하는 데 161 비트 만 있으면됩니다. 패킹이 실제로 그것의 서수 위치의 직선 이진 인코딩의 엔트로피.

이제 비트 요구 사항을 계산하기 위해 코드를 구현했으며 3 백만 데크 테스트 파일의 경우 데크 당 약 175 비트, 155의 낮은 값과 183의 높은 값을 보여줍니다. 그래서 내 알고리즘은 데크 당 9 개의 추가 비트와 서수 위치 방법의 직선 이진 인코딩을 사용하는 것으로 보입니다. 5.5 %의 추가 스토리지 공간 만 있으면 나쁘지 않습니다. 176 비트는 정확히 22 바이트이므로 데크 당 52 바이트보다 훨씬 낫습니다. 최상의 경우 데크 (3 백만 개의 데크 테스트 파일에 표시되지 않음)를 136 비트로 압축하고 최악의 경우 데크 (테스트 파일에 8206 번 표시됨)는 183 비트입니다. 분석에 따르면 최악의 경우는 카드 40에 가까워 질 때까지 첫 번째 쿼드를 얻지 못하는 경우입니다. 그런 다음 인코딩 모드가 빠르게 떨어지기를 원할 때 블록에 (7 카드만큼 큰) 채우기 블록이 "고정"됩니다 더 높은 비트 인코딩 모드. 잘 섞인 데크를 사용하여 카드 40까지 쿼드를 얻는 것은 매우 드물다고 생각할 수도 있지만, 내 프로그램은 3 백만 데크의 테스트 파일에서 321 번 발생하여 9346 데크마다 약 1 번 발생한다고 알려줍니다. 내가 예상했던 것보다 더 자주입니다. 이 경우를 확인하고 더 적은 비트로 처리 할 수는 있지만 평균 비트에 충분히 영향을 미치지 않는 경우는 거의 없습니다.

여기 또 다른 흥미로운 것이 있습니다. 원시 데크 데이터에서 데크를 정렬하면 상당한 횟수의 반복되는 접두사 길이는 길이가 약 6 (예 : 222244)입니다. 그러나 압축 된 데이터의 경우 길이는 약 16으로 증가합니다. 즉, 압축 된 데이터를 정렬하면 디코더에 16 비트 접두사를 표시 한 다음 데크의 나머지를 출력하여 상당한 비용을 절감 할 수 있습니다. 동일한 접두사를 가진 (반복 접두사 빼기) 다음 접두사로 이동하여 반복하십시오. 이 방법으로 데크 당 10 비트 만 절약한다고 가정하면 데크 당 166 비트를 이길 수 있습니다. 다른 사람들이 열거 한 열거 기술을 사용하면 접두사가 내 알고리즘만큼 길어질 지 확실하지 않습니다. 또한 내 알고리즘을 사용하여 포장 및 포장 풀기 속도가 놀랍도록 좋습니다.

알고리즘의 출력 비트 열을 정렬하는 두 번째 압축 수준과 관련하여 "차이"인코딩을 사용합니다. 매우 간단한 방법은 출력 데이터에 최소 두 번 표시되는 61,278 개의 고유 한 16 비트 접두사를 인코딩하는 것입니다. 두 번째 레벨 압축 풀기 프로그램에 프리픽스 (예 : 0000111100001111)를 인코딩하고 동일한 프리픽스가있는 팩킹 된 데크는 포장 된 데크의 접두사가 아닌 부분을 나타냅니다. 프리픽스가 동일한 팩킹 된 데크의 평균 수는 각 프리픽스에 대해 약 49 개이며 고유 한 것을 포함하지 않습니다 (1 개의 데크에만 해당 프리픽스가 있음). 이 간단한 전략을 사용하여 데크 당 약 15 비트를 절약 할 수 있습니다 (공통 접두사를 한 번 저장).

첫 번째 인코더의 정렬 된 비트 문자열 출력의 차이 (접두사) 인코딩을 사용하여 두 번째 압축 수준을 얻은 후 데크 당 약 160 비트를 얻습니다. 길이 18 접두사를 사용하고 그대로 저장합니다. 가능한 18 비트 접두사 중 거의 모든 것이 (262144 중에서 245013 = 93.5 %) 나타나기 때문에 접두사를 인코딩하는 것이 훨씬 좋습니다. 아마도 2 비트를 사용하여 어떤 유형의 데이터를 인코딩 할 수 있습니다. 00 = 일반 길이 18 접두사 저장, 01 = "1 업 접두사"(1이 추가 된 것을 제외하고 이전 접두사와 동일), 11 = 첫 번째 레벨 패킹에서 평균 인코딩 (평균 약 175 비트). 10 = 비트를 절약 할 다른 인코딩을 생각할 때 미래 확장.

다른 사람이 아직 갑판 당 160 비트를 이겼습니까? 나는 위에서 언급 한 2 비트 디스크립터를 실험하고 사용하여 조금 더 나아질 수 있다고 생각한다. 아마도 158ish에 바닥이 될 것입니다. 내 목표는 카드 당 3 비트 이하이기 때문에 156 비트 (또는 더 나은)로 만드는 것입니다. 매우 인상적. 첫 번째 레벨 인코딩을 변경하면 최상의 2 레벨 인코딩이며 다시 시도해야 할 조합이 많기 때문에 그 수준으로 낮추기 위해 많은 실험을했습니다. 내가 변경 한 일부 변경 내용은 다른 유사한 임의 데이터에 유용 할 수 있지만 일부는이 데이터 세트에 편향 될 수 있습니다. 확실하지는 않지만 충동이 생기면 비슷한 결과를 얻을 때 어떤 일이 일어나는지 확인하기 위해 3 백만 데크 데이터 세트를 시도 할 수 있습니다.

1050

누구든지 평균적으로 각 데크의 스토리지 비트를 줄 이도록 인코딩 해야하는 다른 경우와 같이 알고리즘을 개선하는 방법에 대한 아이디어가 있습니까? 누군가?

2 더 많은 것들 : 1) 나는 더 많은 사람들이 공간에서 최적은 아니지만 여전히 구현하기에 적당하고 상당히 쉬운 내 솔루션을 공표하지 않았다는 것에 다소 실망했다. 2) 3 백만 개의 데크 데이터 파일을 분석 한 결과 1444 위와 같이 1 순위가 채워지는 가장 자주 발생하는 카드는 26 번 카드라는 것을 알았습니다.이 시간은 약 6.711 % (300 만 데크 중 201322) ). 나는이 정보를 사용하여 12 개의 심볼 인코딩 모드에서 시작하는 등 더 압축하기를 바랐습니다. 왜냐하면 평균 데크까지 모든 순위를 볼 수는 없기 때문에이 방법은 오버 헤드가 절약을 초과하여 압축하지 못했습니다. 실제로 비트를 저장할 수있는 알고리즘에 대한 조정을 찾고 있습니다.

내 알고리즘을 사용하여 데크 당 몇 비트를 절약하기 위해 다음에 시도해야 할 아이디어가 있습니까? 디코더가 어떤 패턴을 기대해야하는지에 대한 과도한 오버 헤드 후에도 데크 당 비트를 줄일 수 있도록 자주 발생하는 패턴을 찾고 있습니다. 나는 보이지 않는 나머지 카드의 예상 확률을 가진 무언가를 생각하고 남아있는 모든 단일 카드를 단일 버킷으로 묶습니다. 이렇게하면 낮은 인코딩 모드로 더 빨리 떨어질 수 있으며 비트를 절약 할 수는 있지만 의심합니다.

또한 참고로, 1 천만 개의 임의 셔플을 생성하여 데이터베이스에 저장하여 쉽게 분석 할 수있었습니다. 그중 488 개만 쿼드 (예 : 5555)로 끝납니다. 내 알고리즘을 사용하여 그것들을 포장하면 평균 165.71712 비트가 157 비트의 낮은 비트와 173 비트의 높은 비트를 얻습니다. 다른 인코딩 방법을 사용하면 166 비트 바로 아래에 있습니다. 나는이 사건이 얼마나 드문 지에 대해 다소 놀랐습니다 (평균 20,492 건의 셔플 중 약 1 건).


3
9 시간 동안 24 번 수정했습니다. 답변을 개선하고자하는 여러분의 소망에 감사드립니다. 그러나 답변을 편집 할 때마다이 정보가 첫 페이지 맨 위에 표시됩니다. 이러한 이유로 과도한 편집을 권장하지 않습니다. 많은 수정을 원할 경우 편집을 일괄 처리 할 수 ​​있으므로 몇 시간마다 한 번만 편집 할 수 있습니까? ( 실수로 답에 "EDIT :"와 "UPDATE :"를 넣는 것은 일반적으로 좋지 않습니다. meta.cs.stackexchange.com/q/657/755을 참조하십시오 . )
DW

4
진행 상황 보고서, 상태 업데이트 또는 블로그 항목을 넣을 수있는 곳이 아닙니다. 우리는 "곧 나올 것"또는 "해결책이 있지만 그것이 무엇인지 설명하지 않을 것"이 아닌 완전한 형식의 답변을 원합니다.
DW

3
관심이 있다면 개선 된 솔루션을 찾으십시오. 가장 좋은 방법은 전체 답변을 기다렸다가 게시하는 것입니다. 업데이트가 있으면 블로그에서 할 수 있습니다. 나는 이것을 장려하지 않지만, 당신이 정말로 해야하는 이유가 있다면 (올바른 이유가 보이지 않습니다) 게시물 아래에 의견을 작성하고 나중에 병합 할 수 있습니다. 또한 쓸모없는 주석을 모두 삭제하고 하나의 완벽한 질문에 포함시키는 것이 좋습니다. 모든 것을 읽기가 어렵습니다. 나는 제시된 것과 다른 알고리즘을 만들려고 노력하지만 결과에 만족하지 않아 편집 할 부분을 게시하지 않습니다. 답변 상자는 전체 알고리즘입니다.
Evil

3
@DavidJames, 이해합니다. 그러나 여전히 가이드 라인을 변경하지는 않습니다. 너무 많이 수정하지 마십시오. (웹 사이트 개선을 제안하고 싶다면 Computer Science Meta 또는 meta.stackexchange.com에서 제안하십시오. 개발자는이 댓글 스레드를 읽지 않습니다.) 그러나 그 동안 우리가 가진 소프트웨어로 작업하고, 많은 편집을하는 것은 질문이 맨 위에 오게되므로 권장하지 않습니다. 이 시점에서 하루에 한 번의 편집으로 제한하는 것이 좋은 지침이 될 수 있습니다. 도움이된다면 오프라인 편집기 또는 StackEdit을 자유롭게 사용하십시오!
DW

3
몇 가지 이유로 귀하의 답변을지지하지 않습니다. 1) 불필요하고 길고 너무 장황하다. 프레젠테이션을 크게 줄일 수 있습니다. 2) 나에게 알려지지 않은 이유로 무시하도록 선택한 더 나은 답변이 게시되어 있습니다. 3) 공감 부족에 대해 묻는 것은 대개 "붉은 깃발"입니다. 4) 이것은 INSANE 양의 편집으로 인해 프론트 페이지에 계속 남아 있습니다.
Nicholas Mancuso
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.