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;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|