frostfs-sdk-csharp/src/FrostFS.SDK.Client/Models/Netmap/Placement/Tools.cs
Pavel Gross 43e300c773
All checks were successful
DCO / DCO (pull_request) Successful in 25s
lint-build / dotnet8.0 (pull_request) Successful in 1m5s
lint-build / dotnet8.0 (push) Successful in 41s
[#29] Client: Add PlacementVector unit tests
Signed-off-by: Pavel Gross <p.gross@yadro.com>
2025-01-13 10:34:44 +03:00

138 lines
3.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using static FrostFS.SDK.FrostFsNetmapSnapshot;
namespace FrostFS.SDK.Client.Models.Netmap.Placement;
public static class Tools
{
internal static ulong Distance(ulong x, ulong y)
{
var acc = x ^ y;
acc ^= acc >> 33;
acc *= 0xff51afd7ed558ccd;
acc ^= acc >> 33;
acc *= 0xc4ceb9fe1a85ec53;
acc ^= acc >> 33;
return acc;
}
internal static double ReverceNormalize(double r, double w)
{
return (r + 1) / (w + 1);
}
internal static double Normalize(double r, double w)
{
if (r == 0)
{
return 0;
}
var x = w / r;
return x / (1 + x);
}
internal static void AppendWeightsTo(FrostFsNodeInfo[] nodes, Func<FrostFsNodeInfo, double> wf, ref double[] weights)
{
if (weights.Length < nodes.Length)
{
weights = new double[nodes.Length];
}
for (int i = 0; i < nodes.Length; i++)
{
weights[i] = wf(nodes[i]);
}
}
internal static List<T> SortHasherSliceByWeightValue<T>(List<T> nodes, Span<double> weights, ulong hash) where T : IHasher
{
if (nodes.Count == 0)
{
return nodes;
}
var allEquals = true;
if (weights.Length > 1)
{
for (int i = 1; i < weights.Length; i++)
{
if (weights[i] != weights[0])
{
allEquals = false;
break;
}
}
}
var dist = new double[nodes.Count];
if (allEquals)
{
for (int i = 0; i < dist.Length; i++)
{
var x = nodes[i].Hash();
dist[i] = Distance(x, hash);
}
return SortHasherByDistance(nodes, dist, true);
}
for (int i = 0; i < dist.Length; i++)
{
var d = Distance(nodes[i].Hash(), hash);
dist[i] = (ulong.MaxValue - d) * weights[i];
}
return SortHasherByDistance(nodes, dist, false);
}
internal static List<T> SortHasherByDistance<T, N>(List<T> nodes, N[] dist, bool asc)
{
IndexedValue<T, N>[] indexes = new IndexedValue<T, N>[nodes.Count];
for (int i = 0; i < dist.Length; i++)
{
indexes[i] = new IndexedValue<T, N>() { nodeInfo = nodes[i], dist = dist[i] };
}
if (asc)
{
return new List<T>(indexes
.OrderBy(x => x.dist)
.Select(x => x.nodeInfo).ToArray());
}
else
{
return new List<T>(indexes
.OrderByDescending(x => x.dist)
.Select(x => x.nodeInfo));
}
}
internal static Func<FrostFsNodeInfo, double> DefaultWeightFunc(IReadOnlyList<FrostFsNodeInfo> nodes)
{
MeanAgg mean = new();
MinAgg minV = new();
foreach (var node in nodes)
{
mean.Add(node.GetCapacity());
minV.Add(node.Price);
}
return NewWeightFunc(
NewSigmoidNorm(mean.Compute()),
NewReverseMinNorm(minV.Compute()));
}
private struct IndexedValue<T, N>
{
internal T nodeInfo;
internal N dist;
}
}