sharplib/ar/PpmModel.cs

114 lines
2.2 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;
}
}
}
}