Merge remote-tracking branch 'origin/master' into reduce-pca-test-size

This commit is contained in:
Ryan Curtin
2024-11-06 09:36:28 -05:00
348 changed files with 2546 additions and 1206 deletions
+2 -2
View File
@@ -5,10 +5,10 @@
# available on your system in order to find the BLAS library. If OpenBLAS will
# be compiled, the OPENBLAS_TARGET variable must be set. This can be done
# by, e.g., setting BOARD_NAME (which will set OPENBLAS_TARGET in
# `board/flags-config.cmake`).
# `flags-config.cmake`).
if (CMAKE_CROSSCOMPILING)
include(board/flags-config.cmake)
include(CMake/crosscompile-arch-config.cmake)
if (NOT CMAKE_SYSROOT AND (NOT TOOLCHAIN_PREFIX))
message(FATAL_ERROR "Neither CMAKE_SYSROOT nor TOOLCHAIN_PREFIX are set; please set both of them and try again.")
elseif(NOT CMAKE_SYSROOT)
@@ -56,7 +56,7 @@ elseif(BOARD MATCHES "RPI3" OR BOARD MATCHES "CORTEXA53")
set(OPENBLAS_TARGET "CORTEXA53")
set(OPENBLAS_BINARY "64")
elseif(BOARD MATCHES "RPI4" OR BOARD MATCHES "CORTEXA72")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=cortex-a72 -ftree-vectorize")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8.2-a+crypto+fp16+rcpc+dotprod -fasynchronous-unwind-tables")
set(OPENBLAS_TARGET "CORTEXA72")
set(OPENBLAS_BINARY "64")
elseif(BOARD MATCHES "JETSONAGX" OR BOARD MATCHES "CORTEXA76")
@@ -1,14 +1,14 @@
## This file handles cross-compilation configurations for aarch64,
## known as arm64. The objective of this file is to find and assign
## cross-compiler and the entire toolchain.
## This file handles cross-compilation configurations for any architecture.
## The objective of this file is to find and assign cross-compiler and the
## entire toolchain.
##
## This configuration works best with the buildroot toolchain. When using this
## file, be sure to set the TOOLCHAIN_PREFIX and CMAKE_SYSROOT variables,
## preferably via the CMake configuration command (e.g. `-DCMAKE_SYSROOT=<...>`).
##
## Currently, we recommend using buildroot toolchain for
## cross-compilation. Here is the link to download the toolchains:
## https://toolchains.bootlin.com/
## You can use any toochain to produce the cross compiled binaries. However,
## we recommend using buildroot toolchain for cross-compilation. Here is the
## link to download the toolchains: https://toolchains.bootlin.com/
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSROOT)
+1 -1
View File
@@ -28,7 +28,7 @@ types cannot be used.
easily defined as below:
```c++
typedef typename MatType::elem_type ElemType;
using ElemType = typename MatType::elem_type;
```
and otherwise a template parameter with the name `ElemType` can be used. It is
+3 -1
View File
@@ -202,7 +202,7 @@ class ExampleTree
public:
// This is the element type held by the matrix.
// It will generally either be `double`, or `float`.
typedef typename MatType::elem_type ElemType;
using ElemType = typename MatType::elem_type;
//////////////////////
//// Constructors ////
@@ -1270,6 +1270,8 @@ TreeType policy API:
- [`MeanSplitKDTree`](../user/core/trees/mean_split_kdtree.md)
- [`BallTree`](../user/core/trees/ball_tree.md)
- [`MeanSplitBallTree`](../user/core/trees/mean_split_ball_tree.md)
- [`RPTree`](../user/core/trees/rp_tree.md)
- [`MaxRPTree`](../user/core/trees/max_rp_tree.md)
- [`UBTree`](../user/core/trees/ub_tree.md)
- `RTree`
- `RStarTree`
+3 -3
View File
@@ -113,9 +113,9 @@ cross-compilation toolchain.
cmake \
-DBUILD_TESTS=ON \
-DBOARD_NAME="RPI2" \
-DCMAKE_CROSSCOMPILE=ON \
-DCMAKE_TOOLCHAIN_FILE=../board/crosscompile-toolchain.cmake \
-DTOOLCHAIN_PREFIX=/path/to/bootlin/toolchain/armv7-eabihf--glibc--stable-2023.08-1/bin/arm-buildroot-linux-gnueabihf- \
-DCMAKE_CROSSCOMPILING=ON \
-DCMAKE_TOOLCHAIN_FILE=../CMake/crosscompile-toolchain.cmake \
-DTOOLCHAIN_PREFIX=/path/to/bootlin/toolchain/armv7-eabihf--glibc--stable-2024.02-1/bin/arm-buildroot-linux-gnueabihf- \
-DCMAKE_SYSROOT=/path/to/bootlin/toolchain/armv7-eabihf--glibc--stable-2024.02-1/arm-buildroot-linux-gnueabihf/sysroot \
../
```
+9 -4
View File
@@ -102,13 +102,18 @@ when the sidebar is built for each page.
</a>
</li>
<li>
<a href="LINKROOTuser/core/trees/ub_tree.html">
<code>UBTree</code>
<a href="LINKROOTuser/core/trees/rp_tree.html">
<code>RPTree</code>
</a>
</li>
<li>
<a href="LINKROOTuser/core/trees/binary_space_tree.html">
<code>BinarySpaceTree</code>
<a href="LINKROOTuser/core/trees/max_rp_tree.html">
<code>MaxRPTree</code>
</a>
</li>
<li>
<a href="LINKROOTuser/core/trees/ub_tree.html">
<code>UBTree</code>
</a>
</li>
<li>
+4 -3
View File
@@ -386,8 +386,9 @@ IPMetric<PolynomialKernel> metric(pk);
// the custom base of 1.5 (default is 1.3). We have to be sure to use the right
// type here -- FastMKS needs the FastMKSStat object as the tree's
// StatisticType.
typedef CoverTree<IPMetric<PolynomialKernel>, FirstPointIsRoot, FastMKSStat>
TreeType; // Convenience typedef.
// Convenience typedef.
using TreeType =
CoverTree<IPMetric<PolynomialKernel>, FirstPointIsRoot, FastMKSStat>;
TreeType* tree = new TreeType(data, metric, 1.5);
// Now initialize FastMKS with that statistic. We don't need to specify the
@@ -455,7 +456,7 @@ extern arma::mat data;
// The custom tree type. We'll assume that the first template parameter is the
// statistic type.
typedef CustomTree<FastMKSStat> TreeType;
using TreeType = CustomTree<FastMKSStat>;
// The FastMKS constructor will create the tree.
FastMKS<LinearKernel, arma::mat, TreeType> f(data);
+1 -1
View File
@@ -213,7 +213,7 @@ The `KNN` class is, specifically, a typedef of the more extensible
distance.
```c++
typedef NeighborSearch<NearestNeighborSort, EuclideanDistance> KNN;
using KNN = NeighborSearch<NearestNeighborSort, EuclideanDistance>;
```
Using the `KNN` class is particularly simple; first, the object must be
+4 -1
View File
@@ -447,7 +447,10 @@ std::cout << "Trigamma(1.0): " << t2 << "." << std::endl;
## `RandVector()`
* `RandVector(v)` generates a random vector on the unit sphere (i.e. with an
L2-norm of 1) and stores it in `v` (an `arma::vec`).
L2-norm of 1) and stores it in the vector `v`.
* `v` should be a dense floating-point Armadillo vector (e.g. `arma::vec` or
`arma::fvec`).
* The [Box-Muller transform](https://en.wikipedia.org/wiki/Box-Muller_transform)
is used to generate the vector.
+4 -2
View File
@@ -7,9 +7,11 @@ different trees. The following tree types are available in mlpack:
* [`KDTree`](trees/kdtree.md)
* [`MeanSplitKDTree`](trees/mean_split_kdtree.md)
* [`MeanSplitBallTree`](trees/mean_split_ball_tree.md)
* [`BinarySpaceTree`](trees/binary_space_tree.md)
* [`BallTree`](trees/ball_tree.md)
* [`MeanSplitBallTree`](trees/mean_split_ball_tree.md)
* [`RPTree`](trees/rp_tree.md)
* [`MaxRPTree`](trees/max_rp_tree.md)
* [`BinarySpaceTree`](trees/binary_space_tree.md)
* [`UBTree`](trees/ub_tree.md)
*Note:* this documentation is a work in progress. Not all trees are documented
+4 -4
View File
@@ -546,16 +546,16 @@ std::cout << "Saved tree with " << tree.Dataset().n_cols << " points to "
---
Load a 32-bit floating point `BallTree` from disk, then traverse it manually and
find the number of leaf nodes with fewer than 10 children.
find the number of leaf nodes with fewer than 10 points.
```c++
// This assumes the tree has already been saved to 'tree.bin' (as in the example
// above).
// This convenient typedef saves us a long type name!
typedef mlpack::BallTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat> TreeType;
using TreeType = mlpack::BallTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat>;
TreeType tree;
mlpack::data::Load("tree.bin", "tree", tree);
+78 -12
View File
@@ -1968,6 +1968,11 @@ to write a fully custom split:
dimension with maximum width
* [`VantagePointSplit`](#vantagepointsplit): split by selecting a 'vantage
point' and then split points into 'near' and 'far' sets
* [`RPTreeMeanSplit`](#rptreemeansplit): projects points onto a random vector,
splitting on the median value of the projections, or in some cases on the
distance from the mean value
* [`RPTreeMaxSplit`](#rptreemaxsplit): projects points onto a random vector,
splitting on a random offset of the median of projected points
* [`UBTreeSplit`](#ubtreesplit): splits a [`CellBound`](#cellbound) into two
balanced children
* [Custom `SplitType`s](#custom-splittypes): implement a fully custom
@@ -2005,7 +2010,7 @@ The splitting strategy for the `MeanSplit` class is, given a set of points:
* Compute the mean value `m` of the points in dimension `d`.
* Split in dimension `d`.
* Points less than `m` will go to the left child.
* Points greater than `m` will go to the right child.
* Points greater than or equal to `m` will go to the right child.
In practice, the `MeanSplit` splitting strategy often results in a tree with
fewer leaf nodes than `MidpointSplit`, because each split is more likely to be
@@ -2063,6 +2068,67 @@ Then, `MyVantagePointSplit` can be used directly with `BinarySpaceTree` as a
For implementation details, see
[the source code](/src/mlpack/core/tree/binary_space_tree/vantage_point_split_impl.hpp).
### `RPTreeMeanSplit`
The `RPTreeMeanSplit` class is a splitting strategy that can be used by
[`BinarySpaceTree`](#binaryspacetree). It is the splitting strategy used by the
[`RPTree`](rp_tree.md) class, and uses a random projection to split points. The
general idea is described in the paper by
[Dasgupta and Freund](https://www.cs.cornell.edu/~abrahao/tdg/papers/p537.pdf),
as the `RPTree-Mean` version of the `ChooseRule()` function.
The splitting strategy for the `RPTreeMeanSplit` class is, given a set of
points:
* Draw a random vector `z`.
* Sample up to 100 points and compute `d`, the average pairwise distance
between the points.
* If `10 * d` is less than or equal to the squared diameter of the bounding box
of the points:
- Project all points onto the vector `z`, and compute the median `v` of the
projected values.
- Points with projected value less than `v` will go to the left child.
- Points with projected value greater than or equal to `v` will go to the
right child.
* Otherwise:
- Compute the mean `s` of all points.
- Points with distance from `s` less than the median distance from `s`
will go to the left child.
- Points with distance from `s` greater than or equal to the median distance
from `s` will go to the right child.
The implementation strategy differs slightly from the `RPTree-Mean` version in
the paper: instead of computing the true average pairwise distance between all
points, a sample of 100 points is used.
For implementation details, see
[the source code](/src/mlpack/core/tree/binary_space_tree/rp_tree_mean_split_impl.hpp).
### `RPTreeMaxSplit`
The `RPTreeMaxSplit` class is a splitting strategy that can be used by
[`BinarySpaceTree`](#binaryspacetree). It is the splitting strategy used by the
[`MaxRPTree`](max_rp_tree.md) class, and uses a random projection to split
points. The general idea is described in the paper by
[Dasgupta and Freund](https://www.cs.cornell.edu/~abrahao/tdg/papers/p537.pdf),
as the `RPTree-Max` version of the `ChooseRule()` function.
The splitting strategy for the `RPTreeMaxSplit` class is, given a set of points,
* Draw a random vector `z`.
* Sample up to 100 points (call this sample `S`).
* Compute `v`, the median value of projections of points in `S` onto `z`.
* Points with projection onto `z` less than `v` will go to the left child.
* Points with projection onto `z` greater than or equal to `v` will go to the
right child.
The implementation strategy differs slightly from the `RPTree-Max` version in
the paper: instead of computing the median on all points, a sample of 100 points
is used.
For implementation details, see
[the source code](/src/mlpack/core/tree/binary_space_tree/rp_tree_max_split_impl.hpp).
### `UBTreeSplit`
The `UBTreeSplit` class is a splitting strategy that can be used by
@@ -2210,11 +2276,11 @@ arma::mat dataset;
mlpack::data::Load("corel-histogram.csv", dataset, true);
// Convenience typedef for the tree type.
typedef mlpack::BinarySpaceTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::mat,
mlpack::HRectBound,
mlpack::MidpointSplit> TreeType;
using TreeType = mlpack::BinarySpaceTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::mat,
mlpack::HRectBound,
mlpack::MidpointSplit>;
// Build trees on the first half and the second half of points.
TreeType tree1(dataset.cols(0, dataset.n_cols / 2));
@@ -2300,18 +2366,18 @@ std::cout << "Saved tree with " << tree.Dataset().n_cols << " points to "
---
Load a 32-bit floating point `BinarySpaceTree` from disk, then traverse it
manually and find the number of leaf nodes with less than 10 children.
manually and find the number of leaf nodes with less than 10 points.
```c++
// This assumes the tree has already been saved to 'tree.bin' (as in the example
// above).
// This convenient typedef saves us a long type name!
typedef mlpack::BinarySpaceTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat,
mlpack::HRectBound,
mlpack::MidpointSplit> TreeType;
using TreeType = mlpack::BinarySpaceTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat,
mlpack::HRectBound,
mlpack::MidpointSplit>;
TreeType tree;
mlpack::data::Load("tree.bin", "tree", tree);
+4 -4
View File
@@ -540,16 +540,16 @@ std::cout << "Saved tree with " << tree.Dataset().n_cols << " points to "
---
Load a 32-bit floating point `KDTree` from disk, then traverse it manually and
find the number of leaf nodes with fewer than 10 children.
find the number of leaf nodes with fewer than 10 points.
```c++
// This assumes the tree has already been saved to 'tree.bin' (as in the example
// above).
// This convenient typedef saves us a long type name!
typedef mlpack::KDTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat> TreeType;
using TreeType = mlpack::KDTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat>;
TreeType tree;
mlpack::data::Load("tree.bin", "tree", tree);
+635
View File
@@ -0,0 +1,635 @@
# `MaxRPTree`
<!-- TODO: link to knn.md once it's done -->
The `MaxRPTree` class represents a random projection tree, a variant of the
[`k`-d tree](kdtree.md) based on random projections. The random projection tree
is a well-known data structure for efficient distance operations (such as
nearest neighbor search) in low dimensions---typically less than 100.
An `MaxRPTree` (or the similar [`RPTree`](rp_tree.md)) may be preferred over
a [`KDTree`](kdtree.md) or other tree structures as it is theoretically known to
adapt to the intrinsic dimension of the data. This is similar to the cover
tree, but the implementation is far simpler and as a result, more efficient.
<!-- TODO: add cover tree link above -->
mlpack's `MaxRPTree` implementation supports three template parameters for
configurable behavior, and implements all the functionality required by the
[TreeType API](../../../developer/trees.md#the-treetype-api), plus some
additional functionality specific to random projection trees.
* [Template parameters](#template-parameters)
* [Constructors](#constructors)
* [Basic tree properties](#basic-tree-properties)
* [Bounding distances with the tree](#bounding-distances-with-the-tree)
* [Tree traversals](#tree-traversals)
* [Example usage](#example-usage)
## See also
<!-- TODO: add links to all distance-based algorithms and other trees? -->
* [`RPTree`](rp_tree.md)
* [kd-tree on Wikipedia](https://en.wikipedia.org/wiki/Kd-tree)
* [Random projection on Wikipedia](https://en.wikipedia.org/wiki/Random_projection)
* [`BinarySpaceTree`](binary_space_tree.md)
* [Binary space partitioning on Wikipedia](https://dl.acm.org/doi/pdf/10.1145/361002.361007)
* [Random Projection Trees and Low Dimensional Manifolds (pdf)](https://www.cs.cornell.edu/~abrahao/tdg/papers/p537.pdf)
* [Tree-Independent Dual-Tree Algorithms (pdf)](https://www.ratml.org/pub/pdf/2013tree.pdf)
## Template parameters
In accordance with the [TreeType
API](../../../developer/trees.md#template-parameters-required-by-the-treetype-policy)
(see also [this more detailed section](../../../developer/trees.md#template-parameters)),
the `MaxRPTree` class takes three template parameters:
```
MaxRPTree<DistanceType, StatisticType, MatType>
```
* `DistanceType`: the [distance metric](../distances.md) to use for distance
computations. For the `MaxRPTree`, this must be an
[`LMetric`](../distances.md#lmetric). By default, this is
[`EuclideanDistance`](../distances.md#lmetric).
* [`StatisticType`](binary_space_tree.md#statistictype): this holds auxiliary
information in each tree node. By default,
[`EmptyStatistic`](binary_space_tree.md#emptystatistic) is used, which holds
no information.
* `MatType`: the type of matrix used to represent points. Must be a type
matching the [Armadillo API](../../matrices.md). By default, `arma::mat` is
used, but other types such as `arma::fmat` or similar will work just fine.
The `MaxRPTree` class itself is a convenience typedef of the generic
[`BinarySpaceTree`](binary_space_tree.md) class, using the
[`HRectBound`](binary_space_tree.md#hrectbound) class as the bounding structure,
and using the [`RPTreeMaxSplit`](binary_space_tree.md#rptreemaxsplit)
splitting strategy for construction, which splits a node along a random
projection, or, in some cases, based on the distance from the vector-valued mean
of points in the node.
If no template parameters are explicitly specified, then defaults are used:
```
MaxRPTree<> = MaxRPTree<EuclideanDistance, EmptyStatistic, arma::mat>
```
## Constructors
`MaxRPTree`s are efficiently constructed by permuting points in a dataset in a
quicksort-like algorithm. However, this means that the ordering of points in
the tree's dataset (accessed with `node.Dataset()`) after construction may be
different.
---
* `node = MaxRPTree(data, maxLeafSize=20)`
* `node = MaxRPTree(data, oldFromNew, maxLeafSize=20)`
* `node = MaxRPTree(data, oldFromNew, newFromOld, maxLeafSize=20)`
- Construct a `MaxRPTree` on the given `data`, using `maxLeafSize` as the
maximum number of points held in a leaf.
- By default, `data` is copied. Avoid a copy by using `std::move()` (e.g.
`std::move(data)`); when doing this, `data` will be set to an empty matrix.
- Optionally, construct mappings from old points to new points. `oldFromNew`
and `newFromOld` will have length `data.n_cols`, and:
* `oldFromNew[i]` indicates that point `i` in the tree's dataset was
originally point `oldFromNew[i]` in `data`; that is,
`node.Dataset().col(i)` is the point `data.col(oldFromNew[i])`.
* `newFromOld[i]` indicates that point `i` in `data` is now point
`newFromOld[i]` in the tree's dataset; that is,
`node.Dataset().col(newFromOld[i])` is the point `data.col(i)`.
---
* `node = MaxRPTree<DistanceType, StatisticType, MatType>(data, maxLeafSize=20)`
* `node = MaxRPTree<DistanceType, StatisticType, MatType>(data, oldFromNew, maxLeafSize=20)`
* `node = MaxRPTree<DistanceType, StatisticType, MatType>(data, oldFromNew, newFromOld, maxLeafSize=20)`
- Construct a `MaxRPTree` on the given `data`, using custom template
parameters to control the behavior of the tree, using `maxLeafSize` as the
maximum number of points held in a leaf.
- By default, `data` is copied. Avoid a copy by using `std::move()` (e.g.
`std::move(data)`); when doing this, `data` will be set to an empty matrix.
- Optionally, construct mappings from old points to new points. `oldFromNew`
and `newFromOld` will have length `data.n_cols`, and:
* `oldFromNew[i]` indicates that point `i` in the tree's dataset was
originally point `oldFromNew[i]` in `data`; that is,
`node.Dataset().col(i)` is the point `data.col(oldFromNew[i])`.
* `newFromOld[i]` indicates that point `i` in `data` is now point
`newFromOld[i]` in the tree's dataset; that is,
`node.Dataset().col(newFromOld[i])` is the point `data.col(i)`.
---
* `node = MaxRPTree()`
- Construct an empty random projection tree with no children and no points.
---
***Notes:***
- The name `node` is used here for `MaxRPTree` objects instead of `tree`,
because each `MaxRPTree` object is a single node in the tree. The
constructor returns the node that is the root of the tree.
- Inserting individual points or removing individual points from a `MaxRPTree`
is not supported, because this generally results in a random projection tree
with very loose bounding boxes. It is better to simply build a new
`MaxRPTree` on the modified dataset. For trees that support individual
insertion and deletions, see the `RectangleTree` class and all its variants
(e.g. `RTree`, `RStarTree`, etc.).
- See also the
[developer documentation on tree constructors](../../../developer/trees.md#constructors-and-destructors).
<!-- TODO: add links to RectangleTree above when it is documented -->
---
### Constructor parameters:
| **name** | **type** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `data` | [`arma::mat`](../../matrices.md) | [Column-major](../../matrices.md#representing-data-in-mlpack) matrix to build the tree on. Pass with `std::move(data)` to avoid copying the matrix. | _(N/A)_ |
| `maxLeafSize` | `size_t` | Maximum number of points to store in each leaf. | `20` |
| `oldFromNew` | `std::vector<size_t>` | Mappings from points in `node.Dataset()` to points in `data`. | _(N/A)_ |
| `newFromOld` | `std::vector<size_t>` | Mappings from points in `data` to points in `node.Dataset()`. | _(N/A)_ |
## Basic tree properties
Once a `MaxRPTree` object is constructed, various properties of the tree can be
accessed or inspected. Many of these functions are required by the [TreeType
API](../../../developer/trees.md#the-treetype-api).
### Navigating the tree
* `node.NumChildren()` returns the number of children in `node`. This is
either `2` if `node` has children, or `0` if `node` is a leaf.
* `node.IsLeaf()` returns a `bool` indicating whether or not `node` is a leaf.
* `node.Child(i)` returns a `MaxRPTree&` that is the `i`th child.
- `i` must be `0` or `1`.
- This function should only be called if `node.NumChildren()` is not `0`
(e.g. if `node` is not a leaf). Note that this returns a valid
`MaxRPTree&` that can itself be used just like the root node of the tree!
- `node.Left()` and `node.Right()` are convenience functions specific to
`MaxRPTree` that will return `MaxRPTree*` (pointers) to the left and right
children, respectively, or `NULL` if `node` has no children.
* `node.Parent()` will return a `MaxRPTree*` that points to the parent of
`node`, or `NULL` if `node` is the root of the `MaxRPTree`.
---
### Accessing members of a tree
* `node.Bound()` will return an
[`HRectBound&`](binary_space_tree.md#hrectbound) object that represents the
hyperrectangle bounding box of `node`. This is the smallest hyperrectangle
that encloses all the descendant points of `node`.
* `node.Stat()` will return an `EmptyStatistic&` (or a `StatisticType&` if a
[custom `StatisticType`](#template-parameters) was specified as a template
parameter) holding the statistics of the node that were computed during tree
construction.
* `node.Distance()` will return a
[`EuclideanDistance&`](../distances.md#lmetric) (or a `DistanceType&` if a
[custom `DistanceType`](#template-parameters) was specified as a template
parameter).
- This function is required by the
[TreeType API](../../../developer/trees.md#the-treetype-api), but given
that `MaxRPTree` requires an [`LMetric`](../distances.md#lmetric) to be
used, and `LMetric` only has `static` functions and holds no state, this
function is not likely to be useful.
See also the
[developer documentation](../../../developer/trees.md#basic-tree-functionality)
for basic tree functionality in mlpack.
---
### Accessing data held in a tree
* `node.Dataset()` will return a `const arma::mat&` that is the dataset the
tree was built on. Note that this is a permuted version of the `data` matrix
passed to the constructor.
- If a [custom `MatType`](#template-parameters) is being used, the return
type will be `const MatType&` instead of `const arma::mat&`.
* `node.NumPoints()` returns a `size_t` indicating the number of points held
directly in `node`.
- If `node` is not a leaf, this will return `0`, as `MaxRPTree` only holds
points directly in its leaves.
- If `node` is a leaf, then the number of points will be less than or equal
to the `maxLeafSize` that was specified when the tree was constructed.
* `node.Point(i)` returns a `size_t` indicating the index of the `i`'th point
in `node.Dataset()`.
- `i` must be in the range `[0, node.NumPoints() - 1]` (inclusive).
- `node` must be a leaf (as non-leaves do not hold any points).
- The `i`'th point in `node` can then be accessed as
`node.Dataset().col(node.Point(i))`.
- In a `MaxRPTree`, because of the permutation of points done [during
construction](#constructors), point indices are contiguous:
`node.Point(i + j)` is the same as `node.Point(i) + j` for valid `i` and
`j`.
- Accessing the actual `i`'th point itself can be done with, e.g.,
`node.Dataset().col(node.Point(i))`.
* `node.NumDescendants()` returns a `size_t` indicating the number of points
held in all descendant leaves of `node`.
- If `node` is the root of the tree, then `node.NumDescendants()` will be
equal to `node.Dataset().n_cols`.
* `node.Descendant(i)` returns a `size_t` indicating the index of the `i`'th
descendant point in `node.Dataset()`.
- `i` must be in the range `[0, node.NumDescendants() - 1]` (inclusive).
- `node` does not need to be a leaf.
- The `i`'th descendant point in `node` can then be accessed as
`node.Dataset().col(node.Descendant(i))`.
- In a `MaxRPTree`, because of the permutation of points done [during
construction](#constructors), point indices are contiguous:
`node.Descendant(i + j)` is the same as `node.Descendant(i) + j` for valid
`i` and `j`.
- Accessing the actual `i`'th descendant itself can be done with, e.g.,
`node.Dataset().col(node.Descendant(i))`.
* `node.Begin()` returns a `size_t` indicating the index of the first
descendant point of `node`.
- This is equivalent to `node.Descendant(0)`.
* `node.Count()` returns a `size_t` indicating the number of descendant points of `node`.
- This is equivalent to `node.NumDescendants()`.
---
### Accessing computed bound quantities of a tree
The following quantities are cached for each node in a `MaxRPTree`, and so
accessing them does not require any computation.
* `node.FurthestPointDistance()` returns a `double` representing the distance
between the center of the bounding hyperrectangle of `node` and the furthest
point held by `node`.
- If `node` is not a leaf, this returns 0 (because `node` does not hold any
points).
* `node.FurthestDescendantDistance()` returns a `double` representing the
distance between the center of the bounding hyperrectangle of `node` and the
furthest descendant point held by `node`.
* `node.MinimumBoundDistance()` returns a `double` representing minimum
possible distance from the center of the node to any edge of the
hyperrectangle bound.
- This quantity is half the width of the smallest dimension of
`node.Bound()`.
* `node.ParentDistance()` returns a `double` representing the distance between
the center of the bounding hyperrectangle of `node` and the center of the
bounding hyperrectangle of its parent.
- If `node` is the root of the tree, `0` is returned.
***Notes:***
- If a [custom `MatType`](#template-parameters) was specified when constructing
the `MaxRPTree`, then the return type of each method is the element type of
the given `MatType` instead of `double`. (e.g., if `MatType` is
`arma::fmat`, then the return type is `float`.)
- For more details on each bound quantity, see the
[developer documentation](../../../developer/trees.md#complex-tree-functionality-and-bounds)
on bound quantities for trees.
---
### Other functionality
* `node.Center(center)` computes the center of the bounding hyperrectangle of
`node` and stores it in `center`.
- `center` should be of type `arma::vec&`. (If a [custom
`MatType`](#template-parameters) was specified when constructing the
`MaxRPTree`, the type is instead the column vector type for the given
`MatType`; e.g., `arma::fvec&` when `MatType` is `arma::fmat`.)
- `center` will be set to have size equivalent to the dimensionality of the
dataset held by `node`.
- This is equivalent to calling `node.Bound().Center(center)`.
* A `MaxRPTree` can be serialized with
[`data::Save()` and `data::Load()`](../../load_save.md#mlpack-objects).
## Bounding distances with the tree
The primary use of trees in mlpack is bounding distances to points or other tree
nodes. The following functions can be used for these tasks.
* `node.GetNearestChild(point)`
* `node.GetFurthestChild(point)`
- Return a `size_t` indicating the index of the child (`0` for left, `1` for
right) that is closest to (or furthest from) `point`, with respect
to the `MinDistance()` (or `MaxDistance()`) function.
- If there is a tie, `0` (the left child) is returned.
- If `node` is a leaf, `0` is returned.
- `point` should be of type `arma::vec`. (If a [custom
`MatType`](#template-parameters) was specified when constructing the
`MaxRPTree`, the type is instead the column vector type for the given
`MatType`; e.g., `arma::fvec` when `MatType` is `arma::fmat`.)
* `node.GetNearestChild(other)`
* `node.GetFurthestChild(other)`
- Return a `size_t` indicating the index of the child (`0` for left, `1` for
right) that is closest to (or furthest from) the `MaxRPTree` node `other`,
with respect to the `MinDistance()` (or `MaxDistance()`) function.
- If there is a tie, `2` (an invalid index) is returned. ***Note that this
behavior differs from the version above that takes a point.***
- If `node` is a leaf, `0` is returned.
---
* `node.MinDistance(point)`
* `node.MinDistance(other)`
- Return a `double` indicating the minimum possible distance between `node`
and `point`, or the `MaxRPTree` node `other`.
- This is equivalent to the minimum possible distance between any point
contained in the bounding hyperrectangle of `node` and `point`, or between
any point contained in the bounding hyperrectangle of `node` and any point
contained in the bounding hyperrectangle of `other`.
- `point` should be of type `arma::vec`. (If a [custom
`MatType`](#template-parameters) was specified when constructing the
`MaxRPTree`, the type is instead the column vector type for the given
`MatType`, and the return type is the element type of `MatType`; e.g.,
`point` should be `arma::fvec` when `MatType` is `arma::fmat`, and the
returned distance is `float`).
* `node.MaxDistance(point)`
* `node.MaxDistance(other)`
- Return a `double` indicating the maximum possible distance between `node`
and `point`, or the `MaxRPTree` node `other`.
- This is equivalent to the maximum possible distance between any point
contained in the bounding hyperrectangle of `node` and `point`, or between
any point contained in the bounding hyperrectangle of `node` and any point
contained in the bounding hyperrectangle of `other`.
- `point` should be of type `arma::vec`. (If a [custom
`MatType`](#template-parameters) was specified when constructing the
`MaxRPTree`, the type is instead the column vector type for the given
`MatType`, and the return type is the element type of `MatType`; e.g.,
`point` should be `arma::fvec` when `MatType` is `arma::fmat`, and the
returned distance is `float`).
* `node.RangeDistance(point)`
* `node.RangeDistance(other)`
- Return a [`Range`](../math.md#range) whose lower bound is
`node.MinDistance(point)` or `node.MinDistance(other)`, and whose upper
bound is `node.MaxDistance(point)` or `node.MaxDistance(other)`.
- `point` should be of type `arma::vec`. (If a
[custom `MatType`](#template-parameters) was specified when constructing
the `MaxRPTree`, the type is instead the column vector type for the given
`MatType`, and the return type is a `RangeType` with element type the same
as `MatType`; e.g., `point` should be `arma::fvec` when `MatType` is
`arma::fmat`, and the returned type is
[`RangeType<float>`](../math.md#range)).
### Tree traversals
Like every mlpack tree, the `MaxRPTree` class provides a [single-tree and
dual-tree traversal](../../../developer/trees.md#traversals) that can be paired
with a [`RuleType` class](../../../developer/trees.md#rules) to implement a
single-tree or dual-tree algorithm.
* `MaxRPTree::SingleTreeTraverser`
- Implements a depth-first single-tree traverser.
* `MaxRPTree::DualTreeTraverser`
- Implements a dual-depth-first dual-tree traverser.
In addition to those two classes, which are required by the
[`TreeType` policy](../../../developer/trees.md), an additional traverser is
available:
* `MaxRPTree::BreadthFirstDualTreeTraverser`
- Implements a dual-breadth-first dual-tree traverser.
- ***Note:*** this traverser is not useful for all tasks; because the
`MaxRPTree` only holds points in the leaves, this means that no base cases
(e.g. comparisons between points) will be called until *all* pairs of
intermediate nodes have been scored!
## Example usage
Build a `MaxRPTree` on the `cloud` dataset and print basic statistics about the
tree.
```c++
// See https://datasets.mlpack.org/cloud.csv.
arma::mat dataset;
mlpack::data::Load("cloud.csv", dataset, true);
// Build the random projection tree with a leaf size of 10. (This means that
// nodes are split until they contain 10 or fewer points.)
//
// The std::move() means that `dataset` will be empty after this call, and no
// data will be copied during tree building.
//
// Note that the '<>' isn't necessary if C++20 is being used (e.g.
// `mlpack::MaxRPTree tree(...)` will work fine in C++20 or newer).
mlpack::MaxRPTree<> tree(std::move(dataset));
// Print the bounding box of the root node.
std::cout << "Bounding box of root node:" << std::endl;
for (size_t i = 0; i < tree.Bound().Dim(); ++i)
{
std::cout << " - Dimension " << i << ": [" << tree.Bound()[i].Lo() << ", "
<< tree.Bound()[i].Hi() << "]." << std::endl;
}
std::cout << std::endl;
// Print the number of descendant points of the root, and of each of its
// children.
std::cout << "Descendant points of root: "
<< tree.NumDescendants() << "." << std::endl;
std::cout << "Descendant points of left child: "
<< tree.Left()->NumDescendants() << "." << std::endl;
std::cout << "Descendant points of right child: "
<< tree.Right()->NumDescendants() << "." << std::endl;
std::cout << std::endl;
// Compute the center of the rp-tree.
arma::vec center;
tree.Center(center);
std::cout << "Center of random projection tree: " << center.t();
```
---
Build two `MaxRPTree`s on subsets of the corel dataset and compute minimum and
maximum distances between different nodes in the tree.
```c++
// See https://datasets.mlpack.org/corel-histogram.csv.
arma::mat dataset;
mlpack::data::Load("corel-histogram.csv", dataset, true);
// Build rp-trees on the first half and the second half of points.
mlpack::MaxRPTree<> tree1(dataset.cols(0, dataset.n_cols / 2));
mlpack::MaxRPTree<> tree2(dataset.cols(dataset.n_cols / 2 + 1,
dataset.n_cols - 1));
// Compute the maximum distance between the trees.
std::cout << "Maximum distance between tree root nodes: "
<< tree1.MaxDistance(tree2) << "." << std::endl;
// Get the leftmost grandchild of the first tree's root---if it exists.
if (!tree1.IsLeaf() && !tree1.Child(0).IsLeaf())
{
mlpack::MaxRPTree<>& node1 = tree1.Child(0).Child(0);
// Get the rightmost grandchild of the second tree's root---if it exists.
if (!tree2.IsLeaf() && !tree2.Child(1).IsLeaf())
{
mlpack::MaxRPTree<>& node2 = tree2.Child(1).Child(1);
// Print the minimum and maximum distance between the nodes.
mlpack::Range dists = node1.RangeDistance(node2);
std::cout << "Possible distances between two grandchild nodes: ["
<< dists.Lo() << ", " << dists.Hi() << "]." << std::endl;
// Print the minimum distance between the first node and the first
// descendant point of the second node.
const size_t descendantIndex = node2.Descendant(0);
const double descendantMinDist =
node1.MinDistance(node2.Dataset().col(descendantIndex));
std::cout << "Minimum distance between grandchild node and descendant "
<< "point: " << descendantMinDist << "." << std::endl;
// Which child of node2 is closer to node1?
const size_t closerIndex = node2.GetNearestChild(node1);
if (closerIndex == 0)
std::cout << "The left child of node2 is closer to node1." << std::endl;
else if (closerIndex == 1)
std::cout << "The right child of node2 is closer to node1." << std::endl;
else // closerIndex == 2 in this case.
std::cout << "Both children of node2 are equally close to node1."
<< std::endl;
// And which child of node1 is further from node2?
const size_t furtherIndex = node1.GetFurthestChild(node2);
if (furtherIndex == 0)
std::cout << "The left child of node1 is further from node2."
<< std::endl;
else if (furtherIndex == 1)
std::cout << "The right child of node1 is further from node2."
<< std::endl;
else // furtherIndex == 2 in this case.
std::cout << "Both children of node1 are equally far from node2."
<< std::endl;
}
}
```
---
Build a `MaxRPTree` on 32-bit floating point data and save it to disk.
```c++
// See https://datasets.mlpack.org/corel-histogram.csv.
arma::fmat dataset;
mlpack::data::Load("corel-histogram.csv", dataset);
// Build the MaxRPTree using 32-bit floating point data as the matrix type.
// We will still use the default EmptyStatistic and EuclideanDistance
// parameters. A leaf size of 100 is used here.
mlpack::MaxRPTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat> tree(std::move(dataset), 100);
// Save the MaxRPTree to disk with the name 'tree'.
mlpack::data::Save("tree.bin", "tree", tree);
std::cout << "Saved tree with " << tree.Dataset().n_cols << " points to "
<< "'tree.bin'." << std::endl;
```
---
Load a 32-bit floating point `MaxRPTree` from disk, then traverse it manually
and find the number of leaf nodes with fewer than 10 points.
```c++
// This assumes the tree has already been saved to 'tree.bin' (as in the example
// above).
// This convenient typedef saves us a long type name!
typedef mlpack::MaxRPTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat> TreeType;
TreeType tree;
mlpack::data::Load("tree.bin", "tree", tree);
std::cout << "Tree loaded with " << tree.NumDescendants() << " points."
<< std::endl;
// Recurse in a depth-first manner. Count both the total number of leaves, and
// the number of leaves with fewer than 10 points.
size_t leafCount = 0;
size_t totalLeafCount = 0;
std::stack<TreeType*> stack;
stack.push(&tree);
while (!stack.empty())
{
TreeType* node = stack.top();
stack.pop();
if (node->NumPoints() < 10)
++leafCount;
++totalLeafCount;
if (!node->IsLeaf())
{
stack.push(node->Left());
stack.push(node->Right());
}
}
// Note that it would be possible to use TreeType::SingleTreeTraverser to
// perform the recursion above, but that is more well-suited for more complex
// tasks that require pruning and other non-trivial behavior; so using a simple
// stack is the better option here.
// Print the results.
std::cout << leafCount << " out of " << totalLeafCount << " leaves have fewer "
<< "than 10 points." << std::endl;
```
---
Build a `MaxRPTree` and map between original points and new points.
```c++
// See https://datasets.mlpack.org/cloud.csv.
arma::mat dataset;
mlpack::data::Load("cloud.csv", dataset, true);
// Build the tree.
std::vector<size_t> oldFromNew, newFromOld;
mlpack::MaxRPTree<> tree(dataset, oldFromNew, newFromOld);
// oldFromNew and newFromOld will be set to the same size as the dataset.
std::cout << "Number of points in dataset: " << dataset.n_cols << "."
<< std::endl;
std::cout << "Size of oldFromNew: " << oldFromNew.size() << "." << std::endl;
std::cout << "Size of newFromOld: " << newFromOld.size() << "." << std::endl;
std::cout << std::endl;
// See where point 42 in the tree's dataset came from.
std::cout << "Point 42 in the permuted tree's dataset:" << std::endl;
std::cout << " " << tree.Dataset().col(42).t();
std::cout << "Was originally point " << oldFromNew[42] << ":" << std::endl;
std::cout << " " << dataset.col(oldFromNew[42]).t();
std::cout << std::endl;
// See where point 7 in the original dataset was mapped.
std::cout << "Point 7 in original dataset:" << std::endl;
std::cout << " " << dataset.col(7).t();
std::cout << "Mapped to point " << newFromOld[7] << ":" << std::endl;
std::cout << " " << tree.Dataset().col(newFromOld[7]).t();
```
+4 -4
View File
@@ -544,16 +544,16 @@ std::cout << "Saved tree with " << tree.Dataset().n_cols << " points to "
---
Load a 32-bit floating point `BallTree` from disk, then traverse it manually and
find the number of leaf nodes with fewer than 10 children.
find the number of leaf nodes with fewer than 10 points.
```c++
// This assumes the tree has already been saved to 'tree.bin' (as in the example
// above).
// This convenient typedef saves us a long type name!
typedef mlpack::MeanSplitBallTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat> TreeType;
using TreeType = mlpack::MeanSplitBallTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat>;
TreeType tree;
mlpack::data::Load("tree.bin", "tree", tree);
+4 -4
View File
@@ -553,16 +553,16 @@ std::cout << "Saved tree with " << tree.Dataset().n_cols << " points to "
---
Load a 32-bit floating point `MeanSplitKDTree` from disk, then traverse it
manually and find the number of leaf nodes with fewer than 10 children.
manually and find the number of leaf nodes with fewer than 10 points.
```c++
// This assumes the tree has already been saved to 'tree.bin' (as in the example
// above).
// This convenient typedef saves us a long type name!
typedef mlpack::MeanSplitKDTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat> TreeType;
using TreeType = mlpack::MeanSplitKDTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat>;
TreeType tree;
mlpack::data::Load("tree.bin", "tree", tree);
+635
View File
@@ -0,0 +1,635 @@
# `RPTree`
<!-- TODO: link to knn.md once it's done -->
The `RPTree` class represents a random projection tree, a variant of the
[`k`-d tree](kdtree.md) based on random projections. The random projection tree
is a well-known data structure for efficient distance operations (such as
nearest neighbor search) in low dimensions---typically less than 100.
An `RPTree` (or the similar [`MaxRPTree`](max_rp_tree.md)) may be preferred over
a [`KDTree`](kdtree.md) or other tree structures as it is theoretically known to
adapt to the intrinsic dimension of the data. This is similar to the cover
tree, but the implementation is far simpler and as a result, more efficient.
<!-- TODO: add cover tree link above -->
mlpack's `RPTree` implementation supports three template parameters for
configurable behavior, and implements all the functionality required by the
[TreeType API](../../../developer/trees.md#the-treetype-api), plus some
additional functionality specific to random projection trees.
* [Template parameters](#template-parameters)
* [Constructors](#constructors)
* [Basic tree properties](#basic-tree-properties)
* [Bounding distances with the tree](#bounding-distances-with-the-tree)
* [Tree traversals](#tree-traversals)
* [Example usage](#example-usage)
## See also
<!-- TODO: add links to all distance-based algorithms and other trees? -->
* [`MaxRPTree`](max_rp_tree.md)
* [kd-tree on Wikipedia](https://en.wikipedia.org/wiki/Kd-tree)
* [Random projection on Wikipedia](https://en.wikipedia.org/wiki/Random_projection)
* [`BinarySpaceTree`](binary_space_tree.md)
* [Binary space partitioning on Wikipedia](https://dl.acm.org/doi/pdf/10.1145/361002.361007)
* [Random Projection Trees and Low Dimensional Manifolds (pdf)](https://www.cs.cornell.edu/~abrahao/tdg/papers/p537.pdf)
* [Tree-Independent Dual-Tree Algorithms (pdf)](https://www.ratml.org/pub/pdf/2013tree.pdf)
## Template parameters
In accordance with the [TreeType
API](../../../developer/trees.md#template-parameters-required-by-the-treetype-policy)
(see also [this more detailed section](../../../developer/trees.md#template-parameters)),
the `RPTree` class takes three template parameters:
```
RPTree<DistanceType, StatisticType, MatType>
```
* `DistanceType`: the [distance metric](../distances.md) to use for distance
computations. For the `RPTree`, this must be an
[`LMetric`](../distances.md#lmetric). By default, this is
[`EuclideanDistance`](../distances.md#lmetric).
* [`StatisticType`](binary_space_tree.md#statistictype): this holds auxiliary
information in each tree node. By default,
[`EmptyStatistic`](binary_space_tree.md#emptystatistic) is used, which holds
no information.
* `MatType`: the type of matrix used to represent points. Must be a type
matching the [Armadillo API](../../matrices.md). By default, `arma::mat` is
used, but other types such as `arma::fmat` or similar will work just fine.
The `RPTree` class itself is a convenience typedef of the generic
[`BinarySpaceTree`](binary_space_tree.md) class, using the
[`HRectBound`](binary_space_tree.md#hrectbound) class as the bounding structure,
and using the [`RPTreeMeanSplit`](binary_space_tree.md#rptreemeansplit)
splitting strategy for construction, which splits a node along a random
projection, or, in some cases, based on the distance from the vector-valued mean
of points in the node.
If no template parameters are explicitly specified, then defaults are used:
```
RPTree<> = RPTree<EuclideanDistance, EmptyStatistic, arma::mat>
```
## Constructors
`RPTree`s are efficiently constructed by permuting points in a dataset in a
quicksort-like algorithm. However, this means that the ordering of points in
the tree's dataset (accessed with `node.Dataset()`) after construction may be
different.
---
* `node = RPTree(data, maxLeafSize=20)`
* `node = RPTree(data, oldFromNew, maxLeafSize=20)`
* `node = RPTree(data, oldFromNew, newFromOld, maxLeafSize=20)`
- Construct an `RPTree` on the given `data`, using `maxLeafSize` as the
maximum number of points held in a leaf.
- By default, `data` is copied. Avoid a copy by using `std::move()` (e.g.
`std::move(data)`); when doing this, `data` will be set to an empty matrix.
- Optionally, construct mappings from old points to new points. `oldFromNew`
and `newFromOld` will have length `data.n_cols`, and:
* `oldFromNew[i]` indicates that point `i` in the tree's dataset was
originally point `oldFromNew[i]` in `data`; that is,
`node.Dataset().col(i)` is the point `data.col(oldFromNew[i])`.
* `newFromOld[i]` indicates that point `i` in `data` is now point
`newFromOld[i]` in the tree's dataset; that is,
`node.Dataset().col(newFromOld[i])` is the point `data.col(i)`.
---
* `node = RPTree<DistanceType, StatisticType, MatType>(data, maxLeafSize=20)`
* `node = RPTree<DistanceType, StatisticType, MatType>(data, oldFromNew, maxLeafSize=20)`
* `node = RPTree<DistanceType, StatisticType, MatType>(data, oldFromNew, newFromOld, maxLeafSize=20)`
- Construct an `RPTree` on the given `data`, using custom template parameters
to control the behavior of the tree, using `maxLeafSize` as the maximum
number of points held in a leaf.
- By default, `data` is copied. Avoid a copy by using `std::move()` (e.g.
`std::move(data)`); when doing this, `data` will be set to an empty matrix.
- Optionally, construct mappings from old points to new points. `oldFromNew`
and `newFromOld` will have length `data.n_cols`, and:
* `oldFromNew[i]` indicates that point `i` in the tree's dataset was
originally point `oldFromNew[i]` in `data`; that is,
`node.Dataset().col(i)` is the point `data.col(oldFromNew[i])`.
* `newFromOld[i]` indicates that point `i` in `data` is now point
`newFromOld[i]` in the tree's dataset; that is,
`node.Dataset().col(newFromOld[i])` is the point `data.col(i)`.
---
* `node = RPTree()`
- Construct an empty random projection tree with no children and no points.
---
***Notes:***
- The name `node` is used here for `RPTree` objects instead of `tree`, because
each `RPTree` object is a single node in the tree. The constructor returns
the node that is the root of the tree.
- Inserting individual points or removing individual points from an `RPTree` is
not supported, because this generally results in a random projection tree
with very loose bounding boxes. It is better to simply build a new `RPTree`
on the modified dataset. For trees that support individual insertion and
deletions, see the `RectangleTree` class and all its variants (e.g. `RTree`,
`RStarTree`, etc.).
- See also the
[developer documentation on tree constructors](../../../developer/trees.md#constructors-and-destructors).
<!-- TODO: add links to RectangleTree above when it is documented -->
---
### Constructor parameters:
| **name** | **type** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `data` | [`arma::mat`](../../matrices.md) | [Column-major](../../matrices.md#representing-data-in-mlpack) matrix to build the tree on. Pass with `std::move(data)` to avoid copying the matrix. | _(N/A)_ |
| `maxLeafSize` | `size_t` | Maximum number of points to store in each leaf. | `20` |
| `oldFromNew` | `std::vector<size_t>` | Mappings from points in `node.Dataset()` to points in `data`. | _(N/A)_ |
| `newFromOld` | `std::vector<size_t>` | Mappings from points in `data` to points in `node.Dataset()`. | _(N/A)_ |
## Basic tree properties
Once an `RPTree` object is constructed, various properties of the tree can be
accessed or inspected. Many of these functions are required by the [TreeType
API](../../../developer/trees.md#the-treetype-api).
### Navigating the tree
* `node.NumChildren()` returns the number of children in `node`. This is
either `2` if `node` has children, or `0` if `node` is a leaf.
* `node.IsLeaf()` returns a `bool` indicating whether or not `node` is a leaf.
* `node.Child(i)` returns an `RPTree&` that is the `i`th child.
- `i` must be `0` or `1`.
- This function should only be called if `node.NumChildren()` is not `0`
(e.g. if `node` is not a leaf). Note that this returns a valid `RPTree&`
that can itself be used just like the root node of the tree!
- `node.Left()` and `node.Right()` are convenience functions specific to
`RPTree` that will return `RPTree*` (pointers) to the left and right
children, respectively, or `NULL` if `node` has no children.
* `node.Parent()` will return an `RPTree*` that points to the parent of `node`,
or `NULL` if `node` is the root of the `RPTree`.
---
### Accessing members of a tree
* `node.Bound()` will return an
[`HRectBound&`](binary_space_tree.md#hrectbound) object that represents the
hyperrectangle bounding box of `node`. This is the smallest hyperrectangle
that encloses all the descendant points of `node`.
* `node.Stat()` will return an `EmptyStatistic&` (or a `StatisticType&` if a
[custom `StatisticType`](#template-parameters) was specified as a template
parameter) holding the statistics of the node that were computed during tree
construction.
* `node.Distance()` will return a
[`EuclideanDistance&`](../distances.md#lmetric) (or a `DistanceType&` if a
[custom `DistanceType`](#template-parameters) was specified as a template
parameter).
- This function is required by the
[TreeType API](../../../developer/trees.md#the-treetype-api), but given
that `RPTree` requires an [`LMetric`](../distances.md#lmetric) to be used,
and `LMetric` only has `static` functions and holds no state, this function
is not likely to be useful.
See also the
[developer documentation](../../../developer/trees.md#basic-tree-functionality)
for basic tree functionality in mlpack.
---
### Accessing data held in a tree
* `node.Dataset()` will return a `const arma::mat&` that is the dataset the
tree was built on. Note that this is a permuted version of the `data` matrix
passed to the constructor.
- If a [custom `MatType`](#template-parameters) is being used, the return
type will be `const MatType&` instead of `const arma::mat&`.
* `node.NumPoints()` returns a `size_t` indicating the number of points held
directly in `node`.
- If `node` is not a leaf, this will return `0`, as `RPTree` only holds
points directly in its leaves.
- If `node` is a leaf, then the number of points will be less than or equal
to the `maxLeafSize` that was specified when the tree was constructed.
* `node.Point(i)` returns a `size_t` indicating the index of the `i`'th point
in `node.Dataset()`.
- `i` must be in the range `[0, node.NumPoints() - 1]` (inclusive).
- `node` must be a leaf (as non-leaves do not hold any points).
- The `i`'th point in `node` can then be accessed as
`node.Dataset().col(node.Point(i))`.
- In an `RPTree`, because of the permutation of points done [during
construction](#constructors), point indices are contiguous:
`node.Point(i + j)` is the same as `node.Point(i) + j` for valid `i` and
`j`.
- Accessing the actual `i`'th point itself can be done with, e.g.,
`node.Dataset().col(node.Point(i))`.
* `node.NumDescendants()` returns a `size_t` indicating the number of points
held in all descendant leaves of `node`.
- If `node` is the root of the tree, then `node.NumDescendants()` will be
equal to `node.Dataset().n_cols`.
* `node.Descendant(i)` returns a `size_t` indicating the index of the `i`'th
descendant point in `node.Dataset()`.
- `i` must be in the range `[0, node.NumDescendants() - 1]` (inclusive).
- `node` does not need to be a leaf.
- The `i`'th descendant point in `node` can then be accessed as
`node.Dataset().col(node.Descendant(i))`.
- In an `RPTree`, because of the permutation of points done [during
construction](#constructors), point indices are contiguous:
`node.Descendant(i + j)` is the same as `node.Descendant(i) + j` for valid
`i` and `j`.
- Accessing the actual `i`'th descendant itself can be done with, e.g.,
`node.Dataset().col(node.Descendant(i))`.
* `node.Begin()` returns a `size_t` indicating the index of the first
descendant point of `node`.
- This is equivalent to `node.Descendant(0)`.
* `node.Count()` returns a `size_t` indicating the number of descendant points of `node`.
- This is equivalent to `node.NumDescendants()`.
---
### Accessing computed bound quantities of a tree
The following quantities are cached for each node in an `RPTree`, and so
accessing them does not require any computation.
* `node.FurthestPointDistance()` returns a `double` representing the distance
between the center of the bounding hyperrectangle of `node` and the furthest
point held by `node`.
- If `node` is not a leaf, this returns 0 (because `node` does not hold any
points).
* `node.FurthestDescendantDistance()` returns a `double` representing the
distance between the center of the bounding hyperrectangle of `node` and the
furthest descendant point held by `node`.
* `node.MinimumBoundDistance()` returns a `double` representing minimum
possible distance from the center of the node to any edge of the
hyperrectangle bound.
- This quantity is half the width of the smallest dimension of
`node.Bound()`.
* `node.ParentDistance()` returns a `double` representing the distance between
the center of the bounding hyperrectangle of `node` and the center of the
bounding hyperrectangle of its parent.
- If `node` is the root of the tree, `0` is returned.
***Notes:***
- If a [custom `MatType`](#template-parameters) was specified when constructing
the `RPTree`, then the return type of each method is the element type of the
given `MatType` instead of `double`. (e.g., if `MatType` is `arma::fmat`,
then the return type is `float`.)
- For more details on each bound quantity, see the
[developer documentation](../../../developer/trees.md#complex-tree-functionality-and-bounds)
on bound quantities for trees.
---
### Other functionality
* `node.Center(center)` computes the center of the bounding hyperrectangle of
`node` and stores it in `center`.
- `center` should be of type `arma::vec&`. (If a [custom
`MatType`](#template-parameters) was specified when constructing the
`RPTree`, the type is instead the column vector type for the given
`MatType`; e.g., `arma::fvec&` when `MatType` is `arma::fmat`.)
- `center` will be set to have size equivalent to the dimensionality of the
dataset held by `node`.
- This is equivalent to calling `node.Bound().Center(center)`.
* A `RPTree` can be serialized with
[`data::Save()` and `data::Load()`](../../load_save.md#mlpack-objects).
## Bounding distances with the tree
The primary use of trees in mlpack is bounding distances to points or other tree
nodes. The following functions can be used for these tasks.
* `node.GetNearestChild(point)`
* `node.GetFurthestChild(point)`
- Return a `size_t` indicating the index of the child (`0` for left, `1` for
right) that is closest to (or furthest from) `point`, with respect
to the `MinDistance()` (or `MaxDistance()`) function.
- If there is a tie, `0` (the left child) is returned.
- If `node` is a leaf, `0` is returned.
- `point` should be of type `arma::vec`. (If a [custom
`MatType`](#template-parameters) was specified when constructing the
`RPTree`, the type is instead the column vector type for the given
`MatType`; e.g., `arma::fvec` when `MatType` is `arma::fmat`.)
* `node.GetNearestChild(other)`
* `node.GetFurthestChild(other)`
- Return a `size_t` indicating the index of the child (`0` for left, `1` for
right) that is closest to (or furthest from) the `RPTree` node `other`,
with respect to the `MinDistance()` (or `MaxDistance()`) function.
- If there is a tie, `2` (an invalid index) is returned. ***Note that this
behavior differs from the version above that takes a point.***
- If `node` is a leaf, `0` is returned.
---
* `node.MinDistance(point)`
* `node.MinDistance(other)`
- Return a `double` indicating the minimum possible distance between `node`
and `point`, or the `RPTree` node `other`.
- This is equivalent to the minimum possible distance between any point
contained in the bounding hyperrectangle of `node` and `point`, or between
any point contained in the bounding hyperrectangle of `node` and any point
contained in the bounding hyperrectangle of `other`.
- `point` should be of type `arma::vec`. (If a [custom
`MatType`](#template-parameters) was specified when constructing the
`RPTree`, the type is instead the column vector type for the given
`MatType`, and the return type is the element type of `MatType`; e.g.,
`point` should be `arma::fvec` when `MatType` is `arma::fmat`, and the
returned distance is `float`).
* `node.MaxDistance(point)`
* `node.MaxDistance(other)`
- Return a `double` indicating the maximum possible distance between `node`
and `point`, or the `RPTree` node `other`.
- This is equivalent to the maximum possible distance between any point
contained in the bounding hyperrectangle of `node` and `point`, or between
any point contained in the bounding hyperrectangle of `node` and any point
contained in the bounding hyperrectangle of `other`.
- `point` should be of type `arma::vec`. (If a [custom
`MatType`](#template-parameters) was specified when constructing the
`RPTree`, the type is instead the column vector type for the given
`MatType`, and the return type is the element type of `MatType`; e.g.,
`point` should be `arma::fvec` when `MatType` is `arma::fmat`, and the
returned distance is `float`).
* `node.RangeDistance(point)`
* `node.RangeDistance(other)`
- Return a [`Range`](../math.md#range) whose lower bound is
`node.MinDistance(point)` or `node.MinDistance(other)`, and whose upper
bound is `node.MaxDistance(point)` or `node.MaxDistance(other)`.
- `point` should be of type `arma::vec`. (If a
[custom `MatType`](#template-parameters) was specified when constructing
the `RPTree`, the type is instead the column vector type for the given
`MatType`, and the return type is a `RangeType` with element type the same
as `MatType`; e.g., `point` should be `arma::fvec` when `MatType` is
`arma::fmat`, and the returned type is
[`RangeType<float>`](../math.md#range)).
### Tree traversals
Like every mlpack tree, the `RPTree` class provides a [single-tree and dual-tree
traversal](../../../developer/trees.md#traversals) that can be paired with a
[`RuleType` class](../../../developer/trees.md#rules) to implement a single-tree
or dual-tree algorithm.
* `RPTree::SingleTreeTraverser`
- Implements a depth-first single-tree traverser.
* `RPTree::DualTreeTraverser`
- Implements a dual-depth-first dual-tree traverser.
In addition to those two classes, which are required by the
[`TreeType` policy](../../../developer/trees.md), an additional traverser is
available:
* `RPTree::BreadthFirstDualTreeTraverser`
- Implements a dual-breadth-first dual-tree traverser.
- ***Note:*** this traverser is not useful for all tasks; because the
`RPTree` only holds points in the leaves, this means that no base cases
(e.g. comparisons between points) will be called until *all* pairs of
intermediate nodes have been scored!
## Example usage
Build an `RPTree` on the `cloud` dataset and print basic statistics about the
tree.
```c++
// See https://datasets.mlpack.org/cloud.csv.
arma::mat dataset;
mlpack::data::Load("cloud.csv", dataset, true);
// Build the random projection tree with a leaf size of 10. (This means that
// nodes are split until they contain 10 or fewer points.)
//
// The std::move() means that `dataset` will be empty after this call, and no
// data will be copied during tree building.
//
// Note that the '<>' isn't necessary if C++20 is being used (e.g.
// `mlpack::RPTree tree(...)` will work fine in C++20 or newer).
mlpack::RPTree<> tree(std::move(dataset));
// Print the bounding box of the root node.
std::cout << "Bounding box of root node:" << std::endl;
for (size_t i = 0; i < tree.Bound().Dim(); ++i)
{
std::cout << " - Dimension " << i << ": [" << tree.Bound()[i].Lo() << ", "
<< tree.Bound()[i].Hi() << "]." << std::endl;
}
std::cout << std::endl;
// Print the number of descendant points of the root, and of each of its
// children.
std::cout << "Descendant points of root: "
<< tree.NumDescendants() << "." << std::endl;
std::cout << "Descendant points of left child: "
<< tree.Left()->NumDescendants() << "." << std::endl;
std::cout << "Descendant points of right child: "
<< tree.Right()->NumDescendants() << "." << std::endl;
std::cout << std::endl;
// Compute the center of the rp-tree.
arma::vec center;
tree.Center(center);
std::cout << "Center of random projection tree: " << center.t();
```
---
Build two `RPTree`s on subsets of the corel dataset and compute minimum and
maximum distances between different nodes in the tree.
```c++
// See https://datasets.mlpack.org/corel-histogram.csv.
arma::mat dataset;
mlpack::data::Load("corel-histogram.csv", dataset, true);
// Build rp-trees on the first half and the second half of points.
mlpack::RPTree<> tree1(dataset.cols(0, dataset.n_cols / 2));
mlpack::RPTree<> tree2(dataset.cols(dataset.n_cols / 2 + 1,
dataset.n_cols - 1));
// Compute the maximum distance between the trees.
std::cout << "Maximum distance between tree root nodes: "
<< tree1.MaxDistance(tree2) << "." << std::endl;
// Get the leftmost grandchild of the first tree's root---if it exists.
if (!tree1.IsLeaf() && !tree1.Child(0).IsLeaf())
{
mlpack::RPTree<>& node1 = tree1.Child(0).Child(0);
// Get the rightmost grandchild of the second tree's root---if it exists.
if (!tree2.IsLeaf() && !tree2.Child(1).IsLeaf())
{
mlpack::RPTree<>& node2 = tree2.Child(1).Child(1);
// Print the minimum and maximum distance between the nodes.
mlpack::Range dists = node1.RangeDistance(node2);
std::cout << "Possible distances between two grandchild nodes: ["
<< dists.Lo() << ", " << dists.Hi() << "]." << std::endl;
// Print the minimum distance between the first node and the first
// descendant point of the second node.
const size_t descendantIndex = node2.Descendant(0);
const double descendantMinDist =
node1.MinDistance(node2.Dataset().col(descendantIndex));
std::cout << "Minimum distance between grandchild node and descendant "
<< "point: " << descendantMinDist << "." << std::endl;
// Which child of node2 is closer to node1?
const size_t closerIndex = node2.GetNearestChild(node1);
if (closerIndex == 0)
std::cout << "The left child of node2 is closer to node1." << std::endl;
else if (closerIndex == 1)
std::cout << "The right child of node2 is closer to node1." << std::endl;
else // closerIndex == 2 in this case.
std::cout << "Both children of node2 are equally close to node1."
<< std::endl;
// And which child of node1 is further from node2?
const size_t furtherIndex = node1.GetFurthestChild(node2);
if (furtherIndex == 0)
std::cout << "The left child of node1 is further from node2."
<< std::endl;
else if (furtherIndex == 1)
std::cout << "The right child of node1 is further from node2."
<< std::endl;
else // furtherIndex == 2 in this case.
std::cout << "Both children of node1 are equally far from node2."
<< std::endl;
}
}
```
---
Build an `RPTree` on 32-bit floating point data and save it to disk.
```c++
// See https://datasets.mlpack.org/corel-histogram.csv.
arma::fmat dataset;
mlpack::data::Load("corel-histogram.csv", dataset);
// Build the RPTree using 32-bit floating point data as the matrix type.
// We will still use the default EmptyStatistic and EuclideanDistance
// parameters. A leaf size of 100 is used here.
mlpack::RPTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat> tree(std::move(dataset), 100);
// Save the RPTree to disk with the name 'tree'.
mlpack::data::Save("tree.bin", "tree", tree);
std::cout << "Saved tree with " << tree.Dataset().n_cols << " points to "
<< "'tree.bin'." << std::endl;
```
---
Load a 32-bit floating point `RPTree` from disk, then traverse it manually and
find the number of leaf nodes with fewer than 10 points.
```c++
// This assumes the tree has already been saved to 'tree.bin' (as in the example
// above).
// This convenient typedef saves us a long type name!
using TreeType = mlpack::RPTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat>;
TreeType tree;
mlpack::data::Load("tree.bin", "tree", tree);
std::cout << "Tree loaded with " << tree.NumDescendants() << " points."
<< std::endl;
// Recurse in a depth-first manner. Count both the total number of leaves, and
// the number of leaves with fewer than 10 points.
size_t leafCount = 0;
size_t totalLeafCount = 0;
std::stack<TreeType*> stack;
stack.push(&tree);
while (!stack.empty())
{
TreeType* node = stack.top();
stack.pop();
if (node->NumPoints() < 10)
++leafCount;
++totalLeafCount;
if (!node->IsLeaf())
{
stack.push(node->Left());
stack.push(node->Right());
}
}
// Note that it would be possible to use TreeType::SingleTreeTraverser to
// perform the recursion above, but that is more well-suited for more complex
// tasks that require pruning and other non-trivial behavior; so using a simple
// stack is the better option here.
// Print the results.
std::cout << leafCount << " out of " << totalLeafCount << " leaves have fewer "
<< "than 10 points." << std::endl;
```
---
Build an `RPTree` and map between original points and new points.
```c++
// See https://datasets.mlpack.org/cloud.csv.
arma::mat dataset;
mlpack::data::Load("cloud.csv", dataset, true);
// Build the tree.
std::vector<size_t> oldFromNew, newFromOld;
mlpack::RPTree<> tree(dataset, oldFromNew, newFromOld);
// oldFromNew and newFromOld will be set to the same size as the dataset.
std::cout << "Number of points in dataset: " << dataset.n_cols << "."
<< std::endl;
std::cout << "Size of oldFromNew: " << oldFromNew.size() << "." << std::endl;
std::cout << "Size of newFromOld: " << newFromOld.size() << "." << std::endl;
std::cout << std::endl;
// See where point 42 in the tree's dataset came from.
std::cout << "Point 42 in the permuted tree's dataset:" << std::endl;
std::cout << " " << tree.Dataset().col(42).t();
std::cout << "Was originally point " << oldFromNew[42] << ":" << std::endl;
std::cout << " " << dataset.col(oldFromNew[42]).t();
std::cout << std::endl;
// See where point 7 in the original dataset was mapped.
std::cout << "Point 7 in original dataset:" << std::endl;
std::cout << " " << dataset.col(7).t();
std::cout << "Mapped to point " << newFromOld[7] << ":" << std::endl;
std::cout << " " << tree.Dataset().col(newFromOld[7]).t();
```
+3 -3
View File
@@ -558,9 +558,9 @@ find the number of leaf nodes with less than 10 children.
// above).
// This convenient typedef saves us a long type name!
typedef mlpack::VPTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat> TreeType;
using TreeType = mlpack::VPTree<mlpack::EuclideanDistance,
mlpack::EmptyStatistic,
arma::fmat>;
TreeType tree;
mlpack::data::Load("tree.bin", "tree", tree);
+2 -2
View File
@@ -256,10 +256,10 @@ arma::Row<size_t> labels =
// Train in the constructor, using floating-point data.
// The weak learner type is now a floating-point Perceptron.
typedef mlpack::Perceptron<
using PerceptronType = mlpack::Perceptron<
mlpack::SimpleWeightUpdate,
mlpack::ZeroInitialization,
arma::fmat> PerceptronType;
arma::fmat>;
mlpack::AdaBoost<PerceptronType, arma::fmat> ab(dataset, labels, 5);
// Create test data (500 points).
+3 -3
View File
@@ -418,9 +418,9 @@ arma::Row<size_t> labels =
// Train in the constructor, using floating-point data.
// The weak learner type is now a floating-point Perceptron.
typedef mlpack::Perceptron<mlpack::SimpleWeightUpdate,
mlpack::ZeroInitialization,
arma::fmat> PerceptronType;
using PerceptronType = mlpack::Perceptron<mlpack::SimpleWeightUpdate,
mlpack::ZeroInitialization,
arma::fmat>;
mlpack::AdaBoost<PerceptronType, arma::fmat> ab(dataset, labels, 5);
// Create test data (500 points).
+3 -2
View File
@@ -659,8 +659,9 @@ mlpack::RandomAcolInitialization<5> initW;
mlpack::RandomAMFInitialization initH;
// Combine the two initializations so we can pass it to the AMF class.
typedef mlpack::MergeInitialization<mlpack::RandomAcolInitialization<5>,
mlpack::RandomAMFInitialization> InitType;
using InitType =
mlpack::MergeInitialization<mlpack::RandomAcolInitialization<5>,
mlpack::RandomAMFInitialization>;
InitType init(initW, initH);
// Create an AMF object with the custom initialization.
+1 -1
View File
@@ -35,7 +35,7 @@ void PrintR(util::Params& params,
const util::BindingDetails& doc = params.Doc();
map<string, util::ParamData>& parameters = params.Parameters();
typedef map<string, util::ParamData>::iterator ParamIter;
using ParamIter = map<string, util::ParamData>::iterator;
// First, let's get a list of input and output options. We'll take two passes
// so that the required input options are the first in the list.
@@ -195,7 +195,7 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& /* timers */)
// All numeric elements should be multiplied by 3.
if (params.Has("matrix_and_info_in"))
{
typedef tuple<data::DatasetInfo, arma::mat> TupleType;
using TupleType = tuple<data::DatasetInfo, arma::mat>;
TupleType tuple = std::move(params.Get<TupleType>("matrix_and_info_in"));
const data::DatasetInfo& di = std::get<0>(tuple);
@@ -42,7 +42,7 @@ void DeleteAllocatedMemoryImpl(
const std::enable_if_t<data::HasSerialize<T>::value>* = 0)
{
// Delete the allocated memory (hopefully we actually own it).
typedef std::tuple<T*, std::string> TupleType;
using TupleType = std::tuple<T*, std::string>;
delete std::get<0>(*std::any_cast<TupleType>(&d.value));
}
@@ -44,7 +44,7 @@ void* GetAllocatedMemory(
{
// Here we have a model, which is a tuple, and we need the address of the
// memory.
typedef std::tuple<T*, std::string> TupleType;
using TupleType = std::tuple<T*, std::string>;
return std::get<0>(*std::any_cast<TupleType>(&d.value));
}
+3 -3
View File
@@ -51,7 +51,7 @@ T& GetParam(
// contains the filename. It's possible we could load empty matrices many
// times, but I am not bothered by that---it shouldn't be something that
// happens.
typedef std::tuple<T, typename ParameterType<T>::type> TupleType;
using TupleType = std::tuple<T, typename ParameterType<T>::type>;
TupleType& tuple = *std::any_cast<TupleType>(&d.value);
const std::string& value = std::get<0>(std::get<1>(tuple));
T& matrix = std::get<0>(tuple);
@@ -85,7 +85,7 @@ T& GetParam(
{
// If this is an input parameter, we need to load both the matrix and the
// dataset info.
typedef std::tuple<T, std::tuple<std::string, size_t, size_t>> TupleType;
using TupleType = std::tuple<T, std::tuple<std::string, size_t, size_t>>;
TupleType* tuple = std::any_cast<TupleType>(&d.value);
const std::string& value = std::get<0>(std::get<1>(*tuple));
T& t = std::get<0>(*tuple);
@@ -115,7 +115,7 @@ T*& GetParam(
{
// If the model is an input model, we have to load it from file. 'value'
// contains the filename.
typedef std::tuple<T*, std::string> TupleType;
using TupleType = std::tuple<T*, std::string>;
TupleType* tuple = std::any_cast<TupleType>(&d.value);
const std::string& value = std::get<1>(*tuple);
if (d.input && !d.loaded)
@@ -77,7 +77,7 @@ std::string GetPrintableParam(
std::tuple<data::DatasetInfo, arma::mat>>>* /* junk */)
{
// Extract the string from the tuple that's being held.
typedef std::tuple<T, typename ParameterType<T>::type> TupleType;
using TupleType = std::tuple<T, typename ParameterType<T>::type>;
const TupleType* tuple = std::any_cast<TupleType>(&data.value);
std::ostringstream oss;
@@ -105,7 +105,7 @@ std::string GetPrintableParam(
const std::enable_if_t<data::HasSerialize<T>::value>*)
{
// Extract the string from the tuple that's being held.
typedef std::tuple<T*, typename ParameterType<T>::type> TupleType;
using TupleType = std::tuple<T*, typename ParameterType<T>::type>;
const TupleType* tuple = std::any_cast<TupleType>(&data.value);
std::ostringstream oss;
+2 -2
View File
@@ -48,7 +48,7 @@ T& GetRawParam(
arma::mat>>>* = 0)
{
// Don't load the matrix.
typedef std::tuple<T, std::tuple<std::string, size_t, size_t>> TupleType;
using TupleType = std::tuple<T, std::tuple<std::string, size_t, size_t>>;
T& value = std::get<0>(*std::any_cast<TupleType>(&d.value));
return value;
}
@@ -63,7 +63,7 @@ T*& GetRawParam(
const std::enable_if_t<data::HasSerialize<T>::value>* = 0)
{
// Don't load the model.
typedef std::tuple<T*, std::string> TupleType;
using TupleType = std::tuple<T*, std::string>;
T*& value = std::get<0>(*std::any_cast<TupleType>(&d.value));
return value;
}
+2 -2
View File
@@ -56,7 +56,7 @@ void InPlaceCopyInternal(
= 0)
{
// Make the output filename the same as the input filename.
typedef std::tuple<T, typename ParameterType<T>::type> TupleType;
using TupleType = std::tuple<T, typename ParameterType<T>::type>;
TupleType& tuple = *std::any_cast<TupleType>(&d.value);
std::string& value = std::get<0>(std::get<1>(tuple));
@@ -78,7 +78,7 @@ void InPlaceCopyInternal(
const std::enable_if_t<data::HasSerialize<T>::value>* = 0)
{
// Make the output filename the same as the input filename.
typedef std::tuple<T*, typename ParameterType<T>::type> TupleType;
using TupleType = std::tuple<T*, typename ParameterType<T>::type>;
TupleType& tuple = *std::any_cast<TupleType>(&d.value);
std::string& value = std::get<1>(tuple);
@@ -53,7 +53,7 @@ void OutputParamImpl(
util::ParamData& data,
const std::enable_if_t<arma::is_arma_type<T>::value>*)
{
typedef std::tuple<T, std::tuple<std::string, size_t, size_t>> TupleType;
using TupleType = std::tuple<T, std::tuple<std::string, size_t, size_t>>;
const T& output = std::get<0>(*std::any_cast<TupleType>(&data.value));
const std::string& filename =
std::get<0>(std::get<1>(*std::any_cast<TupleType>(&data.value)));
@@ -77,7 +77,7 @@ void OutputParamImpl(
// The const cast is necessary here because Serialize() can't ever be marked
// const. In this case we can assume it though, since we will be saving and
// not loading.
typedef std::tuple<T*, std::string> TupleType;
using TupleType = std::tuple<T*, std::string>;
T*& output = const_cast<T*&>(std::get<0>(*std::any_cast<TupleType>(
&data.value)));
const std::string& filename =
@@ -95,7 +95,7 @@ void OutputParamImpl(
std::tuple<data::DatasetInfo, arma::mat>>>* /* junk */)
{
// Output the matrix with the mappings.
typedef std::tuple<T, std::tuple<std::string, size_t, size_t>> TupleType;
using TupleType = std::tuple<T, std::tuple<std::string, size_t, size_t>>;
const T& tuple = std::get<0>(*std::any_cast<TupleType>(&data.value));
const std::string& filename =
std::get<0>(std::get<1>(*std::any_cast<TupleType>(&data.value)));
+8 -8
View File
@@ -23,14 +23,14 @@ namespace cli {
template<bool HasSerialize, typename T>
struct ParameterTypeDeducer
{
typedef T type;
using type = T;
};
// If we have a serialize() function, then the type is a string.
template<typename T>
struct ParameterTypeDeducer<true, T>
{
typedef std::string type;
using type = std::string;
};
/**
@@ -41,8 +41,8 @@ struct ParameterTypeDeducer<true, T>
template<typename T>
struct ParameterType
{
typedef typename ParameterTypeDeducer<data::HasSerialize<T>::value, T>::type
type;
using type =
typename ParameterTypeDeducer<data::HasSerialize<T>::value, T>::type;
};
/**
@@ -53,7 +53,7 @@ struct ParameterType
template<typename eT>
struct ParameterType<arma::Col<eT>>
{
typedef std::tuple<std::string, size_t, size_t> type;
using type = std::tuple<std::string, size_t, size_t>;
};
/**
@@ -65,7 +65,7 @@ struct ParameterType<arma::Col<eT>>
template<typename eT>
struct ParameterType<arma::Row<eT>>
{
typedef std::tuple<std::string, size_t, size_t> type;
using type = std::tuple<std::string, size_t, size_t>;
};
/**
@@ -76,7 +76,7 @@ struct ParameterType<arma::Row<eT>>
template<typename eT>
struct ParameterType<arma::Mat<eT>>
{
typedef std::tuple<std::string, size_t, size_t> type;
using type = std::tuple<std::string, size_t, size_t>;
};
/**
@@ -86,7 +86,7 @@ template<typename eT, typename PolicyType>
struct ParameterType<std::tuple<mlpack::data::DatasetMapper<PolicyType,
std::string>, arma::Mat<eT>>>
{
typedef std::tuple<std::string, size_t, size_t> type;
using type = std::tuple<std::string, size_t, size_t>;
};
} // namespace cli
+2 -2
View File
@@ -62,7 +62,7 @@ void SetParam(
std::tuple<data::DatasetInfo, arma::mat>>>* = 0)
{
// We're setting the string filename.
typedef std::tuple<T, typename ParameterType<T>::type> TupleType;
using TupleType = std::tuple<T, typename ParameterType<T>::type>;
TupleType& tuple = *std::any_cast<TupleType>(&d.value);
std::get<0>(std::get<1>(tuple)) = std::any_cast<std::string>(value);
}
@@ -79,7 +79,7 @@ void SetParam(
const std::enable_if_t<data::HasSerialize<T>::value>* = 0)
{
// We're setting the string filename.
typedef std::tuple<T*, typename ParameterType<T>::type> TupleType;
using TupleType = std::tuple<T*, typename ParameterType<T>::type>;
TupleType& tuple = *std::any_cast<TupleType>(&d.value);
std::get<1>(tuple) = std::any_cast<std::string>(value);
}
@@ -377,7 +377,7 @@ void mlpackToArmaMatWithInfo(void* params,
int mlpackArmaMatWithInfoElements(void* params, const char* identifier)
{
util::Params& p = *((util::Params*) params);
typedef std::tuple<data::DatasetInfo, arma::mat> TupleType;
using TupleType = std::tuple<data::DatasetInfo, arma::mat>;
return std::get<1>(p.Get<TupleType>(identifier)).n_elem;
}
@@ -387,7 +387,7 @@ int mlpackArmaMatWithInfoElements(void* params, const char* identifier)
int mlpackArmaMatWithInfoRows(void* params, const char* identifier)
{
util::Params& p = *((util::Params*) params);
typedef std::tuple<data::DatasetInfo, arma::mat> TupleType;
using TupleType = std::tuple<data::DatasetInfo, arma::mat>;
return std::get<1>(p.Get<TupleType>(identifier)).n_rows;
}
@@ -397,7 +397,7 @@ int mlpackArmaMatWithInfoRows(void* params, const char* identifier)
int mlpackArmaMatWithInfoCols(void* params, const char* identifier)
{
util::Params& p = *((util::Params*) params);
typedef std::tuple<data::DatasetInfo, arma::mat> TupleType;
using TupleType = std::tuple<data::DatasetInfo, arma::mat>;
return std::get<1>(p.Get<TupleType>(identifier)).n_cols;
}
@@ -408,7 +408,7 @@ int mlpackArmaMatWithInfoCols(void* params, const char* identifier)
void* mlpackArmaPtrMatWithInfoPtr(void* params, const char* identifier)
{
util::Params& p = *((util::Params*) params);
typedef std::tuple<data::DatasetInfo, arma::mat> TupleType;
using TupleType = std::tuple<data::DatasetInfo, arma::mat>;
arma::mat& m = std::get<1>(p.Get<TupleType>(identifier));
if (m.is_empty())
{
+1 -1
View File
@@ -43,7 +43,7 @@ void PrintGo(util::Params& params,
const std::string& bindingName)
{
std::map<std::string, util::ParamData>& parameters = params.Parameters();
typedef std::map<std::string, util::ParamData>::iterator ParamIter;
using ParamIter = std::map<std::string, util::ParamData>::iterator;
// Split into input and output parameters. Take two passes on the input
// parameters, so that we get the required ones first.
@@ -191,7 +191,7 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& /* timer */)
// All numeric elements should be multiplied by 3.
if (params.Has("matrix_and_info_in"))
{
typedef tuple<data::DatasetInfo, arma::mat> TupleType;
using TupleType = tuple<data::DatasetInfo, arma::mat>;
TupleType tuple = std::move(params.Get<TupleType>("matrix_and_info_in"));
const data::DatasetInfo& di = std::get<0>(tuple);
+1 -1
View File
@@ -34,7 +34,7 @@ void PrintJL(const string& bindingName,
const BindingDetails& doc = p.Doc();
map<string, ParamData>& parameters = p.Parameters();
typedef map<string, ParamData>::iterator ParamIter;
using ParamIter = map<string, ParamData>::iterator;
// First, let's get a list of input and output options. We'll take two passes
// so that the required input options are the first in the list.
@@ -193,7 +193,7 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& /* timers */)
// All numeric elements should be multiplied by 3.
if (params.Has("matrix_and_info_in"))
{
typedef tuple<data::DatasetInfo, arma::mat> TupleType;
using TupleType = tuple<data::DatasetInfo, arma::mat>;
TupleType tuple = std::move(params.Get<TupleType>("matrix_and_info_in"));
const data::DatasetInfo& di = std::get<0>(tuple);
@@ -89,8 +89,8 @@ inline void SetParamWithInfo(util::Params& params,
T& matrix,
const bool* dims)
{
typedef typename std::tuple<data::DatasetInfo, T> TupleType;
typedef typename T::elem_type eT;
using TupleType = std::tuple<data::DatasetInfo, T>;
using eT = typename T::elem_type;
// The true type of the parameter is std::tuple<T, DatasetInfo>.
const size_t dimensions = matrix.n_rows;
@@ -149,7 +149,7 @@ T& GetParamWithInfo(util::Params& params,
const std::string& paramName)
{
// T will be the Armadillo type.
typedef std::tuple<data::DatasetInfo, T> TupleType;
using TupleType = std::tuple<data::DatasetInfo, T>;
return std::get<1>(params.Get<TupleType>(paramName));
}
@@ -302,7 +302,7 @@ void PrintOutputProcessing(util::ParamData& d,
const void* input,
void* /* output */)
{
typedef std::tuple<util::Params, std::tuple<size_t, bool>> TupleType;
using TupleType = std::tuple<util::Params, std::tuple<size_t, bool>>;
TupleType* tuple = (TupleType*) input;
PrintOutputProcessing<std::remove_pointer_t<T>>(
+2 -2
View File
@@ -40,7 +40,7 @@ void PrintPYX(const util::BindingDetails& doc,
util::Params params = IO::Parameters(bindingName);
std::map<std::string, util::ParamData>& parameters = params.Parameters();
typedef std::map<std::string, util::ParamData>::iterator ParamIter;
using ParamIter = std::map<std::string, util::ParamData>::iterator;
// Split into input and output parameters. Take two passes on the input
// parameters, so that we get the required ones first.
@@ -258,7 +258,7 @@ void PrintPYX(const util::BindingDetails& doc,
cout << " result = {}" << endl;
cout << endl;
typedef std::tuple<util::Params, std::tuple<size_t, bool>> TupleType;
using TupleType = std::tuple<util::Params, std::tuple<size_t, bool>>;
for (size_t i = 0; i < outputOptions.size(); ++i)
{
@@ -293,7 +293,7 @@ class TestPythonBinding(unittest.TestCase):
"""
Test a Pandas Series input paramter
"""
x = pd.Series(np.random.rand(100))
x = pd.Series(np.random.rand(100))
z = copy.deepcopy(x)
output = test_python_binding(string_in='hello',
@@ -313,7 +313,7 @@ class TestPythonBinding(unittest.TestCase):
"""
Test a Pandas Series input paramter
"""
x = pd.Series(np.random.rand(100))
x = pd.Series(np.random.rand(100))
output = test_python_binding(string_in='hello',
int_in=12,
@@ -235,7 +235,7 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& /* timer */)
// All numeric elements should be multiplied by 3.
if (params.Has("matrix_and_info_in"))
{
typedef tuple<data::DatasetInfo, arma::mat> TupleType;
using TupleType = tuple<data::DatasetInfo, arma::mat>;
TupleType tuple = std::move(params.Get<TupleType>("matrix_and_info_in"));
const data::DatasetInfo& di = std::get<0>(tuple);
@@ -26,8 +26,8 @@ class TestFunctionMap
{
public:
// Convenience typedef.
typedef std::map<std::string, std::map<std::string,
void (*)(util::ParamData&, const void*, void*)>> FunctionMapType;
using FunctionMapType = std::map<std::string, std::map<std::string,
void (*)(util::ParamData&, const void*, void*)>>;
//! Get the instantiated TestFunctionMap object.
static TestFunctionMap& GetSingleton();
@@ -22,7 +22,7 @@ namespace data {
inline void CheckCategoricalParam(util::Params& params,
const std::string& paramName)
{
typedef typename std::tuple<DatasetInfo, arma::mat> TupleType;
using TupleType = std::tuple<DatasetInfo, arma::mat>;
arma::mat& matrix = std::get<1>(params.Get<TupleType>(paramName));
// This comes from Params::CheckInputMatrix().
+2 -2
View File
@@ -170,8 +170,8 @@ class DatasetMapper
std::vector<Datatype> types;
// Forward mapping type.
using ForwardMapType = typename std::unordered_map<InputType, typename
PolicyType::MappedType>;
using ForwardMapType = std::unordered_map<InputType,
typename PolicyType::MappedType>;
// Reverse mapping type. Multiple inputs may map to a single output, hence
// the need for std::vector.
+2 -2
View File
@@ -160,8 +160,8 @@ void LoadARFF(const std::string& filename,
}
// Make sure all strings are mapped, if we have any.
typedef std::map<size_t, std::vector<std::string>>::const_iterator
IteratorType;
using IteratorType =
std::map<size_t, std::vector<std::string>>::const_iterator;
for (IteratorType it = categoryStrings.begin(); it != categoryStrings.end();
++it)
{
@@ -122,7 +122,7 @@ class IncrementPolicy
if (numMappings == 0)
types[dimension] = Datatype::categorical;
typedef typename std::pair<InputType, MappedType> PairType;
using PairType = std::pair<InputType, MappedType>;
maps[dimension].first.insert(PairType(input, numMappings));
// Do we need to create the second map?
@@ -112,7 +112,7 @@ class MissingPolicy
maps[dimension].first.count(string) == 0)
{
// This string does not exist yet.
typedef std::pair<std::string, MappedType> PairType;
using PairType = std::pair<std::string, MappedType>;
maps[dimension].first.insert(PairType(string, value));
// Insert right mapping too.
@@ -158,7 +158,7 @@ class TfIdfEncodingPolicy
InverseDocumentFrequency<typename MatType::elem_type>(
output.n_cols, numContainingStrings[value]);
output(value - 1, line) = tf * idf;
output(value - 1, line) = tf * idf;
}
/**
@@ -188,7 +188,7 @@ class TfIdfEncodingPolicy
const ElemType idf = InverseDocumentFrequency<ElemType>(
output.size(), numContainingStrings[value]);
output[line][value - 1] = tf * idf;
output[line][value - 1] = tf * idf;
}
/*
+1 -1
View File
@@ -66,7 +66,7 @@ class IoUDistance
static typename VecTypeA::elem_type Evaluate(const VecTypeA& a,
const VecTypeB& b)
{
typedef typename VecTypeA::elem_type ElemType;
using ElemType = typename VecTypeA::elem_type;
return (ElemType) (1.0 - IoU<UseCoordinates>::Evaluate(a, b));
}
+4 -4
View File
@@ -97,23 +97,23 @@ class LMetric
/**
* The Manhattan (L1) distance.
*/
typedef LMetric<1, false> ManhattanDistance;
using ManhattanDistance = LMetric<1, false>;
/**
* The squared Euclidean (L2) distance. Note that this is not technically a
* metric! But it can sometimes be used when distances are required.
*/
typedef LMetric<2, false> SquaredEuclideanDistance;
using SquaredEuclideanDistance = LMetric<2, false>;
/**
* The Euclidean (L2) distance.
*/
typedef LMetric<2, true> EuclideanDistance;
using EuclideanDistance = LMetric<2, true>;
/**
* The L-infinity distance.
*/
typedef LMetric<INT_MAX, false> ChebyshevDistance;
using ChebyshevDistance = LMetric<2147483647, false>;
} // namespace mlpack
@@ -59,7 +59,7 @@ template<bool TakeRoot = true, typename MatType = arma::mat>
class MahalanobisDistance
{
public:
typedef typename GetColType<MatType>::type VecType;
using VecType = typename GetColType<MatType>::type;
/**
* Initialize the Mahalanobis distance with the empty matrix as Q.
@@ -22,8 +22,8 @@ class DiagonalGaussianDistribution
{
public:
// Convenience typedefs.
typedef typename GetColType<MatType>::type VecType;
typedef typename MatType::elem_type ElemType;
using VecType = typename GetColType<MatType>::type;
using ElemType = typename MatType::elem_type;
private:
//! Mean of the distribution.
@@ -54,10 +54,10 @@ class DiscreteDistribution
{
public:
// Convenience typedefs.
typedef typename GetColType<MatType>::type VecType;
typedef typename MatType::elem_type ElemType;
typedef typename GetColType<ObsMatType>::type ObsVecType;
typedef typename ObsMatType::elem_type ObsType;
using VecType = typename GetColType<MatType>::type;
using ElemType = typename MatType::elem_type;
using ObsVecType = typename GetColType<ObsMatType>::type;
using ObsType = typename ObsMatType::elem_type;
/**
* Default constructor, which creates a distribution that has no
@@ -54,8 +54,8 @@ class GammaDistribution
{
public:
// Convenience typedefs.
typedef typename GetColType<MatType>::type VecType;
typedef typename MatType::elem_type ElemType;
using VecType = typename GetColType<MatType>::type;
using ElemType = typename MatType::elem_type;
/**
* Construct the Gamma distribution with the given number of dimensions
@@ -25,8 +25,8 @@ class GaussianDistribution
{
public:
// Convenience typedefs for derived types of MatType.
typedef typename GetColType<MatType>::type VecType;
typedef typename MatType::elem_type ElemType;
using VecType = typename GetColType<MatType>::type;
using ElemType = typename MatType::elem_type;
private:
//! Mean of the distribution.
@@ -52,8 +52,8 @@ class LaplaceDistribution
{
public:
// Convenience typedefs.
typedef typename GetColType<MatType>::type VecType;
typedef typename MatType::elem_type ElemType;
using VecType = typename GetColType<MatType>::type;
using ElemType = typename MatType::elem_type;
/**
* Default constructor, which creates a Laplace distribution with zero
@@ -32,9 +32,9 @@ class RegressionDistribution
{
public:
// Convenience typedefs.
typedef typename MatType::elem_type ElemType;
typedef typename GetColType<MatType>::type VecType;
typedef typename GetRowType<MatType>::type RowType;
using ElemType = typename MatType::elem_type;
using VecType = typename GetColType<MatType>::type;
using RowType = typename GetRowType<MatType>::type;
private:
//! Regression function for representing conditional mean.
@@ -58,7 +58,7 @@ class KernelTraits<CosineSimilarity>
};
// This name is deprecated and can be removed in mlpack 5.0.0.
typedef CosineSimilarity CosineDistance;
using CosineDistance = CosineSimilarity;
} // namespace mlpack
+1 -1
View File
@@ -59,7 +59,7 @@ inline arma::Mat<std::complex<T>> ColumnCovariance(
Log::Fatal << "ColumnCovariance(): normType must be 0 or 1" << std::endl;
}
typedef typename std::complex<T> eT;
using eT = std::complex<T>;
arma::Mat<eT> out;
+1 -1
View File
@@ -65,7 +65,7 @@ typename T::elem_type AccuLog(const T& x)
if (maxVal == -std::numeric_limits<typename T::elem_type>::infinity())
return maxVal;
return maxVal + std::log(sum(exp(x - maxVal)));;
return maxVal + std::log(sum(exp(x - maxVal)));
}
/**
+2 -1
View File
@@ -17,7 +17,8 @@ namespace mlpack {
/**
* Overwrites a dimension-N vector to a random vector on the unit sphere in R^N.
*/
inline void RandVector(arma::vec& v)
template<typename eT>
inline void RandVector(arma::Col<eT>& v)
{
for (size_t i = 0; i + 1 < v.n_elem; i += 2)
{
+1 -1
View File
@@ -17,7 +17,7 @@ namespace mlpack {
template<typename T>
class RangeType;
typedef RangeType<double> Range;
using Range = RangeType<double>;
/**
* Simple real-valued range. It contains an upper and lower bound.
+1 -1
View File
@@ -53,7 +53,7 @@ ElemType BLEU<ElemType, PrecisionType>::Evaluate(
{
// WordVector is a string container type.
// Also, TranslationCorpusType is an array of such containers.
typedef typename TranslationCorpusType::value_type WordVector;
using WordVector = typename TranslationCorpusType::value_type;
// matchesByOrder: It catches how many times sequence of a particular order
// is encountered in both reference corpus and translation corpus.
@@ -83,7 +83,7 @@ void NMS<UseCoordinates>::Evaluate(
sortedIndices);
BoundingBoxesType x1 = boundingBoxes.submat(arma::uvec(1).fill(0),
sortedIndices);;
sortedIndices);
BoundingBoxesType y2 = boundingBoxes.submat(arma::uvec(1).fill(3),
sortedIndices);
+8 -8
View File
@@ -54,11 +54,11 @@ namespace mlpack {
template<typename AddressType, typename VecType>
void PointToAddress(AddressType& address, const VecType& point)
{
typedef typename VecType::elem_type VecElemType;
using VecElemType = typename VecType::elem_type;
// Check that the arguments are compatible.
typedef std::conditional_t<sizeof(VecElemType) * CHAR_BIT <= 32,
uint32_t,
uint64_t> AddressElemType;
using AddressElemType =
std::conditional_t<sizeof(VecElemType) * CHAR_BIT <= 32,
uint32_t, uint64_t>;
static_assert(std::is_same_v<typename AddressType::elem_type,
AddressElemType> == true, "The vector element type does not "
@@ -150,11 +150,11 @@ void PointToAddress(AddressType& address, const VecType& point)
template<typename AddressType, typename VecType>
void AddressToPoint(VecType& point, const AddressType& address)
{
typedef typename VecType::elem_type VecElemType;
using VecElemType = typename VecType::elem_type;
// Check that the arguments are compatible.
typedef std::conditional_t<sizeof(VecElemType) * CHAR_BIT <= 32,
uint32_t,
uint64_t> AddressElemType;
using AddressElemType =
std::conditional_t<sizeof(VecElemType) * CHAR_BIT <= 32,
uint32_t, uint64_t>;
static_assert(std::is_same_v<typename AddressType::elem_type,
AddressElemType> == true, "The vector element type does not "
+1 -1
View File
@@ -33,7 +33,7 @@ class BallBound
{
public:
//! A public version of the vector type.
typedef VecType Vec;
using Vec = VecType;
private:
//! The radius of the ball bound.
@@ -55,11 +55,11 @@ class BinarySpaceTree
{
public:
//! So other classes can use TreeType::Mat.
typedef MatType Mat;
using Mat = MatType;
//! The type of element held in MatType.
typedef typename MatType::elem_type ElemType;
using ElemType = typename MatType::elem_type;
typedef SplitType<BoundType<DistanceType, ElemType>, MatType> Split;
using Split = SplitType<BoundType<DistanceType, ElemType>, MatType>;
private:
//! The left child node.
@@ -50,8 +50,8 @@ class BinarySpaceTree<DistanceType, StatisticType, MatType, BoundType,
*/
BreadthFirstDualTreeTraverser(RuleType& rule);
typedef QueueFrame<BinarySpaceTree, typename RuleType::TraversalInfoType>
QueueFrameType;
using QueueFrameType =
QueueFrame<BinarySpaceTree, typename RuleType::TraversalInfoType>;
/**
* Traverse the two trees. This does not reset the number of prunes.
@@ -32,7 +32,7 @@ class RPTreeMaxSplit
{
public:
//! The element type held by the matrix type.
typedef typename MatType::elem_type ElemType;
using ElemType = typename MatType::elem_type;
//! An information about the partition.
struct SplitInfo
{
@@ -32,7 +32,7 @@ class RPTreeMeanSplit
{
public:
//! The element type held by the matrix type.
typedef typename MatType::elem_type ElemType;
using ElemType = typename MatType::elem_type;
//! An information about the partition.
struct SplitInfo
{
@@ -18,11 +18,11 @@
namespace mlpack {
template<typename BoundType, typename MatType>
bool RPTreeMeanSplit<BoundType, MatType>::SplitNode(const BoundType& bound,
MatType& data,
const size_t begin,
const size_t count,
SplitInfo& splitInfo)
bool RPTreeMeanSplit<BoundType, MatType>::SplitNode(const BoundType& bound,
MatType& data,
const size_t begin,
const size_t count,
SplitInfo& splitInfo)
{
const size_t maxNumSamples = 100;
const size_t numSamples = std::min(maxNumSamples, count);
@@ -232,8 +232,9 @@ using VPTree = BinarySpaceTree<DistanceType,
*
* @see @ref trees, BinarySpaceTree, BallTree, MeanSplitKDTree
*/
template<typename DistanceType, typename StatisticType, typename MatType>
template<typename DistanceType = EuclideanDistance,
typename StatisticType = EmptyStatistic,
typename MatType = arma::mat>
using MaxRPTree = BinarySpaceTree<DistanceType,
StatisticType,
MatType,
@@ -267,7 +268,9 @@ using MaxRPTree = BinarySpaceTree<DistanceType,
*
* @see @ref trees, BinarySpaceTree, BallTree, MeanSplitKDTree
*/
template<typename DistanceType, typename StatisticType, typename MatType>
template<typename DistanceType = EuclideanDistance,
typename StatisticType = EmptyStatistic,
typename MatType = arma::mat>
using RPTree = BinarySpaceTree<DistanceType,
StatisticType,
MatType,
@@ -29,10 +29,9 @@ class UBTreeSplit
{
public:
//! The type of an address element.
typedef std::conditional_t<
using AddressElemType = std::conditional_t<
sizeof(typename MatType::elem_type) * CHAR_BIT <= 32,
uint32_t,
uint64_t> AddressElemType;
uint32_t, uint64_t>;
//! An information about the partition.
struct SplitInfo
@@ -32,9 +32,9 @@ class VantagePointSplit
{
public:
//! The matrix element type.
typedef typename MatType::elem_type ElemType;
using ElemType = typename MatType::elem_type;
//! The bounding shape type.
typedef typename BoundType::DistanceType DistanceType;
using DistanceType = typename BoundType::DistanceType;
//! A struct that contains an information about the split.
struct SplitInfo
{
+2 -3
View File
@@ -76,9 +76,8 @@ class CellBound
public:
//! Depending on the precision of the tree element type, we may need to use
//! uint32_t or uint64_t.
typedef std::conditional_t<sizeof(ElemType) * CHAR_BIT <= 32,
uint32_t,
uint64_t> AddressElemType;
using AddressElemType = std::conditional_t<sizeof(ElemType) * CHAR_BIT <= 32,
uint32_t, uint64_t>;
/**
* Empty constructor; creates a bound of dimensionality 0.
@@ -32,7 +32,7 @@ template<typename MatType = arma::mat>
class CosineTree
{
public:
typedef typename GetDenseColType<MatType>::type VecType;
using VecType = typename GetDenseColType<MatType>::type;
/**
* CosineTree constructor for the root node of the tree. It initializes the
@@ -99,9 +99,9 @@ class CoverTree
{
public:
//! So that other classes can access the matrix type.
typedef MatType Mat;
using Mat = MatType;
//! The type held by the matrix type.
typedef typename MatType::elem_type ElemType;
using ElemType = typename MatType::elem_type;
/**
* Create the cover tree with the given dataset and given base.
@@ -72,8 +72,8 @@ SingleTreeTraverser<RuleType>::Traverse(
{
// This is a non-recursive implementation (which should be faster than a
// recursive implementation).
typedef CoverTreeMapEntry<DistanceType, StatisticType, MatType,
RootPointPolicy> MapEntryType;
using MapEntryType = CoverTreeMapEntry<DistanceType, StatisticType, MatType,
RootPointPolicy>;
// We will use this map as a priority queue. Each key represents the scale,
// and then the vector is all the nodes in that scale which need to be
+1 -1
View File
@@ -33,7 +33,7 @@ class HollowBallBound
{
public:
//! A public version of the metric type.
typedef TDistanceType DistanceType;
using DistanceType = TDistanceType;
private:
//! The inner and the outer radii of the bound.
+2 -2
View File
@@ -25,9 +25,9 @@ class Octree
{
public:
//! So other classes can use TreeType::Mat.
typedef MatType Mat;
using Mat = MatType;
//! The type of element held in MatType.
typedef typename MatType::elem_type ElemType;
using ElemType = typename MatType::elem_type;
//! A single-tree traverser; see single_tree_traverser.hpp.
template<typename RuleType>
@@ -30,9 +30,9 @@ class DiscreteHilbertValue
public:
//! Depending on the precision of the tree element type, we may need to use
//! uint32_t or uint64_t.
typedef std::conditional_t<sizeof(TreeElemType) * CHAR_BIT <= 32,
uint32_t,
uint64_t> HilbertElemType;
using HilbertElemType =
std::conditional_t<sizeof(TreeElemType) * CHAR_BIT <= 32,
uint32_t, uint64_t>;
//! Default constructor.
DiscreteHilbertValue();
@@ -152,7 +152,7 @@ DiscreteHilbertValue<TreeElemType>::
CalculateValue(const VecType& pt,
typename std::enable_if_t<IsVector<VecType>::value>*)
{
typedef typename VecType::elem_type VecElemType;
using VecElemType = typename VecType::elem_type;
arma::Col<HilbertElemType> res(pt.n_rows);
// Calculate the number of bits for the exponent.
const int numExpBits = std::ceil(std::log2(
@@ -22,7 +22,7 @@ class HilbertRTreeAuxiliaryInformation
{
public:
//! The element type held by the tree.
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
//! Default constructor
HilbertRTreeAuxiliaryInformation();
@@ -33,7 +33,7 @@ class MinimalCoverageSweep
template<typename TreeType>
struct SweepCost
{
typedef typename TreeType::ElemType type;
using type = typename TreeType::ElemType;
};
/**
@@ -24,8 +24,8 @@ SweepNonLeafNode(const size_t axis,
const TreeType* node,
typename TreeType::ElemType& axisCut)
{
typedef typename TreeType::ElemType ElemType;
typedef HRectBound<EuclideanDistance, ElemType> BoundType;
using ElemType = typename TreeType::ElemType;
using BoundType = HRectBound<EuclideanDistance, ElemType>;
std::vector<std::pair<ElemType, size_t>> sorted(node->NumChildren());
@@ -88,8 +88,8 @@ SweepLeafNode(const size_t axis,
const TreeType* node,
typename TreeType::ElemType& axisCut)
{
typedef typename TreeType::ElemType ElemType;
typedef HRectBound<EuclideanDistance, ElemType> BoundType;
using ElemType = typename TreeType::ElemType;
using BoundType = HRectBound<EuclideanDistance, ElemType>;
std::vector<std::pair<ElemType, size_t>> sorted(node->Count());
@@ -34,7 +34,7 @@ class MinimalSplitsNumberSweep
template<typename>
struct SweepCost
{
typedef size_t type;
using type = size_t;
};
/**
@@ -24,7 +24,7 @@ size_t MinimalSplitsNumberSweep<SplitPolicy>::SweepNonLeafNode(
const TreeType* node,
typename TreeType::ElemType& axisCut)
{
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
std::vector<std::pair<ElemType, size_t>> sorted(node->NumChildren());
@@ -24,9 +24,9 @@ class RPlusPlusTreeAuxiliaryInformation
{
public:
//! The element type held by the tree.
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
//! The bound type held by the auxiliary information.
typedef HRectBound<EuclideanDistance, ElemType> BoundType;
using BoundType = HRectBound<EuclideanDistance, ElemType>;
//! Construct the auxiliary information object.
RPlusPlusTreeAuxiliaryInformation();
@@ -104,7 +104,7 @@ void RPlusPlusTreeAuxiliaryInformation<TreeType>::SplitAuxiliaryInfo(
const size_t axis,
const typename TreeType::ElemType cut)
{
typedef HRectBound<EuclideanDistance, ElemType> Bound;
using Bound = HRectBound<EuclideanDistance, ElemType>;
Bound& treeOneBound = treeOne->AuxiliaryInfo().OuterBound();
Bound& treeTwoBound = treeTwo->AuxiliaryInfo().OuterBound();
@@ -22,7 +22,7 @@ template<typename TreeType>
size_t RPlusTreeDescentHeuristic::ChooseDescentNode(TreeType* node,
const size_t point)
{
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
size_t bestIndex = 0;
bool success = true;
@@ -31,7 +31,7 @@ template<typename SplitPolicyType,
class RPlusTreeSplit
{
public:
typedef SplitPolicyType SplitPolicy;
using SplitPolicy = SplitPolicyType;
/**
* Split a leaf node using the "default" algorithm. If necessary, this split
* will propagate upwards through the tree.
@@ -25,7 +25,7 @@ template<typename TreeType>
void RPlusTreeSplit<SplitPolicyType, SweepType>::
SplitLeafNode(TreeType* tree, std::vector<bool>& relevels)
{
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
if (tree->Count() == 1)
{
@@ -122,7 +122,7 @@ template<typename TreeType>
bool RPlusTreeSplit<SplitPolicyType, SweepType>::
SplitNonLeafNode(TreeType* tree, std::vector<bool>& relevels)
{
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
// If we are splitting the root node, we need will do things differently so
// that the constructor and other methods don't confuse the end user by giving
// an address of another node.
@@ -333,9 +333,8 @@ PartitionNode(const TreeType* node, size_t& minCutAxis,
return false; // No partition required.
// Define the type of the sweep cost.
typedef typename
SweepType<SplitPolicyType>::template SweepCost<TreeType>::type
SweepCostType;
using SweepCostType = typename
SweepType<SplitPolicyType>::template SweepCost<TreeType>::type;
SweepCostType minCost = std::numeric_limits<SweepCostType>::max();
minCutAxis = node->Bound().Dim();
@@ -23,7 +23,7 @@ inline size_t RStarTreeDescentHeuristic::ChooseDescentNode(
const size_t point)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
bool tiedOne = false;
std::vector<ElemType> originalScores(node->NumChildren());
@@ -164,7 +164,7 @@ inline size_t RStarTreeDescentHeuristic::ChooseDescentNode(
const TreeType* insertedNode)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
std::vector<ElemType> scores(node->NumChildren());
std::vector<ElemType> vols(node->NumChildren());
@@ -28,7 +28,7 @@ size_t RStarTreeSplit::ReinsertPoints(TreeType* tree,
std::vector<bool>& relevels)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
// Check if we need to reinsert.
if (relevels[tree->TreeDepth() - 1])
@@ -83,8 +83,8 @@ void RStarTreeSplit::PickLeafSplit(TreeType* tree,
size_t& bestIndex)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
typedef HRectBound<EuclideanDistance, ElemType> BoundType;
using ElemType = typename TreeType::ElemType;
using BoundType = HRectBound<EuclideanDistance, ElemType>;
bestAxis = 0;
bestIndex = 0;
@@ -176,7 +176,7 @@ template<typename TreeType>
void RStarTreeSplit::SplitLeafNode(TreeType *tree, std::vector<bool>& relevels)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
// If there's no need to split, don't.
if (tree->Count() <= tree->MaxLeafSize())
@@ -272,8 +272,8 @@ bool RStarTreeSplit::SplitNonLeafNode(
std::vector<bool>& relevels)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
typedef HRectBound<EuclideanDistance, ElemType> BoundType;
using ElemType = typename TreeType::ElemType;
using BoundType = HRectBound<EuclideanDistance, ElemType>;
// Reinsertion isn't done for non-leaf nodes; the paper doesn't seem to make
// it clear how to reinsert an entire node without reinserting each of the
@@ -22,7 +22,7 @@ inline size_t RTreeDescentHeuristic::ChooseDescentNode(const TreeType* node,
const size_t point)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
ElemType minScore = std::numeric_limits<ElemType>::max();
int bestIndex = 0;
@@ -66,7 +66,7 @@ inline size_t RTreeDescentHeuristic::ChooseDescentNode(
const TreeType* insertedNode)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
ElemType minScore = std::numeric_limits<ElemType>::max();
int bestIndex = 0;
@@ -195,7 +195,7 @@ template<typename TreeType>
void RTreeSplit::GetBoundSeeds(const TreeType *tree, int& iRet, int& jRet)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
ElemType worstPairScore = -1.0;
for (size_t i = 0; i < tree->NumChildren(); ++i)
@@ -230,7 +230,7 @@ void RTreeSplit::AssignPointDestNode(TreeType* oldTree,
const int intJ)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
size_t end = oldTree->Count();
@@ -366,7 +366,7 @@ void RTreeSplit::AssignNodeDestNode(TreeType* oldTree,
const int intJ)
{
// Convenience typedef.
typedef typename TreeType::ElemType ElemType;
using ElemType = typename TreeType::ElemType;
size_t end = oldTree->NumChildren();
assert(end > 1); // If this isn't true, the tree is really weird.
@@ -58,11 +58,11 @@ class RectangleTree
public:
//! So other classes can use TreeType::Mat.
typedef MatType Mat;
using Mat = MatType;
//! The element type held by the matrix type.
typedef typename MatType::elem_type ElemType;
using ElemType = typename MatType::elem_type;
//! The auxiliary information type held by the tree.
typedef AuxiliaryInformationType<RectangleTree> AuxiliaryInformation;
using AuxiliaryInformation = AuxiliaryInformationType<RectangleTree>;
private:
//! The max number of child nodes a non-leaf node can have.
size_t maxNumChildren;
@@ -165,7 +165,7 @@ class XTreeAuxiliaryInformation
* The X tree requires that the tree records it's "split history". To make
* this easy, we use the following structure.
*/
typedef struct SplitHistoryStruct
struct SplitHistoryStruct
{
int lastDimension;
std::vector<bool> history;
@@ -201,7 +201,7 @@ class XTreeAuxiliaryInformation
ar(CEREAL_NVP(lastDimension));
ar(CEREAL_NVP(history));
}
} SplitHistoryStruct;
};
private:
//! The max number of child nodes a non-leaf normal node can have.

Some files were not shown because too many files have changed in this diff Show More