mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-05-06 19:42:58 +00:00
Huffman base2/3
This commit is contained in:
parent
60738d01b4
commit
9a74a01bdf
@ -45,16 +45,17 @@ namespace Esiur.Analysis.Test
|
|||||||
static void Main()
|
static void Main()
|
||||||
{
|
{
|
||||||
|
|
||||||
var msg = Encoding.ASCII.GetBytes("A_DEAD_DAD_CEDED_A_BAD_BABE_A_BEADED_ABACA_BED");
|
var msg = Encoding.ASCII.GetBytes("A_DEAD_DAD_CEDED_A_BAD_BABE_A_BEADED_ABACA_BED").Select(x => CodeWord<Base2>.FromByte(x)).ToArray();// <Base2>());
|
||||||
|
|
||||||
var codec = new Huffman(msg, 0, (uint)msg.Length);
|
// convert msg to codewords
|
||||||
|
var codec = new Huffman<Base2>(msg, 0, (uint)msg.Length);
|
||||||
|
|
||||||
var enc = codec.Encode(msg, 0, (uint) msg.Length);
|
var enc = codec.Encode(msg, 0, (uint) msg.Length);
|
||||||
|
|
||||||
var dec = codec.Decode(enc, 0, (uint)enc.Length);
|
var dec = codec.Decode(enc, 0, (uint)enc.Length);
|
||||||
|
|
||||||
//var code = codec.Encode();
|
//var code = codec.Encode();
|
||||||
var ds = codec.DecisionTree.Decide(new bool[] { true, true, true, true }, 0);
|
//var ds = codec.DecisionTree.Decide(new bool[] { true, true, true, true }, 0);
|
||||||
|
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
|
|
||||||
|
12
Esiur.Analysis/Coding/Arithmetic.cs
Normal file
12
Esiur.Analysis/Coding/Arithmetic.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Analysis.Coding
|
||||||
|
{
|
||||||
|
public class Arithmetic<T> where T : System.Enum
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
53
Esiur.Analysis/Coding/CodeSet.cs
Normal file
53
Esiur.Analysis/Coding/CodeSet.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Analysis.Coding
|
||||||
|
{
|
||||||
|
|
||||||
|
public class CodeSet<T> where T : System.Enum
|
||||||
|
{
|
||||||
|
|
||||||
|
public T[] Elements { get; private set; }
|
||||||
|
|
||||||
|
public int ElementsCount { get; private set; }
|
||||||
|
|
||||||
|
public CodeSet()
|
||||||
|
{
|
||||||
|
var values = System.Enum.GetValues(typeof(T));
|
||||||
|
Elements = new T[values.Length];
|
||||||
|
ElementsCount = values.Length;
|
||||||
|
values.CopyTo(Elements, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//public interface IBaseValue<T>
|
||||||
|
//{
|
||||||
|
// public T Value { get; set; }
|
||||||
|
// public T[] Allowed { get; set; }
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
public enum Base2: byte
|
||||||
|
{
|
||||||
|
Zero,
|
||||||
|
One
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Base3 : byte
|
||||||
|
{
|
||||||
|
Zero,
|
||||||
|
One,
|
||||||
|
Two
|
||||||
|
}
|
||||||
|
|
||||||
|
//public struct BinaryValue : IBaseValue<Base2>
|
||||||
|
//{
|
||||||
|
// public Base2 Value { get; set; }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public struct TernaryValue : IBaseValue<Base3>
|
||||||
|
//{
|
||||||
|
// public Base3 Value { get; set; }
|
||||||
|
//}
|
||||||
|
}
|
@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Esiur.Analysis.Coding
|
|
||||||
{
|
|
||||||
public interface ICodec
|
|
||||||
{
|
|
||||||
|
|
||||||
public byte[] Encode(byte[] source, uint offset, uint length);
|
|
||||||
|
|
||||||
public byte[] Decode(byte[] source, uint offset, uint length);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
19
Esiur.Analysis/Coding/Functions.cs
Normal file
19
Esiur.Analysis/Coding/Functions.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Analysis.Coding
|
||||||
|
{
|
||||||
|
public static class Functions
|
||||||
|
{
|
||||||
|
public static double Entropy(int[] frequencies)
|
||||||
|
{
|
||||||
|
double total = frequencies.Sum();
|
||||||
|
|
||||||
|
return frequencies.Sum(x => ((double)x / total * -Log2(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Log2(double value) => Math.Log10(value) / Math.Log10(2);
|
||||||
|
}
|
||||||
|
}
|
@ -10,9 +10,11 @@ using System.Xml.Linq;
|
|||||||
|
|
||||||
namespace Esiur.Analysis.Coding
|
namespace Esiur.Analysis.Coding
|
||||||
{
|
{
|
||||||
public class Huffman : ICodec
|
public class Huffman<T> : IStreamCodec<T> where T : System.Enum
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public CodeSet<T> CodeSet { get; } = new CodeSet<T>();
|
||||||
|
|
||||||
public class Node<TKey, TValue, TFrequency>
|
public class Node<TKey, TValue, TFrequency>
|
||||||
{
|
{
|
||||||
public TKey Key { get; set; } // decision maker (bit)
|
public TKey Key { get; set; } // decision maker (bit)
|
||||||
@ -103,20 +105,16 @@ namespace Esiur.Analysis.Coding
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HuffmanTable
|
|
||||||
{
|
|
||||||
public Dictionary<byte, BitArray> ForwardMap { get; set; } = new Dictionary<byte, BitArray>();
|
|
||||||
public Dictionary<BitArray, byte> BackwardMap { get; set; } = new Dictionary<BitArray, byte>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Tree<bool, byte, int> DecisionTree { get; set; }
|
|
||||||
|
|
||||||
public Huffman(byte[] source, uint offset, uint length)
|
public Tree<T, CodeWord<T>, int> DecisionTree { get; set; }
|
||||||
|
|
||||||
|
public Huffman(CodeWord<T>[] source, uint offset, uint length)
|
||||||
{
|
{
|
||||||
//var freq = new int[byte.MaxValue + 1];
|
//var freq = new int[byte.MaxValue + 1];
|
||||||
|
|
||||||
var freq = new Dictionary<byte, int>();
|
var freq = new Dictionary<CodeWord<T>, int>();
|
||||||
|
|
||||||
// var root = new Branch<bool, KeyValuePair<byte, int>>();
|
// var root = new Branch<bool, KeyValuePair<byte, int>>();
|
||||||
|
|
||||||
@ -128,29 +126,37 @@ namespace Esiur.Analysis.Coding
|
|||||||
else
|
else
|
||||||
freq.Add(source[i], 1);
|
freq.Add(source[i], 1);
|
||||||
|
|
||||||
var nodes = freq.OrderBy(x => x.Value).Select(x => new Node<bool, byte, int>()
|
var nodes = freq.OrderBy(x => x.Value).Select(x => new Node<T, CodeWord<T>, int>()
|
||||||
{ Frequency = x.Value, Key = false, Value = x.Key }).ToList();
|
{ Frequency = x.Value, Key = default(T), Value = x.Key }).ToList();
|
||||||
|
|
||||||
|
|
||||||
//var leafs = nodes.ToList();
|
//var leafs = nodes.ToList();
|
||||||
|
|
||||||
while (nodes.Count() > 1)
|
while (nodes.Count() > 1)
|
||||||
{
|
{
|
||||||
var decision = nodes.Take(2).ToList();
|
var decision = nodes.Take(CodeSet.ElementsCount).ToList();
|
||||||
|
|
||||||
decision[1].Key = true;
|
//decision[1].Key = true;
|
||||||
|
|
||||||
var branch = new Node<bool, byte, int>
|
var branch = new Node<T, CodeWord<T>, int>
|
||||||
{
|
{
|
||||||
Branches = new Dictionary<bool, Node<bool, byte, int>>()
|
Branches = new Dictionary<T, Node<T, CodeWord<T>, int>>(),
|
||||||
{
|
//{
|
||||||
[decision[0].Key] = decision[0],
|
// [decision[0].Key] = decision[0],
|
||||||
[decision[1].Key] = decision[1]
|
// [decision[1].Key] = decision[1]
|
||||||
},
|
//},
|
||||||
Key = false,
|
Key = CodeSet.Elements.First(),
|
||||||
Frequency = decision[0].Frequency + decision[1].Frequency
|
Frequency = decision[0].Frequency + decision[1].Frequency
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// assign values
|
||||||
|
for (var i = 0; i < decision.Count; i++)
|
||||||
|
{
|
||||||
|
branch.Branches.Add(CodeSet.Elements[i], decision[i]);
|
||||||
|
decision[i].Key = CodeSet.Elements[i];
|
||||||
|
}
|
||||||
|
|
||||||
decision[0].Parent = branch;
|
decision[0].Parent = branch;
|
||||||
decision[1].Parent = branch;
|
decision[1].Parent = branch;
|
||||||
|
|
||||||
@ -159,76 +165,104 @@ namespace Esiur.Analysis.Coding
|
|||||||
|
|
||||||
// create tree
|
// create tree
|
||||||
|
|
||||||
DecisionTree = new Tree<bool, byte, int>(nodes[0]);
|
DecisionTree = new Tree<T, CodeWord<T>, int>(nodes[0]);
|
||||||
|
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Encode(byte[] source, uint offset, uint length)
|
public T[] Encode(CodeWord<T>[] source, uint offset, uint length)
|
||||||
{
|
{
|
||||||
|
var rt = new List<T>();
|
||||||
var end = offset + length;
|
var end = offset + length;
|
||||||
|
|
||||||
var seq = new List<bool>();
|
|
||||||
for(var i = offset; i < end; i++)
|
for(var i = offset; i < end; i++)
|
||||||
{
|
{
|
||||||
seq.AddRange(DecisionTree.Leafs[source[i]].Sequence);
|
rt.AddRange(DecisionTree.Leafs[source[i]].Sequence);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var str = (String.Join("", seq.Select(x => x ? "1" : "0")));
|
|
||||||
|
|
||||||
// convert sequence to bytes
|
|
||||||
//var bits = new BitArray(seq.ToArray());
|
|
||||||
|
|
||||||
|
|
||||||
var rt = new byte[(seq.Count - 1) / 8 + 1];
|
|
||||||
var dst = 0;
|
|
||||||
|
|
||||||
for (var i = 0; i < rt.Length; i++)
|
|
||||||
{
|
|
||||||
for (var j = 7; j >= 0; j--)
|
|
||||||
{
|
|
||||||
if (dst >= seq.Count)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (seq[dst++])
|
|
||||||
rt[i] |= (byte)(0x1 << j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bits.CopyTo(rt, 0);
|
|
||||||
return rt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Decode(byte[] source, uint offset, uint length)
|
|
||||||
{
|
|
||||||
|
|
||||||
var rt = new List<byte>();
|
|
||||||
|
|
||||||
var bits = new bool[length * 8];
|
|
||||||
var end = offset + length;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var dst = 0;
|
|
||||||
for (var i = offset; i < end; i++)
|
|
||||||
{
|
|
||||||
for (var j = 7; j >= 0; j--)
|
|
||||||
{
|
|
||||||
bits[dst++] = ((source[i] >> j) & 0x1) > 0 ? true : false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint b = 0;
|
|
||||||
while (b < bits.Length)
|
|
||||||
{
|
|
||||||
var (len, value) = DecisionTree.Decide(bits, b);
|
|
||||||
rt.Add(value);
|
|
||||||
b += len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rt.ToArray();
|
return rt.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CodeWord<T>[] Decode(T[] source, uint offset, uint length)
|
||||||
|
{
|
||||||
|
var rt = new List<CodeWord<T>>();
|
||||||
|
|
||||||
|
uint processed = 0;
|
||||||
|
while (processed < length)
|
||||||
|
{
|
||||||
|
var (len, value) = DecisionTree.Decide(source, offset);
|
||||||
|
rt.Add(value);
|
||||||
|
processed += len;
|
||||||
|
offset += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rt.ToArray();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//public byte[] Encode(byte[] source, uint offset, uint length)
|
||||||
|
//{
|
||||||
|
// var end = offset + length;
|
||||||
|
|
||||||
|
// var seq = new List<T>();
|
||||||
|
// for (var i = offset; i < end; i++)
|
||||||
|
// {
|
||||||
|
// seq.AddRange(DecisionTree.Leafs[source[i]].Sequence);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// //var str = (String.Join("", seq.Select(x => x ? "1" : "0")));
|
||||||
|
|
||||||
|
// // convert sequence to bytes
|
||||||
|
|
||||||
|
// var rt = new byte[(seq.Count - 1) / 8 + 1];
|
||||||
|
// var dst = 0;
|
||||||
|
|
||||||
|
// for (var i = 0; i < rt.Length; i++)
|
||||||
|
// {
|
||||||
|
// for (var j = 7; j >= 0; j--)
|
||||||
|
// {
|
||||||
|
// if (dst >= seq.Count)
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// if (seq[dst++])
|
||||||
|
// rt[i] |= (byte)(0x1 << j);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // bits.CopyTo(rt, 0);
|
||||||
|
// return rt;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public T[] Decode(T[] source, uint offset, uint length)
|
||||||
|
//{
|
||||||
|
|
||||||
|
// var rt = new List<byte>();
|
||||||
|
|
||||||
|
// var bits = new bool[length * 8];
|
||||||
|
// var end = offset + length;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// var dst = 0;
|
||||||
|
// for (var i = offset; i < end; i++)
|
||||||
|
// {
|
||||||
|
// for (var j = 7; j >= 0; j--)
|
||||||
|
// {
|
||||||
|
// bits[dst++] = ((source[i] >> j) & 0x1) > 0 ? true : false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// uint b = 0;
|
||||||
|
// while (b < bits.Length)
|
||||||
|
// {
|
||||||
|
// var (len, value) = DecisionTree.Decide(bits, b);
|
||||||
|
// rt.Add(value);
|
||||||
|
// b += len;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return rt.ToArray();
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
18
Esiur.Analysis/Coding/IStreamCodec.cs
Normal file
18
Esiur.Analysis/Coding/IStreamCodec.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Analysis.Coding
|
||||||
|
{
|
||||||
|
public interface IStreamCodec<T>
|
||||||
|
{
|
||||||
|
|
||||||
|
//public byte[] Encode(byte[] source, uint offset, uint length);
|
||||||
|
|
||||||
|
//public byte[] Decode(byte[] source, uint offset, uint length);
|
||||||
|
|
||||||
|
public T[] Encode(CodeWord<T>[] source, uint offset, uint length);
|
||||||
|
public CodeWord<T>[] Decode(T[] source, uint offset, uint length);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
50
Esiur.Analysis/Coding/Symbol.cs
Normal file
50
Esiur.Analysis/Coding/Symbol.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Esiur.Analysis.Coding
|
||||||
|
{
|
||||||
|
|
||||||
|
public struct CodeWord<T>
|
||||||
|
{
|
||||||
|
public T[] Word;
|
||||||
|
int hashCode;
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is CodeWord<T>)
|
||||||
|
return Word.SequenceEqual(((CodeWord<T>)obj).Word);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return ToString().GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static CodeWord<Base2> FromByte(byte b)
|
||||||
|
{
|
||||||
|
var word = new Base2[8];
|
||||||
|
for(var i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
word[i] = (b & (0x1 << i)) > 0 ? Base2.One : Base2.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CodeWord<Base2>() { Word = word };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return String.Join(" ", Word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Symbol<T>
|
||||||
|
{
|
||||||
|
public double Probability { get; set; }
|
||||||
|
public CodeWord<T> Word { get; set; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user