KeccakSpongeManaged.cs

Posted on June 8, 2020  Leave a comment on KeccakSpongeManaged.cs

Keccak Sponge (Sha3) Checked

using System;
using System.Runtime.CompilerServices;
[Serializable]
public class SHA3Managed : HashAlgorithmEx
{
    private readonly KeccakSpongeManaged ksm;
    public SHA3Managed(int size, ulong[] seed = null) : this(size, 24, seed)
    {
    }
    public SHA3Managed(int size) : this(size, 24)
    {
    }
    public SHA3Managed() : this(512, 24)
    {
    }
    public SHA3Managed(int size, int rounds = 24, ulong[] seed = null)
    {
        if (rounds > 24)
            throw new Exception($"Maximum rounds allowed is {24}");
        var MaxBR     = (64 >> 3) * 25;
        var sizeBytes = size >> 3;
        var rateBytes = MaxBR - (sizeBytes << 1);
        var MaxSize   = ((MaxBR - 8)       >> 1) << 3;
        if (rateBytes < 8)
            throw new Exception($"Maximum size allowed is {MaxSize} Bits with {64} bit Width specified. Specified Size is {size} Bits.");
        var outputLength = size >> 3;
        ksm           = new KeccakSpongeManaged(rateBytes, 200 - rateBytes, KeccakSpongeManaged.KeccakDelimiter, outputLength, seed);
        ksm.Rounds    = rounds;
        HashSizeValue = size;
    }
    public int HashLength => ksm.HashLength;
    public override void Initialize()
    {
        ksm.Initialize();
    }
    protected override void HashCore(byte[] array, int ibStart, int cbSize)
    {
        Initialize();
        ksm.Absorb(array, ibStart, cbSize);
    }
    protected override byte[] HashFinal()
    {
        return ksm.Squeeze();
    }
}
[Serializable]
public class KeccakSpongeManaged
{
    public const     int KeccakDelimiter = 6;
    public const     int ShakeDelimiter  = 31;
    private readonly int _delimiter;
    private readonly int _outputLength;
    private readonly int _rateBytes;
    private readonly ulong[] _roundConstants =
    {
        0x0000000000000001,
        0x0000000000008082,
        0x800000000000808A,
        0x8000000080008000,
        0x000000000000808B,
        0x0000000080000001,
        0x8000000080008081,
        0x8000000000008009,
        0x000000000000008A,
        0x0000000000000088,
        0x0000000080008009,
        0x000000008000000A,
        0x000000008000808B,
        0x800000000000008B,
        0x8000000000008089,
        0x8000000000008003,
        0x8000000000008002,
        0x8000000000000080,
        0x000000000000800A,
        0x800000008000000A,
        0x8000000080008081,
        0x8000000000008080,
        0x0000000080000001,
        0x8000000080008008
    };
    private readonly ulong[] _seed;
    private          int     _blockSize;
    private          int     _input;
    private          int     _output;
    private          byte[]  _result;
    private          ulong[] _state;
    public           int     HashLength;
    public           int     Rounds = 24;
    public KeccakSpongeManaged(int rateBytes, int capacityBytes, int delimiter, int outputLength, ulong[] seed)
    {
        if (rateBytes + capacityBytes != 200 || (uint) (rateBytes % 8) > 0U)
            throw new ArgumentException($"rateBytes {rateBytes} + capacityBytes {capacityBytes}={rateBytes + capacityBytes} must be 200 or {rateBytes} must be a multiple of 8");
        _rateBytes    = rateBytes;
        _delimiter    = delimiter;
        _outputLength = outputLength;
        HashLength    = outputLength;
        _seed         = seed;
    }
    public void Initialize()
    {
        _blockSize = 0;
        _input     = 0;
        _output    = 0;
        _state     = new ulong[25];
        _result    = new byte[_outputLength];
        if (_seed != null && _seed[0] != 0)
        {
            for (var i = 0; i < _seed.Length && i < _state.Length; ++i)
                _state[i] = _seed[i];
            Permute(_state);
        }
    }
    public void Absorb(byte[] array, int start, int size)
    {
        while (size > 0)
        {
            _blockSize = Math.Min(size, _rateBytes);
            for (var index = start; index < _blockSize; ++index)
            {
                var num = Convert.ToByte(Buffer.GetByte(_state, index) ^ array[index + _input]);
                Buffer.SetByte(_state, index, num);
            }
            _input += _blockSize;
            size   -= _blockSize;
            if (_blockSize == _rateBytes)
            {
                Permute(_state);
                _blockSize = 0;
            }
        }
    }
    public byte[] Squeeze()
    {
        Buffer.SetByte(_state, _blockSize, Convert.ToByte(Buffer.GetByte(_state, _blockSize) ^ _delimiter));
        if ((_delimiter & 128) != 0 && _blockSize == _rateBytes - 1)
            Permute(_state);
        Buffer.SetByte(_state, _rateBytes - 1, Convert.ToByte(Buffer.GetByte(_state, _rateBytes - 1) ^ 128));
        Permute(_state);
        var outputLength = _outputLength;
        while (outputLength > 0)
        {
            _blockSize = Math.Min(outputLength, _rateBytes);
            Buffer.BlockCopy(_state, 0, _result, _output, _blockSize);
            _output      += _blockSize;
            outputLength -= _blockSize;
            if (outputLength > 0)
                Permute(_state);
        }
        return _result;
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void Permute(ulong[] state)
    {
        for (var round = 0; round < Rounds; ++round)
        {
            Theta(out var C0, state, out var C1, out var C2, out var C3, out var C4);
            RhoPi(state);
            Chi(ref C0, state, ref C1, ref C2, ref C3, ref C4);
            Iota(round, state);
        }
    }
    private static void Theta(out ulong C0, ulong[] state, out ulong C1, out ulong C2, out ulong C3, out ulong C4)
    {
        C0 = state[0] ^ state[5] ^ state[10] ^ state[15] ^ state[20];
        C1 = state[1] ^ state[6] ^ state[11] ^ state[16] ^ state[21];
        C2 = state[2] ^ state[7] ^ state[12] ^ state[17] ^ state[22];
        C3 = state[3] ^ state[8] ^ state[13] ^ state[18] ^ state[23];
        C4 = state[4] ^ state[9] ^ state[14] ^ state[19] ^ state[24];
        var D0 = Rol(C1, 1) ^ C4;
        var D1 = Rol(C2, 1) ^ C0;
        var D2 = Rol(C3, 1) ^ C1;
        var D3 = Rol(C4, 1) ^ C2;
        var D4 = Rol(C0, 1) ^ C3;
        state[0]  ^= D0;
        state[5]  ^= D0;
        state[10] ^= D0;
        state[15] ^= D0;
        state[20] ^= D0;
        state[1]  ^= D1;
        state[6]  ^= D1;
        state[11] ^= D1;
        state[16] ^= D1;
        state[21] ^= D1;
        state[2]  ^= D2;
        state[7]  ^= D2;
        state[12] ^= D2;
        state[17] ^= D2;
        state[22] ^= D2;
        state[3]  ^= D3;
        state[8]  ^= D3;
        state[13] ^= D3;
        state[18] ^= D3;
        state[23] ^= D3;
        state[4]  ^= D4;
        state[9]  ^= D4;
        state[14] ^= D4;
        state[19] ^= D4;
        state[24] ^= D4;
    }
    private static void RhoPi(ulong[] state)
    {
        var a = Rol(state[1], 1);
        state[1]  = Rol(state[6],  44);
        state[6]  = Rol(state[9],  20);
        state[9]  = Rol(state[22], 61);
        state[22] = Rol(state[14], 39);
        state[14] = Rol(state[20], 18);
        state[20] = Rol(state[2],  62);
        state[2]  = Rol(state[12], 43);
        state[12] = Rol(state[13], 25);
        state[13] = Rol(state[19], 8);
        state[19] = Rol(state[23], 56);
        state[23] = Rol(state[15], 41);
        state[15] = Rol(state[4],  27);
        state[4]  = Rol(state[24], 14);
        state[24] = Rol(state[21], 2);
        state[21] = Rol(state[8],  55);
        state[8]  = Rol(state[16], 45);
        state[16] = Rol(state[5],  36);
        state[5]  = Rol(state[3],  28);
        state[3]  = Rol(state[18], 21);
        state[18] = Rol(state[17], 15);
        state[17] = Rol(state[11], 10);
        state[11] = Rol(state[7],  6);
        state[7]  = Rol(state[10], 3);
        state[10] = a;
    }
    private void Iota(int round, ulong[] state)
    {
        state[0] ^= _roundConstants[round];
    }
    private static void Chi(ref ulong C0, ulong[] state, ref ulong C1, ref ulong C2, ref ulong C3, ref ulong C4)
    {
        for (var index = 0; index < 25; index += 5)
        {
            C0               = state[index]     ^ (~state[1 + index] & state[2 + index]);
            C1               = state[1 + index] ^ (~state[2 + index] & state[3 + index]);
            C2               = state[2 + index] ^ (~state[3 + index] & state[4 + index]);
            C3               = state[3 + index] ^ (~state[4 + index] & state[index]);
            C4               = state[4 + index] ^ (~state[index]     & state[1 + index]);
            state[index]     = C0;
            state[1 + index] = C1;
            state[2 + index] = C2;
            state[3 + index] = C3;
            state[4 + index] = C4;
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static ulong Rol(ulong x, byte y)
    {
        return (x << y) | (x >> (64 - y));
    }
}

BMPartialPatternSearch.cs

Posted on June 7, 2020  Leave a comment on BMPartialPatternSearch.cs

Boyer Moore Partial Pattern Search

using System;
using System.Collections.Generic;
public class BMPartialPatternSearch
{
    public int MinimumSearchLength;
    public BMPartialPatternSearch(int min = 5)
    {
        MinimumSearchLength = min;
    }
    public (byte[] partialPattern, int idx) SearchPartial(byte[] pattern, byte[] searchArray)
    {
        var bm   = new BoyerMoore(pattern);
        var len  = pattern.Length;
        var tree = new List<byte[]>();
        if (len < MinimumSearchLength)
            throw new Exception("Search Pattern less than minimum search length.");
        var offset = 0;
        var wl     = MinimumSearchLength;
        do
        {
            var tpat = new byte[wl];
            Array.Copy(pattern, offset, tpat, 0, wl);
            tree.Add(tpat);
            bm.SetPattern(tpat);
            var idx = bm.Search(searchArray);
            if (idx != -1)
                return (tpat, idx);
            if (offset + wl >= len)
            {
                offset = 0;
                wl++;
                continue;
            }
            offset++;
        } while (wl != len + 1);
        return (pattern, -1);
    }
    public List<(byte[] partialPattern, int idx)> SearchPartialFirst(byte[] pattern, byte[] searchArray)
    {
        var bm   = new BoyerMoore(pattern);
        var len  = pattern.Length;
        var lst  = new List<(byte[] partialPattern, int idx)>();
        var tree = new List<byte[]>();
        if (len < MinimumSearchLength)
            throw new Exception("Search Pattern less than minimum search length.");
        var offset = 0;
        var wl     = MinimumSearchLength;
        do
        {
            var tpat = new byte[wl];
            Array.Copy(pattern, offset, tpat, 0, wl);
            tree.Add(tpat);
            bm.SetPattern(tpat);
            var idx = bm.Search(searchArray);
            if (idx != -1)
                lst.Add((tpat, idx));
            if (offset + wl >= len)
            {
                offset = 0;
                wl++;
                continue;
            }
            offset++;
        } while (wl != len + 1);
        return new List<(byte[] partialPattern, int idx)> {(pattern, -1)};
    }
    public List<(byte[] partialPattern, int idx)> SearchPartialAll(byte[] pattern, byte[] searchArray)
    {
        var bm   = new BoyerMoore(pattern);
        var len  = pattern.Length;
        var lst  = new List<(byte[] partialPattern, int idx)>();
        var tree = new List<byte[]>();
        if (len < MinimumSearchLength)
            throw new Exception("Search Pattern less than minimum search length.");
        var offset = 0;
        var wl     = MinimumSearchLength;
        do
        {
            var tpat = new byte[wl];
            Array.Copy(pattern, offset, tpat, 0, wl);
            tree.Add(tpat);
            bm.SetPattern(tpat);
            var idxl = bm.SearchAll(searchArray);
            if (idxl.Item1.Count > 0)
                foreach (var idx in idxl.Item1)
                    lst.Add((tpat, idx));
            if (offset + wl >= len)
            {
                offset = 0;
                wl++;
                continue;
            }
            offset++;
        } while (wl != len + 1);
        return lst;
    }
    public static Dictionary<string, int> SearchPartialSubSet(byte[] searchArray, int startLength, int endLength)
    {
        var pattern = (byte[]) searchArray.Clone();
        var bm      = new BoyerMoore(pattern);
        var pLen    = pattern.Length;
        var lst     = new Dictionary<string, int>();
        var tree    = new List<byte[]>();
        if (pLen < endLength)
            throw new Exception("Search Pattern less than minimum search length.");
        var offset = 0;
        var wl     = startLength;
        do
        {
            var tpat = new byte[wl];
            Array.Copy(pattern, offset, tpat, 0, wl);
            tree.Add(tpat);
            bm.SetPattern(tpat);
            var idxl = bm.SearchAll(searchArray);
            if (idxl.Item1.Count > 1)
            {
                var sapat = tpat.ToHexString();
                if (!lst.ContainsKey(sapat))
                    lst.Add(sapat, idxl.Item1.Count);
            }
            if (offset + wl >= pLen)
            {
                offset = 0;
                wl++;
                if (wl > endLength)
                    break;
                continue;
            }
            offset++;
        } while (wl != pLen + 1);
        return lst;
    }
    public static Dictionary<string, int> SearchPartialSubSet(byte[] searchArray1, byte[] searchArray2, int startLength, int endLength)
    {
        var bm   = new BoyerMoore(searchArray2);
        var pLen = searchArray2.Length;
        var lst  = new Dictionary<string, int>();
        var tree = new List<byte[]>();
        if (pLen < endLength)
            throw new Exception("Search Pattern less than minimum search length.");
        var offset = 0;
        var wl     = startLength;
        do
        {
            var tpat = new byte[wl];
            Array.Copy(searchArray2, offset, tpat, 0, wl);
            tree.Add(tpat);
            bm.SetPattern(tpat);
            var idxl = bm.SearchAll(searchArray1);
            if (idxl.Item1.Count > 1)
            {
                var sapat = tpat.ToHexString();
                if (!lst.ContainsKey(sapat))
                    lst.Add(sapat, idxl.Item1.Count);
            }
            if (offset + wl >= pLen)
            {
                offset = 0;
                wl++;
                if (wl > endLength)
                    break;
                continue;
            }
            offset++;
        } while (wl != pLen + 1);
        return lst;
    }
}

BoyerMoore.cs

Posted on June 6, 2020  Leave a comment on BoyerMoore.cs

Boyer Moore Search Algorithm

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class BoyerMoore
{
    private int[]  _jumpTable;
    private byte[] _pattern;
    private int    _patternLength;
    public BoyerMoore()
    {
    }
    public BoyerMoore(byte[] pattern)
    {
        SetPattern(pattern);
    }
    public void SetPattern(byte[] pattern)
    {
        _pattern       = pattern;
        _jumpTable     = new int[256];
        _patternLength = _pattern.Length;
        for (var index = 0; index < 256; index++)
            _jumpTable[index] = _patternLength;
        for (var index = 0; index < _patternLength - 1; index++)
            _jumpTable[_pattern[index]] = _patternLength - index - 1;
    }
    public unsafe int Search(byte[] searchArray, int startIndex = 0)
    {
        if (_pattern == null)
            throw new Exception("Pattern has not been set.");
        if (_patternLength > searchArray.Length)
            throw new Exception("Search Pattern length exceeds search array length.");
        var index                 = startIndex;
        var limit                 = searchArray.Length - _patternLength;
        var patternLengthMinusOne = _patternLength     - 1;
        var Moves                 = 0;
        fixed (byte* pointerToByteArray = searchArray)
        {
            var pointerToByteArrayStartingIndex = pointerToByteArray + startIndex;
            fixed (byte* pointerToPattern = _pattern)
            {
                while (index <= limit)
                {
                    var j = patternLengthMinusOne;
                    while (j >= 0 && pointerToPattern[j] == pointerToByteArrayStartingIndex[index + j])
                        j--;
                    if (j < 0)
                        return index;
                    index += Math.Max(_jumpTable[pointerToByteArrayStartingIndex[index + j]] - _patternLength + 1 + j,
                        1);
                    Moves++;
                }
            }
        }
        return -1;
    }
    public unsafe (List<int>, int) SearchAll(byte[] searchArray, int startIndex = 0)
    {
        if (_pattern == null)
            throw new Exception("Pattern has not been set.");
        if (_patternLength > searchArray.Length)
            throw new Exception("Search Pattern length exceeds search array length.");
        var index                 = startIndex;
        var limit                 = searchArray.Length - _patternLength;
        var patternLengthMinusOne = _patternLength     - 1;
        var list                  = new List<int>();
        var Moves                 = 0;
        fixed (byte* pointerToByteArray = searchArray)
        {
            var pointerToByteArrayStartingIndex = pointerToByteArray + startIndex;
            fixed (byte* pointerToPattern = _pattern)
            {
                while (index <= limit)
                {
                    var j = patternLengthMinusOne;
                    while (j >= 0 && pointerToPattern[j] == pointerToByteArrayStartingIndex[index + j])
                        j--;
                    if (j < 0)
                        list.Add(index);
                    index += Math.Max(_jumpTable[pointerToByteArrayStartingIndex[index + j]] - _patternLength + 1 + j,
                        1);
                    Moves++;
                }
            }
        }
        return (list, Moves);
    }
    public int SuperSearch(byte[] searchArray, int nth, int start = 0)
    {
        var e = start;
        var c = 0;
        do
        {
            e = Search(searchArray, e);
            if (e == -1)
                return -1;
            c++;
            e++;
        } while (c < nth);
        return e - 1;
    }
    public static bool ContainsAny(byte[] sPattern, params byte[][] list)
    {
        return list.Select(v => new BoyerMoore(v)).Any(bm => bm.Search(sPattern) != -1);
    }
    public static bool ContainsAny(string sPattern, params string[] list)
    {
        return list.Select(s => new BoyerMoore(s.ToLower().GetBytes(Encoding.ASCII)))
            .Any(bm => bm.Search(sPattern.ToLower().GetBytes(Encoding.ASCII)) != -1);
    }
    }

MemoryBitmap.cs

Posted on June 6, 2020  Leave a comment on MemoryBitmap.cs

Direct Access Pixel Data, GetPixel, SetPixel

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
public unsafe class MemoryBitmap : IDisposable
{
    private readonly BitmapData _bmpData;
    private readonly int        _depth;
    private readonly byte*      _pfp;
    private readonly int        _stride;
    private          Bitmap     _memoryBitmap;
    public MemoryBitmap(string path)
    {
        if (path.IsNullOrEmpty())
            throw new Exception("Path cannot be null or empty.");
        if (!File.Exists(path))
            throw new Exception($"Path {path} does not exist.");
        var bitmap = new Bitmap(path);
        _memoryBitmap = bitmap;
        if (_memoryBitmap.PixelFormat != PixelFormat.Format32bppArgb && _memoryBitmap.PixelFormat != PixelFormat.Format24bppRgb && _memoryBitmap.PixelFormat != PixelFormat.Format8bppIndexed)
        {
            var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, PixelFormat.Format32bppArgb);
            using (var gr = Graphics.FromImage(clone))
            {
                gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height));
                _memoryBitmap = clone;
            }
        }
        Width  = _memoryBitmap.Width;
        Height = _memoryBitmap.Height;
        var rect = new Rectangle(0, 0, _memoryBitmap.Width, _memoryBitmap.Height);
        try
        {
            _bmpData = _memoryBitmap.LockBits(rect, ImageLockMode.ReadWrite, _memoryBitmap.PixelFormat);
        }
        catch (Exception ex)
        {
            throw new Exception("Could not lock bitmap", ex.InnerException);
        }
        _depth  = Image.GetPixelFormatSize(_bmpData.PixelFormat) / 8;
        _pfp    = (byte*) _bmpData.Scan0.ToPointer();
        _stride = _bmpData.Stride;
    }
    public MemoryBitmap(Bitmap bitmap)
    {
        _memoryBitmap = bitmap ?? throw new Exception("Bitmap cannot be null");
        if (_memoryBitmap.PixelFormat != PixelFormat.Format32bppArgb && _memoryBitmap.PixelFormat != PixelFormat.Format24bppRgb && _memoryBitmap.PixelFormat != PixelFormat.Format8bppIndexed)
        {
            var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, PixelFormat.Format32bppArgb);
            using (var gr = Graphics.FromImage(clone))
            {
                gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height));
                _memoryBitmap = clone;
            }
        }
        Width  = _memoryBitmap.Width;
        Height = _memoryBitmap.Height;
        var rect = new Rectangle(0, 0, _memoryBitmap.Width, _memoryBitmap.Height);
        try
        {
            _bmpData = _memoryBitmap.LockBits(rect, ImageLockMode.ReadWrite, _memoryBitmap.PixelFormat);
        }
        catch (Exception ex)
        {
            throw new Exception("Could not lock bitmap", ex.InnerException);
        }
        _depth  = Image.GetPixelFormatSize(_bmpData.PixelFormat) / 8;
        _pfp    = (byte*) _bmpData.Scan0.ToPointer();
        _stride = _bmpData.Stride;
    }
    public int Width
    {
        get;
    }
    public int Height
    {
        get;
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    public void ConvertFormat(PixelFormat newPf)
    {
        var clone = new Bitmap(_memoryBitmap.Width, _memoryBitmap.Height, newPf);
        using (var gr = Graphics.FromImage(clone))
        {
            gr.DrawImage(_memoryBitmap, new Rectangle(0, 0, clone.Width, clone.Height));
            _memoryBitmap = clone;
        }
    }
    public void Save(string path)
    {
        _memoryBitmap.Save(path);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!disposing)
            return;
        if (_memoryBitmap != null)
            _memoryBitmap.UnlockBits(_bmpData);
    }
    private byte* PixelPointer(int x, int y)
    {
        return _pfp + y * _stride + x * _depth;
    }
    public Color GetPixel(int x, int y)
    {
        if (x < 0 || y < 0 || x >= Width || y >= Height)
            throw new Exception("Coordinates out of range");
        int a, r, g, b;
        var p = PixelPointer(x, y);
        if (_memoryBitmap.PixelFormat == PixelFormat.Format32bppArgb)
        {
            b = *p++;
            g = *p++;
            r = *p++;
            a = *p;
            return Color.FromArgb(a, r, g, b);
        }
        if (_memoryBitmap.PixelFormat == PixelFormat.Format24bppRgb)
        {
            b = *p++;
            g = *p++;
            r = *p;
            return Color.FromArgb(r, g, b);
        }
        if (_memoryBitmap.PixelFormat == PixelFormat.Format8bppIndexed)
        {
            a = *p;
            return Color.FromArgb(a, a, a);
        }
        return default;
    }
    public void SetPixel(int x, int y, Color col)
    {
        if (x < 0 || y < 0 || x >= Width || y >= Height)
            throw new Exception("Coordinates out of range");
        var p = PixelPointer(x, y);
        if (_memoryBitmap.PixelFormat == PixelFormat.Format32bppArgb)
        {
            *p++ = col.B;
            *p++ = col.G;
            *p++ = col.R;
            *p   = col.A;
            return;
        }
        if (_memoryBitmap.PixelFormat == PixelFormat.Format24bppRgb)
        {
            *p++ = col.B;
            *p++ = col.G;
            *p   = col.R;
            return;
        }
        if (_memoryBitmap.PixelFormat == PixelFormat.Format8bppIndexed)
            *p = col.B;
    }
}

