-
Notifications
You must be signed in to change notification settings - Fork 1
Analysis Package Fingerprint
Danmarks Miljøportal edited this page Jan 11, 2021
·
3 revisions
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;
}
}