Skip to content

Analysis Package Fingerprint

Danmarks Miljøportal edited this page Jan 11, 2021 · 3 revisions

.NET C#

public static class PackageAnalysisFingerprintGenerator
{
    private static string _alphabet = "SYWBPQVHCDANRLTKGEXIMUZOJF0123456789";

    public static string Generate(IEnumerable<(int Parameter, int Fraction, int Unit)> analyses)
    {
        if (!analyses.Any())
            throw new Exception("Sequence contains no element");

        var fingerprint = "";

        var hashCode = GenerateAnalysisPackageHashCode(analyses);
        var hashedAlphabet = GenerateSaltedAlphabet(hashCode);

        foreach (var sequence in GenerateSequence(hashCode))
        {
            fingerprint += hashedAlphabet[(int)(sequence % hashedAlphabet.Length)];
        }

        return fingerprint;
    }

    /// <summary>
    /// Linear congruential generator
    /// </summary>
    /// <param name="seed"></param>
    /// <returns></returns>
    private static IEnumerable<long> GenerateSequence(long seed)
    {
        long m = 4294967295;
        long a = 1664525;
        long c = 1013904223;

        long start = seed;

        for (int i = 0; i < 6; i++)
        {
            start = (a * start + c) % m;
            yield return start;
        }
    }

    private static int GenerateAnalysisHashCode(int parameter, int fraction, int unit)
    {
        int result = parameter;
        result ^= fraction << 14;
        result ^= unit << 20;

        return result;
    }

    private static uint GenerateAnalysisPackageHashCode(IEnumerable<(int Parameter, int Fraction, int Unit)> analyses)
    {
        int seed = 17;
        int factor = 31;

        int hash = seed;

        var hashcodes = analyses
            .Select(x => GenerateAnalysisHashCode(x.Parameter, x.Fraction, x.Unit))
            .Distinct();

        foreach (var hashcode in hashcodes)
        {
            hash = (hash * factor) + hashcode;
        }

        return (uint)Math.Abs(hash);
    }

    private static string GenerateSaltedAlphabet(uint hashCode)
    {
        int n;

        var salt = GenerateSalt(hashCode);
        var letters = _alphabet.ToCharArray();

        for (int i = letters.Length - 1, v = 0, p = 0; i > 0; i--, v++)
        {
            v %= salt.Length;
            p += (n = salt[v]);
            var j = (n + v + p) % i;
            var temp = letters[j];
            letters[j] = letters[i];
            letters[i] = temp;
        }

        return new string(letters);

    }

    private static string GenerateSalt(uint hashCode)
    {
        var result = "";

        do
        {
            result += _alphabet[(int)(hashCode % _alphabet.Length)];
            hashCode = (uint)(hashCode / _alphabet.Length);
        }
        while (hashCode > 0);

        return result;
    }
}

Clone this wiki locally