mirror of
https://github.com/esiur/esiur-dotnet.git
synced 2025-05-06 03:32:57 +00:00
Huffman Coding
This commit is contained in:
parent
b9eb9c6adf
commit
60738d01b4
@ -1,4 +1,7 @@
|
||||
using System.Diagnostics;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using Esiur.Analysis.Coding;
|
||||
using Esiur.Analysis.DSP;
|
||||
using Esiur.Analysis.Signals;
|
||||
/*
|
||||
@ -26,6 +29,8 @@ SOFTWARE.
|
||||
*/
|
||||
|
||||
using Esiur.Analysis.Signals.Codes;
|
||||
using Esiur.Data;
|
||||
using Esiur.Resource;
|
||||
|
||||
namespace Esiur.Analysis.Test
|
||||
{
|
||||
@ -40,6 +45,19 @@ namespace Esiur.Analysis.Test
|
||||
static void Main()
|
||||
{
|
||||
|
||||
var msg = Encoding.ASCII.GetBytes("A_DEAD_DAD_CEDED_A_BAD_BABE_A_BEADED_ABACA_BED");
|
||||
|
||||
var codec = new Huffman(msg, 0, (uint)msg.Length);
|
||||
|
||||
var enc = codec.Encode(msg, 0, (uint) msg.Length);
|
||||
|
||||
var dec = codec.Decode(enc, 0, (uint)enc.Length);
|
||||
|
||||
//var code = codec.Encode();
|
||||
var ds = codec.DecisionTree.Decide(new bool[] { true, true, true, true }, 0);
|
||||
|
||||
Console.WriteLine();
|
||||
|
||||
var f = Esiur.Analysis.Algebra.Functions.Sigmoid;
|
||||
|
||||
var signalA = new double[] { V,1, V, 1 , V, V, V };
|
||||
|
15
Esiur.Analysis/Coding/Codec.cs
Normal file
15
Esiur.Analysis/Coding/Codec.cs
Normal file
@ -0,0 +1,15 @@
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
234
Esiur.Analysis/Coding/Huffman.cs
Normal file
234
Esiur.Analysis/Coding/Huffman.cs
Normal file
@ -0,0 +1,234 @@
|
||||
using Esiur.Analysis.Units;
|
||||
using Esiur.Data;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Esiur.Analysis.Coding
|
||||
{
|
||||
public class Huffman : ICodec
|
||||
{
|
||||
|
||||
public class Node<TKey, TValue, TFrequency>
|
||||
{
|
||||
public TKey Key { get; set; } // decision maker (bit)
|
||||
|
||||
|
||||
public TValue Value { get; set; } // node value
|
||||
public TFrequency Frequency { get; set; } // node / subnodes frequency
|
||||
|
||||
public Dictionary<TKey, Node<TKey, TValue, TFrequency>> Branches { get; set; }
|
||||
|
||||
|
||||
public Node<TKey, TValue, TFrequency> Parent { get; set; }
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Sequence != null)
|
||||
return $"{Key} => {Value} [{Frequency}] | {string.Join("->", Sequence)}";
|
||||
else
|
||||
return $"{Key} => {Value} [{Frequency}]";
|
||||
}
|
||||
|
||||
|
||||
public TKey[]? Sequence { get; internal set; }
|
||||
|
||||
public void UpdateDecisionSequence()
|
||||
{
|
||||
var parent = Parent;
|
||||
|
||||
var seq = new List<TKey>() { Key };
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
seq.Add(parent.Key);
|
||||
parent = parent.Parent;
|
||||
}
|
||||
|
||||
seq.Reverse();
|
||||
|
||||
Sequence = seq.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class Tree<TKey, TValue, TFrequency>
|
||||
{
|
||||
|
||||
public (uint, TValue) Decide(TKey[] sequence, uint offset)
|
||||
{
|
||||
var oOffset = offset;
|
||||
|
||||
var node = Branches[sequence[offset++]];
|
||||
|
||||
while (node != null && node.Branches != null && node.Branches.Count > 0)
|
||||
{
|
||||
node = node.Branches[sequence[offset++]];
|
||||
}
|
||||
|
||||
return (offset - oOffset, node.Value);
|
||||
}
|
||||
|
||||
public Dictionary<TKey, Node<TKey, TValue, TFrequency>> Branches { get; }
|
||||
public Dictionary<TValue, Node<TKey, TValue, TFrequency>> Leafs { get; set; }
|
||||
|
||||
public Tree(Node<TKey, TValue, TFrequency> rootNode)
|
||||
{
|
||||
Branches = rootNode.Branches;
|
||||
|
||||
var leafs = new List<Node<TKey, TValue, TFrequency>>();
|
||||
|
||||
GetLeafs(rootNode, leafs, new TKey[0]);
|
||||
|
||||
Leafs = leafs.ToDictionary(x => x.Value, x => x);
|
||||
}
|
||||
|
||||
void GetLeafs(Node<TKey, TValue, TFrequency> node, List<Node<TKey, TValue, TFrequency>> leafs, TKey[] sequence)
|
||||
{
|
||||
foreach (var branch in node.Branches)
|
||||
if (branch.Value.Branches == null || branch.Value.Branches.Count == 0)
|
||||
{
|
||||
leafs.Add(branch.Value);
|
||||
branch.Value.Sequence = sequence.Append(branch.Key).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
GetLeafs(branch.Value, leafs, sequence.Append(branch.Key).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
//var freq = new int[byte.MaxValue + 1];
|
||||
|
||||
var freq = new Dictionary<byte, int>();
|
||||
|
||||
// var root = new Branch<bool, KeyValuePair<byte, int>>();
|
||||
|
||||
// calculate probabilities
|
||||
var end = offset + length;
|
||||
for (var i = offset; i < end; i++)
|
||||
if (freq.ContainsKey(source[i]))
|
||||
freq[source[i]]++;
|
||||
else
|
||||
freq.Add(source[i], 1);
|
||||
|
||||
var nodes = freq.OrderBy(x => x.Value).Select(x => new Node<bool, byte, int>()
|
||||
{ Frequency = x.Value, Key = false, Value = x.Key }).ToList();
|
||||
|
||||
|
||||
//var leafs = nodes.ToList();
|
||||
|
||||
while (nodes.Count() > 1)
|
||||
{
|
||||
var decision = nodes.Take(2).ToList();
|
||||
|
||||
decision[1].Key = true;
|
||||
|
||||
var branch = new Node<bool, byte, int>
|
||||
{
|
||||
Branches = new Dictionary<bool, Node<bool, byte, int>>()
|
||||
{
|
||||
[decision[0].Key] = decision[0],
|
||||
[decision[1].Key] = decision[1]
|
||||
},
|
||||
Key = false,
|
||||
Frequency = decision[0].Frequency + decision[1].Frequency
|
||||
};
|
||||
|
||||
decision[0].Parent = branch;
|
||||
decision[1].Parent = branch;
|
||||
|
||||
nodes = nodes.Skip(2).Append(branch).OrderBy(x => x.Frequency).ToList();
|
||||
}
|
||||
|
||||
// create tree
|
||||
|
||||
DecisionTree = new Tree<bool, byte, int>(nodes[0]);
|
||||
|
||||
Console.WriteLine();
|
||||
|
||||
}
|
||||
|
||||
public byte[] Encode(byte[] source, uint offset, uint length)
|
||||
{
|
||||
var end = offset + length;
|
||||
|
||||
var seq = new List<bool>();
|
||||
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 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();
|
||||
}
|
||||
}
|
||||
}
|
10
Esiur.Analysis/DSP/Filters.cs
Normal file
10
Esiur.Analysis/DSP/Filters.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Esiur.Analysis.DSP
|
||||
{
|
||||
internal class Filters
|
||||
{
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user