GArray.cs

Posted on June 6, 2020  Leave a comment on GArray.cs

Used By Lz77.cs

using System;
using System.Collections.Generic;
using System.Linq;
[Serializable]
public class GArray<T>
{
    private readonly int _capacity = 4096;
    private          int _count;
    private          int _position;
    private          T[] Thing;
    public GArray()
    {
        _capacity = 4096;
        _position = 0;
        _count    = 0;
        Thing     = new T[_capacity];
    }
    public GArray(IEnumerable<T> collection)
    {
        if (collection == null)
            throw new Exception("Collection cannot be null.");
        var Collection = collection as T[] ?? collection.ToArray();
        var count      = Collection.Count();
        _capacity = 32;
        _position = 0;
        _count    = count;
        Thing     = new T[count];
        Array.Copy(Collection, 0, Thing, 0, count);
    }
    public bool ReadEnd => _position == Thing.Length;
    public void Write(IEnumerable<T> collection)
    {
        if (collection == null)
            throw new Exception("Collection cannot be null.");
        var Collection = collection as T[] ?? collection.ToArray();
        var count      = Collection.Count();
        EnsureSize(_count + count);
        Array.Copy(Collection, 0, Thing, _count, count);
        _count += count;
    }
    public void Write(T value)
    {
        EnsureSize(_count + 1);
        Thing[_count] = value;
        _count++;
    }
    /// <summary>
    ///     Read an array of items from the main array starting from read position of count items.
    /// </summary>
    public T[] Read(int count)
    {
        if (_position + count > Thing.Length - 1)
            throw new ArgumentException("Position out of range.");
        var tarray = new T[count];
        Array.Copy(Thing, _position, tarray, 0, count);
        _position += count;
        return tarray;
    }
    /// <summary>
    ///     Reads one items from the array
    /// </summary>
    public T Read()
    {
        if (_position > Thing.Length - 1)
            throw new ArgumentException("Position out of range.");
        return Thing[_position++];
    }
    private void EnsureSize(int MinimumSize)
    {
        if (Thing.Length >= MinimumSize) return;
        var NewLength                          = Thing.Length == 0 ? 4096 : Thing.Length * 2;
        if (NewLength < MinimumSize) NewLength = MinimumSize;
        var newtArray                          = new T[NewLength];
        Array.Copy(Thing, 0, newtArray, 0, _count);
        Thing = newtArray;
    }
    /// <summary>
    ///     Returns an array of type T items.
    /// </summary>
    public T[] ToArray()
    {
        var objArray = new T[_count];
        Array.Copy(Thing, 0, objArray, 0, _count);
        return objArray;
    }
}

