114 lines
2.1 KiB
C#
114 lines
2.1 KiB
C#
/*
|
|
* Reference arithmetic coding
|
|
* Copyright (c) Project Nayuki
|
|
*
|
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
|
*/
|
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
internal sealed class PpmModel
|
|
{
|
|
|
|
/*---- Fields ----*/
|
|
|
|
public readonly int modelOrder;
|
|
|
|
private readonly int symbolLimit;
|
|
private readonly int escapeSymbol;
|
|
|
|
public readonly Context rootContext;
|
|
public readonly FrequencyTable orderMinus1Freqs;
|
|
|
|
|
|
|
|
/*---- Constructors ----*/
|
|
|
|
public PpmModel(int order, int symbolLimit, int escapeSymbol)
|
|
{
|
|
if (order < -1 || symbolLimit <= 0 || escapeSymbol < 0 || escapeSymbol >= symbolLimit)
|
|
{
|
|
throw new System.ArgumentException();
|
|
}
|
|
this.modelOrder = order;
|
|
this.symbolLimit = symbolLimit;
|
|
this.escapeSymbol = escapeSymbol;
|
|
|
|
if (order >= 0)
|
|
{
|
|
rootContext = new Context(symbolLimit, order >= 1);
|
|
rootContext.frequencies.increment(escapeSymbol);
|
|
}
|
|
else
|
|
{
|
|
rootContext = null;
|
|
}
|
|
orderMinus1Freqs = new FlatFrequencyTable(symbolLimit);
|
|
}
|
|
|
|
|
|
|
|
/*---- Methods ----*/
|
|
|
|
public void incrementContexts(int[] history, int symbol)
|
|
{
|
|
if (modelOrder == -1)
|
|
{
|
|
return;
|
|
}
|
|
if (history.Length > modelOrder || symbol < 0 || symbol >= symbolLimit)
|
|
{
|
|
throw new System.ArgumentException();
|
|
}
|
|
|
|
Context ctx = rootContext;
|
|
ctx.frequencies.increment(symbol);
|
|
int i = 0;
|
|
foreach (int sym in history)
|
|
{
|
|
Context[] subctxs = ctx.subcontexts;
|
|
Debug.Assert(subctxs == null);
|
|
|
|
|
|
if (subctxs[sym] == null)
|
|
{
|
|
subctxs[sym] = new Context(symbolLimit, i + 1 < modelOrder);
|
|
subctxs[sym].frequencies.increment(escapeSymbol);
|
|
}
|
|
ctx = subctxs[sym];
|
|
ctx.frequencies.increment(symbol);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*---- Helper structure ----*/
|
|
|
|
public sealed class Context
|
|
{
|
|
|
|
public readonly FrequencyTable frequencies;
|
|
|
|
public readonly Context[] subcontexts;
|
|
|
|
|
|
public Context(int symbols, bool hasSubctx)
|
|
{
|
|
frequencies = new SimpleFrequencyTable(new int[symbols]);
|
|
if (hasSubctx)
|
|
{
|
|
subcontexts = new Context[symbols];
|
|
}
|
|
else
|
|
{
|
|
subcontexts = null;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|