Many machine learning methods operate with some sort of metric, and often, this metric can be any arbitrary metric. For instance, consider the problem of nearest neighbor search; one can find the nearest neighbor of a point with respect to the standard Euclidean distance, or the Manhattan (city-\/block) distance. The actual search techniques, though, remain the same. And this is true of many machine learning methods\+: the specific metric that is used can be any valid metric.

mlpack algorithms, when possible, allow the use of an arbitrary metric via the use of the {\ttfamily Metric\+Type} template parameter. Any metric passed as a {\ttfamily Metric\+Type} template parameter will need to have


\begin{DoxyItemize}
\item an {\ttfamily Evaluate} function
\item a default constructor.
\end{DoxyItemize}

The signature of the {\ttfamily Evaluate} function is straightforward\+:


\begin{DoxyCode}
\textcolor{keyword}{template}<\textcolor{keyword}{typename} VecTypeA, \textcolor{keyword}{typename} VecTypeB>
\textcolor{keywordtype}{double} Evaluate(\textcolor{keyword}{const} VecTypeA& a, \textcolor{keyword}{const} VecTypeB& b);
\end{DoxyCode}


The function takes two vector arguments, {\ttfamily a} and {\ttfamily b}, and returns a {\ttfamily double} that is the evaluation of the metric between the two arguments. So, for a particular metric $d(\cdot, \cdot)$, the {\ttfamily Evaluate()} function should return $d(a, b)$.

The arguments {\ttfamily a} and {\ttfamily b}, of types {\ttfamily Vec\+TypeA} and {\ttfamily Vec\+TypeB}, respectively, will be an Armadillo-\/like vector type (usually {\ttfamily arma\+::vec}, {\ttfamily arma\+::sp\+\_\+vec}, or similar). In general it should be valid to assume that {\ttfamily Vec\+TypeA} is a class with the same A\+PI as {\ttfamily arma\+::vec}.

Note that for metrics that do not hold any state, the {\ttfamily Evaluate()} method can be marked as {\ttfamily static}.

Overall, the {\ttfamily Metric\+Type} template policy is quite simple (much like the \doxyref{The Kernel\+Type policy in mlpack}{p.}{kernels} Kernel\+Type policy). Below is an example metric class, which implements the L2 distance\+:


\begin{DoxyCode}
\textcolor{keyword}{class }ExampleMetric
\{
  \textcolor{comment}{// Default constructor is required.}
  ExampleMetric() \{ \}

  \textcolor{comment}{// The example metric holds no state, so we can mark Evaluate() as static.}
  \textcolor{keyword}{template}<\textcolor{keyword}{typename} VecTypeA, \textcolor{keyword}{typename} VecTypeB>
  \textcolor{keyword}{static} \textcolor{keywordtype}{double} Evaluate(\textcolor{keyword}{const} VecTypeA& a, \textcolor{keyword}{const} VecTypeB& b)
  \{
    \textcolor{comment}{// Return the L2 norm of the difference between the points, which is the}
    \textcolor{comment}{// same as the L2 distance.}
    \textcolor{keywordflow}{return} arma::norm(a - b);
  \}
\};
\end{DoxyCode}


Then, this metric can easily be used inside of other mlpack algorithms. For example, the code below runs range search on a random dataset with the {\ttfamily Example\+Kernel}, by instantiating a {\ttfamily \doxyref{mlpack\+::range\+::\+Range\+Search}{p.}{classmlpack_1_1range_1_1RangeSearch}} object that uses the {\ttfamily Example\+Kernel}. Then, the number of results are printed. The {\ttfamily Range\+Search} class takes three template parameters\+: {\ttfamily Metric\+Type}, {\ttfamily Mat\+Type}, and {\ttfamily Tree\+Type}. (All three have defaults, so we will just leave {\ttfamily Mat\+Type} and {\ttfamily Tree\+Type} to their defaults.)


\begin{DoxyCode}
\textcolor{preprocessor}{#include <mlpack/core.hpp>}
\textcolor{preprocessor}{#include <mlpack/methods/range_search/range_search.hpp>}
\textcolor{preprocessor}{#include "example\_metric.hpp"} \textcolor{comment}{// A file that contains ExampleKernel.}

\textcolor{keyword}{using namespace }mlpack;
\textcolor{keyword}{using namespace }mlpack::range;
\textcolor{keyword}{using namespace }std;

\textcolor{keywordtype}{int} main()
\{
  \textcolor{comment}{// Create a random dataset with 10 dimensions and 5000 points.}
  arma::mat data = arma::randu<arma::mat>(10, 5000);

  \textcolor{comment}{// Instantiate the RangeSearch object with the ExampleKernel.}
  RangeSearch<ExampleKernel> rs(data);

  \textcolor{comment}{// These vectors will store the results.}
  vector<vector<size\_t>> neighbors;
  vector<vector<double>> distances;

  \textcolor{comment}{// Create a random 10-dimensional query point.}
  arma::vec query = arma::randu<arma::vec>(10);

  \textcolor{comment}{// Find those points with distance (according to ExampleMetric) between 1 and}
  \textcolor{comment}{// 2 from the query point.}
  rs.Search(query, math::Range(1.0, 2.0), neighbors, distances);

  \textcolor{comment}{// Now, print the number of points inside the desired range.  We know that}
  \textcolor{comment}{// neighbors and distances will have length 1, since there was only one query}
  \textcolor{comment}{// point.}
  cout << neighbors[0].size() << \textcolor{stringliteral}{" points within the range [1.0, 2.0] of the "}
      << \textcolor{stringliteral}{"query point!"} << endl;
\}
\end{DoxyCode}


mlpack comes with a number of pre-\/written metrics that satisfy the {\ttfamily Metric\+Type} policy\+:


\begin{DoxyItemize}
\item \doxyref{mlpack\+::metric\+::\+Manhattan\+Distance}{p.}{namespacemlpack_1_1metric_a70063851fc04406ab432862576463215}
\item \doxyref{mlpack\+::metric\+::\+Euclidean\+Distance}{p.}{namespacemlpack_1_1metric_a0306f114fdf32dcdfa8f015408cfc37d}
\item \doxyref{mlpack\+::metric\+::\+Chebyshev\+Distance}{p.}{namespacemlpack_1_1metric_ad0e0d71e65dddac145245399cb7b0b15}
\item \doxyref{mlpack\+::metric\+::\+Mahalanobis\+Distance}{p.}{classmlpack_1_1metric_1_1MahalanobisDistance}
\item \doxyref{mlpack\+::metric\+::\+L\+Metric}{p.}{classmlpack_1_1metric_1_1LMetric} (for arbitrary L-\/metrics)
\item \doxyref{mlpack\+::metric\+::\+I\+P\+Metric}{p.}{classmlpack_1_1metric_1_1IPMetric} (requires a \doxyref{Kernel\+Type}{p.}{kernels} parameter) 
\end{DoxyItemize}