From fa0d5cb6f6a23677dfd61b7d43c94e981781d0a1 Mon Sep 17 00:00:00 2001 From: nadeem Date: Fri, 25 Jan 2008 06:52:29 +0000 Subject: [PATCH] Updated documentation --- .../FASTlib_manual/FASTlibManual_v0.tex | 699 +++++++++++------- .../u/nadeem/FASTlib_manual/Fastlib_Archi.png | Bin 29243 -> 29142 bytes fastlib/u/nadeem/FASTlib_manual/fastlib.bib | 107 +++ 3 files changed, 557 insertions(+), 249 deletions(-) create mode 100644 fastlib/u/nadeem/FASTlib_manual/fastlib.bib diff --git a/fastlib/u/nadeem/FASTlib_manual/FASTlibManual_v0.tex b/fastlib/u/nadeem/FASTlib_manual/FASTlibManual_v0.tex index 700b259c3f..a48b756204 100755 --- a/fastlib/u/nadeem/FASTlib_manual/FASTlibManual_v0.tex +++ b/fastlib/u/nadeem/FASTlib_manual/FASTlibManual_v0.tex @@ -1,10 +1,25 @@ \documentclass[letter]{report} -\usepackage{graphicx, subfigure, epsfig} +\usepackage{amsthm,amsmath,amssymb,bm,epic,geometry, graphicx, subfigure, epsfig} \oddsidemargin -0.25in \textwidth 6.5in %\newcommand {\linespace}{\renewcommand{\baselinestretch}{2}} %\linespace +\newtheorem{thm}{Theorem}[section] +\newtheorem{cor}[thm]{Corollary} +\newtheorem{lem}[thm]{Lemma} +\newtheorem{defn}[thm]{Definition} + +\DeclareGraphicsRule{.tif}{png}{.png}{`convert #1 `dirname #1`/`basename #1 .tif`.png} + +\newcommand{\spcA}{\hspace*{0in}} +\newcommand{\spcB}{\hspace*{.1in}} +\newcommand{\spcC}{\hspace*{.2in}} +\newcommand{\spcD}{\hspace*{.3in}} +\newcommand{\spcE}{\hspace*{.4in}} +\newcommand{\spcF}{\hspace*{.5in}} +\newcommand{\spcG}{\hspace*{.6in}} + \begin {document} @@ -13,11 +28,15 @@ %\renewcommand{\baselinestretch}{1} \large \bf FASTlib Design and Development Manual\\ -\normalsize version 0.1\\ +\normalsize version 0.1\footnote{ +NOTE: Please note that this is a draft document and it is undergoing intensive revision at this time. While it provides a good and reasonably accurate insight into FASTlib and MLPack, it is by no means complete and some details may change as this document and the library are packaged for public release. +}\\ \large \bf Fundamental Algorithmic and Statistical Tools (FAST) Lab\\ Georgia Institute of Technology\\ -Atlanta, GA +Atlanta, GA\\ +Dated: \today \end{center} + \end{titlepage} \tableofcontents @@ -30,7 +49,7 @@ learning methods. Its primary design goals are to be versatile, easy to use, and as fast as possible while still avoiding the worst problems of developing in a low-level language. Special emphasis is given to scalable computation, including algorithms for generalized -$N$-body problems \cite{gray_nips2000} and some support for +$N$-body problems \cite{gray2000nbp} and some support for parallelization. Library components are designed to be modular, facilitating their use as subcomputations of other algorithms. Further, FASTlib aims to permit rapid, distributed development in an @@ -76,7 +95,7 @@ applications. Our aim with FASTlib is to meet this demand by providing high-performance implementations for numerical and machine learning methods united by an effective, portable, and consistent API. We link to other libraries when appropriate---for instance, we defer to -BLAS/LAPACK for (dense) linear algebra---but provide wrappers in order +BLAS/LAPACK \cite{anderson1999lug} for (dense) linear algebra---but provide wrappers in order to standardize and simplify use---finding singular values in LAPACK involves fourteen parameters, while we need only two. For the most part, though, FASTlib directly implements methods of interest in an @@ -137,12 +156,6 @@ sketch, this path is as follows: everyone's needs. \end{enumerate} -\begin {figure*}[h] -\includegraphics[width=7in,height=5.25in]{Fastlib_Archi.png} -\caption{ Overall Organization of the different components of FASTlib} -\label{fastlib_archi} -\end{figure*} - \section{Why do I want to use FASTlib?} Maybe you have an application for an ``out of box'' method, but other toolkits are too slow. Maybe you have an algorithm you'd like to @@ -153,9 +166,46 @@ want to make your work available to a community that values fast yet flexible solutions. FASTlib is posed to help with all of these scenarios, so if any of them sound like you, give us a try! -\chapter {Code Development in FASTlib} +\section{Overall organization and key supported features} + +As mentioned earlier, the library is organized in a modular fashion and it uses the proven and established open source libraries for low-level linear algebra routines. Figure \ref{fastlib_archi} shows the overall organization of the library. As of writing of this document, FASTlib supports the following key functionality and methods: + +\begin{enumerate} +\item Templated classes for data structures for vectors, matrices, trees, sparse vectors and matrices etc. +\item An extensive set of basic and expert versions of linear algebra methods. Majority of these act as wrappers for LAPACK routines and provide simple interface for linear algebra operations. +\item Support for sparse linear algebra through the trilinos library \cite{heroux2005otp}. +\item THOR (Tree High-Order Reduce) framework. THOR is a mechanism for parallelizing dual-tree algorithms. More details and references are provided in the next chapter. +\item Extensive compilation and debugging infrastructure to help with development using FASTlib. +\item methods for data storage and manipulation, memory management, serialization. +\item MLPack - collection of machine learning algorithms that can be compiled to either run stand-alone or to be linked as libraries to other software. Following methods are currently supported: + \begin{itemize} + \item Dual-tree based Nearest Neigbour classifier + \item Mixture of Guassian using L2E and EM algorithms + \item Naive Bayes Classifier + \item Support Vector Machine classifier trained using SMO + \item Support Vector Machine with Non-negativity constrained wights + \item Hidden Markov Model + \item Kalman Filter \cite {kai2000le} + \item ICA using FastICA algorithm \cite{hyvarinen1999far} and ICA using Infomax method \cite{bell95} + \item Kernel PCA + \item Kernel Density Estimator - 5 different variants of fast methods for KDE + \item Naive and tree-based algorithms for orthogonal range search. More details in the next chapter. + \item Dual-tree version of Bor\r{u}vka's algorithm for finding minimum spanning trees + \end{itemize} +\end{enumerate} + + +\begin {figure*}[ht] +\begin{center} +\includegraphics[width=5in]{Fastlib_Archi.png} +\vspace{-0.4in} +\caption{ Overall Organization of the different components of FASTlib} +\label{fastlib_archi} +\end{center} +\end{figure*} + +\chapter {Obtaining and Using FASTlib} -\section{Obtaining and Building FASTlib} FASTlib is intended to be multi-platform, though (without extension) it relies heavily on the command line; much of the below assumes a Linux-like interface. We have tested compilation on the following @@ -204,41 +254,390 @@ the end of the output, you should see to be easy. \section {Code Organization} -The following is subject to some reorganization while FASTlib is still -in its earliest versions, but for now FASTlib is arranged as follows: +The following summarizes the current code organization of FASTlib + \begin{itemize} -\item Core Libraries + +\item - Core Library \begin{itemize} - \item \verb@base/@ - compiler abstractions, debugging, and memory management - \item \verb@fx/@ - FASTexec client library for managing parameters, timers, and results - \item \verb@col/@ - templated storage types (dynamic arrays, heaps, etc.) - \item \verb@data/@ - data set types and utilities - \item \verb@file/@ - file reading, writing, and tokenization - \item \verb@math/@ - a collection of math utilities, to be extended as needed - \item \verb@la/@ - linear algebra routines (mostly a wrapper for BLAS/LAPACK) - \item \verb@sparse/@ - sparse linear algebra routines (mostly a wrapper for Trilinos) - \item \verb@trilinos/@ - includes needed for Trilinos - \item \verb@tree/@ - utilities to build and manage $kd$-trees, among others - \item \verb@par/@ - rudimentary parallelization utilities - \item \verb@thor/@ - templated, parallelized algorithm for GNPs - \item \verb@fastlib/@ - wraps the rest of the library into one convenient include + \item \verb@fastlib/@ wraps the rest of the library into one convenient include + \begin{itemize} + \item \verb@base/ @- compiler abstractions, debugging, and memory management + \item \verb@col/ @- templated storage types (dynamic arrays, heaps, etc.) + \item \verb@data/ @- data set types and utilities + \item \verb@fx/ @- FASTexec client library for managing parameters, timers, and results + \item \verb@file/ @- file reading, writing, and tokenization + \item \verb@la/ @- linear algebra routines (mostly a wrapper for BLAS/LAPACK) + \item \verb@math/ @- a collection of math utilities, to be extended as needed + \item \verb@par/ @- rudimentary parallelization utilities + \item \verb@sparse/ @- sparse linear algebra routines (mostly a wrapper for Trilinos) + \begin{itemize} + \item \verb@trilinos/@ - includes needed for Trilinos + \end{itemize} + \item \verb@thor/ @- templated, parallelized algorithm for GNPs + \item \verb@tree/ @- utilities to build and manage $kd$-trees, among others. + \end{itemize} + \end{itemize} +\item Toolbox of machine learning methods- this is a growing list and the listing below is incomplete as of this writing. + \begin{itemize} + \item \verb@MLPack/@ + \begin{itemize} + \item \verb@allknn/ @- Dual-tree based Nearest Neigbour classifier + \item \verb@mog_l2e/ @- Mixture of Guassian using L2E + \item \verb@mog_em/ @- Mixture of Guassian using EM + \item \verb@nbc/ @- Naive Bayes Classifier + \item \verb@svm/ @- Support Vector Machine classifier trained using SMO + \item \verb@nnsvm/ @- Support Vector Machine with Non-negativity constrained wights + \item \verb@hmm/ @- Hidden Markov Model + \item \verb@kalman/ @- Kalman Filter + \item \verb@infomax_ica/ @- ICA using Infomax method + \item \verb@fastica/ @- ICA using FastICA algorithm + \item more $\cdots$ + \end{itemize} \end{itemize} \item Community-build Code \begin {itemize} - \item \verb@u/@ - the user directory, which contains individual developers' directories + \item \verb@contrib/@ - the user directory, which contains individual developers' directories. \end {itemize} \item Other \begin {itemize} - \item \verb@script/@ - scripts for compiling code, running experiments, etc. - \item \verb@util/@ - additional utilities that may assist FASTlib development - \item \verb@bin/@ - files generated by compilation; \verb@make clean@ deletes this - \item \verb@bin_keep/@ - compiled binaries that should not be cleaned, such as BLAS/LAPACK + \item \verb@bin/ @- files generated by compilation; \verb@make clean@ deletes this + \item \verb@bin_keep/ @- compiled binaries that should not be cleaned, such as BLAS/LAPACK + \item \verb@doc/ @- All documentation, including the Doxygen generated ones are here + \item \verb@examples/ @- Example code and tutorial(s) for using FASTlib library and MLPack + \item \verb@include @- Symbolic links to all the header files gathered in one place + \item \verb@lib @- linkable libraries + \item \verb@script/ @- scripts for compiling code, running experiments, etc. + \item \verb@util/ @- simple utilities used for routine tasks, like random sampling, format conversion etc. \end {itemize} \end{itemize} -\section {Developing your own code using FASTlib} +\section{Overview of some tools} +To help you get started with using FASTlib and MLPack for your applications, we provide a brief summary of THOR and some of the cutting edge methods available in the MLPack. We are in the process of generating user documentation for the rest of the methods in MLPack. In the meantime please refer to the README files in the individual MLPack method folders. + +\subsection{THOR (Tree High-Order Reduce) framework} +THOR stands for Tree High-Order Reduce. THOR aims to solve the class of high-order-reduce problems (although currently only second-order reduce problems). Its goal is to handle the set of high-order reduce problems that can be accelerated using trees. THOR requires only very abstract information about the tree algorithm at hand, and it is designed to have a lot of freedom and flexibility in executing it. In extremely simple terms, when given a system of reduce functions to solve, in the form of template classes, THOR executes them. THOR considers a combination of summary statistics, pruning rules, and update rules, and uses these to execute your tree-based algorithm in any expansion pattern. Parallel is just another expansion pattern. THOR parallelizes very effectively by dividing the query tree (you must label one of your trees as a query tree even if it is not a query-reference problem) into smaller trees. It then solves each query subtree with the root of the reference tree, which in practice seems to have minimal noticeable overhead compared to solving the problem monolithically. Solving queries independently prevents the need of having to relay pruning information among processors. + +Currently, the software implements a depth-first solver and KD-trees, with data and tree-building occurring on the originating machine. It currently sports excellent multithreaded performance for every problem tested. The networked version has good to excellent performance for small clusters (64 processors) depending on how computationally intensive the problem is. Kernel density estimation, two-point correlation, affinity propagation, high-dimensional nearest neighbors, and more will be able to take advantage of more machines you throw at it. + +Please see \cite{boyer2007tho} for more details on THOR. + +\subsection{Kernel Density Estimator} +Kernel density estimation (KDE) is the most widely used and studied nonparametric density estimation method. The 'model' is the reference dataset $\mathcal{R}$ itself, containing the {\it reference points} +indexed by natural numbered. In addition, assume a local kernel function $K_h(\cdot)$ centered upon each reference point, and its scale parameter $h$ (the 'bandwidth'). The common choices for $K_h(\cdot)$ include the spherical, Gaussian and Epanechnikov kernels. We are given the {\it query dataset} $\mathcal{Q}$, which contains {\it query points} whose densities we want to predict. + +For the first time, this package offers the following five variants of +the algorithms for efficiently computing kernel density estimates. All +of these algorithms are implemented in C++, adhering to the strict +FastLib standards. + +\begin{enumerate} +\item{Dual-tree Fast Gauss Transform with $O(D^p)$ expansion for the +Gaussian kernel~\cite{LEE06}: kde.h} +\item{Dual-tree Fast Gauss Transform with $O(p^D)$ expansion for the +Gaussian kernel~\cite{LEE05}: kde.h} +\item{The original fast Gauss transform~\cite{ggstrain}: fgt\_kde.h} +\item{The original improved fast Gauss transform with automatic +parameter tuning~\cite{YANG03}: original\_ifgt.h} +\item{The KDE algorithm using the multidimensional fast Fourier +transform~\cite{wand94}: fft\_kde.h} +\end{enumerate} + +These algorithms are fairly simple to use. Each algorithm has a +separate build-rule. +\subsubsection{Dual-tree FGT} +In order to compile this tool, do: +\begin{verbatim} +fl-build kde\_bin --mode=fast +\end{verbatim} + +In order to run this method, type the following (which consists of +both required and optional arguments) in a single command line: +\begin{align*} +& \mathit{./kde\_bin} \ +\mathit{--data=name\_of\_the\_reference\_dataset}\\ & +\mathit{--query=name\_of\_the\_query\_dataset} \ +\mathit{--kde/bandwidth=0.0130619} \\ & \mathit{--kde/scaling=range} \ +\mathit{--kde/fast\_kde\_output=fast\_kde\_output.txt}\\ & +\mathit{--kde/naive\_kde\_output=naive\_kde\_output.txt} \ +\mathit{--kde/do\_naive}\\ & \mathit{--kde/relative\_error=0.1} \ +\mathit{--kde/multiplicative\_expansion} +\end{align*} + +Explanations for the arguments listed with possible values: + +\begin{enumerate} +\item{data (required): the name of the reference dataset} +\item{query (optional): the name of the query dataset (if missing, the + query dataset is assumed to be the same as the reference dataset)} +\item{kde/bandwidth (required): smoothing parameter used for KDE; this + has to be positive.} +\item{kde/scaling (optional): whether to prescale the dataset - range: +scales both the query and the reference sets to be within the unit +hypercube $[0, 1]^D$ where $D$ is the dimensionality. - none: default +value; no scaling} +\item{kde/do\_naive (optional): run the naive algorithm after the fast +algorithm.} +\item{kde/fast\_kde\_output (optional): if this flag is present, the +approximated density estimates are output to the filename provided +after it.} +\item{kde/naive\_kde\_output (optional): if this flag is present, the + exact density estimates computed by the naive algorithm are output to + the filename provided after it. This flag is not ignored if + --kde/do\_naive flag is not present.} +\item{kde/relative\_error (optional): relative error criterion for the + fast algorithm; default value is 0.1 (0.1 relative error for all + query density estimates)} +\item{kde/multiplicative\_expansion (optional): if present, the KDE +algorithm does $O(p^D)$ expansion for the Gaussian kernel. Otherwise, +it defaults to the $O(D^p)$ expansion.} +\end{enumerate} + +\subsubsection{Original Fast Gauss Transform} +In order to compile this part, do: +\begin{verbatim} +fl-build fgt\_kde\_bin --mode=fast +\end{verbatim} + + To run the FGT-based KDE algorithm, type the +following (which consists of both required and optional arguments) in +a single command line: +\begin{align*} +& \mathit{./fgt\_kde\_bin} \ +\mathit{--data=name\_of\_the\_reference\_dataset}\\ & +\mathit{--query=name\_of\_the\_query\_dataset} \ +\mathit{--kde/bandwidth=0.0130619} \\ & \mathit{--kde/scaling=range} \ +\mathit{--kde/fgt\_kde\_output=fgt\_kde\_output.txt}\\ & +\mathit{--kde/naive\_kde\_output=naive\_kde\_output.txt} \ +\mathit{--kde/do\_naive}\\ & \mathit{--kde/absolute\_error=0.1} +\end{align*} + +Explanations for the arguments listed with possible values: + +\begin{enumerate} +\item{data (required): the name of the reference dataset} +\item{query (optional): the name of the query dataset (if missing, the + query dataset is assumed to be the same as the reference dataset)} +\item{kde/bandwidth (required): smoothing parameter used for KDE; this + has to be positive.} +\item{kde/scaling (optional): whether to prescale the dataset - range: +scales both the query and the reference sets to be within the unit +hypercube $[0, 1]^D$ where $D$ is the dimensionality. - none: default +value; no scaling} +\item{kde/do\_naive (optional): run the naive algorithm after the fast +algorithm.} +\item{kde/fgt\_kde\_output (optional): if this flag is present, the +approximated density estimates are output to the filename provided +after it.} +\item{kde/naive\_kde\_output (optional): if this flag is present, the + exact density estimates computed by the naive algorithm are output to + the filename provided after it. This flag is not ignored if + --kde/do\_naive flag is not present.} +\item{kde/absolute\_error (optional): absolute error criterion for the + fast algorithm; default value is 0.1 (0.1 absolute error for all + query density estimates)} +\end{enumerate} + +\subsubsection{Improved Fast Gauss Transform} +In order to compile this algorithm, do: +\begin{verbatim} +fl-build original\_ifgt\_bin --mode=fast +\end{verbatim} + +For the IFGT-based KDE algorithm, type the +following (which consists of both required and optional arguments) in +a single command line: +\begin{align*} +& \mathit{./orignal\_ifgt\_bin} \ +\mathit{--data=name\_of\_the\_reference\_dataset}\\ & +\mathit{--query=name\_of\_the\_query\_dataset} \ +\mathit{--kde/bandwidth=0.0130619} \\ & \mathit{--kde/scaling=range} \ +\mathit{--kde/ifgt\_kde\_output=ifgt\_kde\_output.txt}\\ & +\mathit{--kde/naive\_kde\_output=naive\_kde\_output.txt} \ +\mathit{--kde/do\_naive}\\ & \mathit{--kde/absolute\_error=0.1} +\end{align*} + +Explanations for the arguments listed with possible values: + +\begin{enumerate} +\item{data (required): the name of the reference dataset} +\item{query (optional): the name of the query dataset (if missing, the + query dataset is assumed to be the same as the reference dataset)} +\item{kde/bandwidth (required): smoothing parameter used for KDE; this + has to be positive.} +\item{kde/scaling (optional): whether to prescale the dataset - range: +scales both the query and the reference sets to be within the unit +hypercube $[0, 1]^D$ where $D$ is the dimensionality. - none: default +value; no scaling} +\item{kde/do\_naive (optional): run the naive algorithm after the fast +algorithm.} +\item{kde/ifgt\_kde\_output (optional): if this flag is present, the +approximated density estimates are output to the filename provided +after it.} +\item{kde/naive\_kde\_output (optional): if this flag is present, the + exact density estimates computed by the naive algorithm are output to + the filename provided after it. This flag is not ignored if + --kde/do\_naive flag is not present.} +\item{kde/absolute\_error (optional): absolute error criterion for the + fast algorithm; default value is 0.1 (0.1 absolute error for all + query density estimates)} +\end{enumerate} + +\subsubsection{FFT-based KDE} +In order to compile this code, do: +\begin{verbatim} +fl-build fft\_kde\_bin --mode=fast +\end{verbatim} +For the FFT-based KDE algorithm, type the +following (which consists of both required and optional arguments) in +a single command line: +\begin{align*} +& \mathit{./fft\_kde\_bin} \ +\mathit{--data=name\_of\_the\_reference\_dataset}\\ & +\mathit{--query=name\_of\_the\_query\_dataset} \ +\mathit{--kde/bandwidth=0.0130619} \\ & \mathit{--kde/scaling=range} \ +\mathit{--kde/fft\_kde\_output=fft\_kde\_output.txt}\\ & +\mathit{--kde/naive\_kde\_output=naive\_kde\_output.txt} \ +\mathit{--kde/do\_naive}\\ & \mathit{--kde/num\_grid\_pts\_per\_dim=128} +\end{align*} + +Explanations for the arguments listed with possible values: + +\begin{enumerate} +\item{data (required): the name of the reference dataset} +\item{query (optional): the name of the query dataset (if missing, the + query dataset is assumed to be the same as the reference dataset)} +\item{kde/bandwidth (required): smoothing parameter used for KDE; this + has to be positive.} +\item{kde/scaling (optional): whether to prescale the dataset - range: +scales both the query and the reference sets to be within the unit +hypercube $[0, 1]^D$ where $D$ is the dimensionality. - none: default +value; no scaling} +\item{kde/do\_naive (optional): run the naive algorithm after the fast +algorithm.} +\item{kde/fft\_kde\_output (optional): if this flag is present, the +approximated density estimates are output to the filename provided +after it.} +\item{kde/naive\_kde\_output (optional): if this flag is present, the + exact density estimates computed by the naive algorithm are output to + the filename provided after it. This flag is not ignored if + --kde/do\_naive flag is not present.} +\item{kde/num\_grid\_pts\_per\_dim (optional): specifies the number of +grid points per each dimension (for discretizing and gridding the +datasets). This is the only way to do any type of error control on +approximated KDE values. In general, the higher the value, more +accurate the density estimates will be. The default value is 128.} +\end{enumerate} + +\subsection{Orthogonal Range Search} +The orthogonal range search problem answers the following question: +Given a set of points $\mathcal{R}$ in $D$-dimensional Euclidean +space, what points lie in the search window: $[l(1), u(1)]\times +[l(2),u(2)]\times \cdots \times [l(D),u(D)]$? + +\subsubsection{FastLib-based Orthogonal Range Search} +This package offers two algorithms - a naive algorithm and a +tree-based algorithm for computing orthogonal range search. All of +these algorithms are implemented in C++, adhering to the strict +FastLib standards. + +In order to compile this package, do: +\begin{verbatim} +fl-build ortho\_range\_search\_bin --mode=fast +\end{verbatim} +In order to run this tool, type the following (which consists of +both required and optional arguments) in a single command line: +\begin{align*} +& \mathit{./ortho\_range\_search\_bin} \ \mathit{--data=dataset} \ +\mathit{--do\_naive} +\end{align*} + +Explanations for the arguments listed with possible values: + +\begin{enumerate} +\item{data (required): the name of the reference dataset} +\item{do\_naive (optional): run the naive algorithm after the fast +algorithm.} +\end{enumerate} +The example code usages are described in ortho\_range\_search.h. + +\subsection{EMST} +The FASTlib EMST code implements a dual-tree version of Bor\r{u}vka's algorithm for finding minimum spanning trees. Bor\r{u}vka's algorithm is similar to Kruskal's well-known algorithm. Instead of connecting the two closest components of the spanning forest, Bor\r{u}vka's algorithm connects each component to its nearest neighbor. We accelerate the computation of these neighbors in each step using a dual-tree search. + +\textbf{Please note:} This algorithm is awaiting publication. It is not intended for widespread distribution. + +\vspace{0.2in} +\noindent \textbf{Command line use.} +\begin{itemize} +\item \textbf{Compile:} \texttt{fl-build emst\_main} +\item \textbf{Run:} \texttt{./emst\_main --data=filename} This will create a file ``output.txt'' with the minimum spanning tree in edge-list form. +\item \textbf{Command-line parameters:} + \begin{itemize} + \item \texttt{string --data} : The name of the input file + \item \texttt{int --dtb/leaf\_size} : Number of points in the leaves of the tree. \emph{Default}=\texttt{1} + \item \texttt{bool --do\_naive} : If true, will perform both the \textsc{DualTreeBoruvka} algorithm and a naive implementation of Bor\r{u}vka's algorithm and will compare the results. + \item \texttt{string --naive/output\_filename} : The name of the file where the edge list of the naive computation will be printed. \emph{Default}=\texttt{naive\_output.txt} + \item \texttt{string --dtb/output\_filename} : The name of the file where the edge list from \textsc{DualTreeBoruvka} will be printed. \emph{Default}=\texttt{output.txt} + \end{itemize} +\end{itemize} + +\begin{figure}[ht] +\fbox{ +\begin{minipage}[t]{0.95\linewidth} +\spcA \textbf{function} boruvka($V$) \newline +\spcB $E = \emptyset$ \newline +\spcB \textbf{while} $|E| < |V| - 1$ \newline +\spcC \textbf{for} all components $C$ \newline +\spcD $(u, v) = \arg \min d(i, j)$ where $i \in C, j \not\in C$\newline +\spcD $E = E \cup (u, v)$ \newline +\spcB \textbf{return} $E$ +\end{minipage} +} +\vspace{-0.1in} +\caption{Pseudocode for Bor\r{u}vka's algorithm.} +\label{boruvka_pseudocode} +\end{figure} + +\vspace{-1.5in} + +\begin{figure}[tbh] +\fbox{ +\begin{minipage}[t]{0.95\linewidth} +\spcA \textbf{init} $E = \emptyset$ \newline +\spcA \textbf{function} dtb($Q^{\textrm{root}}, R^{\textrm{root}}$) \newline +\spcB \textbf{while} $|E| < |V| - 1$ \newline +\spcC $\forall Q, a^u(Q) = \infty, \forall q, a(q) = \infty$ \newline +\spcC cnn($Q^{\textrm{root}}, R^{\textrm{root}}$) \newline +\spcC for all $q$, $E = E \cup n(q)$ \newline +\spcB \textbf{end}\newline +\spcB \textbf{return} $E$ \newline +\newline +\spcA \textbf{function} cnn($Q, R$) \newline +\spcB \textbf{if} $a^u(Q) < d^l(Q, R)$, \textbf{return} \newline +\spcB \textbf{else if} $Q$ and $R$ are fully connected, \textbf{return} \newline +\spcB \textbf{else if} $(Q, R) = (\{q\}, \{r\})$ \newline +\spcC \textbf{if} $d(q, r) < a(q)$ \newline +\spcD $a(q) = d(q, r), n(q) = r$ \newline +\spcD \textbf{if} $a(q) < a^u(Q)$ \newline +\spcE $a^u(Q) = a(q)$ \newline +\spcB \textbf{else} \newline +\spcC prioritize $\{R^1, R^2\} = \{R^L, R^R\}$ by $d^l(Q^L, \cdot)$ \newline +\spcD cnn($Q^L, R^1$), cnn($Q^L, R^2$) \newline +\spcC prioritize $\{R^1, R^2\} = \{R^L, R^R\}$ by $d^l(Q^R, \cdot)$ \newline +\spcD cnn($Q^R, R^1$), cnn($Q^R, R^2$) \newline +\spcC $a^u(Q) = \max\{a^u(Q^L), a^u(Q^R)\}$ +\end{minipage} +} +\caption{Pseudocode for our \textsc{DualTreeBoruvka} algorithm. $a^u(Q)$ represents the upper bound on candidate neighbors found so far for node $Q$, and $d^l(Q, R)$ represents the minimum distance between the bounding boxes of $Q$ and $R$. $n(q)$ is the current candidate for the nearest neighbor of $q$, and $a(q) = d(q, n(q))$.} +\label{DTB} +\end{figure} + + +\chapter {Code development using FASTlib} -\subsection {Using the build tool} +This chapter provides a very brief tutorial of modifying build files, using FASTexec and inbuilt debugging tools etc. to help you get started with writing your own code using FASTlib. For more extensive tutorial please refer to the FASTlib developer tutorial and API reference manual. + +\section {Using the build tool} As stated earlier, building is done via the fl-build tool, which stands for FASTlib build. This tool reads through very short files which just have a list of sources (.cc files), headers (.h files), and other sub-packages it depends on, and produces a Makefile, which it runs automatically. @@ -263,7 +662,7 @@ fl-build mybinary --mode=fast --cflags="-march=pentium4 -DCOAGULATE" \end{verbatim} -\subsubsection{Writing build files} +\subsection{Writing build files} The fl-build tool looks in the current directory for a file called build.py. The build file is executed as straight Python code, with access to a few specific functions defined by the build system, that correspond to "meta build rules". In processing these, the build system recursively pulls build files from other directories and resolves the dependencies. A Makefile is then created in your current directory, which fl-build automatically runs for you. @@ -298,7 +697,7 @@ binrule( ) \end{verbatim} -\subsection{Use of C++} +\section{Use of C++} FASTlib is C++, but only to an extent. If you are familiar with C, you will have no problem. The things we use from C++ is: \begin{itemize} @@ -321,7 +720,7 @@ for (index_t i = 0; i < 10; i++) { \end{verbatim} Some quick notes before we move on. The matrix must be initialized before it is usable, but keep in mind everything is freed by default. Caution -- if you declare a matrix and never initialize it, the program will crash at the end of the function. In debug mode, many FASTlib classes will let you know that this is happening. Next, the \verb= index_t = type is usually an regular int, but is wired through the system to become 64-bit if you tell it to. -\subsection{Copying and Aliasing} +\section{Copying and Aliasing} C++ is infamous for its desire to make copies of everything. If you forget to pass a parameter as a constant reference (const Classname\&), everything will be copied, but sometimes, there is just no way to get around of it. By avoiding constructors, we find copying is usually not needed. To avoid accidental copies of your class, put \verb= FORBID_COPY = at the beginning like this: \begin{verbatim} @@ -353,7 +752,7 @@ An example is shown here: original.Init(99, 99); \end{verbatim} -\subsection{Debugging} +\section{Debugging} C++, and equally C, can sometimes make it easy to shoot yourself in the foot. To help you avoid this, we made debugging an important part of FASTlib. @@ -366,7 +765,7 @@ To use debugging yourself, plaster your code with the following: \end{itemize} You can safely leave these in at no cost in non debug mode. To set verbosity level to 3.0, you would specify the command line argument: \verb= --debug/verbosity_level=3.0 =.See the Doxygen for base/debug.h for more information. -\subsection{FASTexec - Command-line parameters and experimentation} +\section{FASTexec - Command-line parameters and experimentation} We felt it is important that machine learning researchers can run a lot of experiments without too much trouble. Parameter passing is integral to the experimentation process, so we unified these. @@ -479,7 +878,7 @@ We admit this is a lot of text, but when you later comb through the results, you \end{itemize} This output could indeed just be an s-expression, or it could be an attribute-less XML file. We chose this path-value dump format because it is stateless -- i.e. anyone can process it with a little bit of grep. Corruption in the file will only affect it until the next newline. -\subsubsection{Running automated experiments and collecting results} +\subsection{Running automated experiments and collecting results} Running experiments and collecting results is made simpler using FASTexec. After using the FASTexec code to store output variables in the datastore, you can use FASTexec to run multiple experiments. If you type the command: \begin{verbatim} @@ -495,19 +894,19 @@ You can try an example with the K-nearest-neighbors classifier example in u/exam fx-latex knn_k ./main /params/knn/k /kfold/results/p_correct --preview \end{verbatim} -\subsection{Little gotchas} +\section{Some tips} -\subsubsection{Success and failure} +\subsection{Success and failure} The \verb= success_t type = in \verb= base/common.h = defines our standard for indicating success or failure. Rather than assuming 1 or 0 or -1 indicates something or other, we explicitly return \verb= SUCCESS_PASS = (succeeded), \verb= SUCCESS_FAIL = (failed), or \verb= SUCCESS_WARN = (something was suboptimal). -\subsubsection{Basic types} +\subsection{Basic types} You will notice heavy use of \verb= index_t = (in \verb= base/scale.h =) rather than integers. For practical purposes, \verb= index_t = is a signed integer -- signed so you can loop over >= 0. On 32-bit and 64-bit Intel/AMD machines, this will be 32-bits, which is the fastest int for both systems and is relatively compact. But if you want to operate on datasets larger than a few gigabytes, you can define the \verb= SCALE_LARGE = macro, and these will instantly switch to the largest size your computer can address. Also, the \verb= base/basic_types.h = file (it will be in bin/ since it is auto-generated) defines standard int16, int32, int64, uint16, uint32, uint64 types. -\subsubsection{Printf versus Streams} +\subsection{Printf versus Streams} We operate under the assumption that more of our audience is familiar with C I/O than with C++ I/O, especially when it comes to fancy floating-point formatting. The caveat is that printf only works with native types like int, short, long. To print an \verb= index_t =, you use: \begin{verbatim} @@ -522,208 +921,10 @@ The LI macro is a string that will have the suitable "l" modifier for \verb= ind \end{itemize} Alternately, you can just cast the variable to a native type like (int) (short) or (long), if you want to be lazy. - -\chapter {Complete code development walkthrough - Dual-Tree k-NN} -This chapter is intended for people who have read the FASTlib Tutorial and successfully compiled and run the example code. You should also understand how a dual-tree all nearest neighbors algorithm works, since this is assumed. - -This should help you get started on understanding the basic features of the library. For complete documentation, please see the Doxygen file. - -\section{Walkthrough} -\subsection{build.py} -The build.py file is a necessary part of any FASTlib directory. It tells the fl-build script how to compile your code and link to the rest of the library. Essentially, the build.py functions like a Makefile, but is much easier to understand and write. - -There are two important kinds of entry in build.py files: binrules and librules. The distinction between these is that binrules create stand-alone executables (somewhere in their code is the main function) while librules are for code used in linking (no main). It is usually a good idea for the bulk of your project to be compiled with a librule, linked to by a simiple binrule in the same build.py: - -\subsection{Librule} -\begin{verbatim} - librule( - name = "allnn", - sources = ["allnn.cc"], - headers = ["allnn.h"], - deplibs = ["fastlib:fastlib"], - tests = ["allnn_test.cc"] - ) -\end{verbatim} -name - the name of the library being created. If this line is omitted, fl-build will use the name of the directory as a default.\\ -sources - The .c or .cc files necessary. This line can be omitted if there are none.\\ -headers - The .h files necessary. This line can also be omitted if there are none.\\ -deplibs - Other libraries linked to by the current one. The name before the colon is the directory within fastlib that contains the library, the name after the colon is the name of the library itself. :\$LIBNAME indicates that the library is in the same directory as the build.py file. -tests - A file containing unit tests. If this line is in the librule, you can compile the unit tests with fl-build allnn\_test. -\subsection{Binrule} - -\begin{verbatim} - binrule( - name = "allnn_main", - sources = "allnn_main.cc", - headers = "allnn_main.h", - deplibs = [":allnn"] - ) -\end{verbatim} -The tags are similar as above. Running "fl-build allnn\_main" will create an executable called "allnn\_main". - -\subsection{allnn\_main.cc} -Our main file contains only the main function. In general, FASTlib code should have very simple main functions. Our main function reads in the command line arguments, loads the data, and saves the results. All of the computation is done by an AllNN object, defined in allnn.h. - -\section{FASTexec} -See FASTexec Tutorial for a more detailed discussion of FASTexec. -FASTlib code starts by calling: - -\begin {verbatim} fx_init(argc, argv);\end{verbatim} -which initializes the FASTexec system. It must be accompanied by: - -\begin{verbatim} fx_done(argc, argv);\end{verbatim} -at the end of the main function. - -\section {Reading and writing data} -Our function determines the files containing the query and reference data. We accomplish this with: -\begin{verbatim} -const char* queries_file_name = fx_param_str_req(NULL, "q"); -Matrix queries; -data::Load(queries_file_name, &queries); -end{verbatim} -The only other parameters our program reads are a boolean: -\begin{verbatim} -int do_naive = fx_param_bool(NULL, "do_naive", 0); -\end{verbatim} -and the output filename: -\begin{verbatim} -const char* output_filename = fx_param_str(NULL, "output_filename", "output.csv"); -\end{verbatim} -In general, data can be read in from the command line using -\begin{verbatim} -fx_param_$TYPE_req(module, "name"); -\end{verbatim} -for required parameters (the program will terminate with an error if it is not specified). Alternatively, one can specify a default value with: -\begin{verbatim} -fx_param_$TYPE(module, "name", $DEFAULT_VALUE); -\end{verbatim} -In both cases, the parameter is given on the command line as -\begin{verbatim} ---name=$VALUE" -\end{verbatim} - -\section{Modules} -The first argument to each of these functions indicates a module. Modules contain parameters, results, and timing information for various portions of the program. For a detailed explanation of modules, consult the FASTexec Tutorial. - -For this code, we only utilize a few modules. When NULL is passed as a module, it indicates the root module of FASTexec. So, the line: -\begin{verbatim} -const char* output_filename = fx_param_str(NULL, "output_filename", "output.csv"); -\end{verbatim} -indicates that \begin{verbatim}--output_filename="some_file.csv"\end{verbatim} will appear on the command line (i.e. specified in the root module's /params folder), or else "output.csv" will be used as the default. - -We also create a module for our AllNN object. The line: -\begin{verbatim}fx_submodule(NULL, "allnn", "allnn_module");\end{verbatim} -creates a new module called "allnn\_module", copies all parameters -stored under allnn to this module, and places the entire thing under -the root directory (NULL). - -\section{Timers} -Timers are also handled by FASTexec. They are stored in the /timers section of a module. We can start a timer with: -\begin{verbatim} -fx_timer_start(allnn_module, "dual_tree_computation"); -\end{verbatim} -and stop it with -\begin{verbatim} -fx_timer_stop(allnn_module, "dual_tree_computation"); -\end{verbatim} - -These timers will print as a part of the final output of the program, and are suitable for parsing with the fx-run commands. -Timers, modules, and command line parameters can be accessed from any part of the program, not just main. - -\section{Development Walkthrough} -You are developing code. What to do, step by step: - -Step 0: You should have read the FASTlib tutorial and successfully compiled and run the example.\\ - -Step 1: Your code needs a home. You will work on it in your user directory, i.e.: u/plato/allnn\\ - -Step 2: You need a build.py file, which tells fl-build what to do to compile your work. It is the equivalent of a Makefile, but a bit easier to understand. - -There are two important kinds of entry in build.py files: binrules and librules. The distinction between these is that binrules create stand-alone executables (somewhere in their code is the main function) while librules are for code used in linking (no main). It is usually a good idea for the bulk of your project to be compiled with a librule, linked to by a simiple binrule in the same build.py: - -\begin{verbatim} - librule( - name = "allnn", - sources = ["allnn.cc"], - headers = ["allnn.h"], - deplibs = ["fastlib:fastlib"], - tests = ["allnn_test.cc"] - ) - - binrule( - name = "allnn_main", - sources = "allnn_main.cc", - headers = "allnn_main.h", - deplibs = [":allnn"] - ) -\end{verbatim} - -Note that "tests" in the librule allows you to compile your unit tests with "fl-build allnn\_test". - -Step 3: Now we need to start writing the code. We will start with allnn\_main.cc by incluidng allnn.h at the top and writing a main function: - -\begin{verbatim} - #include "allnn.h" - int main(int argc, char *argv[]) { - fx_init(argc, argv); - ... - fx_done(); - return 0; - } -\end{verbatim} - -FASTlib main functions should always begin and end by initializing and finalizing fx, or FASTexec, which manages command line input among other things. - -In our particular project, the first logical thing to do is to load the data. We need to get the input file names out of the command line arguments and then to use a library function that reads matrices. - -\begin{verbatim} - const char *q_filename = fx_param_str_req(NULL, "queries"); - const char *r_filename = fx_param_str_req(NULL, "references"); - Matrix q; - Matrix r; - data::Load(q_filename, &q); - data::Load(r_filename, &r); -\end{verbatim} - -We organize all of our project's tasks into a class called AllNN. After declaring an object of this class, we initialize it with the two data sets and a submodule, which serves to pass it its own parameters from the command line. - -\begin{verbatim} - struct datanode *allnn_mod = fx_submodule(NULL, "allnn", "allnn_mod"); - AllNN allnn; - allnn.Init(q, r, allnn_mod); -\end{verbatim} -We must declare a local variable to receive the results of computation. -\begin{verbatim} - ArrayList results; - allnn.ComputeNeighbors(&results); -\end{verbatim} -We emit result by printing to a file. -\begin{verbatim} - const char *o_filename = fx_param_str(NULL, "out", "out.csv"); - FILE* o_file = fopen(o_filename, "w"); - ot::Print(results, o_file); -\end{verbatim} - -Step 4: Moving to allnn.h, the first thing to do include the rest of FASTlib within appropriate inclusion guards: - -\begin{verbatim} - #ifndef ALLNN_H - #define ALLNN_H - #include "fastlib/fastlib.h" - ... - #endif -\end{verbatim} - -Make sure you include "fastlib/fastlib.h" as opposed to "fastlib.h" so the complier can properly find the file.\\ - -Step n: Write your unit tests. - -NOTE: This chapter still need more work. - -\chapter {Examples of some common tasks - FASTlib Cookbook} - -\chapter {Code Style Suggestion for developers} -The coding style suggestions in this chapter stem from our own development expereince and the style used to develop FASTlib. It is recommended that you use the suggestions herein for your code development if you would like to contribute your code to be part of the standard FASTlib distribution. You could also choose to skip this chapter. - \chapter {Beyond this Document} + +FASTlib has a growing body of documentation. We have an online documentation of all the supported classes and API (currently temporarily available at http://www.cc.gatech.edu/\~nadeem/fastlib). There is also a code walkthrough tutorial that shows how to implement a simple machine learning method (k-NN) starting from scratch. A cook-book with tutorial and code snippets for doing various common tasks is also available. We will bringing these together through a web-page to support FASTlib. + +\bibliographystyle{plain} +\bibliography{fastlib} \end{document} diff --git a/fastlib/u/nadeem/FASTlib_manual/Fastlib_Archi.png b/fastlib/u/nadeem/FASTlib_manual/Fastlib_Archi.png index a600a3760dfe264e16552d7aa554522375cfc0bb..ff98c3ebbc7648ee7bb9c85e1bcff1fa5c3d2453 100755 GIT binary patch literal 29142 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%0A?)!3r_HwMDqd2(7Ot3|GLIpjzRTj1*Et6!Lc zWLy$qcHWhPck|Ha1Rcc|e&d-h`?_#v98HJim+$yX8!xwt(ZS_=N<4Z?rmP!(OAT%L zsYXpTvTCmj;wB7+bCW0eBnAziwn$^z2`(F^&tDUI##}<26B#bW`gt!;PgT5+_7|IA z9s-A@LL7gQOnBSIO0M6$?iOA_KJ~)9_=P|C;Lm5cD8-j&hh1@RkMIFIce8qq{hR!D zyN-KEKaY2G?>$9`P~WJQb`V0$@543^PfkuwX%DFb~Nm{!@dlan1_uouh~GL_r!q&-~1d z)6enk#gpktTMk}q##TP)ffxkX(4%1pT7*MpW&puyjMm<8yR@%s<@JHBVZ7nIu7fyC z`!v6Z|HIsrcH;Aew@R^BWo|Tuhi80B>-b%2g*DMNZne>5EVR;7T%bas_pOxH5ylMd z!oP^w*%ayttpnG1?G%|4_jzsSMV9DKSQRBDCCl>@OB0=AOMgpX5;r+3UMAeY8Z^|X z9aan^xCyXWOqR5;LQUvIIWE}ZW0vZ-10JHZXga7~l diff --git a/fastlib/u/nadeem/FASTlib_manual/fastlib.bib b/fastlib/u/nadeem/FASTlib_manual/fastlib.bib new file mode 100644 index 0000000000..4ad91be2be --- /dev/null +++ b/fastlib/u/nadeem/FASTlib_manual/fastlib.bib @@ -0,0 +1,107 @@ +@STRING{AI = "Artificial Intelligence"} +@STRING{CACM = "Communications of the Association for Computing Machinery"} +@STRING{JACM = "Journal of the ACM"} +@STRING{PAMI = "IEEE Transactions on Pattern Analysis and Machine + Intelligence"} + +% Bibliography + +@article{gray2000nbp, + title={{N-Body.problems in statistical learning}}, + author={Gray, A. and Moore, A.}, + journal={NIPS}, + volume={4}, + pages={521--527}, + year={2000} +} + +@book{anderson1999lug, + title={{LAPACK Users' guide}}, + author={Anderson, E. and McKenney, A. and Sorensen, D. and Bai, Z. and Bischof, C. and Blackford, LS and Demmel, J. and Dongarra, J.J. and Du Croz, J. and Hammarling, S. and others}, + year={1999}, + publisher={Society for Industrial and Applied Mathematics Philadelphia, PA, USA} +} + +@article{heroux2005otp, + title={{An overview of the Trilinos project}}, + author={Heroux, M.A. and Phipps, E.T. and Salinger, A.G. and Thornquist, H.K. and Tuminaro, R.S. and Willenbring, J.M. and Williams, A. and Stanley, K.S. and Bartlett, R.A. and Howle, V.E. and others}, + journal={ACM Transactions on Mathematical Software (TOMS)}, + volume={31}, + number={3}, + pages={397--423}, + year={2005}, + publisher={ACM Press New York, NY, USA} +} + + +@incollection{LEE05, + title = {Dual-Tree Fast Gauss Transforms}, + author = {Dongryeol Lee and Alexander Gray and Andrew Moore}, + booktitle = {Advances in Neural Information Processing Systems 18}, + editor = {Y. Weiss and B. Sch\"{o}lkopf and J. Platt}, + publisher = {MIT Press}, + address = {Cambridge, MA}, + pages = {747--754}, + year = {2006} +} + +@incollection{LEE06, +title = {Faster Gaussian Summation: Theory and Experiment}, +Author = {Dongryeol Lee and Alexander Gray}, +booktitle = {Proceedings of the Twenty-second Conference on Uncertainty in Artificial Intelligence}, +year={2006} +} + + +@Article{ggstrain, +Author = "L. Greengard and J. Strain", +Title = "{The Fast Gauss Transform}", +Journal = "SIAM Journal of Scientific and Statistical Computing", +Volume = "12(1)", +Year = "1991", +Pages = "79-94" +} + +@article{YANG03, +Author="C. Yang and R. Duraiswami and N.~A. Gumerov and L. Davis", +title="Improved Fast Gauss Transform and Efficient Kernel +Density Estimation", +journal="International Conference on Computer Vision", +year="2003" +} + +@Article{wand94, +Author = "M. P. Wand", +Title = "{Fast Computation of Multivariate Kernel Estimators}", +Journal = "Journal of Computational and Graphical Statistics", +Year = "1994" +} + +@book{kai2000le, + Author = {Kailath, T. and Sayed, A. H. and Hassibi, B.}, + Title = {Linear Estimation}, + Publisher = {Prentice Hall}, + Year = {2000} +} + +@ARTICLE{bell95, + author = {A. J. Bell and T. J. Sejnowski}, + title = {An information maximization approach to blind separation and blind + deconvolution to blind source separation and blind deconvolution}, + journal = {Neural Computation}, + year = {1995}, + volume = {7}, + pages = {1129-1159}, + number = {6} +} + +@article{hyvarinen1999far, + title={{Fast and Robust Fixed-Point Algorithms for Independent +Component Analysis}}, + author={Hyv{\"a}rinen, A.}, + journal={IEEE Trans. on Neural Networks}, + volume={10}, + number={3}, + pages={626--634}, + year={1999} +}