Lz77.cs

Posted on June 6, 2020  Leave a comment on Lz77.cs

LZ77 Compression Algorithm

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public static class Lz77
{
    private const           int      RingBufferSize   = 1024 * 4;
    private const           int      UpperMatchLength = 18;
    private const           int      LowerMatchLength = 3;
    private const           int      None             = RingBufferSize;
    private static readonly int[]    Parent           = new int[RingBufferSize                       + 1];
    private static readonly int[]    LeftChild        = new int[RingBufferSize                       + 1];
    private static readonly int[]    RightChild       = new int[RingBufferSize                       + 257];
    private static readonly ushort[] Buffer           = new ushort[RingBufferSize + UpperMatchLength - 1];
    private static          int      matchPosition, matchLength;
    /// <summary>
    ///     Size of the compressed code during and after compression
    /// </summary>
    public static int CompressedSize
    {
        get;
        set;
    }
    /// <summary>
    ///     Size of the original code packet while decompressing
    /// </summary>
    public static int DeCompressedSize
    {
        get;
        set;
    }
    public static double Ratio => (double) CompressedSize / DeCompressedSize * 100.0;
    public static byte[] Lz77Decompress(this byte[] ins)
    {
        if (ins == null)
            throw new Exception("Input buffer is null.");
        if (ins.Length == 0)
            throw new Exception("Input buffer is empty.");
        var outa = new GArray<byte>();
        var ina  = new GArray<byte>(ins);
        CompressedSize   = 0;
        DeCompressedSize = ina.Read(4).ToInt();
        for (var i = 0; i < RingBufferSize - UpperMatchLength; i++)
            Buffer[i] = 0;
        var  r     = RingBufferSize - UpperMatchLength;
        uint flags = 7;
        var  z     = 7;
        while (true)
        {
            flags <<= 1;
            z++;
            if (z == 8)
            {
                if (ina.ReadEnd)
                    break;
                flags = ina.Read();
                z     = 0;
            }
            if ((flags & 0x80) == 0)
            {
                if (ina.ReadEnd)
                    break;
                var c = ina.Read();
                if (CompressedSize < DeCompressedSize)
                    outa.Write(c);
                Buffer[r++] =  c;
                r           &= RingBufferSize - 1;
                CompressedSize++;
            }
            else
            {
                if (ina.ReadEnd)
                    break;
                int i = ina.Read();
                if (ina.ReadEnd)
                    break;
                int j = ina.Read();
                j = j | ((i << 8) & 0xF00);
                i = ((i     >> 4) & 0xF) + LowerMatchLength;
                for (var k = 0; k <= i; k++)
                {
                    var c = Buffer[(r - j - 1) & (RingBufferSize - 1)];
                    if (CompressedSize < DeCompressedSize)
                        outa.Write((byte) c);
                    Buffer[r++] =  (byte) c;
                    r           &= RingBufferSize - 1;
                    CompressedSize++;
                }
            }
        }
        return outa.ToArray();
    }
    /// <summary>
    ///     E:12.5, R:17.3 E:25.0, R:35.9 E:32.3, R:47.7 E:37.5, R:56.5 E:41.5, R:63.0 E:44.8, R:67.6 E:47.6, R:71.7 E:50.0,
    ///     R:75.8 E:52.1, R:79.9 E:54.0, R:83.9 E:55.7, R:87.7
    ///     E:57.3, R:91.0 E:58.8, R:93.9 E:60.1, R:96.6 E:61.3, R:98.8 E:62.5, R:100.6 E:63.6, R:102.1 E:64.6, R:103.5 E:65.6,
    ///     R:104.7 E:66.5, R:105.6 E:67.4, R:106.5
    ///     E:68.2, R:107.2 E:69.0, R:107.8 E:69.8, R:108.3 E:70.5, R:108.7
    /// </summary>
    public static byte[] Lz77Compress(this byte[] ins, bool TestForCompressibility = false)
    {
        if (ins == null)
            throw new Exception("Input buffer is null.");
        if (ins.Length == 0)
            throw new Exception("Input buffer is empty.");
        if (TestForCompressibility)
            if ((int) Entropy(ins) > 61)
                throw new Exception("Input buffer Cannot be compressed.");
        matchLength      = 0;
        matchPosition    = 0;
        CompressedSize   = 0;
        DeCompressedSize = ins.Length;
        int length;
        var codeBuffer = new int[UpperMatchLength - 1];
        var outa       = new GArray<byte>();
        var ina        = new GArray<byte>(ins);
        outa.Write(DeCompressedSize.GetBytes(0, 4));
        InitTree();
        codeBuffer[0] = 0;
        var codeBufferPointer = 1;
        var mask              = 0x80;
        var s                 = 0;
        var r                 = RingBufferSize - UpperMatchLength;
        for (var i = s; i < r; i++)
            Buffer[i] = 0xFFFF;
        for (length = 0; length < UpperMatchLength && !ina.ReadEnd; length++)
            Buffer[r + length] = ina.Read();
        if (length == 0)
            throw new Exception("No Data to Compress.");
        for (var i = 1; i <= UpperMatchLength; i++)
            InsertNode(r - i);
        InsertNode(r);
        do
        {
            if (matchLength > length)
                matchLength = length;
            if (matchLength <= LowerMatchLength)
            {
                matchLength                     = 1;
                codeBuffer[codeBufferPointer++] = Buffer[r];
            }
            else
            {
                codeBuffer[0]                   |= mask;
                codeBuffer[codeBufferPointer++] =  (byte) (((r - matchPosition - 1) >> 8) & 0xF) | ((matchLength - (LowerMatchLength + 1)) << 4);
                codeBuffer[codeBufferPointer++] =  (byte) ((r - matchPosition                                    - 1) & 0xFF);
            }
            if ((mask >>= 1) == 0)
            {
                for (var i = 0; i < codeBufferPointer; i++)
                    outa.Write((byte) codeBuffer[i]);
                CompressedSize    += codeBufferPointer;
                codeBuffer[0]     =  0;
                codeBufferPointer =  1;
                mask              =  0x80;
            }
            var lastMatchLength = matchLength;
            var ii              = 0;
            for (ii = 0; ii < lastMatchLength && !ina.ReadEnd; ii++)
            {
                DeleteNode(s);
                var c = ina.Read();
                Buffer[s] = c;
                if (s < UpperMatchLength - 1)
                    Buffer[s + RingBufferSize] = c;
                s = (s + 1) & (RingBufferSize - 1);
                r = (r + 1) & (RingBufferSize - 1);
                InsertNode(r);
            }
            while (ii++ < lastMatchLength)
            {
                DeleteNode(s);
                s = (s + 1) & (RingBufferSize - 1);
                r = (r + 1) & (RingBufferSize - 1);
                if (--length != 0)
                    InsertNode(r);
            }
        } while (length > 0);
        if (codeBufferPointer > 1)
        {
            for (var i = 0; i < codeBufferPointer; i++)
                outa.Write((byte) codeBuffer[i]);
            CompressedSize += codeBufferPointer;
        }
        if (CompressedSize % 4 != 0)
            for (var i = 0; i < 4 - CompressedSize % 4; i++)
                outa.Write(0);
        return outa.ToArray();
    }
    private static void InitTree()
    {
        for (var i = RingBufferSize + 1; i <= RingBufferSize + 256; i++)
            RightChild[i] = None;
        for (var i = 0; i < RingBufferSize; i++)
            Parent[i] = None;
    }
    private static void InsertNode(int r)
    {
        var cmp                      = 1;
        var p                        = RingBufferSize + 1 + (Buffer[r] == 0xFFFF ? 0 : Buffer[r]);
        RightChild[r] = LeftChild[r] = None;
        matchLength   = 0;
        while (true)
        {
            if (cmp >= 0)
            {
                if (RightChild[p] != None)
                {
                    p = RightChild[p];
                }
                else
                {
                    RightChild[p] = r;
                    Parent[r]     = p;
                    return;
                }
            }
            else
            {
                if (LeftChild[p] != None)
                {
                    p = LeftChild[p];
                }
                else
                {
                    LeftChild[p] = r;
                    Parent[r]    = p;
                    return;
                }
            }
            int i;
            for (i = 1; i < UpperMatchLength; i++)
                if ((cmp = Buffer[r + i] - Buffer[p + i]) != 0)
                    break;
            if (i > matchLength)
            {
                matchPosition = p;
                if ((matchLength = i) >= UpperMatchLength)
                    break;
            }
        }
        Parent[r]             = Parent[p];
        LeftChild[r]          = LeftChild[p];
        RightChild[r]         = RightChild[p];
        Parent[LeftChild[p]]  = r;
        Parent[RightChild[p]] = r;
        if (RightChild[Parent[p]] == p)
            RightChild[Parent[p]] = r;
        else LeftChild[Parent[p]] = r;
        Parent[p] = None;
    }
    private static void DeleteNode(int p)
    {
        int q;
        if (Parent[p] == None)
            return;
        if (RightChild[p] == None)
        {
            q = LeftChild[p];
        }
        else if (LeftChild[p] == None)
        {
            q = RightChild[p];
        }
        else
        {
            q = LeftChild[p];
            if (RightChild[q] != None)
            {
                do
                {
                    q = RightChild[q];
                } while (RightChild[q] != None);
                RightChild[Parent[q]] = LeftChild[q];
                Parent[LeftChild[q]]  = Parent[q];
                LeftChild[q]          = LeftChild[p];
                Parent[LeftChild[p]]  = q;
            }
            RightChild[q]         = RightChild[p];
            Parent[RightChild[p]] = q;
        }
        Parent[q] = Parent[p];
        if (RightChild[Parent[p]] == p)
            RightChild[Parent[p]] = q;
        else LeftChild[Parent[p]] = q;
        Parent[p] = None;
    }
    private static double Entropy(byte[] ba)
    {
        var map = new Dictionary<byte, int>();
        foreach (var c in ba)
            if (!map.ContainsKey(c))
                map.Add(c, 1);
            else
                map[c]++;
        double Len = ba.Length;
        var    re  = map.Select(item => item.Value / Len).Aggregate(0.0, (current, frequency) => current - frequency * (Math.Log(frequency) / Math.Log(2)));
        return re / 8.00D * 100D;
    }
}

