sharplib/ar/PpmModel.cs

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