Skip to content

Commit

Permalink
FVI nodes now have separate ChildrenAscending and `ChildrenDescendi…
Browse files Browse the repository at this point in the history
…ng` properties - for flexibility in how they enumerate children in subsuming/subsumed queries respectively.
  • Loading branch information
sdcondon committed Oct 12, 2024
1 parent f9387dd commit c661784
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private AsyncFeatureVectorIndexDictionaryNode(IComparer<TFeature> featureCompare
public IComparer<TFeature> FeatureComparer { get; }

/// <inheritdoc/>
public IAsyncEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IAsyncFeatureVectorIndexNode<TFeature, TValue>>> Children
public IAsyncEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IAsyncFeatureVectorIndexNode<TFeature, TValue>>> ChildrenAscending
{
get
{
Expand All @@ -77,6 +77,23 @@ async IAsyncEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IAsyncFeat
}
}

/// <inheritdoc/>
public IAsyncEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IAsyncFeatureVectorIndexNode<TFeature, TValue>>> ChildrenDescending
{
get
{
async IAsyncEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IAsyncFeatureVectorIndexNode<TFeature, TValue>>> GetReturnValue()
{
for (int i = childrenByVectorComponent.Count - 1; i >= 0; i--)
{
yield return new KeyValuePair<FeatureVectorComponent<TFeature>, IAsyncFeatureVectorIndexNode<TFeature, TValue>>(childrenByVectorComponent.Keys[i], childrenByVectorComponent.Values[i]);
}
}

return GetReturnValue();
}
}

/// <inheritdoc/>
public IAsyncEnumerable<KeyValuePair<CNFClause, TValue>> KeyValuePairs
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ async ValueTask<bool> ExpandNodeAsync(IAsyncFeatureVectorIndexNode<TFeature, TVa
return false;
}

if (!await childNode.Children.AnyAsync() && !await childNode.KeyValuePairs.AnyAsync())
if (!await childNode.ChildrenAscending.AnyAsync() && !await childNode.KeyValuePairs.AnyAsync())
{
await node.DeleteChildAsync(component);
}
Expand Down Expand Up @@ -171,7 +171,7 @@ async IAsyncEnumerable<TValue> ExpandNode(IAsyncFeatureVectorIndexNode<TFeature,
{
// If matching feature with lower value, then recurse
// todo: can be made more efficient now that node children are ordered
await foreach (var ((childFeature, childMagnitude), childNode) in node.Children)
await foreach (var ((childFeature, childMagnitude), childNode) in node.ChildrenAscending)
{
if (childFeature.Equals(featureVector[elementIndex].Feature) && childMagnitude <= featureVector[elementIndex].Magnitude)
{
Expand Down Expand Up @@ -218,7 +218,7 @@ async IAsyncEnumerable<TValue> ExpandNode(IAsyncFeatureVectorIndexNode<TFeature,
{
if (elementIndex < featureVector.Count)
{
await foreach (var ((childFeature, childMagnitude), childNode) in node.Children)
await foreach (var ((childFeature, childMagnitude), childNode) in node.ChildrenDescending)
{
// todo: is this right? or do we need by feature AND magnitude here?
// todo: can be made more efficient now that node children are ordered
Expand Down Expand Up @@ -256,7 +256,7 @@ async IAsyncEnumerable<TValue> GetAllDescendentValues(IAsyncFeatureVectorIndexNo
yield return value;
}

await foreach (var (_, childNode) in node.Children)
await foreach (var (_, childNode) in node.ChildrenAscending)
{
await foreach (var value in GetAllDescendentValues(childNode))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,19 @@ private FeatureVectorIndexDictionaryNode(IComparer<TFeature> featureComparer, IC
/// <inheritdoc/>
// NB: we don't bother wrapping children in a ReadOnlyDict to stop unscrupulous
// users from casting. Would be more memory for a real edge case.
public IReadOnlyCollection<KeyValuePair<FeatureVectorComponent<TFeature>, IFeatureVectorIndexNode<TFeature, TValue>>> Children => childrenByVectorComponent;
public IEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IFeatureVectorIndexNode<TFeature, TValue>>> ChildrenAscending => childrenByVectorComponent;

/// <inheritdoc/>
public IEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IFeatureVectorIndexNode<TFeature, TValue>>> ChildrenDescending
{
get
{
for (int i = childrenByVectorComponent.Count - 1; i >= 0; i--)
{
yield return new KeyValuePair<FeatureVectorComponent<TFeature>, IFeatureVectorIndexNode<TFeature, TValue>>(childrenByVectorComponent.Keys[i], childrenByVectorComponent.Values[i]);
}
}
}

/// <inheritdoc/>
public IEnumerable<KeyValuePair<CNFClause, TValue>> KeyValuePairs => valuesByKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ bool ExpandNode(IFeatureVectorIndexNode<TFeature, TValue> node, int vectorCompon
return false;
}

if (childNode.Children.Count == 0 && !childNode.KeyValuePairs.Any())
if (!childNode.ChildrenAscending.Any() && !childNode.KeyValuePairs.Any())
{
node.DeleteChild(element);
}
Expand Down Expand Up @@ -173,7 +173,7 @@ IEnumerable<TValue> ExpandNode(IFeatureVectorIndexNode<TFeature, TValue> node, i
{
// If matching feature with lower value, then recurse
// TODO: can be made more efficient now that node children are ordered (e.g. skipwhile, then takeuntil - or "manual" ienumerator stuff)
foreach (var ((childFeature, childMagnitude), childNode) in node.Children)
foreach (var ((childFeature, childMagnitude), childNode) in node.ChildrenAscending)
{
if (childFeature.Equals(featureVector[componentIndex].Feature) && childMagnitude <= featureVector[componentIndex].Magnitude)
{
Expand Down Expand Up @@ -223,7 +223,7 @@ IEnumerable<TValue> ExpandNode(IFeatureVectorIndexNode<TFeature, TValue> node, i
{
if (vectorComponentIndex < featureVector.Count)
{
foreach (var ((childFeature, childMagnitude), childNode) in node.Children)
foreach (var ((childFeature, childMagnitude), childNode) in node.ChildrenDescending)
{
// todo: is this right? or do we need by feature AND magnitude here?
// todo: can be made more efficient now that node children are ordered
Expand Down Expand Up @@ -261,7 +261,7 @@ IEnumerable<TValue> GetAllDescendentValues(IFeatureVectorIndexNode<TFeature, TVa
yield return value;
}

foreach (var (_, childNode) in node.Children)
foreach (var (_, childNode) in node.ChildrenAscending)
{
foreach (var value in GetAllDescendentValues(childNode))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ public interface IAsyncFeatureVectorIndexNode<TFeature, TValue>
/// <summary>
/// Gets the child nodes of this node, keyed by the vector component represented by the child, and in ascending feature order.
/// </summary>
IAsyncEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IAsyncFeatureVectorIndexNode<TFeature, TValue>>> Children { get; }
IAsyncEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IAsyncFeatureVectorIndexNode<TFeature, TValue>>> ChildrenAscending { get; }

/// <summary>
/// Gets the child nodes of this node, keyed by the vector component represented by the child, and in descending feature order.
/// </summary>
IAsyncEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IAsyncFeatureVectorIndexNode<TFeature, TValue>>> ChildrenDescending { get; }

/// <summary>
/// Gets the key-value pairs attached to this node.
Expand Down Expand Up @@ -48,14 +53,14 @@ public interface IAsyncFeatureVectorIndexNode<TFeature, TValue>
ValueTask DeleteChildAsync(FeatureVectorComponent<TFeature> vectorComponent);

/// <summary>
/// Adds a value to this node, in so doing specifying that this node represents the "last" element of a stored set.
/// Adds a value to this node.
/// </summary>
/// <param name="clause"></param>
/// <param name="value">The value to store.</param>
ValueTask AddValueAsync(CNFClause clause, TValue value);

/// <summary>
/// Removes the value from this node, in so doing specifying that this node no longer represents the "last" element of a stored set.
/// Removes the value from this node.
/// </summary>
ValueTask<bool> RemoveValueAsync(CNFClause clause);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ public interface IFeatureVectorIndexNode<TFeature, TValue>
/// <summary>
/// Gets the child nodes of this node, keyed by the vector component represented by the child, and in ascending feature order.
/// </summary>
IReadOnlyCollection<KeyValuePair<FeatureVectorComponent<TFeature>, IFeatureVectorIndexNode<TFeature, TValue>>> Children { get; }
IEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IFeatureVectorIndexNode<TFeature, TValue>>> ChildrenAscending { get; }

/// <summary>
/// Gets the child nodes of this node, keyed by the vector component represented by the child, and in descending feature order.
/// </summary>
IEnumerable<KeyValuePair<FeatureVectorComponent<TFeature>, IFeatureVectorIndexNode<TFeature, TValue>>> ChildrenDescending { get; }

/// <summary>
/// Gets the key-value pairs attached to this node.
Expand Down

0 comments on commit c661784

Please sign in to comment.