FixedBigIntegerRandomNumberGenerator.cs

Posted on June 5, 2020  Leave a comment on FixedBigIntegerRandomNumberGenerator.cs

Fixed BigInteger Random Number Generator

using System;
using System.Security.Cryptography;
public class FixedBigIntegerRandomNumberGenerator : RandomNumberGenerator
{
    private readonly int             _bitWidthHold;
    private readonly byte[]          _buffer;
    private readonly JitterCacheRng  _crng;
    private readonly BigDecimal      _dBi;
    private readonly FixedBigInteger _maxValueHold = new FixedBigInteger(0, 0);
    public FixedBigIntegerRandomNumberGenerator(int bitWidth)
    {
        if (bitWidth < 32)
            bitWidth = 32;
        var maxValue = GetMaxValue(bitWidth);
        var vdp      = maxValue.GetDecimalPlaces();
        if (vdp > BigDecimal.MaxPrecision)
            BigDecimal.MaxPrecision = vdp;
        _bitWidthHold = bitWidth;
        if (_bitWidthHold < 32)
            _bitWidthHold = 32;
        _maxValueHold = maxValue;
        _dBi          = BigDecimal.One / (BigDecimal) maxValue;
        _buffer       = new byte[_bitWidthHold >> 3];
        _crng         = new JitterCacheRng(1000000);
    }
    public FixedBigIntegerRandomNumberGenerator(int bitWidth, int cacheSize)
    {
        if (bitWidth < 32)
            bitWidth = 32;
        var maxValue = GetMaxValue(bitWidth);
        var vdp      = maxValue.GetDecimalPlaces();
        if (vdp > BigDecimal.MaxPrecision)
            BigDecimal.MaxPrecision = vdp;
        _bitWidthHold = bitWidth;
        if (_bitWidthHold < 32)
            _bitWidthHold = 32;
        _maxValueHold = maxValue;
        _dBi          = BigDecimal.One / (BigDecimal) maxValue;
        _buffer       = new byte[_bitWidthHold >> 3];
        _crng         = new JitterCacheRng(cacheSize);
    }
    public bool OddsOnly
    {
        get;
        set;
    }
    public bool Unsigned
    {
        get;
        set;
    }
    protected override void Dispose(bool disposing)
    {
        _crng.Dispose();
    }
    private FixedBigInteger GetMaxValue(int bitWidth)
    {
        var r = new FixedBigInteger(0, bitWidth);
        for (var i = 0; i < r.Data.Length; ++i)
            r.Data[i] = uint.MaxValue;
        r.Data[r.Data.Length - 1] = int.MaxValue;
        return r;
    }
    private FixedBigInteger GetMaxValue()
    {
        var r = new FixedBigInteger(0, _bitWidthHold);
        for (var i = 0; i < r.Data.Length; ++i)
            r.Data[i] = uint.MaxValue;
        r.Data[r.Data.Length - 1] = int.MaxValue;
        return r;
    }
    private BigDecimal Sample()
    {
        FixedBigInteger Internal()
        {
            _crng.GetBytes(_buffer);
            var n = new FixedBigInteger(_buffer, _bitWidthHold);
            return !OddsOnly ? n : n | 1;
        }
        var s = (BigDecimal) Internal() * _dBi;
        if (s.Sign == -1)
            s = s * -1;
        if (s.IsZero)
            throw new Exception("Sample is zero. SEE: MaxPrecision in BigDecimal.cs. Default value is 308.");
        return s;
    }
    public FixedBigInteger Next(FixedBigInteger minValue, FixedBigInteger maxValue)
    {
        var sa = Sample();
        var fi = (BigDecimal) (maxValue - minValue + minValue);
        var n  = new FixedBigInteger(sa * fi, 0);
        n = !OddsOnly ? n : n | 1;
        if (Unsigned)
            return n.Sign < 0 ? new FixedBigInteger(1, n.Data, 0) : n;
        var buffer = new byte[1];
        _crng.GetBytes(buffer);
        if (buffer[0] > 127)
            return n.Sign < 0 ? n : new FixedBigInteger(-1, n.Data, 0);
        return n.Sign < 0 ? new FixedBigInteger(1, n.Data, 0) : n;
    }
    public FixedBigInteger Next(FixedBigInteger maxValue)
    {
        return Next(0, maxValue);
    }
    public FixedBigInteger Next()
    {
        return Next(0, _maxValueHold);
    }
    public override void GetBytes(byte[] data)
    {
        if (data == null)
            throw new ArgumentException("The buffer cannot be null.");
        _crng.GetBytes(data);
    }
    public void NextBytes(byte[] buffer)
    {
        if (buffer == null)
            throw new ArgumentNullException("The buffer cannot be null.");
        for (var index = 0; index < buffer.Length; ++index)
            buffer[index] = (byte) (Sample() * byte.MaxValue);
    }
    public FixedBigInteger[] Next(FixedBigInteger minValue, FixedBigInteger maxValue, int arraySize)
    {
        var array = new FixedBigInteger[arraySize];
        for (var i = 0; i < arraySize; ++i)
            array[i] = Next(minValue, maxValue);
        return array;
    }
    public char[] GetNextCharArray(int size)
    {
        var ca  = new char[size];
        var ptr = 0;
        do
        {
            ca[ptr++] = (char) Next(32, 128);
        } while (ptr < size);
        return ca;
    }
    public byte[] GetNextByteArray(int size)
    {
        var ba = new byte[size];
        _crng.GetBytes(ba);
        return ba;
    }
    public string GetRandomString(int minLen, int maxLen)
    {
        if (minLen == maxLen)
            return new string(GetNextCharArray(minLen));
        return new string(GetNextCharArray((int) Next((uint) minLen, (uint) maxLen)));
    }
}

