mirror of
				https://github.com/esiur/esiur-dotnet.git
				synced 2025-11-04 01:11:35 +00:00 
			
		
		
		
	Huffman base2/3
This commit is contained in:
		@@ -45,16 +45,17 @@ namespace Esiur.Analysis.Test
 | 
			
		||||
        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 dec = codec.Decode(enc, 0, (uint)enc.Length);
 | 
			
		||||
 | 
			
		||||
            //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();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
{
 | 
			
		||||
    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 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 Dictionary<byte, int>();
 | 
			
		||||
            var freq = new Dictionary<CodeWord<T>, int>();
 | 
			
		||||
 | 
			
		||||
            // var root = new Branch<bool, KeyValuePair<byte, int>>();
 | 
			
		||||
 | 
			
		||||
@@ -128,29 +126,37 @@ namespace Esiur.Analysis.Coding
 | 
			
		||||
                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 nodes = freq.OrderBy(x => x.Value).Select(x => new Node<T, CodeWord<T>, int>()
 | 
			
		||||
            { Frequency = x.Value, Key = default(T), Value = x.Key }).ToList();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            //var leafs = nodes.ToList();
 | 
			
		||||
 | 
			
		||||
            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>>()
 | 
			
		||||
                    {
 | 
			
		||||
                        [decision[0].Key] = decision[0],
 | 
			
		||||
                        [decision[1].Key] = decision[1]
 | 
			
		||||
                    },
 | 
			
		||||
                    Key = false,
 | 
			
		||||
                    Branches = new Dictionary<T, Node<T, CodeWord<T>, int>>(),
 | 
			
		||||
                    //{
 | 
			
		||||
                    //    [decision[0].Key] = decision[0],
 | 
			
		||||
                    //    [decision[1].Key] = decision[1]
 | 
			
		||||
                    //},
 | 
			
		||||
                    Key = CodeSet.Elements.First(),
 | 
			
		||||
                    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[1].Parent = branch;
 | 
			
		||||
 | 
			
		||||
@@ -159,76 +165,104 @@ namespace Esiur.Analysis.Coding
 | 
			
		||||
 | 
			
		||||
            // create tree
 | 
			
		||||
 | 
			
		||||
            DecisionTree = new Tree<bool, byte, int>(nodes[0]);
 | 
			
		||||
            DecisionTree = new Tree<T, CodeWord<T>, int>(nodes[0]);
 | 
			
		||||
 | 
			
		||||
            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 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;
 | 
			
		||||
                rt.AddRange(DecisionTree.Leafs[source[i]].Sequence);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user