You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel.HNSW/Model/SearchContext.cs

127 lines
5.2 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace ZeroLevel.HNSW
{
public enum Mode
{
None,
ActiveCheck,
InactiveCheck,
ActiveInactiveCheck
}
public sealed class SearchContext
{
2 years ago
/// <summary>
/// Список номеров которые разрешены к добавлению итогового результата, если поиск ведется в ограниченном наборе точек (например, после предварительной фильтрации)
/// </summary>
private HashSet<int> _activeNodes;
2 years ago
/// <summary>
/// Список точек с которых начинается поиск в графе для расширения
/// </summary>
private HashSet<int> _entryNodes;
2 years ago
/// <summary>
/// Режим работы алгоритма расширения, зависящий от того заданы ли ограничения в точках, и заданы ли точки начала поиска
/// </summary>
private Mode _mode;
public Mode NodeCheckMode => _mode;
public double PercentInTotal { get; private set; } = 0;
public long AvaliableNodesCount => _activeNodes?.Count ?? 0;
public SearchContext()
{
_mode = Mode.None;
}
2 years ago
/// <summary>
/// Расчет процентного содержания точек доступных для использования в данном контексте, по отношению к общему количеству точек
/// </summary>
public SearchContext CaclulatePercentage(long total)
{
2 years ago
if ((_mode == Mode.ActiveCheck || _mode == Mode.ActiveInactiveCheck) && total > 0)
{
2 years ago
PercentInTotal = ((_activeNodes?.Count ?? 0 * 100d) / (double)total) / 100.0d;
}
return this;
}
public SearchContext SetPercentage(double percent)
{
PercentInTotal = percent;
return this;
}
2 years ago
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool _isActiveNode(int nodeId) => _activeNodes?.Contains(nodeId) ?? false;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool _isEntryNode(int nodeId) => _entryNodes?.Contains(nodeId) ?? false;
/// <summary>
/// Проверка, подходит ли указанная точка для включения в набор расширения
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal bool IsActiveNode(int nodeId)
{
switch (_mode)
{
2 years ago
// Если задан набор разрешенных к использованию точек, проверяется вхождение в него
case Mode.ActiveCheck: return _isActiveNode(nodeId);
// Если задан набор точек начала поиска, проверка невхождения точки в него
case Mode.InactiveCheck: return _isEntryNode(nodeId) == false;
// Если задан и ограничивающий и начальный наборы точек, проверка и на ограничение и на невхождение в начальный набор
case Mode.ActiveInactiveCheck: return false == _isEntryNode(nodeId) && _isActiveNode(nodeId);
}
return nodeId >= 0;
}
public IEnumerable<int> EntryPoints => _entryNodes;
public SearchContext SetActiveNodes(IEnumerable<int> activeNodes)
{
if (activeNodes != null && activeNodes.Any())
{
if (_mode == Mode.ActiveCheck || _mode == Mode.ActiveInactiveCheck)
{
throw new InvalidOperationException("Active nodes are already defined");
}
_activeNodes = new HashSet<int>(activeNodes);
if (_mode == Mode.None)
{
_mode = Mode.ActiveCheck;
}
else if (_mode == Mode.InactiveCheck)
{
_mode = Mode.ActiveInactiveCheck;
}
}
return this;
}
public SearchContext SetEntryPointsNodes(IEnumerable<int> entryNodes)
{
if (entryNodes != null && entryNodes.Any())
{
if (_mode == Mode.InactiveCheck || _mode == Mode.ActiveInactiveCheck)
{
throw new InvalidOperationException("Inctive nodes are already defined");
}
_entryNodes = new HashSet<int>(entryNodes);
if (_mode == Mode.None)
{
_mode = Mode.InactiveCheck;
}
else if (_mode == Mode.ActiveCheck)
{
_mode = Mode.ActiveInactiveCheck;
}
}
return this;
}
}
}

Powered by TurnKey Linux.