BigDecimal.cs

Posted on June 5, 2020  Leave a comment on BigDecimal.cs

Arbitrary Precision Signed Decimal

using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
[Serializable]
[DebuggerDisplay("{DDisplay}")]
public class BigDecimal : IComparable, IComparable<BigDecimal>, IEquatable<BigDecimal>
{
    private const           int          MaxFactorials    = 200;
    public static           int          MaxPrecision     = 308;
    private static readonly BigInteger   DoublePrecision  = BigInteger.Pow(10, 308);
    private static readonly BigInteger   DoubleMaxValue   = (BigInteger) double.MaxValue;
    private static readonly BigInteger   DoubleMinValue   = (BigInteger) double.MinValue;
    private static readonly BigInteger   DecimalPrecision = BigInteger.Pow(10, 28);
    private static readonly BigInteger   DecimalMaxValue  = (BigInteger) decimal.MaxValue;
    private static readonly BigInteger   DecimalMinValue  = (BigInteger) decimal.MinValue;
    private static          BigDecimal[] Factorials;
    private                 int          _scale;
    private                 BigInteger   _unscaledValue;
    public BigDecimal() : this(0, 0)
    {
    }
    public BigDecimal(BigInteger value) : this(value, 0)
    {
    }
    public BigDecimal(FixedBigInteger value) : this((BigInteger) value, 0)
    {
    }
    public BigDecimal(BigInteger value, int scale)
    {
        _unscaledValue = value;
        Scale          = scale;
    }
    public BigDecimal(long value) : this(value, 0)
    {
    }
    public BigDecimal(double value) : this((decimal) value)
    {
    }
    public BigDecimal(float value) : this((decimal) value)
    {
    }
    public BigDecimal(byte[] value)
    {
        var number = new byte[value.Length - 4];
        var flags  = new byte[4];
        Array.Copy(value, 0,                number, 0, number.Length);
        Array.Copy(value, value.Length - 4, flags,  0, 4);
        _unscaledValue = new BigInteger(number);
        Scale          = BitConverter.ToInt32(flags, 0);
    }
    public BigDecimal(BigRational value)
    {
        var num       = (BigDecimal) value.Numerator;
        var den       = (BigDecimal) value.Denominator;
        var bigDecRes = num / den;
        _unscaledValue = bigDecRes._unscaledValue;
        Scale          = bigDecRes.Scale;
    }
    public BigDecimal(decimal value)
    {
        var bytes = new byte[16];
        var bits  = decimal.GetBits(value);
        var lo    = bits[0];
        var mid   = bits[1];
        var hi    = bits[2];
        var flags = bits[3];
        bytes[0]  = (byte) lo;
        bytes[1]  = (byte) (lo >> 8);
        bytes[2]  = (byte) (lo >> 0x10);
        bytes[3]  = (byte) (lo >> 0x18);
        bytes[4]  = (byte) mid;
        bytes[5]  = (byte) (mid >> 8);
        bytes[6]  = (byte) (mid >> 0x10);
        bytes[7]  = (byte) (mid >> 0x18);
        bytes[8]  = (byte) hi;
        bytes[9]  = (byte) (hi >> 8);
        bytes[10] = (byte) (hi >> 0x10);
        bytes[11] = (byte) (hi >> 0x18);
        bytes[12] = (byte) flags;
        bytes[13] = (byte) (flags >> 8);
        bytes[14] = (byte) (flags >> 0x10);
        bytes[15] = (byte) (flags >> 0x18);
        var unscaledValueBytes = new byte[12];
        Array.Copy(bytes, unscaledValueBytes, unscaledValueBytes.Length);
        var unscaledValue = new BigInteger(unscaledValueBytes);
        var scale         = bytes[14];
        if (bytes[15] == 128)
            unscaledValue *= BigInteger.MinusOne;
        _unscaledValue = unscaledValue;
        Scale          = scale;
    }
    public BigDecimal(string value)
    {
        if (!value.ContainsOnly("0123456789+-.eE"))
            throw new Exception($"Input value must only contain these '0123456789+-.eE', value'{value}");
        var len      = value.Length;
        var start    = 0;
        var point    = 0;
        var dot      = -1;
        var negative = false;
        if (value[0] == '+')
        {
            ++start;
            ++point;
        }
        else if (value[0] == '-')
        {
            ++start;
            ++point;
            negative = true;
        }
        while (point < len)
        {
            var c = value[point];
            if (c == '.')
            {
                if (dot >= 0)
                    throw new Exception($"There are multiple '.'s in the value {value}");
                dot = point;
            }
            else if (c == 'e' || c == 'E')
            {
                break;
            }
            ++point;
        }
        string val;
        if (dot >= 0)
        {
            val   = value.Substring(start, dot) + value.Substring(dot + 1, point - (dot + 1));
            Scale = point - 1                   - dot;
        }
        else
        {
            val   = value.Substring(start, point);
            Scale = 0;
        }
        if (val.Length == 0)
            throw new Exception($"There are no digits in the value {value}");
        if (negative)
            val = "-" + val;
        _unscaledValue = val.BigIntegerBase10();
        if (point < len)
            try
            {
                point++;
                switch (value[point])
                {
                    case '+':
                    {
                        point++;
                        if (point >= len)
                            throw new Exception($"No exponent following e or E. Value {value}");
                        var scale = value.Substring(point);
                        Scale -= int.Parse(scale);
                        return;
                    }
                    case '-':
                    {
                        point++;
                        if (point >= len)
                            throw new Exception($"No exponent following e or E. Value {value}");
                        var scale = value.Substring(point);
                        Scale += int.Parse(scale);
                        return;
                    }
                    default:
                        throw new Exception($"Malformed exponent in value {value}");
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Malformed exponent in value {value}");
            }
    }
    private string DDisplay => ToString();
    public static BigDecimal Zero
    {
        get;
    } = new BigDecimal(BigInteger.Zero);
    public static BigDecimal One
    {
        get;
    } = new BigDecimal(BigInteger.One);
    public static BigDecimal MinusOne
    {
        get;
    } = new BigDecimal(BigInteger.MinusOne);
    public bool IsEven       => _unscaledValue.IsEven;
    public bool IsOne        => _unscaledValue.IsOne;
    public bool IsPowerOfTwo => _unscaledValue.IsPowerOfTwo;
    public bool IsZero       => _unscaledValue.IsZero;
    public int  Sign         => _unscaledValue.Sign;
    public int Scale
    {
        get => _scale;
        private set => _scale = value;
    }
    public BigInteger UnscaledValue  => _unscaledValue;
    public BigDecimal WholePart      => BigInteger.Divide(_unscaledValue, BigInteger.Pow(10, Scale));
    public BigDecimal FractionalPart => this - WholePart;
    int IComparable.CompareTo(object obj)
    {
        if (obj == null)
            return 1;
        if (!(obj is BigDecimal))
            throw new Exception("Argument must be of type BigDecimal.");
        return Compare(this, (BigDecimal) obj);
    }
    public int CompareTo(BigDecimal other)
    {
        return Compare(this, other);
    }
    public bool Equals(BigDecimal other)
    {
        if (other is null)
            return false;
        return _unscaledValue == other._unscaledValue && Scale == other.Scale;
    }
    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;
        if (!(obj is BigDecimal))
            return false;
        return Equals((BigDecimal) obj);
    }
    public static BigDecimal Round(BigDecimal number, int decimalPlaces)
    {
        BigDecimal power = BigInteger.Pow(10, decimalPlaces);
        number *= power;
        return number >= 0 ? (BigInteger) (number + 0.5) / power : (BigInteger) (number - 0.5) / power;
    }
    public void Round(int decimalPlaces)
    {
        var        number = this;
        BigDecimal power  = BigInteger.Pow(10, decimalPlaces);
        number *= power;
        var n = number >= 0 ? (BigInteger) (number + 0.5) / power : (BigInteger) (number - 0.5) / power;
        _unscaledValue = n._unscaledValue;
        Scale          = n.Scale;
    }
    public override int GetHashCode()
    {
        return UnscaledValue.GetHashCode() ^ Scale.GetHashCode();
    }
    public string ToString()
    {
        var number = _unscaledValue.ToString("G");
        if (Scale > 0 && WholePart != 0 && number.Length - Scale >= 0)
            return number.Insert(number.Length - Scale, ".");
        StringBuilder buf;
        var           intString      = _unscaledValue.ToString();
        var           insertionPoint = intString.Length - Scale;
        if (insertionPoint == 0)
            return (Sign < 0 ? "-0." : "0.") + intString;
        if (insertionPoint > 0)
        {
            buf = new StringBuilder(intString);
            buf.Insert(insertionPoint, '.');
            if (Sign < 0)
                buf.Insert(0, '-');
        }
        else
        {
            buf = new StringBuilder(3 - insertionPoint + intString.Length);
            buf.Append(Sign < 0 ? "-0." : "0.");
            for (var i = 0; i < -insertionPoint; i++)
                buf.Append('0');
            buf.Append(intString);
        }
        if (Scale == 0)
            buf.Append("0");
        return buf.ToString();
    }
    public static BigDecimal Parse(string value)
    {
        return new BigDecimal(value);
    }
    public byte[] ToByteArray()
    {
        var unscaledValue = _unscaledValue.ToByteArray();
        var scale         = BitConverter.GetBytes(Scale);
        var bytes         = new byte[unscaledValue.Length + scale.Length];
        Array.Copy(unscaledValue, 0, bytes, 0,                    unscaledValue.Length);
        Array.Copy(scale,         0, bytes, unscaledValue.Length, scale.Length);
        return bytes;
    }
    public (byte[] unscaledValue, byte[] scale) ToByteArrays()
    {
        return (_unscaledValue.ToByteArray(), BitConverter.GetBytes(Scale));
    }
    public static BigDecimal Abs(BigDecimal value)
    {
        return value._unscaledValue.Sign < 0 ? -value : value;
    }
    public static BigDecimal Negate(BigDecimal value)
    {
        return new BigDecimal(BigInteger.Negate(value._unscaledValue), value.Scale);
    }
    public static BigDecimal Add(BigDecimal x, BigDecimal y)
    {
        return x + y;
    }
    public static BigDecimal Subtract(BigDecimal x, BigDecimal y)
    {
        return x - y;
    }
    public static BigDecimal Multiply(BigDecimal x, BigDecimal y)
    {
        return x * y;
    }
    public static BigDecimal Divide(BigDecimal dividend, BigDecimal divisor)
    {
        return dividend / divisor;
    }
    public static BigDecimal Pow(BigDecimal baseValue, BigInteger exponent)
    {
        if (exponent.Sign == 0)
            return One;
        if (exponent.Sign < 0)
        {
            if (baseValue == Zero)
                throw new Exception("Cannot raise zero to a negative power.");
            baseValue = One / baseValue;
            exponent  = BigInteger.Negate(exponent);
        }
        var result = baseValue;
        while (exponent > BigInteger.One)
        {
            result *= baseValue;
            exponent--;
        }
        return result;
    }
    public static int Compare(BigDecimal r1, BigDecimal r2)
    {
        return (r1 - r2)._unscaledValue.Sign;
    }
    public static bool operator ==(BigDecimal x, BigDecimal y)
    {
        return x.Equals(y);
    }
    public static bool operator !=(BigDecimal x, BigDecimal y)
    {
        return !x.Equals(y);
    }
    public static bool operator <(BigDecimal x, BigDecimal y)
    {
        return Compare(x, y) < 0;
    }
    public static bool operator <=(BigDecimal x, BigDecimal y)
    {
        return Compare(x, y) <= 0;
    }
    public static bool operator >(BigDecimal x, BigDecimal y)
    {
        return Compare(x, y) > 0;
    }
    public static bool operator >=(BigDecimal x, BigDecimal y)
    {
        return Compare(x, y) >= 0;
    }
    public static BigDecimal operator +(BigDecimal value)
    {
        return value;
    }
    public static BigDecimal operator -(BigDecimal value)
    {
        return new BigDecimal(-value._unscaledValue, value.Scale);
    }
    public static BigDecimal operator ++(BigDecimal value)
    {
        return value + One;
    }
    public static BigDecimal operator --(BigDecimal value)
    {
        return value - One;
    }
    public static BigDecimal operator +(BigDecimal left, BigDecimal right)
    {
        BigDecimal ret;
        if (left.Scale >= right.Scale)
        {
            ret = left;
        }
        else
        {
            var value = left._unscaledValue * BigInteger.Pow(10, right.Scale - left.Scale);
            ret = new BigDecimal(value, right.Scale);
        }
        BigDecimal ret1;
        if (right.Scale >= left.Scale)
        {
            ret1 = right;
        }
        else
        {
            var value1 = right._unscaledValue * BigInteger.Pow(10, left.Scale - right.Scale);
            ret1 = new BigDecimal(value1, left.Scale);
        }
        return new BigDecimal(ret._unscaledValue + ret1._unscaledValue, ret.Scale);
    }
    public static BigDecimal operator -(BigDecimal left, BigDecimal right)
    {
        BigDecimal ret;
        if (left.Scale >= right.Scale)
        {
            ret = left;
        }
        else
        {
            var value = left._unscaledValue * BigInteger.Pow(10, right.Scale - left.Scale);
            ret = new BigDecimal(value, right.Scale);
        }
        BigDecimal ret1;
        if (right.Scale >= left.Scale)
        {
            ret1 = right;
        }
        else
        {
            var value1 = right._unscaledValue * BigInteger.Pow(10, left.Scale - right.Scale);
            ret1 = new BigDecimal(value1, left.Scale);
        }
        return new BigDecimal(ret._unscaledValue - ret1._unscaledValue, ret.Scale);
    }
    public static BigDecimal operator *(BigDecimal left, BigDecimal right)
    {
        return new BigDecimal(left._unscaledValue * right._unscaledValue, left.Scale + right.Scale);
    }
    public static BigDecimal operator /(BigDecimal left, BigDecimal right)
    {
        var value = left._unscaledValue;
        var scale = left.Scale;
        while (scale > 0 && value % 10 == 0)
        {
            value /= 10;
            scale--;
        }
        var v1     = new BigDecimal(value, scale);
        var value1 = right._unscaledValue;
        var scale1 = right.Scale;
        while (scale1 > 0 && value1 % 10 == 0)
        {
            value1 /= 10;
            scale1--;
        }
        var v2 = new BigDecimal(value1, scale1);
        while (v1.Scale > 0 || v2.Scale > 0)
        {
            if (v1.Scale > 0)
                v1 = new BigDecimal(v1._unscaledValue, v1.Scale - 1);
            else
                v1 = new BigDecimal(v1._unscaledValue * 10, 0);
            if (v2.Scale > 0)
                v2 = new BigDecimal(v2._unscaledValue, v2.Scale - 1);
            else
                v2 = new BigDecimal(v2._unscaledValue * 10, 0);
        }
        var factor  = 0;
        var v1Value = v1._unscaledValue;
        while (factor < MaxPrecision && v1Value % v2._unscaledValue != 0)
        {
            v1Value *= 10;
            factor++;
        }
        return new BigDecimal(v1Value / v2._unscaledValue, factor);
    }
    public static BigDecimal operator %(BigDecimal left, BigDecimal right)
    {
        var value = left._unscaledValue;
        var scale = left.Scale;
        while (scale > 0 && value % 10 == 0)
        {
            value /= 10;
            scale--;
        }
        var v1     = new BigDecimal(value, scale);
        var value1 = right._unscaledValue;
        var scale1 = right.Scale;
        while (scale1 > 0 && value1 % 10 == 0)
        {
            value1 /= 10;
            scale1--;
        }
        var v2 = new BigDecimal(value1, scale1);
        while (v1.Scale > 0 || v2.Scale > 0)
        {
            if (v1.Scale > 0)
                v1 = new BigDecimal(v1._unscaledValue, v1.Scale - 1);
            else
                v1 = new BigDecimal(v1._unscaledValue * 10, 0);
            if (v2.Scale > 0)
                v2 = new BigDecimal(v2._unscaledValue, v2.Scale - 1);
            else
                v2 = new BigDecimal(v2._unscaledValue * 10, 0);
        }
        return new BigDecimal(v1._unscaledValue % v2._unscaledValue);
    }
    public static explicit operator sbyte(BigDecimal value)
    {
        return (sbyte) BigInteger.Divide(value._unscaledValue, (BigInteger) Math.Pow(10, value.Scale - 1));
    }
    public static explicit operator ushort(BigDecimal value)
    {
        return (ushort) BigInteger.Divide(value._unscaledValue, (BigInteger) Math.Pow(10, value.Scale - 1));
    }
    public static explicit operator uint(BigDecimal value)
    {
        return (uint) BigInteger.Divide(value._unscaledValue, (BigInteger) Math.Pow(10, value.Scale - 1));
    }
    public static explicit operator ulong(BigDecimal value)
    {
        return (ulong) BigInteger.Divide(value._unscaledValue, (BigInteger) Math.Pow(10, value.Scale - 1));
    }
    public static explicit operator byte(BigDecimal value)
    {
        return (byte) BigInteger.Divide(value._unscaledValue, (BigInteger) Math.Pow(10, value.Scale - 1));
    }
    public static explicit operator short(BigDecimal value)
    {
        return (short) BigInteger.Divide(value._unscaledValue, (BigInteger) Math.Pow(10, value.Scale - 1));
    }
    public static explicit operator int(BigDecimal value)
    {
        return (int) BigInteger.Divide(value._unscaledValue, (BigInteger) Math.Pow(10, value.Scale - 1));
    }
    public static explicit operator long(BigDecimal value)
    {
        return (long) BigInteger.Divide(value._unscaledValue, (BigInteger) Math.Pow(10, value.Scale - 1));
    }
    public static explicit operator BigInteger(BigDecimal value)
    {
        return BigInteger.Divide(value._unscaledValue, (BigInteger) Math.Pow(10, value.Scale));
    }
    public static explicit operator FixedBigInteger(BigDecimal value)
    {
        return FixedBigInteger.Divide(value._unscaledValue, (FixedBigInteger) Math.Pow(10, value.Scale));
    }
    public static explicit operator float(BigDecimal value)
    {
        return (float) (double) value;
    }
    public static explicit operator double(BigDecimal value)
    {
        var factor = BigInteger.Pow(10, value.Scale);
        if (SafeCastToDouble(value._unscaledValue) && SafeCastToDouble(factor))
            return (double) value._unscaledValue / (double) factor;
        var dnv = value._unscaledValue * DoublePrecision / factor;
        if (dnv.IsZero)
            return value.Sign < 0 ? BitConverter.Int64BitsToDouble(unchecked((long) 0x8000000000000000)) : 0d;
        double result   = 0;
        var    isDouble = false;
        var    scale    = 308;
        while (scale > 0)
        {
            if (!isDouble)
            {
                if (SafeCastToDouble(dnv))
                {
                    result   = (double) dnv;
                    isDouble = true;
                }
                else
                {
                    dnv /= 10;
                }
            }
            result /= 10;
            scale--;
        }
        if (!isDouble)
            return value.Sign < 0 ? double.NegativeInfinity : double.PositiveInfinity;
        return result;
    }
    public static explicit operator decimal(BigDecimal value)
    {
        var factor = BigInteger.Pow(10, value.Scale);
        if (SafeCastToDecimal(value._unscaledValue) && SafeCastToDecimal(factor))
            return (decimal) value._unscaledValue / (decimal) factor;
        var dnv = value._unscaledValue * DecimalPrecision / factor;
        if (dnv.IsZero)
            return decimal.Zero;
        for (var scale = 28; scale >= 0; scale--)
            if (!SafeCastToDecimal(dnv))
            {
                dnv /= 10;
            }
            else
            {
                var dec = new DecimalUInt32();
                dec.dec   = (decimal) dnv;
                dec.flags = (dec.flags & ~0x00FF0000) | (scale << 16);
                return dec.dec;
            }
        throw new Exception("Value was either too large or too small for a Decimal.");
    }
    public static implicit operator BigDecimal(sbyte value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(ushort value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(uint value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(ulong value)
    {
        return new BigDecimal((BigInteger) value);
    }
    public static implicit operator BigDecimal(byte value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(short value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(int value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(long value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(BigInteger value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(FixedBigInteger value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(float value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(double value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(decimal value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(BigRational value)
    {
        return new BigDecimal(value);
    }
    public static implicit operator BigDecimal(BigIntX value)
    {
        return new BigDecimal(value.ToString());
    }
    private static bool SafeCastToDouble(BigInteger value)
    {
        return DoubleMinValue <= value && value <= DoubleMaxValue;
    }
    private static bool SafeCastToDecimal(BigInteger value)
    {
        return DecimalMinValue <= value && value <= DecimalMaxValue;
    }
    private static BigInteger GetLastDigit(BigInteger value)
    {
        return value % new BigInteger(10);
    }
    private static int GetNumberOfDigits(BigInteger value)
    {
        return BigInteger.Abs(value).ToString().Length;
    }
    private static BigDecimal Factorial(BigDecimal x)
    {
        BigDecimal r = 1;
        BigDecimal c = 1;
        while (c <= x)
        {
            r *= c;
            c++;
        }
        return r;
    }
    public static BigDecimal Exp(BigDecimal x)
    {
        BigDecimal r  = 0;
        BigDecimal r1 = 0;
        var        k  = 0;
        while (true)
        {
            r += Pow(x, k) / Factorial(k);
            if (r == r1)
                break;
            r1 = r;
            k++;
        }
        return r;
    }
    public static BigDecimal Sine(BigDecimal ar, int n)
    {
        if (Factorials == null)
        {
            Factorials = new BigDecimal[MaxFactorials];
            for (var i = 0; i < MaxFactorials; i++)
                Factorials[i] = new BigDecimal();
            for (var i = 1; i < MaxFactorials + 1; i++)
                Factorials[i - 1] = Factorial(i);
        }
        var sin = ar;
        for (var i = 1; i <= n; i++)
        {
            var trm = Pow(ar, i * 2 + 1);
            trm /= Factorials[i * 2];
            if ((i & 1) == 1)
                sin -= trm;
            else
                sin += trm;
        }
        return sin;
    }
    public static BigDecimal Atan(BigDecimal ar, int n)
    {
        var atan = ar;
        for (var i = 1; i <= n; i++)
        {
            var trm = Pow(ar, i * 2 + 1);
            trm /= i * 2;
            if ((i & 1) == 1)
                atan -= trm;
            else
                atan += trm;
        }
        return atan;
    }
    public static BigDecimal Cosine(BigDecimal ar, int n)
    {
        if (Factorials == null)
        {
            Factorials = new BigDecimal[MaxFactorials];
            for (var i = 0; i < MaxFactorials; i++)
                Factorials[i] = new BigDecimal();
            for (var i = 1; i < MaxFactorials + 1; i++)
                Factorials[i - 1] = Factorial(i);
        }
        BigDecimal cos = 1.0;
        for (var i = 1; i <= n; i++)
        {
            var trm = Pow(ar, i * 2);
            trm /= Factorials[i * 2 - 1];
            if ((i & 1) == 1)
                cos -= trm;
            else
                cos += trm;
        }
        return cos;
    }
    private static BigDecimal GetE(int n)
    {
        BigDecimal e = 1.0;
        var        c = n;
        while (c > 0)
        {
            BigDecimal f = 0;
            if (c == 1)
            {
                f = 1;
            }
            else
            {
                var i = c - 1;
                f = c;
                while (i > 0)
                {
                    f *= i;
                    i--;
                }
            }
            c--;
            e += 1.0 / f;
        }
        return e;
    }
    public static BigDecimal Tangent(BigDecimal ar, int n)
    {
        return Sine(ar, n) / Cosine(ar, n);
    }
    public static BigDecimal CoTangent(BigDecimal ar, int n)
    {
        return Cosine(ar, n) / Sine(ar, n);
    }
    public static BigDecimal Secant(BigDecimal ar, int n)
    {
        return 1.0 / Cosine(ar, n);
    }
    public static BigDecimal NthRoot(BigDecimal value, int nth)
    {
        BigDecimal lx;
        var        a = value;
        var        n = nth;
        BigDecimal s = 1.0;
        do
        {
            var t = s;
            lx = a / Pow(s, n - 1);
            var r = (n        - 1) * s;
            s = (lx + r) / n;
        } while (lx != s);
        return s;
    }
    public static BigDecimal LogN(BigDecimal value)
    {
        var        E = GetE(MaxFactorials);
        BigDecimal a;
        var        p = value;
        BigDecimal n = 0.0;
        while (p >= E)
        {
            p /= E;
            n++;
        }
        n += p / E;
        p =  value;
        do
        {
            a = n;
            var lx = p         / Exp(n - 1.0);
            var r  = (n - 1.0) * E;
            n = (lx + r) / E;
        } while (n != a);
        return n;
    }
    public static BigDecimal Log(BigDecimal n, int b)
    {
        return LogN(n) / LogN(b);
    }
    public static BigDecimal CoSecant(BigDecimal ar, int n)
    {
        return 1.0 / Sine(ar, n);
    }
    public void Ceiling(int precision)
    {
        RemoveTrailingZeros();
        var diff = GetNumberOfDigits(_unscaledValue) - precision;
        if (diff > 0)
        {
            for (var i = 0; i < diff; i++)
            {
                _unscaledValue = BigInteger.Divide(_unscaledValue, 10);
                Scale--;
            }
            if (_unscaledValue.Sign < 0)
                _unscaledValue--;
            else
                _unscaledValue++;
        }
    }
    public void Floor(int precision)
    {
        RemoveTrailingZeros();
        var diff = GetNumberOfDigits(_unscaledValue) - precision;
        if (diff > 0)
        {
            for (var i = 0; i < diff; i++)
            {
                _unscaledValue = BigInteger.Divide(_unscaledValue, 10);
                Scale--;
            }
            if (_unscaledValue.Sign > 0)
                _unscaledValue--;
            else
                _unscaledValue++;
        }
    }
    private void RemoveTrailingZeros()
    {
        BigInteger remainder;
        do
        {
            var shortened = BigInteger.DivRem(_unscaledValue, 10, out remainder);
            if (remainder == BigInteger.Zero)
            {
                _unscaledValue = shortened;
                Scale--;
            }
        } while (remainder == BigInteger.Zero);
    }
    public BigDecimal Min(BigDecimal value)
    {
        return CompareTo(value) <= 0 ? this : value;
    }
    public BigDecimal Max(BigDecimal value)
    {
        return CompareTo(value) >= 0 ? this : value;
    }
    public static BigDecimal Sqrt(BigDecimal value)
    {
        return BigRational.Sqrt(value);
    }
    [StructLayout(LayoutKind.Explicit)]
    internal struct DecimalUInt32
    {
        [FieldOffset(0)] public decimal dec;
        [FieldOffset(0)] public int     flags;
    }
}

ChiSquaredImageComparison.cs

Posted on June 5, 20202 Comments on ChiSquaredImageComparison.cs

Chi Squared Image Comparison (Work In Progress)

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
public class ChiSquaredImageComparison
{
    private readonly int[]                               _expectedHistogram  = new int[256];
    private readonly ConcurrentDictionary<string, float> _finalDistList      = new ConcurrentDictionary<string, float>();
    private          ConcurrentDictionary<string, int[]> _observedHistograms = new ConcurrentDictionary<string, int[]>();
    private volatile float                               c, p, t, s1, s2;
    private volatile int                                 ExpectedLength;
    private volatile int                                 ExpectedMetric;
    private volatile int                                 XYExpectedLength;
    public void SetExpectedHistogram(string path)
    {
        try
        {
            using (var org = new Bitmap(path))
            {
                using (var img = new MemoryBitmap(org))
                {
                    XYExpectedLength = img.Height * img.Width;
                    for (var y = 0; y < img.Height; y++)
                    for (var x = 0; x < img.Width; x++)
                    {
                        var pixel = img.GetPixel(x, y);
                        _expectedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++;
                    }
                }
            }
        }
        catch
        {
        }
        ExpectedLength = _expectedHistogram.Sum(e => e);
        ExpectedMetric = _expectedHistogram.Count(e => e > 0);
    }
    public void BuildHistograms(EnumBase.IEnumBase[] paths)
    {
        if (File.Exists(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin"))
        {
            var file = LoadFromFile(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin");
            _observedHistograms = new ConcurrentDictionary<string, int[]>(file);
            var list1 = paths.Select(e => e.PathString).ToList();
            var list2 = file.Select(e => e.Key).ToList();
            var list3 = list1.Except(list2).ToArray();
            foreach (var e in list3)
                try
                {
                    using (var org = new Bitmap(e))
                    {
                        var observedHistogram = new int[256];
                        using (var img = new MemoryBitmap(org))
                        {
                            c++;
                            p = c / t * 100f;
                            for (var y = 0; y < img.Height; y++)
                            for (var x = 0; x < img.Width; x++)
                            {
                                var pixel = img.GetPixel(x, y);
                                observedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++;
                            }
                            if (!_observedHistograms.ContainsKey(e))
                                _observedHistograms.TryAdd(e, observedHistogram);
                        }
                    }
                }
                catch
                {
                }
        }
        else
        {
            t = paths.Length;
            paths.AsParallel().WithDegreeOfParallelism(8).ForAll(i =>
            {
                try
                {
                    using (var org = new Bitmap(i.PathString))
                    {
                        var observedHistogram = new int[256];
                        using (var img = new MemoryBitmap(org))
                        {
                            c++;
                            p = c / t * 100f;
                            for (var y = 0; y < img.Height; y++)
                            for (var x = 0; x < img.Width; x++)
                            {
                                var pixel = img.GetPixel(x, y);
                                observedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++;
                            }
                            _observedHistograms.TryAdd(i.PathString, observedHistogram);
                        }
                    }
                }
                catch
                {
                }
            });
        }
        var kpa = _observedHistograms.ToArray();
        SaveToFile(kpa, LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin");
    }
    public void SaveToFile(KeyValuePair<string, int[]>[] kpa, string path)
    {
        using (var wrtr = new Writer(path))
        {
            foreach (var i in kpa)
            {
                var k = i.Key;
                var v = i.Value;
                wrtr.WriteString(k);
                wrtr.WriteInts(v);
            }
        }
    }
    public KeyValuePair<string, int[]>[] LoadFromFile(string path)
    {
        var kpd = new Dictionary<string, int[]>();
        using (var reader = new Reader(path))
        {
            while (true)
                try
                {
                    var k = reader.ReadString();
                    var v = reader.ReadInts();
                    kpd.Add(k, v);
                }
                catch
                {
                    return kpd.ToArray();
                }
        }
        return kpd.ToArray();
    }
    public ConcurrentDictionary<string, float> HistogramChiSquared(EnumBase.IEnumBase[] paths)
    {
        t = paths.Length;
        paths.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i =>
        {
            try
            {
                using (var org = new Bitmap(i.PathString))
                {
                    var observedHistogram = new int[256];
                    using (var img = new MemoryBitmap(org))
                    {
                        c++;
                        p = c / t * 100f;
                        var XYObservedLength = img.Height * img.Width;
                        if (XYObservedLength != XYExpectedLength)
                        {
                            s1++;
                            return;
                        }
                        for (var y = 0; y < img.Height; y++)
                        for (var x = 0; x < img.Width; x++)
                        {
                            var pixel = img.GetPixel(x, y);
                            observedHistogram[(pixel.R + pixel.G + pixel.B) / 3]++;
                        }
                        var observedLength = observedHistogram.Sum(e => e);
                        if (observedLength > ExpectedLength)
                        {
                            s2++;
                            return;
                        }
                        var ChiSqrd = 0.0f;
                        for (var j = 0; j < 256; j++)
                            if (_expectedHistogram[j] + observedHistogram[j] != 0)
                                ChiSqrd += (float) Math.Pow(_expectedHistogram[j] - observedHistogram[j], 2) / (_expectedHistogram[j] + observedHistogram[j]);
                        var fp = Math.Abs(ChiSqrd / ExpectedLength * 100f);
                        if (fp >= 0 && fp < 15)
                            _finalDistList.TryAdd(i.PathString, fp);
                    }
                }
            }
            catch
            {
            }
        });
        return _finalDistList;
    }
    public ConcurrentDictionary<string, float> LoadedHistogramChiSquared()
    {
        var file = LoadFromFile(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin");
        t = file.Length;
        file.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i =>
        {
            try
            {
                c++;
                p = c / t * 100f;
                var d = 0.0f;
                for (var j = 0; j < 256; j++)
                {
                    var e = _expectedHistogram[j];
                    var o = i.Value[j];
                    if (e + o != 0)
                        d += (float) Math.Pow(e - o, 2) / (e + o);
                }
                var dd = d / 100;
                if (dd >= 0 && dd < 500)
                    _finalDistList.TryAdd(i.Key, dd);
            }
            catch
            {
            }
        });
        var srt = _finalDistList.OrderBy(x => x.Value);
        return _finalDistList;
    }
    public ConcurrentDictionary<string, float> LoadedHistogramIntersection()
    {
        var file = LoadFromFile(LocalSettings.ProgramDir + "C_JPG_HISTOGRAM.bin");
        t = file.Length;
        file.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount - 2).ForAll(i =>
        {
            try
            {
                c++;
                p = c / t * 100f;
                var d = 0.0f;
                for (var j = 0; j < 256; j++)
                {
                    var e = _expectedHistogram[j];
                    var o = i.Value[j];
                    d += e + o - Math.Abs(e - o);
                }
                var observedLength = i.Value.Sum(e => e);
                var dd             = 0.5f * d / Math.Max(ExpectedLength, observedLength);
                if (d >= 0 && d < 5)
                    _finalDistList.TryAdd(i.Key, d);
            }
            catch
            {
            }
        });
        var srt = _finalDistList.OrderBy(x => x.Value);
        return _finalDistList;
    }
}

Rdtsc.cs

Posted on June 4, 2020  Leave a comment on Rdtsc.cs

Rdtsc 32 and 64 Bit In C#

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
public static class Rdtsc
{
    [SuppressUnmanagedCodeSecurity]
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate ulong FuncUInt64();
    private const          uint       PAGE_READWRITE         = 0x04;
    private const          uint       PAGE_EXECUTE           = 0x10;
    private const          uint       PAGE_EXECUTE_READWRITE = 0x40;
    private const          uint       MEM_COMMIT             = 0x1000;
    private const          uint       MEM_RELEASE            = 0x8000;
    public static readonly FuncUInt64 Timestamp;
    public static readonly FuncUInt64 TimestampP;
    public static readonly bool       IsRdtscSupported;
    public static readonly bool       IsRdtscPSupported;
    static Rdtsc()
    {
        SystemInfo systemInfo;
        GetNativeSystemInfo(out systemInfo);
        if (systemInfo.wProcessorArchitecture != 0 && systemInfo.wProcessorArchitecture != 9)
        {
            Timestamp         = StopwatchGetTimestamp;
            TimestampP        = StopwatchGetTimestamp;
            IsRdtscSupported  = false;
            IsRdtscPSupported = false;
            return;
        }
        byte[] cpuid;
        byte[] rdtsc;
        byte[] rdtscp;
        byte[] rdtsccpuid;
        IsRdtscSupported = true;
        if (Is64Bit())
        {
            cpuid = new byte[]
            {
                0x53, 0xB8, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xA2, 0xBB, 0x01, 0x00, 0x00, 0x80, 0x39, 0xD8, 0x72, 0x16, 0x89, 0xD8,
                0x48, 0xC7, 0xC2, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xA2, 0x89, 0xC8, 0x48, 0xC1, 0xE0, 0x20, 0x48, 0x09, 0xD0, 0xEB,
                0x03, 0x48, 0x31, 0xC0, 0x5B, 0xC3
            };
            rdtsc  = new byte[] {0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3};
            rdtscp = new byte[] {0x0F, 0x01, 0xF9, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0xC3};
            rdtsccpuid = new byte[]
                {0x53, 0x31, 0xC0, 0x0F, 0xA2, 0x0F, 0x31, 0x48, 0xC1, 0xE2, 0x20, 0x48, 0x09, 0xD0, 0x5B, 0xC3};
        }
        else
        {
            cpuid = new byte[]
            {
                0x53, 0xB8, 0x00, 0x00, 0x00, 0x80, 0x0F, 0xA2, 0xBB, 0x01, 0x00, 0x00, 0x80, 0x39, 0xD8, 0x72, 0x0A, 0x89, 0xD8,
                0x0F, 0xA2, 0x89, 0xD0, 0x89, 0xCA, 0xEB, 0x04, 0x31, 0xC0, 0x31, 0xD2, 0x5B, 0xC3
            };
            rdtsc      = new byte[] {0x0F, 0x31, 0xC3};
            rdtscp     = new byte[] {0x0F, 0x01, 0xF9, 0xC3};
            rdtsccpuid = new byte[] {0x53, 0x31, 0xC0, 0x0F, 0xA2, 0x0F, 0x31, 0x5B, 0xC3};
        }
        var buf = IntPtr.Zero;
        try
        {
            var cpuidLength      = (cpuid.Length      & 63) != 0 ? (cpuid.Length      | 63) + 1 : cpuid.Length;
            var rdtscLength      = (rdtsc.Length      & 63) != 0 ? (rdtsc.Length      | 63) + 1 : rdtsc.Length;
            var rdtscpLength     = (rdtscp.Length     & 63) != 0 ? (rdtscp.Length     | 63) + 1 : rdtscp.Length;
            var rdtsccpuidLength = (rdtsccpuid.Length & 63) != 0 ? (rdtsccpuid.Length | 63) + 1 : rdtsccpuid.Length;
            var totalLength      = cpuidLength + rdtscLength + Math.Max(rdtscpLength, rdtsccpuidLength);
            buf = VirtualAlloc(IntPtr.Zero, (IntPtr) totalLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
            if (buf != IntPtr.Zero)
            {
                Marshal.Copy(cpuid, 0, buf, cpuid.Length);
                for (var i = cpuid.Length; i < cpuidLength; i++)
                    Marshal.WriteByte(buf, i, 0x90);
                Marshal.Copy(rdtsc, 0, buf + cpuidLength, rdtsc.Length);
                for (var i = rdtsc.Length; i < rdtscLength; i++)
                    Marshal.WriteByte(buf, cpuidLength + i, 0x90);
                var    cpuidFunc         = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf, typeof(FuncUInt64));
                var    supportedFeatures = cpuidFunc();
                byte[] rdtscpSelected;
                int    rdtscpSelectedLength;
                if ((supportedFeatures & (1L << 27)) != 0)
                {
                    rdtscpSelected       = rdtscp;
                    rdtscpSelectedLength = rdtscpLength;
                    IsRdtscPSupported    = true;
                }
                else
                {
                    rdtscpSelected       = rdtsccpuid;
                    rdtscpSelectedLength = rdtsccpuidLength;
                    IsRdtscPSupported    = false;
                }
                Marshal.Copy(rdtscpSelected, 0, buf + cpuidLength + rdtscLength, rdtscpSelected.Length);
                for (var i = rdtscpSelected.Length; i < rdtscpSelectedLength; i++)
                    Marshal.WriteByte(buf, cpuidLength + rdtscLength + i, 0x90);
                var result = VirtualProtect(buf, (IntPtr) totalLength, PAGE_EXECUTE, out var oldProtection);
                if (result)
                {
                    Timestamp = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf + cpuidLength, typeof(FuncUInt64));
                    TimestampP = (FuncUInt64) Marshal.GetDelegateForFunctionPointer(buf + cpuidLength + rdtscLength,
                        typeof(FuncUInt64));
                    buf = IntPtr.Zero;
                }
            }
        }
        finally
        {
            if (buf != IntPtr.Zero)
                VirtualFree(buf, IntPtr.Zero, MEM_RELEASE);
        }
    }
    private static bool Is64Bit()
    {
        return Marshal.SizeOf(typeof(IntPtr)) == 8;
    }
    [DllImport("kernel32.dll", ExactSpelling = true)]
    private static extern void GetNativeSystemInfo(out SystemInfo lpSystemInfo);
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    private static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, out uint lpflOldProtect);
    [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool VirtualFree(IntPtr lpAddress, IntPtr dwSize, uint dwFreeType);
    private static ulong StopwatchGetTimestamp()
    {
        return unchecked((ulong) Stopwatch.GetTimestamp());
    }
    [StructLayout(LayoutKind.Sequential)]
    private struct SystemInfo
    {
        public readonly ushort wProcessorArchitecture;
        public readonly ushort wReserved;
        public readonly uint   dwPageSize;
        public readonly IntPtr lpMinimumApplicationAddress;
        public readonly IntPtr lpMaximumApplicationAddress;
        public readonly IntPtr dwActiveProcessorMask;
        public readonly uint   dwNumberOfProcessors;
        public readonly uint   dwProcessorType;
        public readonly uint   dwAllocationGranularity;
        public readonly ushort wProcessorLevel;
        public readonly ushort wProcessorRevision;
    }
}