Deflate 알고리즘에서 블록 크기를 결정하기위한 몇 가지 좋은 전략은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/484295

문제

나는 작은 사이드 프로젝트로 압축 라이브러리를 쓰고 있으며, (내 라이브러리가 표준 GZIP 파일을 추출 할 수있을뿐만 아니라, 아직 최적의 GZIP 출력을 준수 할 수 있지만) 의미있는 블록 종료 전략. 현재 32k의 입력 (LZ77 창 크기)마다 블록을 차단하고 구현하기가 빠르기 때문에 블록을 차단합니다. 이제 돌아가서 실제로 압축 효율을 향상 시키려고 노력하고 있습니다.

그만큼 사양 디플레이트 "압축기는 신선한 나무로 새 블록을 시작하는 것이 유용하거나 블록 크기가 압축기의 블록 버퍼를 채울 때 블록을 종료합니다."

SharpZiplib 코드를 정렬했으며 (가장 많이 읽을 수있는 오픈 소스 구현이라고 생각했듯이) 입력을 무시하고 16k 리터의 출력마다 블록을 종료하는 것을 발견했습니다. 이것은 구현하기에 쉽지만, 특히 사양의 언어를 감안할 때 더 대상이되는 접근 방식이 있어야합니다. "신선한 나무로 새로운 블록을 시작하는 것이 유용하다고 결정합니다.

그렇다면 새로운 전략에 대한 아이디어 나 기존 전략에 대한 아이디어가 있습니까?

미리 감사드립니다!

도움이 되었습니까?

해결책

당신을 가기위한 제안으로.

우수한 압축을 표시하기에 충분한 크기의 버퍼로 추측적인 모습은 변화의 가치가 있습니다.

이는 스트리밍 동작을 변경하고 (출력이 발생하기 전에 더 많은 데이터가 입력되어야 함) Flush와 같은 작업을 크게 복잡하게합니다. 또한 압축 스테이크에서 상당한 추가 부하입니다.

일반적으로 새로운 블록을 시작할 수있는 각 지점에서 분기하여 단순히 최적의 출력을 생성 할 수 있으며, 모든 경로가 취해질 때까지 두 가지 분기를 필요에 따라 복귀시킬 수 있습니다. 둥지 행동을 한 길은 승리합니다. 새로운 블록을 시작할시기를 선택하는 것이 너무 열려 있기 때문에 비 사소한 입력 크기에서는 불가능할 수 있습니다.

단순히 최소 8K 출력 리터럴로 제한하지만 블록에서 32k 이상의 리터럴을 방지하면 투기 알고리즘을 시도하기위한 상대적으로 다루기 쉬운 기초가됩니다. 8K를 서브 블록으로 호출하십시오.

가장 간단한 것은 (의사 코드)입니다.

create empty sub block called definite
create empty sub block called specChange
create empty sub block called specKeep
target = definite
While (incomingData)
{
  compress data into target(s)    
  if (definite.length % SUB_BLOCK_SIZ) == 0)
  {
    if (targets is definite)
    {
      targets becomes 
        specChange assuming new block 
        specKeep assuming same block as definite
    }        
    else
    {
      if (compression specChange - OVERHEAD better than specKeep)
      {
        flush definite as a block.
        definite = specChange
        specKeep,specChange = empty
        // target remains specKeep,specChange as before 
        but update the meta data associated with specChange to be fresh
      }
      else 
      {
        definite += specKeep
        specKeep,specChange = empty
        // again update the block meta data
        if (definite is MAX_BLOCK_SIZE)
        {
          flush definite
          target becomes definite 
        }
      }
    }
  }
}
take best of specChange/specKeep if non empty and append to definite
flush definite.

오버 헤드는 블록 위로 전환하는 비용을 설명하기 위해 일정합니다.

이것은 거칠고 개선 될 수 있지만 다른 것이 없다면 분석의 시작입니다. 스위치의 원인에 대한 정보를위한 코드를 기기로,이를 사용하여 변경이 유익 할 수 있다는 우수한 휴리스틱을 결정하십시오 (아마도 압축 비율이 크게 떨어 졌을 것입니다).

이것은 휴리스틱이 합리적으로 간주 한 경우에만 Specchange의 구축이 이루어질 수 있습니다. 휴리스틱이 강력한 지표로 판명되면 투기 적 특성을 없애고 무엇이든지 지점에서 교환하기로 결정할 수 있습니다.

다른 팁

흠, 나는 블록을 끝내는 것이 유익 할 수있는 "규칙"을 내놓으려고 노력하려는 휴리스틱 분석의 아이디어를 좋아합니다. 나는 오늘 밤 당신의 제안 된 접근 방식을 살펴보고 내가 무엇을 할 수 있는지 볼 것입니다.

그 동안,이 문제에 대해 완전히 정보를 선택하기 위해서는 블록 크기 결정의 장단점에 대한 더 나은 정신적 그림이 필요합니다. 정말 빨리 나는 작은 블록을 통해 나무를 더 자주 정의하는 데 오버 헤드가 증가하는 비용으로 잠재적으로 더 나은 타겟 기호 알파벳을 가질 수 있습니다. 더 큰 블록은 더 일반적인 기호 알파벳을 스케일의 효율성으로 반대합니다 (많은 인코딩 된 데이터를 위해 저장하고 디코딩 할 트리 하나만).

내 머리 꼭대기에서, 쓰레기 코드의 상대적 분포와 길이, 거리 코드가 최적의 블록 크기에 특정한 영향을 미칠지 여부는 분명하지 않습니다. 그래도 좋은 음식.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top