New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vantage point tree #708
Vantage point tree #708
Changes from 2 commits
88f1bb9
6d8976e
430cbe3
805eaa9
dbdf3ca
6c68a88
300882a
923bfe7
601de29
eea2ea3
cc326f3
d5fb40f
ce2ab20
add74d0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,16 +79,23 @@ DualTreeTraverser<RuleType>::Traverse( | |
{ | ||
// We have to recurse down the query node. In this case the recursion order | ||
// does not matter. | ||
const double pointScore = rule.Score(queryNode.Point(0), referenceNode); | ||
++numScores; | ||
|
||
if (pointScore != DBL_MAX) | ||
Traverse(queryNode.Point(0), referenceNode); | ||
else | ||
++numPrunes; | ||
|
||
// Before recursing, we have to set the traversal information correctly. | ||
rule.TraversalInfo() = traversalInfo; | ||
// If the first point of the query node is the centroid, the query node | ||
// contains a point. In this case we should run the single tree traverser. | ||
if (queryNode.IsFirstPointCentroid()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the query node contains a point we have to use the single tree traverser. |
||
{ | ||
const double pointScore = rule.Score(queryNode.Point(0), referenceNode); | ||
++numScores; | ||
|
||
if (pointScore != DBL_MAX) | ||
Traverse(queryNode.Point(0), referenceNode); | ||
else | ||
++numPrunes; | ||
|
||
// Before recursing, we have to set the traversal information correctly. | ||
rule.TraversalInfo() = traversalInfo; | ||
} | ||
|
||
const double leftScore = rule.Score(*queryNode.Left(), referenceNode); | ||
++numScores; | ||
|
||
|
@@ -109,10 +116,15 @@ DualTreeTraverser<RuleType>::Traverse( | |
} | ||
else if (queryNode.IsLeaf() && (!referenceNode.IsLeaf())) | ||
{ | ||
const size_t queryEnd = queryNode.Begin() + queryNode.Count(); | ||
for (size_t query = queryNode.Begin(); query < queryEnd; ++query) | ||
rule.BaseCase(query, referenceNode.Point(0)); | ||
numBaseCases += queryNode.Count(); | ||
// If the reference node contains a point we should calculate all | ||
// base cases with this point. | ||
if (referenceNode.IsFirstPointCentroid()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the reference node contains a point we have to calculate all base cases. |
||
{ | ||
const size_t queryEnd = queryNode.Begin() + queryNode.Count(); | ||
for (size_t query = queryNode.Begin(); query < queryEnd; ++query) | ||
rule.BaseCase(query, referenceNode.Point(0)); | ||
numBaseCases += queryNode.Count(); | ||
} | ||
// We have to recurse down the reference node. In this case the recursion | ||
// order does matter. Before recursing, though, we have to set the | ||
// traversal information correctly. | ||
|
@@ -189,69 +201,36 @@ DualTreeTraverser<RuleType>::Traverse( | |
} | ||
else | ||
{ | ||
for (size_t i = 0; i < queryNode.NumDescendants(); ++i) | ||
rule.BaseCase(queryNode.Descendant(i), referenceNode.Point(0)); | ||
numBaseCases += queryNode.NumDescendants(); | ||
// If the reference node contains a point we should calculate all | ||
// base cases with this point. | ||
if (referenceNode.IsFirstPointCentroid()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is inefficient. Is it possible to implement the score algorithm for a reference point and a query node? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree that this is inefficient. I think that the better solution is to do this: during recursion, for all query points in a node, perform a base case with all parent vantage points. Something like this:
That would have to come after the base case section but before any recursions, so I guess up by line 50 or so would be the right place. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah hang on, but we could end up with duplicated base cases like this. Let me think for a while if there might be a better way to avoid duplications but preserve this type of technique. Maybe you are right that traversing with a query node and a reference point could work, but that would require a lot of refactoring of all the dual-tree algorithms so I'd prefer to avoid that... |
||
{ | ||
for (size_t i = 0; i < queryNode.NumDescendants(); ++i) | ||
rule.BaseCase(queryNode.Descendant(i), referenceNode.Point(0)); | ||
numBaseCases += queryNode.NumDescendants(); | ||
} | ||
// We have to recurse down both query and reference nodes. Because the | ||
// query descent order does not matter, we will go to the left query child | ||
// first. Before recursing, we have to set the traversal information | ||
// correctly. | ||
double leftScore = rule.Score(queryNode.Point(0), *referenceNode.Left()); | ||
typename RuleType::TraversalInfoType leftInfo = rule.TraversalInfo(); | ||
rule.TraversalInfo() = traversalInfo; | ||
double rightScore = rule.Score(queryNode.Point(0), *referenceNode.Right()); | ||
typename RuleType::TraversalInfoType rightInfo; | ||
numScores += 2; | ||
|
||
if (leftScore < rightScore) | ||
{ | ||
// Recurse to the left. Restore the left traversal info. Store the right | ||
// traversal info. | ||
rightInfo = rule.TraversalInfo(); | ||
rule.TraversalInfo() = leftInfo; | ||
Traverse(queryNode.Point(0), *referenceNode.Left()); | ||
|
||
// Is it still valid to recurse to the right? | ||
rightScore = rule.Rescore(queryNode.Point(0), *referenceNode.Right(), | ||
rightScore); | ||
double leftScore; | ||
typename RuleType::TraversalInfoType leftInfo; | ||
double rightScore; | ||
typename RuleType::TraversalInfoType rightInfo; | ||
|
||
if (rightScore != DBL_MAX) | ||
{ | ||
// Restore the right traversal info. | ||
rule.TraversalInfo() = rightInfo; | ||
Traverse(queryNode.Point(0), *referenceNode.Right()); | ||
} | ||
else | ||
++numPrunes; | ||
} | ||
else if (rightScore < leftScore) | ||
if (queryNode.IsFirstPointCentroid()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the single tree traverser if the query node contains a point. |
||
{ | ||
// Recurse to the right. | ||
Traverse(queryNode.Point(0), *referenceNode.Right()); | ||
|
||
// Is it still valid to recurse to the left? | ||
leftScore = rule.Rescore(queryNode.Point(0), *referenceNode.Left(), | ||
leftScore); | ||
leftScore = rule.Score(queryNode.Point(0), *referenceNode.Left()); | ||
leftInfo = rule.TraversalInfo(); | ||
rule.TraversalInfo() = traversalInfo; | ||
rightScore = rule.Score(queryNode.Point(0), *referenceNode.Right()); | ||
numScores += 2; | ||
|
||
if (leftScore != DBL_MAX) | ||
if (leftScore < rightScore) | ||
{ | ||
// Restore the left traversal info. | ||
rule.TraversalInfo() = leftInfo; | ||
Traverse(queryNode.Point(0), *referenceNode.Left()); | ||
} | ||
else | ||
++numPrunes; | ||
} | ||
else | ||
{ | ||
if (leftScore == DBL_MAX) | ||
{ | ||
numPrunes += 2; | ||
} | ||
else | ||
{ | ||
// Choose the left first. Restore the left traversal info and store the | ||
// right traversal info. | ||
// Recurse to the left. Restore the left traversal info. Store the right | ||
// traversal info. | ||
rightInfo = rule.TraversalInfo(); | ||
rule.TraversalInfo() = leftInfo; | ||
Traverse(queryNode.Point(0), *referenceNode.Left()); | ||
|
@@ -262,17 +241,63 @@ DualTreeTraverser<RuleType>::Traverse( | |
|
||
if (rightScore != DBL_MAX) | ||
{ | ||
// Restore the right traversal information. | ||
// Restore the right traversal info. | ||
rule.TraversalInfo() = rightInfo; | ||
Traverse(queryNode.Point(0), *referenceNode.Right()); | ||
} | ||
else | ||
++numPrunes; | ||
} | ||
} | ||
else if (rightScore < leftScore) | ||
{ | ||
// Recurse to the right. | ||
Traverse(queryNode.Point(0), *referenceNode.Right()); | ||
|
||
// Restore the main traversal information. | ||
rule.TraversalInfo() = traversalInfo; | ||
// Is it still valid to recurse to the left? | ||
leftScore = rule.Rescore(queryNode.Point(0), *referenceNode.Left(), | ||
leftScore); | ||
|
||
if (leftScore != DBL_MAX) | ||
{ | ||
// Restore the left traversal info. | ||
rule.TraversalInfo() = leftInfo; | ||
Traverse(queryNode.Point(0), *referenceNode.Left()); | ||
} | ||
else | ||
++numPrunes; | ||
} | ||
else | ||
{ | ||
if (leftScore == DBL_MAX) | ||
{ | ||
numPrunes += 2; | ||
} | ||
else | ||
{ | ||
// Choose the left first. Restore the left traversal info and store the | ||
// right traversal info. | ||
rightInfo = rule.TraversalInfo(); | ||
rule.TraversalInfo() = leftInfo; | ||
Traverse(queryNode.Point(0), *referenceNode.Left()); | ||
|
||
// Is it still valid to recurse to the right? | ||
rightScore = rule.Rescore(queryNode.Point(0), *referenceNode.Right(), | ||
rightScore); | ||
|
||
if (rightScore != DBL_MAX) | ||
{ | ||
// Restore the right traversal information. | ||
rule.TraversalInfo() = rightInfo; | ||
Traverse(queryNode.Point(0), *referenceNode.Right()); | ||
} | ||
else | ||
++numPrunes; | ||
} | ||
} | ||
|
||
// Restore the main traversal information. | ||
rule.TraversalInfo() = traversalInfo; | ||
} | ||
|
||
// Now recurse down the left node. | ||
leftScore = rule.Score(*queryNode.Left(), *referenceNode.Left()); | ||
|
@@ -452,8 +477,12 @@ DualTreeTraverser<RuleType>::Traverse( | |
return; | ||
} | ||
|
||
rule.BaseCase(queryIndex, referenceNode.Point(0)); | ||
numBaseCases++; | ||
// If the reference node contains a point we should calculate the base case. | ||
if (referenceNode.IsFirstPointCentroid()) | ||
{ | ||
rule.BaseCase(queryIndex, referenceNode.Point(0)); | ||
numBaseCases++; | ||
} | ||
|
||
// Store the current traversal info. | ||
traversalInfo = rule.TraversalInfo(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,7 +51,9 @@ SingleTreeTraverser<RuleType>::Traverse( | |
return; | ||
} | ||
|
||
rule.BaseCase(queryIndex, referenceNode.Point(0)); | ||
// If the reference node contains a point we should calculate the base case. | ||
if (referenceNode.IsFirstPointCentroid()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the reference node contains a point we have to calculate the base case. |
||
rule.BaseCase(queryIndex, referenceNode.Point(0)); | ||
|
||
// If either score is DBL_MAX, we do not recurse into that node. | ||
double leftScore = rule.Score(queryIndex, *referenceNode.Left()); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea I had here for
IsFirstPointCentroid()
was to leave it a part ofTreeTraits
, but just to make it a function:and then for the VP tree we can specialize and make it non-constexpr:
It changes the syntax of all of the traits, but it keeps them out of the definition of each tree itself, and we are guaranteed that there is a value for these even if the person who wrote the tree did not specify them. Does that seem reasonable to you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I agree. That should simplify the TreeType API.