private void ApplyBlockSplit(BlockSwitchBuilder builder, List <int> lengths) { builder.Reset(); if (lengths.Count < 2) { return; } for (int i = 0; i < lengths.Count; i++) { builder.AddBlock((byte)(i % 256), lengths[i]); } }
public void ProcessSequence(BlockSwitchBuilder builder, List <T> sequence, ContextInfo?contextParam = null) { builder.Reset(); ContextInfo ctx = contextParam ?? ContextInfo.Default; int numContexts = 1 + ctx.Map.Max(); int maxBlockTypes = 256 / numContexts; int maxNumBlocks = sequence.Count / minBlockSize + 1; var histograms = FrequencyList <T> .Array(numContexts *Math.Min(maxNumBlocks, maxBlockTypes + 1)); int numBlocks = 0; int blockSize = 0; int targetBlockSize = minBlockSize; int currHistogramIx = 0; var lastHistogramIx = new int[2]; var lastEntropy = new double[2 * numContexts]; int mergeLastCount = 0; void FinishBlock(bool isFinal) { blockSize = Math.Max(blockSize, minBlockSize); if (numBlocks == 0) { builder.SetInitialLength(blockSize); for (int context = 0; context < numContexts; context++) { lastEntropy[context] = BitsEntropy(histograms[context]); lastEntropy[context + numContexts] = lastEntropy[context]; } currHistogramIx += numContexts; ++numBlocks; blockSize = 0; } else if (blockSize > 0) { var entropy = new double[numContexts]; var combinedHisto = FrequencyList <T> .Array(2 *numContexts); var combinedEntropy = new double[2 * numContexts]; var diff = new double[2]; for (int context = 0; context < numContexts; context++) { int currHistoIx = currHistogramIx + context; entropy[context] = BitsEntropy(histograms[currHistoIx]); for (int i = 0; i < 2; i++) { int ix = i * numContexts + context; int lastHistogramIxValue = lastHistogramIx[i] + context; var newHisto = new FrequencyList <T> { histograms[currHistoIx], histograms[lastHistogramIxValue] }; combinedHisto[ix] = newHisto; combinedEntropy[ix] = BitsEntropy(combinedHisto[ix]); diff[i] += combinedEntropy[ix] - entropy[context] - lastEntropy[ix]; } } if (builder.TypeCount < maxBlockTypes && diff[0] > splitThreshold && diff[1] > splitThreshold) { byte nextBlockType = (byte)(builder.TypeCount); builder.AddBlock(nextBlockType, blockSize); lastHistogramIx[1] = lastHistogramIx[0]; lastHistogramIx[0] = nextBlockType * numContexts; for (int context = 0; context < numContexts; context++) { lastEntropy[context + numContexts] = lastEntropy[context]; lastEntropy[context] = entropy[context]; } currHistogramIx += numContexts; if (currHistogramIx < histograms.Length) { histograms[currHistogramIx].Clear(); } ++numBlocks; blockSize = 0; mergeLastCount = 0; targetBlockSize = minBlockSize; } else if (diff[1] < diff[0] - 20.0) { builder.AddBlock(builder.Commands.Count >= 2 ? builder.Commands[^ 2].Type : (byte)0, blockSize);