From 60738d01b4607019193cfdc3b16c6f5326eaf24e Mon Sep 17 00:00:00 2001 From: Ahmed Zamil Date: Sat, 25 Mar 2023 19:54:15 +0300 Subject: [PATCH] Huffman Coding --- Esiur.Analysis.Test/Program.cs | 18 +++ Esiur.Analysis/Coding/Codec.cs | 15 ++ Esiur.Analysis/Coding/Huffman.cs | 234 +++++++++++++++++++++++++++++++ Esiur.Analysis/DSP/Filters.cs | 10 ++ 4 files changed, 277 insertions(+) create mode 100644 Esiur.Analysis/Coding/Codec.cs create mode 100644 Esiur.Analysis/Coding/Huffman.cs create mode 100644 Esiur.Analysis/DSP/Filters.cs diff --git a/Esiur.Analysis.Test/Program.cs b/Esiur.Analysis.Test/Program.cs index bb05509..2318c68 100644 --- a/Esiur.Analysis.Test/Program.cs +++ b/Esiur.Analysis.Test/Program.cs @@ -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 }; diff --git a/Esiur.Analysis/Coding/Codec.cs b/Esiur.Analysis/Coding/Codec.cs new file mode 100644 index 0000000..1db0823 --- /dev/null +++ b/Esiur.Analysis/Coding/Codec.cs @@ -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); + + } +} diff --git a/Esiur.Analysis/Coding/Huffman.cs b/Esiur.Analysis/Coding/Huffman.cs new file mode 100644 index 0000000..0707a1d --- /dev/null +++ b/Esiur.Analysis/Coding/Huffman.cs @@ -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 + { + 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> Branches { get; set; } + + + public Node 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() { Key }; + + while (parent != null) + { + seq.Add(parent.Key); + parent = parent.Parent; + } + + seq.Reverse(); + + Sequence = seq.ToArray(); + } + } + + + public class Tree + { + + 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> Branches { get; } + public Dictionary> Leafs { get; set; } + + public Tree(Node rootNode) + { + Branches = rootNode.Branches; + + var leafs = new List>(); + + GetLeafs(rootNode, leafs, new TKey[0]); + + Leafs = leafs.ToDictionary(x => x.Value, x => x); + } + + void GetLeafs(Node node, List> 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 ForwardMap { get; set; } = new Dictionary(); + public Dictionary BackwardMap { get; set; } = new Dictionary(); + } + + + public Tree DecisionTree { get; set; } + + public Huffman(byte[] source, uint offset, uint length) + { + //var freq = new int[byte.MaxValue + 1]; + + var freq = new Dictionary(); + + // var root = new Branch>(); + + // 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() + { 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 + { + Branches = new Dictionary>() + { + [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(nodes[0]); + + Console.WriteLine(); + + } + + public byte[] Encode(byte[] source, uint offset, uint length) + { + var end = offset + length; + + var seq = new List(); + 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(); + + 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(); + } + } +} diff --git a/Esiur.Analysis/DSP/Filters.cs b/Esiur.Analysis/DSP/Filters.cs new file mode 100644 index 0000000..c2f069c --- /dev/null +++ b/Esiur.Analysis/DSP/Filters.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Esiur.Analysis.DSP +{ + internal class Filters + { + } +}