First steps towards documenting VPTree.
This commit is contained in:
@@ -86,6 +86,11 @@ when the sidebar is built for each page.
|
||||
<code>MeanSplitKDTree</code>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="LINKROOTuser/core/trees/vptree.html">
|
||||
<code>VPTree</code>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="LINKROOTuser/core/trees/binary_space_tree.html">
|
||||
<code>BinarySpaceTree</code>
|
||||
|
||||
@@ -421,6 +421,8 @@ write a custom `BoundType` for use with `BinarySpaceTree`:
|
||||
|
||||
* [`HRectBound`](#hrectbound): hyperrectangle bound, encloses the descendant
|
||||
points in the smallest possible hyperrectangle
|
||||
* [`HollowBallBound`](#hollowballbound): hollow ball bound, equivalent to a
|
||||
ball bound with a ball subtracted from it.
|
||||
* [Custom `BoundType`s](#custom-boundtypes): implement a fully custom
|
||||
`BoundType`
|
||||
|
||||
@@ -567,7 +569,7 @@ operations with data points or other bounds.
|
||||
|
||||
Once an `HRectBound` has been successfully created and set to the desired
|
||||
bounding hyperrectangle, there are a number of functions that can bound the
|
||||
distance between a `HRectBound` and other objects.
|
||||
distance between an `HRectBound` and other objects.
|
||||
|
||||
* `b.Contains(point)`
|
||||
* `b.Contains(bound)`
|
||||
@@ -764,13 +766,352 @@ std::cout << "Distance between Manhattan distance HRectBound and "
|
||||
// point.
|
||||
arma::fmat floatData(3, 25, arma::fill::randu);
|
||||
mlpack::HRectBound<mlpack::ChebyshevDistance, float> cb;
|
||||
cb |= floatData; // This will set the bound to [2.0, 3.0] in every dimension.
|
||||
cb |= floatData;
|
||||
// Note the use of arma::fvec to represent a point, since ElemType is float.
|
||||
const mlpack::RangeType<float> r3 = cb.RangeDistance(arma::fvec("1.5 1.5 4.0"));
|
||||
std::cout << "Distance between Chebyshev distance HRectBound and "
|
||||
<< "[1.5, 1.5, 4.0]: [" << r3.Lo() << ", " << r3.Hi() << "]." << std::endl;
|
||||
```
|
||||
|
||||
### `HollowBallBound`
|
||||
|
||||
The `HollowBallBound` class represents a bounding shape that is an
|
||||
arbitrary-dimensional ball bound with another smaller ball subtracted from its
|
||||
inside. A `HollowBallBound` consists of a center point, an outer radius, and a
|
||||
secondary center point and inner radius. An example `HollowBallBound` is shown
|
||||
below in two dimensions; shaded area represents area held within the bound.
|
||||
|
||||
<center>
|
||||
<img src="../../../img/hollowballbound.png" width="50%" alt="hollow ball bound">
|
||||
</center>
|
||||
|
||||
`HollowBallBound` is used directly by the [`VPTree`](vptree.md) class.
|
||||
|
||||
#### Constructors
|
||||
|
||||
`HollowBallBound` allows configurable behavior via its two template parameters:
|
||||
|
||||
```
|
||||
HollowBallBound<DistanceType, ElemType>
|
||||
```
|
||||
|
||||
Different constructor forms can be used to specify different template parameters
|
||||
(and thus different bound behavior).
|
||||
|
||||
* `b = HollowBallBound(dimensionality)`
|
||||
- Construct a `HollowBallBound` with the given `dimensionality`.
|
||||
- The bound will be empty with invalid centers and radii (e.g., `b` will not
|
||||
contain any points at all).
|
||||
- The bound will use the [Euclidean distance](../distances.md#lmetric) for
|
||||
distance computation, and will expect data to have elements with type
|
||||
`double`.
|
||||
|
||||
* `b = HollowBallBound<DistanceType, ElemType>(dimensionality)`
|
||||
- Construct a `HollowBallBound` with the given `dimensionality` that will use
|
||||
the given `DistanceType` class to compute distances, and expect data to
|
||||
have elements with type `ElemType`.
|
||||
- `ElemType` should generally be `double` or `float`.
|
||||
|
||||
<!-- TODO: update links here after merge of BallBound PR -->
|
||||
|
||||
***Note***: these constructors provide an empty bound; be sure to
|
||||
[grow](#growing-and-shrinking-the-bound-1) the bound or
|
||||
[directly modify the bound](#accessing-and-modifying-properties-of-the-bound-1)
|
||||
before using it!
|
||||
|
||||
---
|
||||
|
||||
* `b = HollowBallBound(innerRadius, outerRadius, center)`
|
||||
- Construct a `HollowBallBound` with the given `innerRadius` for the inner
|
||||
ball, `outerRadius` for the outer ball, and `center`.
|
||||
- Both the inner and outer ball are centered at `center`.
|
||||
- `innerRadius` and `outerRadius` should have type `double`.
|
||||
- `center` should have type `arma::vec`.
|
||||
- The bound will use the [Euclidean distance](../distances.md#lmetric) for
|
||||
distance computation, and will expect data to have elements with type
|
||||
`double`.
|
||||
|
||||
* `b = HollowBallBound<DistanceType, ElemType>(innerRadius, outerRadius, center)`
|
||||
- Construct a `HollowBallBound` with the given `innerRadius` for the inner
|
||||
ball, `outerRadius` for the outer ball, and `center`.
|
||||
- Both the inner and outer ball are centered at `center`.
|
||||
- `innerRadius` and `outerRadius` should have type `ElemType`.
|
||||
- `center` should be a vector with element type `ElemType` (e.g.
|
||||
`arma::Col<ElemType>`).
|
||||
- The bound will use the given `DistanceType` class to compute distances, and
|
||||
expect data to have elements with type `ElemType`.
|
||||
|
||||
#### Accessing and modifying properties of the bound
|
||||
|
||||
The individual bounds associated with each dimension of a `HollowBallBound` can
|
||||
be accessed and modified.
|
||||
|
||||
* `b.Dim()` will return a `size_t` indicating the dimensionality of the bound.
|
||||
|
||||
* `b.Center()` returns an `arma::vec&` containing the center of the outer ball.
|
||||
Its elements can be directly modified.
|
||||
|
||||
* `b.HollowCenter()` returns an `arma::vec&` containing the center of the inner
|
||||
ball. Its elements can be directly modified.
|
||||
|
||||
* `b.OuterRadius()` will return a `double` that is the radius of the outer
|
||||
ball.
|
||||
- `b.OuterRadius() = r` will set the radius of the outer ball to `r`.
|
||||
|
||||
* `b.InnerRadius()` will return a `double` that is the radius of the inner
|
||||
ball.
|
||||
- `b.InnerRadius() = r` will set the radius of the inner ball to `r`.
|
||||
|
||||
* `b[dim]` will return a [`Range`](../math.md#range) object representing the
|
||||
extents of the bound in dimension `dim`.
|
||||
- The range is defined as
|
||||
`[b.Center()[dim] - b.OuterRadius(), b.Center()[dim] + b.OuterRadius()]`.
|
||||
- ***Note:*** this returns the maximum extents of the bound and does not
|
||||
consider the inner (hollow) ball.
|
||||
|
||||
* `b.Diameter()` returns the diameter of the ball. This is always equal to
|
||||
`2 * b.OuterRadius()`.
|
||||
|
||||
* `b.MinWidth()` returns the minimum width of the bound in any dimension as a
|
||||
`double`. This is always equal to `b.Diameter()`.
|
||||
|
||||
* `b.Distance()` returns either a
|
||||
[`EuclideanDistance`](../distances.md#lmetric) distance metric object, or a
|
||||
`DistanceType` if a custom `DistanceType` has been specified in the
|
||||
constructor.
|
||||
|
||||
* `b.Center(center)` will store the center of the `HollowBallBound` in the
|
||||
vector `center`. `center` should be of type `arma::vec`.
|
||||
|
||||
* `b.MinWidth()` returns the minimum width of the bound in any dimension as a
|
||||
`double`. This value is cached and no computation is performed when calling
|
||||
`b.MinWidth()`. If the bound is empty, `0` is returned.
|
||||
|
||||
* `b.Distance()` returns either a
|
||||
[`EuclideanDistance`](../distances.md#lmetric) distance metric object, or a
|
||||
`DistanceType` if a custom `DistanceType` has been specified in the
|
||||
constructor.
|
||||
|
||||
* `b.Center(center)` will compute the center of the `HRectBound` (e.g. the
|
||||
vector with elements equal to the midpoint of `b` in each dimension) and
|
||||
store it in the vector `center`. `center` should be of type `arma::vec`.
|
||||
|
||||
* `b.Volume()` computes the volume of the hyperrectangle specified by `b`. The
|
||||
volume is returned as a `double`.
|
||||
|
||||
* `b.Diameter()` computes the longest diagonal of the hyperrectangle specified
|
||||
by `b`.
|
||||
|
||||
* A `HollowBallBound` can be serialized with
|
||||
[`data::Save()` and `data::Load()`](../../load_save.md#mlpack-objects).
|
||||
|
||||
***Note:*** if a custom `ElemType` was specified in the constructor, then:
|
||||
|
||||
* `b[dim]` will return a `RangeType<ElemType>`;
|
||||
* `b.OuterRadius()`, `b.InnerRadius()`, `b.MinWidth()`, and `b.Diameter()` will
|
||||
return `ElemType`;
|
||||
* `b.Center()` and `b.HollowCenter()` will return `arma::Col<ElemType>&`; and
|
||||
* `b.Center(center)` expects `center` to be of type `arma::Col<ElemType>`.
|
||||
|
||||
#### Growing the bound
|
||||
|
||||
The `HollowBallBound` uses the logical `|=` to grow the bound to include points.
|
||||
|
||||
* `b |= data` expands `b` so the outer ball includes all of the data points in
|
||||
`data`, shrinking the inner ball as necessary. `data` should be a
|
||||
[column-major `arma::mat`](../../matrices.md#representing-data-in-mlpack).
|
||||
The expansion operation is minimal, so `b` is not expanded any more than
|
||||
necessary.
|
||||
- The bound is grown using [Jack Ritter's bounding sphere
|
||||
algorithm](https://en.wikipedia.org/wiki/Bounding_sphere#Ritter's_bounding_sphere),
|
||||
which may move the center of the bound as it iteratively adds points to the
|
||||
bound. (The hollow center is not moved.)
|
||||
- If the bound is empty, the centers are initialized to the first point of
|
||||
`data`.
|
||||
- If the bound is not empty, then `data` is expected to have dimensionality
|
||||
that matches `b.Dim()`.
|
||||
|
||||
***Notes:***
|
||||
|
||||
- The growth operation does not grow the inner (hollow) ball. Properties
|
||||
related to the inner ball should be set manually with `b.HollowCenter()` and
|
||||
`b.InnerRadius()`.
|
||||
|
||||
- If a custom `ElemType` was specified, then any `data` argument should be a
|
||||
matrix with that `ElemType` (e.g. `arma::Mat<ElemType>`).
|
||||
|
||||
#### Bounding distances to other objects
|
||||
|
||||
Once a `HollowBallBound` has been successfully created and set to the desired
|
||||
bounding balls, there are a number of functions that can bound the
|
||||
distance between a `HollowBallBound` and other objects.
|
||||
|
||||
* `b.Contains(point)`
|
||||
* `b.Contains(bound)`
|
||||
- Return a `bool` indicating whether or not `b` contains the given `point`
|
||||
(an `arma::vec`) or another `bound` (an `HRectBound`).
|
||||
- When passing another `bound`, `true` will be returned if `bound` even
|
||||
partially overlaps with `b`.
|
||||
|
||||
* `b.MinDistance(point)`
|
||||
* `b.MinDistance(bound)`
|
||||
- Return a `double` whose value is the minimum possible distance between `b`
|
||||
and either a `point` (an `arma::vec`) or another `bound` (a
|
||||
`HollowBallBound`).
|
||||
- The minimum distance between `b` and another point or bound is the length
|
||||
of the shortest possible line that can connect the other point or bound to
|
||||
`b`.
|
||||
- If `point` or `bound` are contained in `b`, then the returned distance is
|
||||
0.
|
||||
|
||||
* `b.MaxDistance(point)`
|
||||
* `b.MaxDistance(bound)`
|
||||
- Return a `double` whose value is the maximum possible distance between `b`
|
||||
and either a `point` (an `arma::vec`) or another `bound` (a
|
||||
`HollowBallBound`).
|
||||
- The maximum distance between `b` and a given `point` is the furthest
|
||||
possible distance between `point` and any possible point falling within the
|
||||
bounding hyperrectangle of `b`.
|
||||
- The maximum distance between `b` and another `bound` is the furthest
|
||||
possible distance between any possible point falling within the bounding
|
||||
hyperrectangle of `b`, and any possible point falling within the bounding
|
||||
hyperrectangle of `bound`.
|
||||
- Note that this definition means that even if `b.Contains(point)` or
|
||||
`b.Contains(bound)` is `true`, the maximum distance may be greater than
|
||||
`0`.
|
||||
|
||||
* `b.RangeDistance(point)`
|
||||
* `b.RangeDistance(bound)`
|
||||
- Compute the minimum and maximum distance between `b` and `point` or
|
||||
`bound`, returning the result as a [`Range`](../math.md#range) object.
|
||||
- This is more efficient than calling `b.MinDistance()` and
|
||||
`b.MaxDistance()`.
|
||||
|
||||
***Note:*** if a custom `DistanceType` and `ElemType` were specified in the
|
||||
constructor, then all distances will be computed with respect to the specified
|
||||
`DistanceType` and all return values will either be `ElemType` or
|
||||
[`RangeType<ElemType>`](../math.md#range) (except for `Contains()`, which will
|
||||
still return a `bool`).
|
||||
|
||||
#### Example usage
|
||||
|
||||
```c++
|
||||
// Create a hollow ball bound in 3 dimensions whose outer ball is the unit ball
|
||||
// and whose inner ball is the ball with radius 0.5 centered at the origin.
|
||||
// The bounding range for all three dimensions is [0.0, 1.0].
|
||||
mlpack::HollowBallBound b(0.5, 1.0, arma::vec(3));
|
||||
|
||||
std::cout << "Hollow unit ball bound created manually:" << std::endl;
|
||||
std::cout << " - Center: " << b.Center().t();
|
||||
std::cout << " - Outer radius: " << b.OuterRadius() << "." << std::endl;
|
||||
std::cout << " - Hollow center: " << b.HollowCenter.();
|
||||
std::cout << " - Inner radius: " << b.InnerRadius() << "." << std::endl;
|
||||
for (size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
std::cout << " - Dimension " << i << " extents: [" << b[i].Lo() << ", "
|
||||
<< b[i].Hi() << "]." << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// Create a small dataset of 5 points.
|
||||
arma::mat dataset(3, 5);
|
||||
dataset.col(0) = arma::vec("2.0 2.0 2.0");
|
||||
dataset.col(1) = arma::vec("2.5 2.5 2.5");
|
||||
dataset.col(2) = arma::vec("3.0 2.0 3.0");
|
||||
dataset.col(3) = arma::vec("2.0 3.0 2.0");
|
||||
dataset.col(4) = arma::vec("3.0 3.0 3.0");
|
||||
|
||||
// If we simply build a HollowBallBound to enclose those points, the hollow part
|
||||
// of the ball is unmodified and remains empty.
|
||||
mlpack::HollowBallBound b2(3);
|
||||
b2 |= dataset;
|
||||
std::cout << "Hollow ball bound on points with only `operator|=()`:"
|
||||
<< std::endl;
|
||||
std::cout << " - Center: " << b2.Center().t();
|
||||
std::cout << " - Outer radius: " << b2.OuterRadius() << "." << std::endl;
|
||||
std::cout << " - Hollow center: " << b2.HollowCenter().t();
|
||||
std::cout << " - Inner radius: " << b2.InnerRadius() << "." << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
// On the other hand, if we initialize a HollowBallBound to a non-empty bound,
|
||||
// then `operator|=()` will shrink the hollow ball as necessary.
|
||||
//
|
||||
// We initialize this ball bound to a "slice" with radii [2.6, 2.7].
|
||||
mlpack::HollowBallBound b3(2.6, 2.7, arma::vec(3));
|
||||
b3 |= dataset;
|
||||
std::cout << "Hollow ball bound on points with pre-initialization and "
|
||||
<< "`operator|=()`:" << std::endl;
|
||||
std::cout << " - Center: " << b3.Center().t();
|
||||
std::cout << " - Outer radius: " << b3.OuterRadius() << "." << std::endl;
|
||||
std::cout << " - Hollow center: " << b3.HollowCenter().t();
|
||||
std::cout << " - Inner radius: " << b3.InnerRadius() << "." << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
// Manually create a hollow ball bound whose hollow center is different than the
|
||||
// outer ball's center.
|
||||
mlpack::HollowBallBound b4(3);
|
||||
b4.OuterRadius() = 3.0;
|
||||
b4.InnerRadius() = 1.5;
|
||||
b4.Center() = arma::vec(3);
|
||||
b4.HollowCenter() = arma::vec("1.0 1.0 1.0");
|
||||
|
||||
// Compute the minimum distance between a point inside the hollow unit ball's
|
||||
// outer ball.
|
||||
const double d1 = b.MinDistance(arma::vec("0.75 0.75 0.75"));
|
||||
std::cout << "Minimum distance between hollow unit ball bound and [0.75, 0.75, "
|
||||
<< "0.75]: " << d1 << "." << std::endl;
|
||||
|
||||
// Compute the minimum distance between a point inside the hollow unit ball's
|
||||
// inner ball (so the point is not contained in the bound---it is within the
|
||||
// hollow section).
|
||||
const double d2 = b.MinDistance(arma::vec("0.25 0.25 0.25"));
|
||||
std::cout << "Minimum distance between hollow unit ball bound and [0.25, 0.25, "
|
||||
<< "0.25]: " << d2 << "." << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
// Use Contains(). In this case, the 'else' will be taken.
|
||||
if (b.Contains(arma::vec("1.5 1.5 1.5")))
|
||||
{
|
||||
std::cout << "Hollow unit ball bound contains [1.5, 1.5, 1.5]." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Hollow unit ball bound does not contain [1.5, 1.5, 1.5]."
|
||||
<< std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// Compute the maximum distance between a point inside the unit ball and the
|
||||
// unit hollow ball bound.
|
||||
const double d2 = b4.MaxDistance(arma::vec("0.1 0.1 0.1"));
|
||||
std::cout << "Maximum distance between hollow unit ball bound and [0.1, 0.1, "
|
||||
<< "0.1]: " << d2 << "." << std::endl;
|
||||
|
||||
// Compute the minimum and maximum distances between the hollow unit ball bound
|
||||
// and the bound built on data points.
|
||||
const mlpack::Range r = b.RangeDistance(b3);
|
||||
std::cout << "Distances between hollow unit ball bound and second hollow "
|
||||
<< "dataset bound: [" << r.Lo() << ", " << r.Hi() << "]." << std::endl;
|
||||
|
||||
// Create a bound using the Manhattan (L1) distance and compute the minimum and
|
||||
// maximum distance to a point.
|
||||
mlpack::HollowBallBound<mlpack::ManhattanDistance> mb(2.0, 5.0, arma::vec(3));
|
||||
const mlpack::Range r2 = mb.RangeDistance(arma::vec("1.5 1.5 4.0"));
|
||||
std::cout << "Distance between Manhattan distance HollowBallBound and "
|
||||
<< "[1.5, 1.5, 4.0]: [" << r2.Lo() << ", " << r2.Hi() << "]." << std::endl;
|
||||
|
||||
// Create a bound using the Chebyshev (L-inf) distance, using random 32-bit
|
||||
// floating point elements, and compute the minimum and maximum distance to a
|
||||
// point.
|
||||
arma::fmat floatData(3, 25, arma::fill::randu);
|
||||
mlpack::HollowBallBound<mlpack::ChebyshevDistance, float> cb;
|
||||
cb |= floatData;
|
||||
// Note the use of arma::fvec to represent a point, since ElemType is float.
|
||||
const mlpack::RangeType<float> r3 = cb.RangeDistance(arma::fvec("1.5 1.5 4.0"));
|
||||
std::cout << "Distance between Chebyshev distance HollowBallBound and "
|
||||
<< "[1.5, 1.5, 4.0]: [" << r3.Lo() << ", " << r3.Hi() << "]." << std::endl;
|
||||
```
|
||||
|
||||
### Custom `BoundType`s
|
||||
|
||||
The `BinarySpaceTree` class allows an arbitrary `BoundType` template parameter
|
||||
|
||||
@@ -212,16 +212,6 @@ class HollowBallBound
|
||||
template<typename MatType>
|
||||
const HollowBallBound& operator|=(const MatType& data);
|
||||
|
||||
/**
|
||||
* Expand the bound to include the given bound. The centroid will not be
|
||||
* moved.
|
||||
*
|
||||
* @tparam MatType Type of matrix; could be arma::mat, arma::spmat, or a
|
||||
* vector.
|
||||
* @tparam data Data points to add.
|
||||
*/
|
||||
const HollowBallBound& operator|=(const HollowBallBound& other);
|
||||
|
||||
/**
|
||||
* Returns the diameter of the ballbound.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user